/* The Wall's own theme: a clean, high-contrast palette in the spirit of
 * Instagram's whites and Blind's cool grays, with one violet accent doing all
 * the work links and focus states need. No licensed type — a plain system
 * stack, with weight rather than a second family telling titles from body
 * text apart.
 */

:root {
  /* colour */
  --tw-color__primary__base: #5851ff;
  --tw-color__primary__base--state-1: #4640cc;
  --tw-color__primary__base--state-2: #3a35ad;
  --tw-color__primary__surface: #edebff;
  --tw-color__primary-cta__base: #141414;
  --tw-color__primary-cta__on-base: #ffffff;
  --tw-color__text__base: #141414;
  --tw-color__text__subtle: #6b7280;
  --tw-color__background__base: #fff;
  --tw-color__background__subtle: #fafafa;
  --tw-color__background__sunken: #f1f2f4;
  --tw-color__border__base: #dbdbdb;
  --tw-color__border__subtle: #00000014;
  --tw-color__border__bold: #a8a8a8;
  --tw-color__success__base: #0d7d4d;
  --tw-color__success__surface: #e3f6ec;
  --tw-color__warning__surface: #fff4d6;
  --tw-color__warning__on-surface: #7a5b00;
  --tw-color__alert__base: #ed4956;
  --tw-color__alert__surface: #fdebec;
  --tw-color__utility__focus-ring: #8d85ff;

  /* type — one system stack; weight carries the distinction a second
     licensed family used to. */
  --tw-type__family__text: -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif;
  --tw-type__family__title: var(--tw-type__family__text);
  --tw-type__weight__base: 400;
  --tw-type__weight__strong: 600;
  --tw-type__letterspacing__action: 0.01em;

  /* radius */
  --tw-radius__xsmall: 4px;
  --tw-radius__small: 6px;
  --tw-radius__medium: 8px;
  --tw-radius__large: 12px;
  --tw-radius__xlarge: 16px;
  --tw-radius__xxlarge: 20px;
  --tw-radius__circular: 999px;

  /* spacing — 8px base */
  --tw-spacing__micro__small: 8px;
  --tw-spacing__micro__medium: 12px;
  --tw-spacing__micro__large: 16px;
  --tw-spacing__macro__small: 24px;
  --tw-spacing__macro__medium: 32px;

  --tw-utilities__focus-ring__thickness: 3px;

  --shadow: 0 1px 2px rgba(20, 20, 20, 0.06), 0 4px 12px rgba(20, 20, 20, 0.05);
  --shadow-hover: 0 2px 4px rgba(20, 20, 20, 0.08), 0 12px 28px rgba(20, 20, 20, 0.1);
  --narrow: 34rem;
  --wide: 76rem;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--tw-color__background__subtle);
  color: var(--tw-color__text__base);
  font-family: var(--tw-type__family__text);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

a { color: var(--tw-color__primary__base); }

h1, h2, h3 {
  font-family: var(--tw-type__family__title);
  font-weight: 500;
  letter-spacing: -0.01em;
}

.skip { position: absolute; left: -999px; top: 0; }
.skip:focus {
  left: 8px;
  top: 8px;
  z-index: 20;
  background: var(--tw-color__background__base);
  padding: 10px 14px;
  border-radius: var(--tw-radius__medium);
}

:focus-visible {
  outline: var(--tw-utilities__focus-ring__thickness) solid var(--tw-color__utility__focus-ring);
  outline-offset: 1px;
}

/* ---------- header ---------- */

.top {
  background: var(--tw-color__background__base);
  border-bottom: 1px solid var(--tw-color__border__subtle);
  position: sticky;
  top: 0;
  z-index: 10;
}

.top-inner {
  max-width: var(--wide);
  margin: 0 auto;
  padding: 14px var(--tw-spacing__macro__small);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--tw-spacing__micro__large);
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--tw-type__family__title);
  font-weight: 600;
  font-size: 1.0625rem;
  color: var(--tw-color__text__base);
  text-decoration: none;
}

.logo-mark {
  width: 26px;
  height: 24px;
  fill: var(--tw-color__primary__base);
  flex: none;
}

nav {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}

nav a {
  color: var(--tw-color__text__base);
  text-decoration: none;
  padding: 8px 12px;
  border-radius: var(--tw-radius__medium);
  font-weight: var(--tw-type__weight__strong);
  font-size: 0.9375rem;
}

nav a:hover { background: var(--tw-color__background__subtle); }

