/* Login View */
#view-login {
  justify-content: center;
  align-items: center;
  padding: var(--space-9);
}

/* Gallery view (Chunk 1 basic responsive grid) */
.map-scroll-container {
  padding: 0;
  position: relative;
}

.map-canvas {
  width: 100%;
  height: calc(100vh - 170px);
  min-height: 420px;
}

/* Cleared the floating nav pill, which was sitting on top of this card. */
.map-state-wrap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--nav-clearance) + var(--space-4));
  display: flex;
  justify-content: center;
  pointer-events: none;
}

/* Floats over the tiles, so it keeps its own ground, paper, matching
   .back-fab and the carousel controls, rather than the frosted near-black
   panel it was. */
.map-state-card {
  pointer-events: auto;
  width: min(92%, 560px);
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline-strong);
  background: var(--paper-raised);
  box-shadow: 0 4px 14px rgba(90, 74, 58, 0.24);
  padding: 14px 16px;
}

.map-state-card-error {
  border-color: rgba(143, 42, 34, 0.45);
}

.map-state-title {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--tracking-display);
  font-size: var(--text-heading);
  color: var(--text-primary);
}

.map-state-sub {
  margin-top: 4px;
  font-size: var(--text-meta);
  color: var(--ink-soft);
}

.map-info-wrap {
  position: absolute;
  top: var(--space-4);
  left: calc(var(--space-8) + 44px);
  right: var(--space-8);
  z-index: 450;
  pointer-events: none;
}

/* .map-info-row removed: renderMapInfo has not emitted it since the filter and
   mode rows replaced it, so it was a dead near-black pill nothing could show. */

.map-mode-row {
  margin-top: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  pointer-events: auto;
}

/* The buttons carry their own paper ground now, so the row does not need a
   tray behind them; it was a near-black blurred pill, and the mode row
   directly below it never had one, which made the two rows look unrelated. */
.map-filter-row {
  margin-top: 8px;
  pointer-events: auto;
  width: fit-content;
  max-width: 100%;
  padding: 0;
  background: none;
  border: none;
  backdrop-filter: none;
  box-shadow: none;
}

.map-filter-scroll {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* Map controls sit on the tiles rather than on the page, so they carry their
   own paper ground, the same treatment as every other control that floats
   over imagery. The text-shadows went with the dark tiles they were fighting. */
.map-filter-btn,
.map-mode-btn {
  border: 1px solid var(--hairline-strong);
  background: var(--paper-raised);
  color: var(--ink);
  border-radius: var(--radius-pill);
  padding: 6px 10px;
  font-size: var(--text-label);
  font-weight: 700;
  cursor: pointer;
  text-shadow: none;
  box-shadow: 0 2px 8px rgba(90, 74, 58, 0.18);
  transition: background var(--duration-fast) ease, border-color var(--duration-fast) ease, color var(--duration-fast) ease;
}

.map-filter-btn:hover,
.map-mode-btn:hover {
  border-color: var(--vermilion);
}

/* Vermilion wash, matching the nav tab and the feed's filter chips. */
.map-filter-btn.active,
.map-mode-btn.active {
  border-color: var(--vermilion);
  background: rgba(206, 64, 26, 0.14);
  color: var(--vermilion-deep);
  box-shadow: 0 2px 8px rgba(90, 74, 58, 0.18);
}

.map-filter-btn:focus-visible {
  outline: 2px solid rgba(206, 64, 26, 0.95);
  outline-offset: 1px;
}

.map-mode-btn:disabled {
  opacity: 0.4;
  cursor: default;
}

.map-mode-btn:focus-visible {
  outline: 2px solid rgba(206, 64, 26, 0.95);
  outline-offset: 1px;
}

/* Leaflet's own chrome, re-skinned for light tiles. */
#map-canvas .leaflet-control-attribution {
  font-size: 10px;
  background: rgba(255, 250, 240, 0.85);
  color: var(--ink-soft);
}

#map-canvas .leaflet-control-attribution a {
  color: var(--vermilion-deep);
}

#map-canvas .leaflet-bar a {
  color: var(--ink);
  background: var(--paper-raised);
  border-bottom-color: var(--hairline);
}

#map-canvas .leaflet-bar a:hover {
  background: var(--paper-sunk);
  color: var(--vermilion-deep);
}

#map-canvas .leaflet-control-zoom {
  border-color: var(--hairline-strong);
  box-shadow: 0 4px 14px rgba(90, 74, 58, 0.22);
}

.map-pin-icon-wrap {
  background: transparent;
  border: 0;
}

/* Flat vermilion teardrop with a paper centre. Was a two-stop gradient with a
   near-black inner disc and a 45%-black drop shadow, built to punch through
   dark tiles, and muddy against light ones. */
.map-pin-icon {
  position: relative;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  background: var(--vermilion);
  border: 1.5px solid var(--paper-raised);
  box-shadow: 0 3px 8px rgba(90, 74, 58, 0.35);
  transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease;
}

.map-pin-icon::after {
  content: '';
  position: absolute;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--paper-raised);
  border: none;
}

.map-pin-dot {
  position: relative;
  z-index: 1;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--vermilion-deep);
  transform: rotate(45deg);
}

.map-pin-icon-wrap:hover .map-pin-icon {
  background: var(--vermilion-deep);
  box-shadow: 0 5px 12px rgba(90, 74, 58, 0.4);
  transform: rotate(-45deg) translateY(-1px);
}

#map-canvas .marker-cluster-small,
#map-canvas .marker-cluster-medium,
#map-canvas .marker-cluster-large {
  background: rgba(206, 64, 26, 0.26);
  border: 1px solid rgba(255, 228, 197, 0.28);
}

#map-canvas .marker-cluster-small div,
#map-canvas .marker-cluster-medium div,
#map-canvas .marker-cluster-large div {
  background: var(--vermilion);
  color: var(--paper-raised);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  border: 1.5px solid var(--paper-raised);
  box-shadow: 0 3px 10px rgba(90, 74, 58, 0.35);
}

#map-canvas .marker-cluster-small div {
  width: 34px;
  height: 34px;
  margin-left: 3px;
  margin-top: 3px;
  line-height: 34px;
}

#map-canvas .marker-cluster-medium div {
  width: 38px;
  height: 38px;
  margin-left: 2px;
  margin-top: 2px;
  line-height: 38px;
}

#map-canvas .marker-cluster-large div {
  width: 42px;
  height: 42px;
  margin-left: 1px;
  margin-top: 1px;
  line-height: 42px;
}

/* Leaflet's popup chrome is light by default, so the popup's own text was
   cream-on-cream once the surrounding panel stopped being dark. */
.map-popup {
  min-width: 180px;
  color: var(--ink);
}

.map-popup-title {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--tracking-display);
  font-size: var(--text-heading);
  color: var(--ink);
  margin-bottom: 2px;
}

.map-popup-location {
  font-size: var(--text-meta);
  color: var(--ink-soft);
  margin-bottom: 8px;
}

.map-popup-preview-wrap {
  width: 100%;
  aspect-ratio: var(--photo-aspect);
  max-height: 150px;
  margin-bottom: 8px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--paper-sunk);
}

/* Fills its frame, like every other photo since Phase 6. */
.map-popup-preview-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  border-radius: 0;
  border: 1px solid var(--hairline);
  display: block;
}

.map-popup-preview-img.is-fallback {
  object-fit: contain;
  background: var(--wash);
  opacity: 0.65;
}

.map-popup-preview-empty {
  width: 100%;
  height: 100%;
  border-radius: 0;
  border: 1px dashed var(--hairline-strong);
  background: var(--paper-sunk);
  color: var(--ink-soft);
  font-size: var(--text-label);
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px;
}

/* The three scores, as chips; they were loose cream text sitting on the old
   dark panel with nothing to hold them together. */
.map-popup-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  font-size: var(--text-label);
  font-weight: 700;
  color: var(--ink);
}

.map-popup-stats span {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px 8px;
  border-radius: var(--radius-pill);
  background: var(--paper-sunk);
  border: 1px solid var(--hairline);
  font-variant-numeric: tabular-nums;
}

.map-popup-foot {
  margin-top: 8px;
  font-size: var(--text-label);
  color: var(--ink-soft);
}

.map-popup-actions {
  margin-top: 8px;
  display: flex;
  gap: 6px;
}

.map-popup-btn {
  border: 1px solid var(--hairline-strong);
  background: var(--paper-sunk);
  color: var(--ink);
  border-radius: var(--radius-pill);
  padding: 7px 12px;
  font-size: var(--text-label);
  font-weight: 700;
  cursor: pointer;
  transition: background 0.14s ease, border-color 0.14s ease, transform 0.14s ease;
}

/* "Read Full Review" is the reason the popup exists, so it gets the app's
   primary treatment rather than a translucent wash with cream text. */
.map-popup-btn-primary {
  border-color: var(--vermilion);
  background: var(--vermilion);
  color: var(--paper-raised);
}

.map-popup-btn:hover:not(:disabled) {
  background: rgba(206, 64, 26, 0.10);
  border-color: var(--vermilion);
}

.map-popup-btn-primary:hover:not(:disabled) {
  background: var(--vermilion-deep);
  border-color: var(--vermilion-deep);
}

.map-popup-btn:active:not(:disabled) {
  transform: scale(0.98);
}

.map-popup-btn:focus-visible {
  outline: 2px solid rgba(206, 64, 26, 0.95);
  outline-offset: 1px;
}

.map-popup-btn:disabled {
  opacity: 0.45;
  cursor: default;
}

/* The popup's own panel. Phase 9 recoloured the title and location to ink but
   left this wrapper near-black, so the popup ended up worse than before that
   pass: dark panel, ink text, effectively unreadable. The whole thing is
   paper now, and every cream text colour inside it went with it. */
#map-canvas .leaflet-popup-content-wrapper,
#map-canvas .leaflet-popup-tip {
  background: var(--paper-raised);
  color: var(--ink);
  border: 1px solid var(--hairline-strong);
}

#map-canvas .leaflet-popup-content-wrapper {
  border-radius: var(--radius-md);
  box-shadow: 0 6px 20px rgba(90, 74, 58, 0.26);
}

#map-canvas .leaflet-popup-close-button {
  color: var(--ink-soft);
}

#map-canvas .leaflet-popup-close-button:hover {
  color: var(--vermilion-deep);
}

#map-canvas .leaflet-popup-content {
  margin: 11px 13px;
}

/* The controls bar sat above the grid as a frosted near-black slab, the last
   of the blurred dark chrome, matching the header before Phase 5. */
#gallery-controls-host {
  padding: var(--space-6) var(--space-8) var(--space-6);
  background: var(--paper);
  border-bottom: 1px solid var(--hairline);
}

.gallery-state-card {
  margin: 20px;
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline);
  background: var(--bg-surface);
  padding: 20px;
}

.gallery-state-card-error {
  border-color: rgba(143, 42, 34, 0.45);
}

.gallery-state-title {
  font-family: var(--font-display);
  font-size: var(--text-title);
  font-weight: 700;
  letter-spacing: var(--tracking-display);
  color: var(--text-primary);
}

.gallery-state-sub {
  margin-top: 6px;
  color: var(--ink-soft);
  font-size: var(--text-meta);
}

.gallery-retry-btn {
  margin-top: 14px;
  border: 1px solid rgba(206, 64, 26, 0.6);
  background: rgba(206, 64, 26, 0.14);
  color: var(--vermilion-deep);
  border-radius: var(--radius-pill);
  padding: 8px 14px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}

.gallery-controls {
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.gallery-control-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.gallery-control-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  /* --text-secondary is already the quiet voice; the extra 0.82 on top of it
     dropped an 11px label to 3.69:1. */
  color: var(--text-secondary);
}

.gallery-pill-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.gallery-sort-row {
  margin-top: 0;
}

.gallery-pill-btn {
  border: 1px solid var(--hairline-strong);
  background: var(--paper-raised);
  color: var(--ink-soft);
  border-radius: var(--radius-pill);
  padding: 7px 12px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--duration-fast) ease, border-color var(--duration-fast) ease, color var(--duration-fast) ease;
}

.gallery-pill-btn:hover {
  border-color: var(--vermilion);
}

.gallery-pill-btn.active {
  border-color: var(--vermilion);
  color: var(--vermilion-deep);
  background: rgba(206, 64, 26, 0.12);
}

.gallery-pill-btn:focus-visible {
  outline: 2px solid rgba(206, 64, 26, 0.95);
  outline-offset: 1px;
}

@media (max-width: 680px) {
  .map-filter-row {
    width: 100%;
    overflow: hidden;
  }

  .map-filter-scroll {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }

  .map-filter-scroll::-webkit-scrollbar {
    display: none;
  }

  .map-mode-row,
  .gallery-pill-row {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    max-width: 100%;
  }

  .map-mode-row {
    width: 100%;
  }

  .map-mode-row::-webkit-scrollbar,
  .gallery-pill-row::-webkit-scrollbar {
    display: none;
  }

  .map-filter-btn,
  .map-mode-btn,
  .gallery-pill-btn {
    flex: 0 0 auto;
  }
}

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 14px;
}

.gallery-card {
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline);
  background: var(--bg-surface);
  overflow: hidden;
  display: block;
  position: relative;
  cursor: pointer;
}

.gallery-grid-loading {
  align-items: stretch;
}

.gallery-skeleton-card {
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline);
  background: var(--paper-raised);
  padding: 10px;
}

/* Loading skeletons were white-on-dark, so on paper the whole loading state
   was invisible, the grid looked empty rather than busy. The shimmer keeps
   its gradient because that is the animation itself, not decoration; it is
   now an ink sweep. */