.who {
  color: var(--tw-color__text__subtle);
  font-size: 0.875rem;
  padding-left: 10px;
  max-width: 12rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Add a photo, parked above the thumb on a phone. Hidden on wide screens, where
 * the header link is already visible and a floating button would just be noise. */
.add-fab {
  display: none;
  position: fixed;
  right: 14px;
  bottom: calc(14px + env(safe-area-inset-bottom, 0px));
  z-index: 9;
  align-items: center;
  gap: 8px;
  padding: 13px 20px 13px 16px;
  border-radius: var(--tw-radius__circular);
  background: var(--tw-color__primary__base);
  color: var(--tw-color__background__base);
  font-family: var(--tw-type__family__title);
  font-weight: var(--tw-type__weight__strong);
  letter-spacing: var(--tw-type__letterspacing__action);
  font-size: 0.9375rem;
  text-decoration: none;
  box-shadow: 0 8px 24px rgba(20, 20, 20, 0.32);
}

.add-fab:active { background: var(--tw-color__primary__base--state-2); }
.add-fab-plus { font-size: 1.25rem; line-height: 1; font-weight: 400; }

/* An open comment popover owns the bottom of the screen while it is up. */
body.panel-open .add-fab { display: none; }

form.inline { display: inline-flex; }

/* ---------- buttons ---------- */

button {
  font-family: var(--tw-type__family__title);
  font-size: 0.9375rem;
  font-weight: var(--tw-type__weight__strong);
  letter-spacing: var(--tw-type__letterspacing__action);
  background: var(--tw-color__background__base);
  color: var(--tw-color__text__base);
  border: 1px solid var(--tw-color__border__base);
  padding: 9px 18px;
  border-radius: var(--tw-radius__circular);
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, transform 120ms ease;
}

button:hover { background: var(--tw-color__background__subtle); }
button:active { transform: translateY(1px); }

/* The primary call to action is near-black, not the accent violet — that
 * stays reserved for links, the active tab, and focus states. */
button.primary, .btn-link.primary {
  background: var(--tw-color__primary-cta__base);
  border-color: var(--tw-color__primary-cta__base);
  color: var(--tw-color__primary-cta__on-base);
}

button.primary:hover, .btn-link.primary:hover { background: #2b2b2b; border-color: #2b2b2b; }

.btn-link.primary {
  display: inline-block;
  text-decoration: none;
  font-family: var(--tw-type__family__title);
  font-weight: var(--tw-type__weight__strong);
  letter-spacing: var(--tw-type__letterspacing__action);
  font-size: 0.9375rem;
  padding: 9px 18px;
  border-radius: var(--tw-radius__circular);
}

button.big { padding: 12px 24px; font-size: 1rem; }

button.ghost {
  background: transparent;
  border-color: transparent;
  color: var(--tw-color__text__subtle);
  padding: 8px 12px;
}
button.ghost:hover {
  background: var(--tw-color__background__subtle);
  color: var(--tw-color__text__base);
}

button.danger {
  color: var(--tw-color__alert__base);
  border-color: var(--tw-color__border__base);
  background: transparent;
}
button.danger:hover {
  background: var(--tw-color__alert__surface);
  border-color: var(--tw-color__alert__base);
}

.chip { padding: 5px 13px; font-size: 0.8125rem; }

/* ---------- banners ---------- */

.banner {
  background: var(--tw-color__primary__surface);
  padding: 9px var(--tw-spacing__macro__small);
  font-size: 0.875rem;
  text-align: center;
}

.banner.warn { background: var(--tw-color__warning__surface); color: var(--tw-color__warning__on-surface); }

.flash {
  max-width: var(--wide);
  width: 100%;
  margin: var(--tw-spacing__micro__large) auto 0;
  padding: 12px var(--tw-spacing__micro__large);
  background: var(--tw-color__success__surface);
  color: var(--tw-color__success__base);
  border-radius: var(--tw-radius__medium);
  font-size: 0.9375rem;
}

.flash.error { background: var(--tw-color__alert__surface); color: var(--tw-color__alert__base); }

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

.wrap {
  width: 100%;
  max-width: var(--narrow);
  margin: 0 auto;
  padding: var(--tw-spacing__macro__medium) var(--tw-spacing__macro__small) 64px;
  flex: 1;
}

.wrap.wide { max-width: var(--wide); }

h1 { font-size: 1.75rem; line-height: 1.2; margin: 0 0 6px; }
h2 { font-size: 1.125rem; margin: 0 0 12px; }

.lede { color: var(--tw-color__text__subtle); margin: 0; }
.empty { color: var(--tw-color__text__subtle); }
.hint { color: var(--tw-color__text__subtle); font-size: 0.8125rem; margin: 0; }

.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
}

.panel {
  background: var(--tw-color__background__base);
  border: 1px solid var(--tw-color__border__subtle);
  border-radius: var(--tw-radius__xlarge);
  padding: 28px;
  box-shadow: var(--shadow);
}

.panel + .panel { margin-top: 18px; }
.panel > h2:first-child { margin-top: 0; }
.panel h3 { margin: 22px 0 8px; font-size: 0.9375rem; }

.manage-panel { margin-bottom: 18px; }
.manage-row { display: flex; align-items: center; gap: 16px; margin-top: 10px; flex-wrap: wrap; }
.manage-row img { border-radius: var(--tw-radius__medium); border: 1px solid var(--tw-color__border__subtle); flex: none; }
.manage-link-box { flex: 1 1 240px; min-width: 0; }
.manage-link-box input {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 0.8125rem;
  padding: 10px 12px;
  border: 1px solid var(--tw-color__border__base);
  border-radius: var(--tw-radius__medium);
  background: var(--tw-color__background__sunken);
  color: var(--tw-color__text__base);
}

/* Numbered build steps, and the key/value list for the request fields. */
.steps { margin: 10px 0 0; padding-left: 22px; }
.steps li { margin-bottom: 8px; }

.kv {
  display: grid;
  grid-template-columns: minmax(8rem, auto) 1fr;
  gap: 6px 16px;
  margin: 0;
  font-size: 0.875rem;
}

.kv dt { color: var(--tw-color__text__subtle); }
.kv dd { margin: 0; }

.mod-wall-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.mod-wall-table th {
  text-align: left;
  padding: 8px 10px;
  color: var(--tw-color__text__subtle);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--tw-color__border__base);
}

.mod-wall-table td {
  padding: 8px 10px;
  border-bottom: 1px solid var(--tw-color__border__subtle);
}

/* A secret meant to be copied by hand onto a phone, so it gets room to breathe
 * and never wraps mid-token. */
.keyline { margin: 0 0 10px; }

.key {
  display: inline-block;
  padding: 8px 12px;
  border: 1px solid var(--tw-color__border__base);
  border-radius: var(--tw-radius__medium);
  background: var(--tw-color__background__sunken);
  font-size: 1rem;
  letter-spacing: 0.04em;
  word-break: break-all;
  user-select: all;
}

/* ---------- tabs + live badge ---------- */

.tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  border-bottom: 1px solid var(--tw-color__border__subtle);
  margin: var(--tw-spacing__macro__small) 0;
}

.tabs a {
  padding: 10px 14px;
  color: var(--tw-color__text__subtle);
  text-decoration: none;
  font-family: var(--tw-type__family__title);
  font-weight: var(--tw-type__weight__strong);
  font-size: 0.9375rem;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.tabs a:hover { color: var(--tw-color__text__base); }

.tabs a.active {
  color: var(--tw-color__text__base);
  border-bottom-color: var(--tw-color__primary__base);
}

.live {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.75rem;
  font-weight: var(--tw-type__weight__strong);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--tw-color__text__subtle);
}