.gallery-skeleton-photo {
  width: 100%;
  aspect-ratio: var(--photo-aspect);
  border-radius: 10px;
  background: linear-gradient(90deg, var(--paper-sunk), var(--wash-strong), var(--paper-sunk));
  animation: galleryPulse 1.1s ease-in-out infinite;
}

.gallery-skeleton-line {
  height: 10px;
  border-radius: 99px;
  margin-top: 9px;
  width: 66%;
  background: var(--paper-sunk);
}

.gallery-skeleton-line-lg {
  width: 84%;
}

.gallery-load-more-wrap {
  padding: 8px 14px 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  justify-content: center;
  align-items: center;
}

.gallery-load-more-error {
  color: #fca5a5;
  font-size: 12px;
  text-align: center;
}

@keyframes galleryPulse {
  0% { opacity: 0.45; }
  50% { opacity: 0.9; }
  100% { opacity: 0.45; }
}

.gallery-card-photo {
  width: 100%;
  display: block;
  height: auto;
  object-fit: contain;
}

.gallery-card-photo.is-fallback {
  aspect-ratio: 4 / 3;
  object-fit: contain;
  opacity: 0.48;
  background: var(--paper-sunk);
}

.gallery-card-overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 24px 12px 12px;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.92) 0%,
    rgba(0, 0, 0, 0.72) 38%,
    rgba(0, 0, 0, 0.34) 68%,
    rgba(0, 0, 0, 0) 100%
  );
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 160ms ease, transform 160ms ease;
  pointer-events: none;
}

.gallery-card-cafe {
  font-weight: 700;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.gallery-card-line {
  margin-top: 4px;
  color: rgba(255, 255, 255, 0.9);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
  font-size: 12px;
}

.gallery-card:hover .gallery-card-overlay,
.gallery-card:focus-visible .gallery-card-overlay,
.gallery-card.is-tapped .gallery-card-overlay {
  opacity: 1;
  transform: translateY(0);
}

.gallery-card:focus-visible {
  outline: 2px solid rgba(206, 64, 26, 0.9);
  outline-offset: 2px;
}

.gallery-lightbox-open {
  overflow: hidden;
}

.gallery-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1400;
  display: none;
}

.gallery-lightbox.open {
  display: block;
}

.gallery-lightbox-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.86);
}

.gallery-lightbox-content {
  position: relative;
  z-index: 1;
  height: 100%;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  padding: 24px 8px;
}

.gallery-lightbox-figure {
  margin: 0;
  width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.gallery-lightbox-image {
  width: 100%;
  max-width: min(92vw, 1080px);
  max-height: calc(100vh - 130px);
  object-fit: contain;
  border-radius: var(--radius-md);
  background: rgba(255, 255, 255, 0.03);
}

.gallery-lightbox-image.is-fallback {
  object-fit: contain;
  opacity: 0.55;
}

.gallery-lightbox-meta {
  text-align: center;
}

.gallery-lightbox-title {
  color: #fff;
  font-weight: 700;
  font-size: 15px;
}

.gallery-lightbox-line {
  margin-top: 4px;
  color: rgba(255, 255, 255, 0.8);
  font-size: 12px;
}

/* The lightbox stays dark deliberately; it is a full-screen photo viewer,
   and the darkness is doing the same job as the scrim behind gallery captions
   that Phase 2 ruled correct. It is the one surface in the app where "dark
   panel" is the right answer rather than a leftover.
   The CTA becomes a real primary action instead of a translucent wash with
   cream text: solid vermilion, paper label, matching every other primary. */
.gallery-lightbox-cta {
  margin-top: 8px;
  border: 1px solid var(--vermilion);
  background: var(--vermilion);
  color: var(--paper-raised);
  border-radius: var(--radius-pill);
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
  transition: background var(--duration-fast) ease, border-color var(--duration-fast) ease;
}

.gallery-lightbox-cta:hover:not(:disabled) {
  background: var(--vermilion-deep);
  border-color: var(--vermilion-deep);
}

.gallery-lightbox-cta:disabled {
  opacity: 0.45;
  cursor: default;
}

.gallery-lightbox-cta:focus-visible {
  outline: 2px solid rgba(206, 64, 26, 0.95);
  outline-offset: 2px;
}

.gallery-lightbox-close,
.gallery-lightbox-nav {
  border: 1px solid rgba(255,255,255,0.18);
  background: rgba(18, 18, 18, 0.55);
  color: #fff;
  cursor: pointer;
}

.gallery-lightbox-close {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  font-size: 18px;
  line-height: 1;
}

.gallery-lightbox-nav {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  font-size: 30px;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.gallery-lightbox-nav:disabled {
  opacity: 0.35;
  cursor: default;
}

.gallery-lightbox-close:focus-visible,
.gallery-lightbox-nav:focus-visible {
  outline: 2px solid rgba(206, 64, 26, 0.95);
  outline-offset: 2px;
}

/* ── Lightbox zoom stage (wheel / pinch / double-tap + pan) ─────────────── */
.lightbox-zoom-stage {
  width: 100%;
  max-width: min(92vw, 1080px);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: var(--radius-md);
  touch-action: none;
  cursor: zoom-in;
}

.lightbox-zoom-stage.is-zoomed {
  cursor: grab;
}

.lightbox-zoom-stage.is-panning {
  cursor: grabbing;
}

.lightbox-zoom-stage .gallery-lightbox-image {
  transform-origin: center center;
  will-change: transform;
  user-select: none;
  -webkit-user-drag: none;
}

.lightbox-zoom-controls {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 2;
  display: flex;
  gap: 6px;
}

.lightbox-zoom-btn {
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(18, 18, 18, 0.55);
  color: #fff;
  cursor: pointer;
  height: 34px;
  min-width: 34px;
  padding: 0 10px;
  border-radius: var(--radius-pill);
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
}

.lightbox-zoom-btn:disabled {
  opacity: 0.35;
  cursor: default;
}

.lightbox-zoom-btn:focus-visible {
  outline: 2px solid rgba(206, 64, 26, 0.95);
  outline-offset: 2px;
}

.lightbox-zoom-reset {
  font-size: 12px;
}

@media (max-width: 640px) {
  .lightbox-zoom-btn {
    height: 30px;
    min-width: 30px;
    font-size: 14px;
  }

  .lightbox-zoom-reset {
    font-size: 11px;
  }
}

/* Review photos that open the zoomable lightbox */
.detail-review-body .review-card-photo.is-zoomable {
  cursor: zoom-in;
}

/* Masonry enhancement with graceful fallback to regular grid */
.gallery-grid-masonry {
  display: block;
  column-count: 2;
  column-gap: 12px;
}

.gallery-grid-masonry .gallery-card {
  break-inside: avoid;
  margin-bottom: 12px;
}

#view-detail {
  overflow-y: auto;
  scrollbar-width: none;
}

#view-detail::-webkit-scrollbar {
  display: none;
}

/* The sign-in card was still frosted near-black glass, the first screen a
   new user sees, and the last dark panel in the app outside the lightbox. */
.login-card {
  width: 100%;
  max-width: 400px;
  background: var(--paper-raised);
  padding: var(--space-11) var(--space-9);
  border-radius: var(--radius-lg);
  border: 1px solid var(--hairline);
  box-shadow: var(--shadow-card);
}

.logo-large {
  font-family: var(--font-display);
  font-size: var(--text-display);
  color: var(--brand);
  text-align: center;
  margin-bottom: var(--space-11);
  font-weight: 700;
  letter-spacing: var(--tracking-display);
}

/* Was #ff5252 on a 10% red wash and #4ade80 on a 12% green one, both
   light-on-light once the card stopped being dark, so an auth error was
   rendering as pale pink on near-white. Logged in Phase 6 as the third
   instance of that pattern; this is the fix. Both now use the palette's own
   dark red and sage. */
.auth-feedback {
  background: rgba(143, 42, 34, 0.08);
  border: 1px solid rgba(143, 42, 34, 0.35);
  color: #8F2A22;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  margin-bottom: var(--space-6);
  font-size: var(--text-meta);
  font-weight: 600;
  text-align: center;
}
.auth-feedback.success {
  background: rgba(95, 112, 71, 0.12);
  border-color: rgba(95, 112, 71, 0.38);
  color: var(--sage);
}
.auth-toggle {
  text-align: center;
  margin-top: var(--space-9);
  font-size: 14px;
  color: var(--text-secondary);
}
.auth-toggle a {
  color: var(--vermilion-text);
  text-decoration: none;
  font-weight: 600;
  transition: opacity var(--transition);
}
.auth-toggle a:hover { opacity: 0.8; }
.auth-forgot {
  text-align: center;
  /* .btn-primary has no bottom margin, so this gap must be positive , 
     a negative value pulls the link up over the submit button. The link's
     own padding supplies the rest of the visual gap. */
  margin-top: var(--space-2);
  font-size: 13px;
}
.auth-forgot a {
  /* Padding rather than margin: grows the tap target on mobile without
     moving the text. */
  display: inline-block;
  padding: var(--space-2) var(--space-4);
  color: var(--text-secondary);
  text-decoration: none;
  transition: color var(--transition);
}
.auth-forgot a:hover { color: var(--brand); }

/* ── Feed shell (Phase 6) ──────────────────────────────────────────────
   Greeting → search → filter chips → horizontal rail → sectioned list, after
   the Brewly reference. Width matches #feed-container so the rail, the chips
   and the review cards all sit on one left edge. */
.feed-shell {
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
  padding: var(--space-8) var(--space-8) 0;
}

.feed-intro {
  margin-bottom: var(--space-7);
}

.feed-greeting {
  font-size: var(--text-display);
  color: var(--ink);
  margin-bottom: var(--space-2);
}

.feed-greeting-sub {
  font-size: var(--text-meta);
  color: var(--ink-soft);
}

.feed-search-wrap {
  position: relative;
  display: flex;
  align-items: center;
  margin-bottom: var(--space-5);
}

.feed-search-icon {
  position: absolute;
  left: var(--space-6);
  color: var(--ink-soft);
  pointer-events: none;
}

.feed-search-input {
  margin-bottom: 0;
  /* Clears the icon: gutter + icon width + gap. */
  padding-left: calc(var(--space-6) + 18px + var(--space-4));
  font-size: var(--text-body);
}

/* The feed's filter chips (All · With photos · 4 and up) were removed after
   review, the search plus the rail carry the feed on their own, and three
   chips above the fold were more chrome than the screen needed. */

.feed-rail-section {
  margin-top: var(--space-9);
  margin-bottom: var(--space-9);
}

.feed-rail {
  display: flex;
  gap: var(--space-5);
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: var(--space-2);
}

.feed-rail::-webkit-scrollbar {
  display: none;
}

.rail-empty {
  font-size: var(--text-meta);
  color: var(--ink-soft);
  padding: var(--space-4) 0;
}

.feed-activity-head {
  margin-bottom: var(--space-2);
}

/* Detail view specific setup */
.detail-hero {
  position: relative;
  height: 40vh;
  overflow: hidden;
  /* Was #121212, the collage's own ground, left over from the dark shell.
     It shows through every gap and behind every un-filled tile. */
  background: var(--paper-sunk);
}

.detail-hero-collage {
  width: 100%;
  height: 100%;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  grid-template-rows: repeat(6, 1fr);
  gap: 3px;
  /* This is the grout between tiles: white at 10% over near-black read as a
     hairline, but over paper it read as nothing at all. */
  background: var(--paper);
  will-change: transform;
}

.detail-hero-collage-cell {
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--paper-sunk);
}

.detail-hero-collage-cell:nth-child(1) {
  grid-column: 1 / 3;
  grid-row: 1 / 5;
}

.detail-hero-collage-cell:nth-child(2) {
  grid-column: 1 / 2;
  grid-row: 5 / 7;
}

.detail-hero-collage-cell:nth-child(3) {
  grid-column: 2 / 3;
  grid-row: 5 / 7;
}

.detail-hero-collage-cell:nth-child(4) {
  grid-column: 3 / 5;
  grid-row: 1 / 7;
}

.detail-hero-collage-cell:nth-child(5) {
  grid-column: 5 / 7;
  grid-row: 1 / 4;
}

.detail-hero-collage-cell:nth-child(6) {
  grid-column: 5 / 7;
  grid-row: 4 / 7;
}

.detail-hero-collage-cell:nth-child(7) {
  grid-column: 7 / 9;
  grid-row: 1 / 4;
}

.detail-hero-collage-cell:nth-child(8) {
  grid-column: 7 / 9;
  grid-row: 4 / 7;
}

.detail-hero-collage-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

.detail-hero-collage--placeholder {
  background: var(--paper-sunk);
}

.detail-hero-collage--placeholder .detail-hero-collage-img {
  object-fit: contain;
  opacity: 0.12;
  padding: 18%;
  box-sizing: border-box;
}

@media (max-width: 479px) {
  .detail-hero {
    min-height: 200px;
  }

  .detail-hero-collage {
    gap: 2px;
  }
}
.detail-hero::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  pointer-events: none;
  /* Fades the collage into the page. The transparent stop must be paper, not
     transparent near-black, or the ramp interpolates through grey and leaves
     a dirty band across the bottom of the hero. */
  background: linear-gradient(to bottom, rgba(246, 237, 221, 0) 45%, var(--bg-color) 100%);
}

/* Sits over the detail hero photo, so it needs its own ground rather than
   inheriting the page's. Was dark glass with a white chevron, styling tuned
   for the near-black ground, which survived the flip because it is a
   self-contained panel and so never failed a contrast check. */