.live .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--tw-color__success__base);
  animation: pulse 2s ease-in-out infinite;
}

.live.stale .dot { background: var(--tw-color__text__subtle); animation: none; }

.live-toggle {
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 4px 10px;
  color: var(--tw-color__text__subtle);
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.2; }
}

/* ---------- the grid ---------- */

/* auto-fill reflows 1 -> 4+ columns on its own; tiles stay square. The 15rem
 * track sits inside the 156-256px tile width range that grid clamps to. */
.feed {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
  gap: var(--tw-spacing__micro__large);
  align-items: start;
}

/* Instagram-grid style: the name and controls sit on the thumbnail under a
 * gradient rather than in a strip below it, so the photo gets the whole tile. */
.tile {
  position: relative;
  background: var(--tw-color__primary-cta__base);
  border-radius: var(--tw-radius__xxlarge);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: opacity 300ms ease, transform 300ms ease, box-shadow 200ms ease;
}

.tile:hover { box-shadow: var(--shadow-hover); transform: translateY(-2px); }

.tile-shot {
  display: block;
  aspect-ratio: 1 / 1;
  background: var(--tw-color__background__sunken);
  overflow: hidden;
}

.tile-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 400ms ease;
}

.tile:hover .tile-shot img { transform: scale(1.03); }
.tile.open:hover .tile-shot img { transform: none; }

.tile-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}

.tile-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(20, 20, 20, 0.55);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  padding-left: 3px;
}

.tile-badge {
  position: absolute;
  top: 10px;
  left: 10px;
  background: rgba(20, 20, 20, 0.68);
  color: #fff;
  font-size: 0.625rem;
  font-weight: var(--tw-type__weight__strong);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: var(--tw-radius__circular);
}

/* The one place a tile names its wall: the cross-wall trending grid on the
 * home page. Inside a single wall's own feed this would just be noise, so
 * callers opt in with show_wall_badge rather than it being automatic. */
.tile-badge-wall {
  left: auto;
  right: 10px;
  max-width: calc(100% - 84px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-transform: none;
  letter-spacing: normal;
  text-decoration: none;
  background: var(--tw-color__primary__base);
}

.tile-overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 36px 14px 12px;
  color: #fff;
  background: linear-gradient(
    to top,
    rgba(20, 20, 20, 0.92) 0%,
    rgba(20, 20, 20, 0.66) 45%,
    rgba(20, 20, 20, 0) 100%
  );
  /* The gradient is decoration: clicks fall through to the photo link, and only
   * the real controls inside it take pointer events. */
  pointer-events: none;
}

.tile-overlay a,
.tile-overlay button,
.tile-overlay form { pointer-events: auto; }

.tile-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

/* The text block flows first, then the controls; spacing lives on the rows so
 * the vibe and caption can each be absent without leaving a gap behind. */
.tile-overlay .tile-row { margin-top: 9px; }

/* One line of identity, ordered by weight rather than by rules or boxes: the
 * name reads first, the handle and age recede. Nothing here has a background. */
.tile-meta {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 5px;
  font-size: 0.8125rem;
  min-width: 0;
}