.back-fab {
  background: var(--paper-raised);
  color: var(--ink);
  top: var(--space-9); left: var(--space-9); bottom: auto; right: auto; width: 44px; height: 44px;
  border: 1px solid var(--hairline-strong);
  box-shadow: 0 4px 14px rgba(90, 74, 58, 0.24);
}

.back-fab:hover {
  background: var(--paper);
}

/* The sheet: content overlapping the hero upward on a large radius, per the
   reference's detail screen. The hairline along the top edge is what makes it
   read as a sheet laid over the photo rather than as the photo simply ending. */
.detail-body {
  z-index: 2;
  position: relative;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background: var(--bg-color);
  border-top: 1px solid var(--hairline);
  margin-top: -24px;
}

#view-detail .detail-body.scroll-container {
  flex: 0 0 auto;
  overflow: visible;
  min-height: 72vh;
  padding-bottom: calc(var(--nav-clearance) + var(--space-9));
  margin-top: -44px;
}

/* Was a two-column header that set the review count level with the cafe name
   and let a long name squeeze into half the width. Now it stacks: name, then
   meta chips, then the one primary action. */
.detail-header {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
  margin-bottom: var(--space-10);
}

.detail-header h1 {
  font-size: var(--text-display);
  line-height: 1.15;
  overflow-wrap: anywhere;
}

.detail-meta-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.meta-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 5px 12px;
  border-radius: var(--radius-pill);
  background: var(--paper-raised);
  border: 1px solid var(--hairline);
  font-size: var(--text-meta);
  font-weight: 500;
  color: var(--ink-soft);
}

.meta-chip svg {
  flex: 0 0 auto;
  color: var(--vermilion);
}

.meta-chip-count {
  font-weight: 700;
  color: var(--ink);
}

.detail-review-btn {
  width: auto;
  padding: 10px 18px;
  font-size: var(--text-meta);
  border-radius: var(--radius-pill);
}

.location-text { color: var(--ink-soft); font-size: var(--text-meta); }

.reviewer-badge {
  background: var(--bg-surface); padding: 6px 14px; border-radius: var(--radius-pill);
  font-size: 13px; font-weight: 600; color: var(--text-primary); border: 1px solid var(--hairline);
}

.score-bars { margin-bottom: var(--space-11); background: var(--bg-surface); padding: var(--space-8); border-radius: var(--radius-md); border: 1px solid var(--hairline); }
/* Editorial rows, after the reference's menu: label left, value right, thin
   rule between. The rule is what makes a list of three scores read as a set
   rather than as three floating pairs. */
.score-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  padding-bottom: var(--space-4);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--hairline);
}

.score-row:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; }
.score-label { font-size: var(--text-body); font-weight: 600; }

.trophy-cabinet {
  margin-bottom: 26px;
}

.trophy-cabinet-list {
  margin-top: 10px;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

/* A printed seal, not a metal medal.
   This was the most skeuomorphic thing left in the app: a near-black card
   under two gradients, a conic-gradient "metal" disc, four inset highlight /
   shadow pairs, a text-shadow and a glow. Every one of those is on the
   direction's reject list, and none of them survive on cream.
   The app already has a printed-seal language in the roast stamps, so an
   award becomes a stamp: flat, hairlined, vermilion where it matters. */
.trophy-badge-card {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline);
  background: var(--paper-raised);
  padding: var(--space-5) var(--space-3);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: 128px;
  text-align: center;
}

/* The seal: a scalloped wax-stamp disc with the award icon knocked out of it
   in paper. Flat colour doing the work of the old gradient metal, an award
   should still feel like a reward, which the first flat pass lost. */
.trophy-badge-seal {
  position: relative;
  width: 58px;
  height: 58px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.seal-rosette {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.seal-rosette path {
  fill: var(--vermilion);
}

.trophy-badge-icon {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
}

.trophy-badge-icon svg {
  width: 24px;
  height: 24px;
  stroke: var(--paper-raised);
  stroke-width: 1.9;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.trophy-badge-text {
  min-width: 0;
}

.trophy-badge-title {
  color: var(--ink);
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: var(--tracking-label);
  line-height: 1.2;
  text-transform: uppercase;
}

.trophy-badge-date {
  margin-top: 3px;
  color: var(--ink-soft);
  font-size: var(--text-label);
  font-weight: 600;
  letter-spacing: 0.2px;
}

/* Gold is spent here and nowhere else in the app: the top prize gets the gold
   seal on a gold-tinted card, the category awards get vermilion. That is the
   hierarchy the old design got from a glow. */
.trophy-badge-card--overall {
  min-height: 140px;
  border-color: var(--gold);
  background: var(--gold-wash);
}

.trophy-badge-card--overall .trophy-badge-seal {
  width: 68px;
  height: 68px;
}

.trophy-badge-card--overall .seal-rosette path {
  fill: var(--gold);
}

.trophy-badge-card--overall .trophy-badge-icon svg {
  width: 28px;
  height: 28px;
}

.trophy-badge-card--overall .trophy-badge-title {
  color: var(--gold);
}

@media (min-width: 760px) {
  .trophy-cabinet-list {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.trophy-empty {
  grid-column: 1 / -1;
  border-radius: var(--radius-md);
  border: 1px dashed var(--hairline-strong);
  background: var(--wash);
  padding: var(--space-4);
  text-align: center;
}

.trophy-empty-sub {
  color: var(--text-secondary);
  font-size: var(--text-meta);
}

.verdict-section h3 { font-size: var(--text-title); margin-bottom: var(--space-4); color: var(--text-primary); }

/* Leaderboard Cards */
/* ── Editorial rank rows ───────────────────────────────────────────────
   Large vermilion numeral in the left gutter, name in the display face,
   score right-aligned in tabular numerals, the Gofé menu's row, where a
   dish sits left and its price sits right against a generous baseline. */
.lb-card {
  background: var(--bg-surface);
  padding: var(--space-5) var(--space-6);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
  border: 1px solid var(--hairline);
  display: flex;
  align-items: center;
  gap: var(--space-5);
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease;
  position: relative;
}

.lb-card:hover {
  border-color: rgba(206, 64, 26, 0.35);
}

.lb-rank {
  flex: 0 0 auto;
  min-width: 34px;
  text-align: center;
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: var(--tracking-display);
  color: var(--vermilion);
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

.lb-row-main {
  flex: 1;
  min-width: 0;
}

/* The name used to be clamped to one line with an ellipsis, so "Maeve's
   Suffolk Coffee" rendered as "Maeve's Suff…". A leaderboard whose whole job
   is naming cafes should not hide their names; two lines are allowed. */
.lb-card-name {
  margin: 0 0 2px;
  font-size: var(--text-heading);
  color: var(--text-primary);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.lb-row-location {
  margin: 0;
  font-size: var(--text-meta);
  color: var(--ink-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.lb-row-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

.lb-row-score {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
}

.lb-score {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-title);
  line-height: 1;
  letter-spacing: var(--tracking-display);
  color: var(--ink);
}

.lb-score.is-empty {
  color: var(--ink-soft);
}

.lb-score-label {
  font-size: var(--text-label);
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  font-weight: 600;
}

.lb-row-reviews {
  font-size: var(--text-label);
  color: var(--ink-soft);
  font-weight: 500;
  margin-top: 3px;
}

/* Podium metals. The original treatment was a coloured glow plus a metallic
   gradient wash on each row, which on cream read as a highlighter smear; this
   keeps the medal signal as a rank numeral and a border, flat. */
.lb-gold {
  border-color: var(--gold);
}

.lb-gold .lb-rank {
  color: var(--gold);
}

.lb-silver {
  border-color: rgba(110, 110, 115, 0.55);
}

.lb-silver .lb-rank {
  color: var(--silver);
}

.lb-bronze {
  border-color: rgba(138, 84, 35, 0.5);
}

.lb-bronze .lb-rank {
  color: var(--bronze);
}

.lb-movement {
  display: inline-flex;
  align-items: center;
  font-size: 10px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: var(--radius-pill);
  letter-spacing: 0.2px;
}

/* Neon green/red were tuned for a dark ground (1.5:1 and 2.38:1 on paper).
   These use the palette's own sage and vermilion instead, in their text
   weights, because each of these labels sits on its own tinted wash and is a
   10–12px letterform. The ramp colours themselves measured 4.01 (sage) and
   3.31–3.67 (vermilion) against those washes. */
.lb-up {
  color: var(--sage-text);
  background: rgba(95, 112, 71, 0.12);
  border: 1px solid rgba(95, 112, 71, 0.30);
}

.lb-down {
  color: var(--vermilion-deep);
  background: rgba(206, 64, 26, 0.10);
  border: 1px solid rgba(206, 64, 26, 0.28);
}

.lb-same {
  color: var(--text-secondary);
  background: var(--paper-sunk);
  border: 1px solid var(--hairline);
}

.lb-new {
  color: var(--vermilion-text);
  background: rgba(206, 64, 26, 0.12);
  border: 1px solid rgba(206, 64, 26, 0.28);
}

/* Sits over the rank numeral's gutter. Uses the award gold established for
   the trophy seals, so "top of the leaderboard" and "won a monthly award"
   speak the same colour. */
.lb-crown {
  position: absolute;
  top: -9px;
  left: var(--space-8);
  width: 18px;
  height: 18px;
  color: var(--gold);
  filter: none;
  pointer-events: none;
}

/* ── Profile / Wrapped Page ───────────────────────────────────────────── */
.profile-loading {
  text-align: center;
  padding: 60px 20px;
  color: var(--text-secondary);
  font-size: 14px;
}

.profile-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 16px 20px 28px;
  gap: 6px;
}

.profile-avatar-large {
  width: 80px;
  height: 80px;
  border-radius: 50%;
  /* Solid vermilion with a paper initial, matching the header and feed
     avatars. The old vermilion-tinted gradient carried vermilion text, which
     only worked because the tint sat on a near-black card. */
  background: var(--vermilion);
  border: none;
  color: var(--paper-raised);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 8px;
  box-shadow: 0 8px 24px rgba(206, 64, 26, 0.18);
}

.profile-username {
  font-family: var(--font-logo);
  font-size: 22px;
  font-weight: 700;
  color: var(--text-primary);
  letter-spacing: -0.2px;
}

.profile-email {
  font-size: 13px;
  color: var(--text-secondary);
  font-weight: 500;
}

/* Account Settings entry button on the Wrapped page */
.profile-settings-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 18px;
  padding: 11px 22px;
  border-radius: var(--radius-pill);
  background: rgba(206, 64, 26, 0.12);
  border: 1px solid rgba(206, 64, 26, 0.5);
  color: var(--brand);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: 0 6px 18px rgba(206, 64, 26, 0.16);
  transition: background var(--duration-fast) ease, border-color var(--duration-fast) ease, transform var(--duration-fast) ease, box-shadow var(--duration-fast) ease;
}

.profile-settings-btn:hover {
  background: rgba(206, 64, 26, 0.20);
  border-color: rgba(206, 64, 26, 0.75);
  box-shadow: 0 8px 22px rgba(206, 64, 26, 0.24);
}

.profile-settings-btn:active {
  transform: scale(0.97);
  box-shadow: 0 4px 12px rgba(206, 64, 26, 0.18);
}

.profile-settings-btn svg {
  flex-shrink: 0;
}

.profile-empty {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-secondary);
}

.profile-empty-title {
  font-family: var(--font-logo);
  font-size: 20px;
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 6px;
}

.profile-empty-sub {
  font-size: 13px;
}

.profile-tabs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  margin-bottom: 12px;
}

.profile-tab-btn {
  border: 1px solid var(--hairline);
  background: var(--paper-raised);
  color: var(--text-secondary);
  border-radius: var(--radius-pill);
  padding: 10px 12px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease;
}

.profile-tab-btn.active {
  border-color: rgba(206, 64, 26, 0.52);
  background: rgba(206, 64, 26, 0.14);
  color: var(--brand);
}

.saved-cafes-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.saved-cafe-card {
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline);
  background: var(--bg-surface);
  padding: 14px 14px 12px;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.16);
}

.saved-cafe-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.saved-cafe-head-main {
  flex: 1;
  min-width: 0;
}

.saved-cafe-name {
  margin: 0;
  font-family: var(--font-logo);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-primary);
}

.saved-cafe-location {
  margin: 4px 0 0;
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.35;
}

.saved-cafe-thumb {
  width: 104px;
  height: 104px;
  border-radius: 12px;
  border: 1px solid rgba(206, 64, 26, 0.3);
  background: var(--paper-sunk);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  overflow: hidden;
}

.saved-cafe-thumb-img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
}

.saved-cafe-thumb span {
  font-size: 19px;
  line-height: 1;
  opacity: 0.9;
}

.saved-cafe-meta {
  margin-top: 9px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
}