.tile-who {
  font-weight: var(--tw-type__weight__strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tile-at,
.tile-sep,
.tile-time {
  color: rgba(255, 255, 255, 0.62);
  font-size: 0.75rem;
  font-weight: var(--tw-type__weight__base);
  flex: none;
}

/* The handle is the first thing to go when the tile runs out of room; the name
 * and the age are the parts that carry information. */
.tile-at {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 0 1 auto;
}

.tile-vibe {
  margin: 5px 0 0;
  font-size: 0.8125rem;
  color: #fff;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tile-vibe-k { color: rgba(255, 255, 255, 0.55); }

.tile-caption {
  margin: 3px 0 0;
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.82);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.tile-stats {
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.88);
  text-decoration: none;
  cursor: pointer;
}

.tile-stats:hover { color: #fff; text-decoration: underline; }
.tile-stats .sep { opacity: 0.5; padding: 0 2px; }

.tile-actions { display: flex; gap: 6px; flex: none; }

.tile-actions .chip,
.chip-link {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.3);
  color: #fff;
  backdrop-filter: blur(8px);
}

.tile-actions .chip:hover, .chip-link:hover { background: rgba(255, 255, 255, 0.32); }
.tile-actions .chip.danger { color: #ffcedb; }
.tile-actions .chip.danger:hover { background: rgba(155, 0, 50, 0.6); border-color: rgba(255, 206, 219, 0.6); }

.chip-link {
  display: inline-block;
  text-decoration: none;
  border-style: solid;
  border-width: 1px;
  border-radius: var(--tw-radius__circular);
  font-family: var(--tw-type__family__title);
  font-weight: var(--tw-type__weight__strong);
  letter-spacing: var(--tw-type__letterspacing__action);
}

/* ---------- in-grid comment popover ---------- */

/* Anchored just above the Like row so the thread opens where you clicked
 * instead of sending you to another page. */
.tile-panel {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 44px;
  z-index: 3;
  max-height: 74%;
  display: flex;
}

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

.cbox {
  background: rgba(255, 255, 255, 0.97);
  backdrop-filter: blur(10px);
  color: var(--tw-color__text__base);
  border-radius: var(--tw-radius__large);
  box-shadow: 0 12px 32px rgba(20, 20, 20, 0.32);
  font-size: 0.8125rem;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 0;
  overflow: hidden;
}

.cbox-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 7px 8px 7px 12px;
  font-weight: var(--tw-type__weight__strong);
  border-bottom: 1px solid var(--tw-color__border__subtle);
  flex: none;
}

.cbox-x {
  background: none;
  border: 0;
  padding: 0 6px;
  font-size: 1.125rem;
  line-height: 1;
  color: var(--tw-color__text__subtle);
}

.cbox-x:hover { background: none; color: var(--tw-color__text__base); }

.cbox-list {
  list-style: none;
  margin: 0;
  padding: 8px 12px;
  overflow-y: auto;
  overscroll-behavior: contain;
  min-height: 0;
  flex: 1;
}

.cbox-list li + li { margin-top: 7px; }
.cbox-who { font-weight: var(--tw-type__weight__strong); margin-right: 5px; }
.cbox-body { overflow-wrap: anywhere; }
.cbox-empty { color: var(--tw-color__text__subtle); }

/* The one nested level. A hairline and an indent, no avatars or connectors: at
 * this size anything heavier reads as clutter, and there is no third level to
 * disambiguate from. */
.cbox-replies {
  list-style: none;
  margin: 6px 0 0;
  padding: 0 0 0 10px;
  border-left: 2px solid var(--tw-color__border__subtle);
}

.cbox-reply {
  border: 0;
  background: none;
  padding: 0;
  margin-top: 2px;
  color: var(--tw-color__text__subtle);
  font-family: var(--tw-type__family__text);
  font-size: 0.75rem;
  letter-spacing: normal;
  cursor: pointer;
}

.cbox-reply:hover { color: var(--tw-color__primary__base); }

/* Which comment the box at the bottom is currently aimed at. */
.cbox-replying {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin: 0;
  padding: 6px 12px;
  border-top: 1px solid var(--tw-color__border__subtle);
  color: var(--tw-color__text__subtle);
  font-size: 0.75rem;
  flex: none;
}

.cbox-replying[hidden] { display: none; }

.cbox-cancel {
  border: 0;
  background: none;
  padding: 0;
  color: var(--tw-color__primary__base);
  font-family: var(--tw-type__family__text);
  font-size: 0.75rem;
  letter-spacing: normal;
  cursor: pointer;
}

.cbox-form {
  display: flex;
  gap: 6px;
  padding: 8px;
  border-top: 1px solid var(--tw-color__border__subtle);
  flex: none;
}

.cbox-form input[type="text"] {
  font-size: 0.8125rem;
  padding: 6px 12px;
  border-radius: var(--tw-radius__circular);
}

.cbox-form .chip { flex: none; }

/* Narrow on purpose: the body input is what people actually look at while
 * typing, this is just "who's saying it" and defaults to whatever name they
 * last used. */
.cbox-name { flex: 0 0 84px; min-width: 0; }

.cbox-note {
  margin: 0;
  padding: 8px 12px;
  border-top: 1px solid var(--tw-color__border__subtle);
  color: var(--tw-color__text__subtle);
  flex: none;
}

/* New tiles start collapsed, then settle in once the browser has painted. */
.tile.arriving { opacity: 0; transform: translateY(-10px) scale(0.98); }

.tile.bumped { animation: bump 500ms ease; }

@keyframes bump {
  0% { box-shadow: 0 0 0 0 rgba(88, 81, 255, 0.4); }
  40% { box-shadow: 0 0 0 6px rgba(88, 81, 255, 0.16); }
  100% { box-shadow: 0 0 0 0 rgba(88, 81, 255, 0); }
}

/* ---------- photo detail ---------- */

.back { margin: 0 0 16px; }
.back a { text-decoration: none; font-weight: var(--tw-type__weight__strong); }

.card {
  background: var(--tw-color__background__base);
  border: 1px solid var(--tw-color__border__subtle);
  border-radius: var(--tw-radius__xlarge);
  overflow: hidden;
  box-shadow: var(--shadow);
}

.card-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px;
  align-items: center;
  border-bottom: 1px solid var(--tw-color__border__subtle);
}

.card-head strong { font-size: 0.9375rem; }

/* Same one-line identity as a tile, in dark-on-light. */
.who-line {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
}

.who-at,
.who-sep,
.who-line time {
  color: var(--tw-color__text__subtle);
  font-size: 0.8125rem;
  font-weight: var(--tw-type__weight__base);
}

.meta {
  color: var(--tw-color__text__subtle);
  font-size: 0.75rem;
  display: flex;
  gap: 10px;
  align-items: center;
}

.pill {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: var(--tw-type__weight__strong);
  font-size: 0.625rem;
  border: 1px solid var(--tw-color__border__base);
  padding: 2px 9px;
  border-radius: var(--tw-radius__circular);
}

.shot { display: block; background: var(--tw-color__background__sunken); }

.shot img, .shot video {
  display: block;
  width: 100%;
  height: auto;
  max-height: 70vh;
  object-fit: contain;
}

.card-body { padding: 18px; }
.vibe { margin: 0 0 6px; }
.vibe-k { color: var(--tw-color__text__subtle); }

.caption { margin: 0 0 10px; }
.counts { margin: 0 0 14px; color: var(--tw-color__text__subtle); font-size: 0.875rem; }

/* ---------- forms ---------- */

.stack {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 18px;
}

.stack button { align-self: flex-start; }

label { font-weight: var(--tw-type__weight__strong); font-size: 0.875rem; }

input[type="text"],
input[type="password"],
input[type="file"],
input:not([type]),
textarea {
  font-family: var(--tw-type__family__text);
  font-size: 1rem;
  padding: 11px 14px;
  border: 1px solid var(--tw-color__border__base);
  border-radius: var(--tw-radius__medium);
  width: 100%;
  background: var(--tw-color__background__base);
  color: var(--tw-color__text__base);
}

input:focus, textarea:focus {
  outline: none;
  border-color: var(--tw-color__primary__base);
  box-shadow: 0 0 0 var(--tw-utilities__focus-ring__thickness) var(--tw-color__primary__surface);
}

textarea { resize: vertical; }

/* ---------- comments ---------- */

.comments { margin-top: var(--tw-spacing__macro__medium); }

.comment-list { list-style: none; padding: 0; margin: 0 0 20px; }

.comment-list li { border-top: 1px solid var(--tw-color__border__subtle); padding: 14px 0; }
.comment-list strong { font-size: 0.9375rem; }
.comment-list time { color: var(--tw-color__text__subtle); font-size: 0.75rem; margin-left: 8px; }
.comment-list p { margin: 6px 0 0; }

/* Same single nested level as the popover, with room to breathe. */
.reply-list {
  list-style: none;
  margin: 10px 0 0;
  padding: 0 0 0 16px;
  border-left: 2px solid var(--tw-color__border__subtle);
}

.reply-list li { border: 0; padding: 8px 0; }
.reply-list li:first-child { padding-top: 0; }

.reply-form {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  max-width: 32rem;
}

.reply-form input[type="text"] {
  flex: 1;
  min-width: 0;
  font-size: 0.875rem;
  padding: 7px 13px;
  border-radius: var(--tw-radius__circular);
}

.reply-form .ghost { flex: none; }

/* ---------- join / QR ---------- */

/* Small code parked next to the heading: on a projector the room can scan the
 * wall itself, so nobody has to be told a URL. */
.join-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--tw-spacing__micro__medium);
  padding: 8px 14px 8px 8px;
  background: var(--tw-color__background__base);
  border: 1px solid var(--tw-color__border__subtle);
  border-radius: var(--tw-radius__large);
  box-shadow: var(--shadow);
  color: var(--tw-color__text__base);
  text-decoration: none;
  font-family: var(--tw-type__family__title);
  font-weight: var(--tw-type__weight__strong);
  font-size: 0.875rem;
  line-height: 1.3;
  flex: none;
}