.saved-cafe-meta-left {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.saved-cafe-chip {
  border: 1px solid var(--hairline-strong);
  background: var(--paper-sunk);
  color: var(--text-secondary);
  border-radius: var(--radius-pill);
  padding: 4px 8px;
  font-size: 11px;
  font-weight: 700;
}

.saved-cafe-chip-reviewed {
  border-color: var(--hairline-strong);
  background: var(--paper-sunk);
  color: var(--text-secondary);
}

.saved-cafe-chip-count {
  color: var(--brand);
  font-weight: 800;
}

.saved-cafe-date {
  color: var(--text-secondary);
  font-size: 11px;
  font-weight: 600;
}

.saved-cafe-date-bottom {
  margin-top: 8px;
  text-align: right;
}

.saved-cafe-actions {
  margin-top: 11px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.saved-cafe-log-btn {
  width: auto;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 1px solid rgba(206, 64, 26, 0.72);
  background: rgba(206, 64, 26, 0.14);
  color: var(--brand);
  border-radius: var(--radius-pill);
  padding: 7px 12px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.2px;
  cursor: pointer;
  box-shadow: 0 5px 12px rgba(206, 64, 26, 0.14);
  transition: background 0.16s ease, border-color 0.16s ease, transform 0.16s ease, box-shadow 0.16s ease;
}

.saved-cafe-log-btn:hover {
  background: rgba(206, 64, 26, 0.2);
  border-color: rgba(206, 64, 26, 0.9);
  box-shadow: 0 7px 14px rgba(206, 64, 26, 0.2);
}

.saved-cafe-log-btn:active {
  transform: scale(0.97);
}

.saved-cafe-log-btn span[aria-hidden="true"] {
  font-size: 13px;
  line-height: 1;
}

.saved-cafe-remove-btn {
  width: 30px;
  height: 30px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--hairline-strong);
  background: var(--paper-sunk);
  color: var(--text-secondary);
  border-radius: var(--radius-pill);
  padding: 0;
  cursor: pointer;
  transition: border-color 0.16s ease, color 0.16s ease, background 0.16s ease, transform 0.16s ease;
}

.saved-cafe-remove-btn:hover {
  border-color: rgba(143, 42, 34, 0.5);
  background: rgba(143, 42, 34, 0.10);
  color: var(--text-primary);
}

.saved-cafe-remove-btn:active {
  transform: scale(0.94);
}

.saved-cafe-remove-icon {
  width: 14px;
  height: 14px;
}

@media (max-width: 520px) {
  .saved-cafe-card {
    padding: 12px 12px 11px;
  }

  .saved-cafe-head {
    gap: 10px;
  }

  .saved-cafe-thumb {
    width: 92px;
    height: 92px;
    border-radius: 10px;
  }

  .saved-cafe-thumb span {
    font-size: 17px;
  }

  .saved-cafe-name {
    font-size: 17px;
  }

  .saved-cafe-meta-left {
    gap: 6px;
  }

  .saved-cafe-actions {
    gap: 6px;
  }
}

.stat-grid {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.stat-card {
  border-radius: var(--radius-md);
  border: 1px solid var(--hairline);
  background: var(--bg-surface);
  padding: 18px;
  position: relative;
  overflow: hidden;
}

/* Hero, total reviews */
.stat-hero {
  text-align: center;
  padding: 28px 20px;
  background: rgba(206, 64, 26, 0.10);
  border-color: rgba(206, 64, 26, 0.3);
  box-shadow: 0 12px 30px rgba(206, 64, 26, 0.12);
}

.stat-hero-num {
  font-family: var(--font-logo);
  font-size: 64px;
  font-weight: 800;
  color: var(--brand);
  line-height: 1;
  letter-spacing: -2px;
  margin-bottom: 4px;
  text-shadow: 0 4px 18px rgba(206, 64, 26, 0.25);
}

.stat-hero-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 1.5px;
}

/* Trinity, three avg scores in one card */
.stat-trinity {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  padding: 18px 0;
}

.stat-trinity-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 0 8px;
  border-right: 1px solid var(--hairline);
}

.stat-trinity-cell:last-child {
  border-right: none;
}

.stat-trinity-emoji {
  font-size: 22px;
  line-height: 1;
  margin-bottom: 4px;
}

.stat-trinity-val {
  font-family: var(--font-logo);
  font-size: 32px;
  font-weight: 800;
  letter-spacing: -1px;
  line-height: 1;
}

.stat-trinity-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 1px;
  margin-top: 4px;
}

/* Feature cards, Favourite + Most Visited */
.stat-feature {
  padding: 20px;
}

.stat-favourite {
  background: var(--gold-wash);
  border-color: rgba(255, 215, 0, 0.28);
  box-shadow: 0 8px 22px rgba(255, 215, 0, 0.06);
}

.stat-loyal {
  background: rgba(176, 99, 44, 0.10);
  border-color: rgba(227, 100, 20, 0.28);
  box-shadow: 0 8px 22px rgba(227, 100, 20, 0.06);
}

.stat-feature-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 1.4px;
  margin-bottom: 10px;
}

.stat-feature-name {
  font-family: var(--font-logo);
  font-size: 24px;
  font-weight: 800;
  color: var(--text-primary);
  line-height: 1.15;
  margin-bottom: 4px;
  letter-spacing: -0.4px;
}

.stat-feature-loc {
  font-size: 13px;
  color: var(--text-secondary);
  margin-bottom: 14px;
}

.stat-feature-meta {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 13px;
  font-weight: 700;
}

.stat-feature-score {
  font-family: var(--font-logo);
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.3px;
}

.stat-feature-count {
  color: var(--text-secondary);
  font-weight: 600;
}

/* Mini grid */
.stat-mini-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.stat-top-picks-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.stat-top-pick-card {
  padding: 14px 12px;
  text-align: center;
}

.stat-top-pick-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--brand);
  letter-spacing: 0.8px;
  text-transform: uppercase;
}

.stat-top-pick-name {
  margin-top: 6px;
  font-family: var(--font-logo);
  font-size: 20px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.15;
}

.stat-top-pick-score {
  margin-top: 8px;
  font-family: var(--font-logo);
  font-size: 28px;
  font-weight: 800;
  letter-spacing: -0.6px;
  line-height: 1;
  text-shadow: none;
}

.stat-top-pick-sub {
  margin-top: 6px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
}

.stat-mini {
  padding: 16px 14px;
  text-align: center;
}

.stat-mini-num {
  font-family: var(--font-logo);
  font-size: 28px;
  font-weight: 800;
  color: var(--brand);
  line-height: 1;
  letter-spacing: -0.5px;
  margin-bottom: 6px;
}

.stat-mini-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 1.1px;
}

.stat-mini-text .stat-mini-text-val {
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 700;
  color: var(--text-primary);
  line-height: 1.2;
  margin-bottom: 6px;
  word-break: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── Account Settings (rendered inside #view-settings) ───────────────── */
.account-settings {
  background: var(--bg-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md);
  padding: 22px 20px 24px;
}

#settings-content .account-settings {
  margin-top: 8px;
}

.settings-title {
  font-family: var(--font-logo);
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.3px;
  color: var(--text-primary);
  margin-bottom: 18px;
}

/* Hide the redundant "Account Settings" title when this section is the
   sole content of the dedicated Settings view (the top-nav already says it). */
#settings-content .account-settings .settings-title {
  display: none;
}

.settings-avatar-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-bottom: 22px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--hairline);
}

.settings-avatar-wrap {
  position: relative;
  cursor: pointer;
}

.settings-avatar-wrap:active .settings-avatar {
  opacity: 0.85;
  transform: scale(0.97);
}