.join-chip:hover { box-shadow: var(--shadow-hover); }

.join-chip img {
  width: 72px;
  height: 72px;
  display: block;
  border-radius: var(--tw-radius__small);
  image-rendering: pixelated;
}

.join-chip small {
  font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace;
  font-weight: var(--tw-type__weight__base);
  font-size: 0.6875rem;
  color: var(--tw-color__text__subtle);
}

.join-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tw-spacing__micro__medium);
  flex: none;
}

.join-chip-text { padding: 8px 14px; }

.join-chip-icon { font-size: 1.75rem; line-height: 1; }

.money-panel {
  background: var(--tw-color__primary__surface);
  border-color: var(--tw-color__primary__base);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--tw-spacing__micro__medium);
}

.money-panel .hint { color: var(--tw-color__text__base); font-size: 0.9375rem; }
.money-panel form.inline { margin: 0; }

.join { text-align: center; }
.join h1 { font-size: 2rem; }
.join .lede { margin-bottom: var(--tw-spacing__macro__small); }

.join-qr {
  display: block;
  width: min(360px, 80vw);
  height: auto;
  margin: 0 auto;
  padding: var(--tw-spacing__micro__large);
  background: #fff;
  border-radius: var(--tw-radius__xlarge);
  box-shadow: var(--shadow);
  image-rendering: pixelated;
}

.join-url {
  font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace;
  font-size: 1.25rem;
  margin: var(--tw-spacing__micro__large) 0 4px;
  word-break: break-all;
}

.photon-panel { margin-top: var(--tw-spacing__macro__medium); text-align: center; }
.photon-panel .hint { margin-bottom: var(--tw-spacing__micro__large); }

.photon-code {
  font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace;
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: 0.25em;
  margin: 0;
  padding: var(--tw-spacing__micro__large) 0;
}

.texting-options {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--tw-spacing__micro__large);
  margin-top: var(--tw-spacing__micro__large);
}

.texting-option {
  flex: 1 1 220px;
  max-width: 280px;
  background: var(--tw-color__background__subtle);
  border-radius: var(--tw-radius__large);
  padding: var(--tw-spacing__micro__large);
}

.texting-option .hint { margin-bottom: 10px; }
.texting-option .hint:last-child { margin-bottom: 0; }

/* ---------- admin ---------- */

.admin-h2 { margin-top: var(--tw-spacing__macro__medium); }

.admin-state { margin: 0 0 12px; font-size: 0.9375rem; }
.admin-state.ok { color: var(--tw-color__success__base); }
.admin-state.off { color: var(--tw-color__warning__on-surface); }

.admin-step { margin-top: var(--tw-spacing__micro__large); }
.admin-step h2 { margin-bottom: 8px; }

.row-form {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: var(--tw-spacing__micro__medium);
  flex-wrap: wrap;
}

.row-form input[type="text"] { flex: 1 1 14rem; }
.row-form button { flex: none; }

.crumbs { margin: 0 0 12px; font-size: 0.875rem; }

/* ---------- wall lists (home page) ---------- */

.wall-list { list-style: none; margin: 0 0 16px; padding: 0; }

.wall-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid var(--tw-color__border__subtle);
}

.wall-list a {
  text-decoration: none;
  font-weight: var(--tw-type__weight__strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---------- walls sidebar ---------- */

/* Pure CSS toggle: a hidden checkbox plus the general-sibling combinator, so
 * opening/closing the panel needs no JavaScript at all. `.shell` wraps the
 * sidebar and the rest of the page as side-by-side flex items — the sidebar
 * is a normal docked column on wide screens (like Slack's), and only becomes
 * a fixed-position overlay drawer with a backdrop under the phone breakpoint,
 * where there is no room to dock it permanently. */
.shell { display: flex; min-height: 100vh; }
.page { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.sidebar-toggle-input { position: absolute; top: 0; left: 0; }

.sidebar-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  margin-right: 4px;
  border-radius: var(--tw-radius__medium);
  font-size: 1.125rem;
  line-height: 1;
  cursor: pointer;
  color: var(--tw-color__text__base);
  flex: none;
}

.sidebar-toggle-btn:hover { background: var(--tw-color__background__subtle); }

/* Same light palette as the rest of the app — a docked panel, not a themed
 * instrument panel bolted onto a different-looking product. A hairline
 * border and the active-row tint (the same violet-on-surface pairing used
 * elsewhere for selected states) are what read as "sidebar" instead of
 * color. Narrower than a typical Slack rail on purpose, so docking it on
 * desktop doesn't meaningfully eat into .wrap.wide's own max-width. */
.sidebar {
  flex: none;
  background: var(--tw-color__background__base);
  border-right: 1px solid var(--tw-color__border__subtle);
  overflow-y: hidden;
}

.sidebar-inner {
  width: 208px;
  height: 100%;
  overflow-y: auto;
  padding: 14px 8px;
}

.sidebar-label {
  margin: 0 0 2px;
  padding: 0 8px;
  font-family: var(--tw-type__family__title);
  font-size: 0.6875rem;
  font-weight: var(--tw-type__weight__strong);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--tw-color__text__subtle);
  white-space: nowrap;
}

.sidebar-label-spaced { margin-top: 18px; }

.sidebar-list { list-style: none; margin: 0 0 2px; padding: 0; }

.sidebar-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 4px 8px;
  border-radius: var(--tw-radius__small);
  color: var(--tw-color__text__base);
  text-decoration: none;
  font-size: 0.8125rem;
  line-height: 1.3;
  font-weight: var(--tw-type__weight__base);
  white-space: nowrap;
  overflow: hidden;
}

.sidebar-row:hover { background: var(--tw-color__background__subtle); }

.sidebar-row.is-active {
  background: var(--tw-color__primary__surface);
  color: var(--tw-color__primary__base--state-1);
  font-weight: var(--tw-type__weight__strong);
}

.sidebar-avatar {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: var(--tw-radius__xsmall);
  background: var(--tw-color__primary__base);
  color: #fff;
  font-family: var(--tw-type__family__title);
  font-size: 0.6875rem;
  font-weight: var(--tw-type__weight__strong);
}

.sidebar-avatar-alt { background: #ed4956; }

.sidebar-row-name {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Private-wall lock and the owner badge: trailing, flex:none so a long name
 * ellipsizes before pushing either off the edge of the 216px rail. */
.sidebar-icon { flex: none; font-size: 0.75rem; opacity: 0.55; }

.sidebar-tag {
  flex: none;
  padding: 1px 6px;
  border-radius: var(--tw-radius__circular);
  background: var(--tw-color__background__sunken);
  color: var(--tw-color__text__subtle);
  font-size: 0.625rem;
  font-weight: var(--tw-type__weight__strong);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.sidebar-row.is-active .sidebar-tag {
  background: #fff;
  color: var(--tw-color__primary__base--state-1);
}

.sidebar-empty {
  margin: 0 0 4px;
  padding: 0 8px;
  color: var(--tw-color__text__subtle);
  font-size: 0.75rem;
}

.sidebar-see-all {
  display: block;
  margin-top: 10px;
  padding: 0 8px;
  color: var(--tw-color__text__subtle);
  text-decoration: none;
  font-size: 0.75rem;
  font-weight: var(--tw-type__weight__strong);
}

.sidebar-see-all:hover { color: var(--tw-color__primary__base); }

.sidebar-backdrop { display: none; }

/* The toggle button works the same way (fold the panel in or out) at every
 * width — only what "folded" looks like changes below. */

/* Docked (pushes the feed over) at any width with real room for a slim
 * 208px column plus content — a dimmed full-page overlay for opening a
 * narrow sidebar reads as "hogging the page" the moment the window is wide
 * enough to just show both side by side instead. Only genuinely tight
 * widths (phones, a narrow split-screen pane) fall through to the overlay
 * drawer below. Folding closed animates width to 0 rather than sliding
 * off-canvas, since there is no overlay/backdrop concept here — the content
 * beside it just reflows. */
@media (min-width: 880px) {
  .sidebar {
    width: 208px;
    transition: width 200ms ease;
  }
  #sidebar-toggle:checked ~ .shell .sidebar {
    width: 0;
    border-right-color: transparent;
  }
}

/* Below that, closed by default and folds out as an overlay drawer with a
 * dimming backdrop instead, same as on a phone — the toggle's
 * unchecked/checked meaning flips here so the feed keeps its full width
 * until someone actually asks for the sidebar. */
@media (max-width: 879px) {
  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: min(280px, 84vw);
    box-shadow: var(--shadow-hover);
    transform: translateX(-100%);
    transition: transform 220ms ease;
    z-index: 40;
  }
  .sidebar-inner { width: 100%; }
  .sidebar-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(20, 20, 20, 0.32);
    z-index: 35;
    opacity: 0;
    pointer-events: none;
    transition: opacity 220ms ease;
  }
  #sidebar-toggle:checked ~ .shell .sidebar { transform: translateX(0); }
  #sidebar-toggle:checked ~ .shell .sidebar-backdrop { opacity: 1; pointer-events: auto; }
}

/* ---------- emoji reactions ---------- */

/* The three sit slightly stacked, like overlapping chips, so the row reads as one
 * object. The overlap is a fixed margin and the pop is a transform: animating the
 * margin instead would reflow the row out from under the cursor. */
.rx { display: flex; align-items: center; flex: none; }

.rx-item { display: inline-flex; margin: 0; }

.rx-item + .rx-item { margin-left: -7px; }

.rx-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  /* Extra padding on the right is the room the next chip overlaps into, so the
   * count stays legible under the stack. */
  padding: 4px 11px 4px 9px;
  border: 1px solid var(--tw-color__border__base);
  border-radius: var(--tw-radius__circular);
  /* Opaque on purpose: stacked chips would show each other through a tint. */
  background: var(--tw-color__background__base);
  color: var(--tw-color__text__base);
  font-family: var(--tw-type__family__text);
  font-size: 0.8125rem;
  font-weight: var(--tw-type__weight__base);
  letter-spacing: normal;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: transform 150ms ease, box-shadow 150ms ease, background-color 150ms ease;
}

.rx-btn:hover {
  background: var(--tw-color__background__subtle);
  border-color: var(--tw-color__border__bold);
}

/* The pop. Raised above its neighbours so the lift is not clipped by the stack. */
.rx-btn:hover,
.rx-btn:focus-visible {
  transform: translateY(-3px) scale(1.09);
  box-shadow: 0 6px 16px rgba(20, 20, 20, 0.26);
  z-index: 3;
}

.rx-btn:active { transform: translateY(-1px) scale(1.03); }

.rx-btn.on {
  background: var(--tw-color__primary__surface);
  border-color: var(--tw-color__primary__base);
  color: var(--tw-color__primary__base--state-2);
  font-weight: var(--tw-type__weight__strong);
}