.settings-avatar {
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.settings-avatar {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  /* Keeps the dashed edge, it signals "tap to change", but on a flat
     vermilion fill with a paper initial, like every other avatar. */
  background: var(--vermilion);
  border: 2px dashed var(--paper-raised);
  color: var(--paper-raised);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 22px rgba(206, 64, 26, 0.16);
}

.settings-avatar-overlay {
  position: absolute;
  bottom: -2px;
  right: -2px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--bg-elevated);
  border: 2px solid var(--bg-surface);
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.settings-avatar-hint {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-secondary);
  font-style: italic;
  letter-spacing: 0.2px;
}

.settings-row {
  margin-bottom: 18px;
}

.settings-row:last-child {
  margin-bottom: 0;
}

/* ── Danger zone ──────────────────────────────────────────────────────────
   Set apart with a rule and space rather than a red panel. A field of red
   makes the destructive control harder to read, not more serious, and the
   palette's one hot accent is already vermilion, a second alarm colour would
   just compete with it. The weight sits on the button. */
.settings-danger {
  margin-top: var(--space-11);
  padding-top: var(--space-8);
  border-top: 1px solid var(--hairline-strong);
}

.settings-danger-copy {
  margin-bottom: var(--space-4);
  color: var(--text-secondary);
  font-size: var(--text-meta);
  line-height: 1.5;
}

.settings-danger-copy strong {
  color: var(--text-primary);
  font-weight: 700;
}

.settings-danger-btn {
  padding: var(--space-4) var(--space-8);
  border: 1px solid var(--vermilion-deep);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--vermilion-deep);
  font-family: var(--font-body);
  font-size: var(--text-meta);
  font-weight: 700;
  cursor: pointer;
  transition: background var(--duration-fast) ease, color var(--duration-fast) ease;
}

.settings-danger-btn:hover:not(:disabled) {
  background: var(--vermilion-deep);
  color: var(--paper-raised);
}

.settings-danger-btn:disabled {
  opacity: 0.45;
  cursor: default;
}

.settings-danger-btn:focus-visible {
  outline: 2px solid var(--vermilion-deep);
  outline-offset: 2px;
}

.settings-danger-confirm {
  margin-top: var(--space-6);
  padding: var(--space-6);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--radius-md);
  background: var(--paper-sunk);
}

.settings-danger-confirm label {
  text-transform: none;
  letter-spacing: normal;
  font-size: var(--text-meta);
}

.settings-danger-confirm input {
  margin-bottom: var(--space-6);
  /* Typing DELETE in lower case should still work; this is a speed bump
     against a mis-tap, not a spelling test. */
  text-transform: uppercase;
}

.settings-danger-actions {
  display: flex;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.settings-row label {
  display: block;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 1.1px;
  margin-bottom: 8px;
}

.settings-input-row {
  display: flex;
  gap: 10px;
  align-items: stretch;
}

.settings-input-row input {
  flex: 1;
  margin-bottom: 0;
  font-size: 14px;
  padding: 12px 14px;
}

.settings-row > input[type="password"] {
  margin-bottom: 8px;
  font-size: 14px;
  padding: 12px 14px;
}

.settings-save-btn {
  background: var(--brand);
  color: var(--paper-raised);
  border: none;
  border-radius: var(--radius-pill);
  padding: 0 18px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.2px;
  cursor: pointer;
  white-space: nowrap;
  font-family: var(--font-body);
  transition: filter 0.18s ease, transform 0.18s ease, box-shadow 0.18s ease;
  box-shadow: 0 4px 12px rgba(206, 64, 26, 0.18);
}

.settings-save-btn:hover {
  filter: brightness(1.06);
  box-shadow: 0 6px 16px rgba(206, 64, 26, 0.24);
}

.settings-save-btn:active {
  transform: scale(0.97);
}

.settings-save-btn:disabled {
  opacity: 0.55;
  cursor: default;
  box-shadow: none;
}

.settings-save-block {
  width: 100%;
  padding: 13px;
  margin-top: 6px;
}

.settings-feedback {
  margin-top: 10px;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
}

.settings-feedback.success {
  background: rgba(74, 222, 128, 0.10);
  border: 1px solid rgba(74, 222, 128, 0.28);
  color: #4ade80;
}

.settings-feedback.error {
  background: rgba(248, 113, 113, 0.10);
  border: 1px solid rgba(248, 113, 113, 0.28);
  color: #f87171;
}

.settings-feedback.info {
  background: var(--paper-sunk);
  border: 1px solid var(--hairline);
  color: var(--text-secondary);
}

@media (max-width: 480px) {
  .activity-scores {
    flex-direction: row;
  }
  .activity-score-pill {
    font-size: 9px;
    padding: 2px 6px;
  }
  .reaction-btn {
    padding: 4px 8px;
  }
}

@media (max-width: 420px) {
  .profile-trigger-name {
    max-width: 80px;
  }
}

@media (max-width: 420px) {
  .map-info-wrap {
    left: calc(var(--space-6) + 40px);
    right: var(--space-6);
  }

  .map-canvas {
    height: calc(100vh - 156px);
    min-height: 360px;
  }

  #gallery-controls-host {
    padding: var(--space-5) var(--space-6) var(--space-5);
  }

  .gallery-lightbox-content {
    padding: 20px 6px 16px;
    gap: 6px;
  }

  .gallery-lightbox-nav {
    width: 36px;
    height: 36px;
    font-size: 24px;
  }

  .gallery-lightbox-close {
    width: 36px;
    height: 36px;
  }

  .gallery-grid-masonry {
    column-count: 1;
    column-gap: 12px;
  }
  .gallery-grid {
    grid-template-columns: 1fr;
    padding: 12px;
  }
  .settings-input-row {
    flex-direction: column;
  }
  .settings-save-btn {
    padding: 12px;
  }
}

@media (max-width: 959px) {
  .detail-hero {
    height: 52vw;
    min-height: 220px;
  }

  #view-detail .detail-body.scroll-container {
    margin-top: -16px;
  }
}

@media (min-width: 600px) {
  .stat-top-picks-grid {
    grid-template-columns: 1fr 1fr 1fr;
  }

  .gallery-grid-masonry {
    column-count: 3;
    column-gap: 14px;
  }

  .gallery-grid-masonry .gallery-card {
    margin-bottom: 14px;
  }

  .gallery-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
    padding: 16px;
  }
  .stat-mini-grid {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

@media (min-width: 960px) {
  .gallery-grid-masonry {
    column-count: 4;
    column-gap: 16px;
  }

  .gallery-grid-masonry .gallery-card {
    margin-bottom: 16px;
  }

  .gallery-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
  }
  #view-detail .detail-hero {
    width: calc(100% - 48px);
    max-width: 1200px;
    min-height: 320px;
    margin-left: auto;
    margin-right: auto;
    margin-top: 12px;
    border-radius: 20px;
    overflow: hidden;
  }

  #view-detail .detail-body {
    max-width: 1320px;
    width: 100%;
    margin-left: auto;
    margin-right: auto;
    margin-top: -72px;
  }

  #view-detail .detail-body.scroll-container {
    min-height: 75vh;
    padding-bottom: 120px;
    margin-top: -72px;
  }
}