.rx-emoji { font-size: 0.9375rem; line-height: 1; }
.rx-n { font-variant-numeric: tabular-nums; }

/* The emoji is decoration; the reaction still needs a name for screen readers. */
.rx-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* On a tile the row sits on top of the photo, so it flips to light-on-dark. The
 * scrim is dark rather than a white tint: stacked chips need to hide the one
 * underneath, and a light tint just piles up into a bright smear. */
.tile-overlay .rx-btn {
  /* No backdrop blur here: blurring while the chip is being transformed is what
   * makes the pop stutter, and the scrim is dark enough not to need it. */
  background: rgba(20, 20, 20, 0.82);
  border-color: rgba(255, 255, 255, 0.3);
  color: #fff;
}

.tile-overlay .rx-btn:hover { background: rgba(20, 20, 20, 0.9); }

.tile-overlay .rx-btn.on {
  background: rgba(255, 255, 255, 0.94);
  border-color: #fff;
  color: var(--tw-color__text__base);
}

/* Reactions and the comment count share a row, and three chips plus a label can
 * outgrow a narrow tile, so this row is the one allowed to wrap. */
.tile-row:has(.rx) { flex-wrap: wrap; row-gap: 6px; }

.tile-mod { justify-content: flex-end; }

/* ---------- upload pickers ---------- */

/* Shortcuts for the vibe field. Outline only, so they read as suggestions
 * rather than as the buttons that actually post anything. */
.picks {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: -4px 0 4px;
}

.ghost-chip {
  padding: 4px 11px;
  border: 1px solid var(--tw-color__border__base);
  border-radius: var(--tw-radius__circular);
  background: transparent;
  color: var(--tw-color__text__subtle);
  font-family: var(--tw-type__family__text);
  font-size: 0.8125rem;
  letter-spacing: normal;
  cursor: pointer;
}

.ghost-chip:hover { border-color: var(--tw-color__border__bold); color: var(--tw-color__text__base); }

.ghost-chip.on {
  border-color: var(--tw-color__text__base);
  color: var(--tw-color__text__base);
}

.pick {
  display: flex;
  gap: var(--tw-spacing__micro__medium);
  flex-wrap: wrap;
  border-radius: var(--tw-radius__large);
  transition: background 120ms ease, box-shadow 120ms ease;
}

/* Dragging a file over the picker area (desktop only — see upload.js) turns
 * the whole zone into an obvious drop target rather than relying on the tiny
 * native browser drag cursor alone. */
.pick.drag-over {
  background: var(--tw-color__primary__surface);
  box-shadow: 0 0 0 2px var(--tw-color__primary__base) inset;
}

.drop-hint {
  margin: -8px 0 0;
  text-align: center;
}

/* Touch devices have no drag-a-file-in gesture, so the hint would just be
 * confusing noise there. */
@media (pointer: coarse) {
  .drop-hint { display: none; }
}

/* What you picked, before it goes anywhere. Capped by viewport height so a tall
 * photo cannot push the Post button off the bottom of a phone screen. */
.shot-preview {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.shot-preview img {
  display: block;
  width: 100%;
  max-height: 46vh;
  object-fit: contain;
  background: var(--tw-color__background__sunken);
  border: 1px solid var(--tw-color__border__subtle);
  border-radius: var(--tw-radius__large);
}

.shot-preview img:not([src]) { display: none; }

.pick-btn {
  position: relative;
  flex: 1 1 11rem;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  padding: var(--tw-spacing__micro__large);
  border: 1px solid var(--tw-color__border__base);
  border-radius: var(--tw-radius__medium);
  background: var(--tw-color__background__base);
  font-weight: var(--tw-type__weight__strong);
  letter-spacing: var(--tw-type__letterspacing__action);
  text-align: center;
  cursor: pointer;
}

.pick-btn:hover {
  border-color: var(--tw-color__border__bold);
  background: var(--tw-color__background__subtle);
}

.pick-btn:focus-within {
  outline: 2px solid var(--tw-color__utility__focus-ring);
  outline-offset: 2px;
}

/* Hidden but still focusable, so the label keeps working as the visible control. */
.pick-btn input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- review queue ---------- */

.review { list-style: none; margin: var(--tw-spacing__micro__large) 0 0; padding: 0; }

.review-item {
  display: flex;
  align-items: center;
  gap: var(--tw-spacing__micro__medium);
  padding: 12px 0;
  border-top: 1px solid var(--tw-color__border__subtle);
}

.review-item.is-hidden { opacity: 0.55; }

.review-thumb {
  position: relative;
  flex: none;
  display: block;
  width: 72px;
  height: 72px;
  border-radius: var(--tw-radius__small);
  overflow: hidden;
  background: var(--tw-color__background__subtle);
}

.review-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

.review-flag {
  position: absolute;
  inset: auto 0 0 0;
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
  font-size: 0.6875rem;
  text-align: center;
  padding: 2px 0;
}

.review-meta { flex: 1 1 auto; min-width: 0; }
.review-meta p { margin: 0; }
.review-who { font-size: 0.9375rem; }
.review-dot { color: var(--tw-color__text__subtle); padding: 0 5px; }
.review-when, .review-src, .review-counts {
  color: var(--tw-color__text__subtle);
  font-size: 0.8125rem;
}

.review-caption {
  margin-top: 2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.review-action { flex: none; }

.pager {
  display: flex;
  align-items: center;
  gap: var(--tw-spacing__micro__medium);
  margin-top: var(--tw-spacing__micro__large);
}

.pager-at { color: var(--tw-color__text__subtle); font-size: 0.875rem; }

@media (max-width: 30rem) {
  .review-thumb { width: 56px; height: 56px; }
  .review-caption, .review-src, .review-dot:last-of-type { display: none; }
}

/* ---------- footer ---------- */

.foot {
  max-width: var(--wide);
  width: 100%;
  margin: 0 auto;
  padding: 20px var(--tw-spacing__macro__small) 32px;
  display: flex;
  justify-content: space-between;
  color: var(--tw-color__text__subtle);
  font-size: 0.8125rem;
  border-top: 1px solid var(--tw-color__border__subtle);
}

.foot a { color: var(--tw-color__text__subtle); text-decoration: none; }
.foot a:hover { color: var(--tw-color__primary__base); }

code {
  font-family: ui-monospace, "SFMono-Regular", "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.875em;
  background: var(--tw-color__background__sunken);
  padding: 1px 5px;
  border-radius: var(--tw-radius__xsmall);
}

@media (max-width: 640px) {
  .top-inner, .banner, .wrap, .foot { padding-left: 12px; padding-right: 12px; }
  h1 { font-size: 1.5rem; }
  .panel { padding: 20px; }

  /* The header was carrying a wordmark, two links and an identity chip, which on
   * a phone wrapped into a squashed two-line bar. Strip it back to the logo mark
   * and who you are; Feed lives on the logo and Add a photo becomes the button
   * fixed above the thumb, which is a far bigger target than the link was. */
  .logo-word, .nav-wide { display: none; }
  .top-inner { padding-top: 10px; padding-bottom: 10px; }
  .logo-mark { width: 30px; height: 28px; }
  .who { max-width: 9rem; }

  .add-fab { display: inline-flex; }
  /* Room for the floating button, so it never covers the last row's controls. */
  .wrap { padding-bottom: 96px; }

  /* The 15rem floor above is wider than half a phone screen, so it collapses to
   * a single column. Drop the floor and tighten the gap to fit two across. */
  .feed {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 9.5rem), 1fr));
    gap: 10px;
  }

  /* Less furniture on a small tile, so the photo stays the point. */
  .tile { border-radius: var(--tw-radius__xlarge); }
  .tile-overlay { padding: 26px 10px 9px; }
  .tile-meta { font-size: 0.75rem; gap: 4px; }
  /* The handle is the one part of the line worth losing at this width: the age
   * is now short enough to keep, which it was not as a full timestamp. */
  .tile-at { display: none; }
  .tile-time { font-size: 0.6875rem; }
  .tile-vibe { font-size: 0.75rem; margin-top: 3px; }
  .tile-caption {
    font-size: 0.75rem;
    -webkit-line-clamp: 1;
    line-clamp: 1;
  }
  .tile-stats { font-size: 0.75rem; }
  .tile-actions .chip, .chip-link { padding: 4px 10px; font-size: 0.75rem; }
  .tile-badge { display: none; }
  .tile-overlay .rx-btn { padding: 3px 8px 3px 6px; font-size: 0.6875rem; gap: 2px; }
  .tile-overlay .rx-emoji { font-size: 0.8125rem; }
  /* Less overlap on a phone: the chips are smaller, so the tap targets need it. */
  .tile-overlay .rx-item + .rx-item { margin-left: -5px; }

  .tile-panel { left: 6px; right: 6px; bottom: 38px; max-height: 80%; }

  .join-chip { padding: 6px 10px 6px 6px; font-size: 0.8125rem; }
  .join-chip img { width: 56px; height: 56px; }
  .page-head { gap: 12px; }
}

/* Very narrow phones: keep two across, and let the vibe stand in for the
 * caption rather than stacking both. */
@media (max-width: 380px) {
  .feed { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .tile-caption { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .tile, .tile.arriving, .tile-shot img { transition: none; transform: none; opacity: 1; }
  .tile:hover { transform: none; }
  .tile.bumped, .live .dot { animation: none; }
  .rx-btn { transition: none; }
  .rx-btn:hover, .rx-btn:focus-visible, .rx-btn:active { transform: none; }
}

/* ---------- chat view ---------- */

.chat-scroll {
  height: calc(100vh - 260px);
  min-height: 320px;
  overflow-y: auto;
  overscroll-behavior: contain;
  border: 1px solid var(--tw-color__border__subtle);
  border-radius: var(--tw-radius__xlarge);
  background: var(--tw-color__background__base);
  padding: var(--tw-spacing__micro__large);
}

.chat-top-sentinel { height: 1px; }

.chat-row {
  display: flex;
  align-items: flex-start;
  gap: var(--tw-spacing__micro__medium);
  padding: 6px 0;
}

.chat-avatar {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--tw-color__primary__base);
  color: #fff;
  font-family: var(--tw-type__family__title);
  font-size: 0.75rem;
  font-weight: var(--tw-type__weight__strong);
  margin-top: 2px;
}

.chat-bubble {
  background: var(--tw-color__background__subtle);
  border-radius: var(--tw-radius__large);
  padding: 8px 12px;
  max-width: min(420px, 80%);
  font-size: 0.8125rem;
}

.chat-meta { margin: 0 0 4px; font-size: 0.75rem; color: var(--tw-color__text__subtle); }
.chat-who { font-weight: var(--tw-type__weight__strong); color: var(--tw-color__text__base); margin-right: 6px; }
.chat-body { margin: 0; overflow-wrap: anywhere; }
.chat-caption { margin: 6px 0 0; overflow-wrap: anywhere; }

.chat-bubble-photo { padding: 8px; }

.chat-photo-link {
  display: block;
  border-radius: var(--tw-radius__medium);
  overflow: hidden;
  line-height: 0;
}

.chat-photo-link img, .chat-photo-link video {
  display: block;
  width: 100%;
  max-width: 280px;
  height: auto;
  border-radius: var(--tw-radius__medium);
}

.chat-reply-ref {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
  padding: 3px 8px 3px 3px;
  border-radius: var(--tw-radius__large);
  background: var(--tw-color__background__sunken);
  color: var(--tw-color__text__subtle);
  font-size: 0.6875rem;
  text-decoration: none;
}

.chat-reply-ref img {
  width: 22px;
  height: 22px;
  border-radius: var(--tw-radius__xsmall);
  object-fit: cover;
}

.chat-reply-ref-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--tw-radius__xsmall);
  background: var(--tw-color__primary-cta__base);
  color: #fff;
  font-size: 0.5625rem;
  padding-left: 2px;
}
