@import url('https://fonts.googleapis.com/css2?family=Prata:ital,wght@0,400;0,500;1,400&family=Stoke:wght@300;400;500;600&display=swap');.auth-page {
  min-height: 100vh;
  min-height: 100svh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(2rem + env(safe-area-inset-top)) 1.5rem calc(3rem + env(safe-area-inset-bottom));
  background: radial-gradient(circle at 100% 100%, rgba(201, 167, 240, 0.1), transparent 45%),
    radial-gradient(circle at 80% 0%, rgba(157, 111, 212, 0.1), transparent 55%),
    var(--background);
  position: relative;
  overflow: hidden;
}

html[data-native-platform='ios'] .auth-page {
  min-height: 100dvh;
  height: auto;
  overflow: visible;
  align-items: flex-start;
  padding-top: calc(3rem + env(safe-area-inset-top));
  padding-bottom: calc(3rem + env(safe-area-inset-bottom));
  background: var(--background);
}

.auth-page::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(120deg, rgba(255, 255, 255, 0.1), transparent 45%, rgba(255, 255, 255, 0.03));
  opacity: 0.7;
  pointer-events: none;
}

.auth-container {
  position: relative;
  width: 100%;
  max-width: 440px;
  padding: 2.75rem;
  border-radius: 22px;
  border: 2px solid rgba(255, 255, 255, 0.1);
  background: rgba(89, 101, 170, 0.1);
  backdrop-filter: blur(10px);
  box-shadow: 0 32px 64px rgba(0, 0, 0, 0.5);
  animation: authFade 650ms cubic-bezier(0.2, 1, 0.3, 1);
  z-index: 1;
}

.auth-title {
  font-size: var(--fs-2xl);
  color: var(--text);
  margin-bottom: 0.4rem;
  letter-spacing: -0.02em;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.65rem;
  width: 100%;
}

.auth-title-icon {
  width: 46px;
  height: 46px;
  border-radius: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.auth-title-icon img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: drop-shadow(0px 2px 20px rgba(255, 255, 255, 0.2));
}

.auth-title-text {
  line-height: 1;
}

.auth-subtitle {
  text-align: center;
  color: var(--text-secondary);
  margin-bottom: 1.75rem;
}

.auth-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.6rem;
  background: rgba(255, 255, 255, 0.02);
  padding: 0.3rem;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.07);
}

.auth-tabs button {
  flex: 1;
  padding: 0.75rem;
  background: transparent;
  color: var(--text-secondary);
  font-weight: 600;
  border-radius: 10px;
  letter-spacing: -0.01em;
  transition: color 0.25s ease, background-color 0.3s ease, transform 0.3s ease;
}

.auth-tabs button.active {
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
  box-shadow: none;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.auth-field-switch {
  position: relative;
  min-height: 0;
  transition: height 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}

.auth-field-group {
  display: grid;
  gap: 0.75rem;
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: translateY(-12px);
  pointer-events: none;
  transition: opacity 0.35s ease, transform 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}

.auth-field-group.is-active {
  position: relative;
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.auth-input {
  padding: 0.9rem 1rem;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.08);
  color: var(--text);
  font-size: var(--fs-base);
  transition: border-color 0.25s ease, background-color 0.25s ease, transform 0.25s ease;
}

.auth-input:focus {
  border-color: rgba(201, 167, 240, 0.75);
  background: rgba(255, 255, 255, 0.06);
}

.auth-password-wrap {
  position: relative;
}

.auth-password-wrap .auth-input {
  width: 100%;
  padding-right: 3rem;
}

.auth-password-toggle {
  position: absolute;
  right: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: none;
  color: var(--text-secondary);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem;
  border-radius: 6px;
  transition: color 0.2s ease;
}
@media (hover: hover) and (pointer: fine) {
  .auth-password-toggle:hover {
    color: var(--text);
  }
}

.auth-password-hint {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin: -0.4rem 0 0;
}

.auth-policy-check {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  line-height: 1.45;
}

.auth-policy-check input {
  margin-top: 0.15rem;
}

.auth-policy-check a {
  color: var(--primary);
  text-decoration: underline;
}

.auth-forgot-link {
  background: none;
  border: none;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  text-align: right;
  align-self: flex-end;
  padding: 0;
  margin-top: -0.25rem;
  transition: color 0.2s ease;
}
@media (hover: hover) and (pointer: fine) {
  .auth-forgot-link:hover {
    color: var(--primary);
  }
}

.auth-forgot-desc {
  color: var(--text-secondary);
  font-size: var(--fs-base);
  line-height: 1.5;
  margin: 0;
}

.auth-success {
  color: var(--success);
  font-size: var(--fs-sm);
  margin: -0.5rem 0 0;
}

.auth-back-link {
  background: none;
  border: none;
  color: var(--text-secondary);
  font-size: var(--fs-base);
  text-align: center;
  padding: 0.25rem;
  transition: color 0.2s ease;
}
@media (hover: hover) and (pointer: fine) {
  .auth-back-link:hover {
    color: var(--primary);
  }
}

.auth-privacy-message {
  margin: 1.5rem 0 1rem;
  padding: 0.875rem 1rem;
  background: rgba(157, 111, 212, 0.08);
  border: 1px solid rgba(157, 111, 212, 0.2);
  border-radius: 10px;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  text-align: center;
  line-height: 1.5;
}

.auth-privacy-message p {
  margin: 0;
  color: inherit;
}

.auth-legal-links {
  margin-top: 1rem;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.auth-legal-links a {
  color: var(--primary);
  text-decoration: underline;
  padding: 0.5rem 0.25rem;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}

.auth-error {
  color: var(--error);
  font-size: var(--fs-sm);
  margin: -0.5rem 0 0;
}

.auth-submit {
  padding: 1rem;
  background: linear-gradient(120deg, #9d6fd4 0%, #c9a7f0 100%);
  color: #f4fbff;
  border-radius: 14px;
  font-weight: 600;
  font-size: var(--fs-base);
  border: 1px solid rgba(15, 54, 105, 0.8);
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), filter 0.3s ease, opacity 0.2s ease;
  box-shadow: none;
}
@media (hover: hover) and (pointer: fine) {
  .auth-submit:hover:not(:disabled) {
    filter: brightness(1.12);
  }
}

.auth-submit:disabled {
  opacity: 0.6;
  cursor: wait;
}

.auth-divider {
  display: flex;
  align-items: center;
  text-align: center;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  margin: 0.5rem 0;
  gap: 1rem;
}

.auth-divider::before,
.auth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: rgba(255, 255, 255, 0.1);
}

.auth-google-btn {
  padding: 0.95rem 1rem;
  background: linear-gradient(135deg, #121826, #1f2a3d);
  color: #f5f7ff;
  border-radius: 12px;
  font-weight: 600;
  font-size: var(--fs-base);
  border: 1px solid rgba(255, 255, 255, 0.08);
  transition: background-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
}
@media (hover: hover) and (pointer: fine) {
  .auth-google-btn:hover:not(:disabled) {
    background: linear-gradient(135deg, #182235, #25324a);
    box-shadow: 0 18px 32px rgba(0, 0, 0, 0.4);
  }
}

.auth-google-btn:disabled {
  opacity: 0.6;
  cursor: wait;
}

.auth-google-btn svg {
  flex-shrink: 0;
}

/* Apple Sign In — black pill per Apple HIG */
.auth-apple-btn {
  padding: 0.95rem 1rem;
  background: #000;
  color: #fff;
  border-radius: 12px;
  font-weight: 600;
  font-size: var(--fs-base);
  border: 1px solid rgba(255, 255, 255, 0.12);
  transition: background-color 0.2s ease, box-shadow 0.2s ease;
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  width: 100%;
  margin-top: 0.6rem;
}
@media (hover: hover) and (pointer: fine) {
  .auth-apple-btn:hover:not(:disabled) {
    background: #111;
    box-shadow: 0 18px 32px rgba(0, 0, 0, 0.5);
  }
}

.auth-apple-btn:disabled {
  opacity: 0.6;
  cursor: wait;
}

.auth-apple-btn svg {
  flex-shrink: 0;
}

@keyframes authFade {
  from {
    opacity: 0;
    transform: translateY(18px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes surfaceDrift {
  from {
    transform: translate3d(-2%, -1%, 0);
    opacity: 0.55;
  }

  to {
    transform: translate3d(3%, 2%, 0);
    opacity: 0.85;
  }
}

@media (max-width: 640px) {
  .auth-container {
    padding: 2.25rem 1.75rem;
    border-radius: 18px;
  }

  .auth-tabs button {
    font-size: var(--fs-base);
  }
}

@media (max-width: 400px) {
  .auth-page {
    padding: 1rem 0 calc(2rem + env(safe-area-inset-bottom));
    align-items: flex-end;
  }

  .auth-container {
    width: 100%;
    border-radius: 20px 20px 0 0;
    padding: 2rem 1.25rem calc(1.5rem + env(safe-area-inset-bottom));
    border-bottom: none;
  }
}
.home-page {
  min-height: 100vh;
  min-height: 100svh;
  min-height: 100dvh;
  color: var(--text);
  padding: clamp(1.25rem, 2vw, 2rem);
  max-width: 960px;
  margin: 0 auto;
}

.home-hero {
  margin-top: 4.5rem;
  padding: clamp(1.75rem, 2.2vw, 2.5rem);
  border-radius: 20px;
  border: 1px solid rgba(90, 188, 234, 0.28);
  background:
    radial-gradient(circle at 20% -10%, rgba(90, 188, 234, 0.24), transparent 35%),
    radial-gradient(circle at 90% 110%, rgba(10, 104, 255, 0.2), transparent 40%),
    rgba(18, 24, 48, 0.78);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}

.home-logo-row {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-bottom: 1.1rem;
}

.home-logo-icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
}

.home-logo-text {
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text);
}

.home-hero h1 {
  margin: 0;
  font-size: clamp(1.9rem, 4vw, 3rem);
  line-height: 1.12;
}

.home-subtitle {
  margin: 1rem 0 0;
  max-width: 68ch;
  color: var(--text-secondary);
  line-height: 1.6;
}

.home-cta-row {
  margin-top: 1.3rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.home-cta-primary,
.home-cta-secondary {
  min-height: 44px;
  padding: 0.72rem 1.1rem;
  border-radius: 10px;
  text-decoration: none;
  font-weight: 600;
}

.home-cta-primary {
  background: linear-gradient(120deg, #9d6fd4, #c9a7f0);
  color: #f4fbff;
}

.home-cta-secondary {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: var(--text);
}

.home-section {
  margin-top: 1.1rem;
  padding: clamp(1rem, 2vw, 1.4rem);
  border-radius: 16px;
  border: 1px solid var(--border);
  background: var(--surface);
}

.home-section h2 {
  margin: 0 0 0.85rem;
}

.home-feature-grid {
  display: grid;
  gap: 0.8rem;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.home-feature-card {
  padding: 0.9rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.08);
  /* Stagger off the card's own index so the three arrive in reading order
     rather than all at once. `backwards` fill — never `both` — so no transform
     is left on the card afterwards. */
  animation: slideInUp 0.32s ease-out backwards;
  animation-delay: calc(0.06s * var(--card-index, 0) + 0.08s);
}

.home-feature-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  margin-bottom: 0.6rem;
  border-radius: 10px;
  font-size: 0.95rem;
  color: var(--primary);
  background: rgba(201, 167, 240, 0.12);
  border: 1px solid rgba(201, 167, 240, 0.22);
}

.home-feature-card h3 {
  margin: 0 0 0.4rem;
  font-size: var(--fs-base);
}

.home-feature-card p {
  margin: 0;
  color: var(--text-secondary);
  line-height: 1.5;
}

/* The icons replace the bullets rather than sitting alongside them, so the
   list gains meaning without gaining clutter. */
.home-security ul {
  margin: 0;
  padding-left: 0;
  list-style: none;
  color: var(--text-secondary);
  line-height: 1.6;
  display: grid;
  gap: 0.5rem;
}

.home-security li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
}

.home-security li > svg {
  flex-shrink: 0;
  width: 15px;
  margin-top: 0.28em;
  color: var(--primary);
  opacity: 0.85;
}

.home-footer {
  margin: 1.15rem 0 0.85rem;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  color: var(--text-secondary);
}

.home-footer a {
  color: var(--primary);
  text-decoration: underline;
}

@media (prefers-reduced-motion: reduce) {
  .home-feature-card {
    animation: none;
  }
}
.loading-indicator {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  text-align: center;
  color: var(--text-secondary);
  letter-spacing: 0.02em;
  animation: fadeIn 0.2s ease-out;
}

.loading-indicator-start {
  align-items: flex-start;
  text-align: left;
}

.loading-track {
  position: relative;
  height: 6px;
  width: 160px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  overflow: hidden;
  box-shadow: inset 0 0 12px rgba(0, 0, 0, 0.25);
}

.loading-track-sm {
  width: 120px;
  height: 5px;
}

.loading-track-lg {
  width: 200px;
}

.loading-track::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(201, 167, 240, 0.3), transparent);
  animation: loading-track-glow 1.4s ease-in-out infinite;
}

.loading-orb {
  position: absolute;
  top: 50%;
  width: 14px;
  height: 14px;
  margin-top: -7px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(142, 214, 255, 0.95) 0%, rgba(201, 167, 240, 0.15) 65%);
  box-shadow: 0 0 12px rgba(138, 210, 255, 0.85);
  animation: loading-orbit 1.35s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

.loading-orb-delay {
  animation-delay: 0.24s;
  opacity: 0.6;
  transform: scale(0.9);
}

.loading-label {
  font-weight: 600;
  font-size: var(--fs-base);
  letter-spacing: 0.01em;
}

@keyframes loading-orbit {
  0% {
    transform: translateX(-35%) scale(0.75);
    opacity: 0;
  }
  15% {
    opacity: 1;
  }
  85% {
    opacity: 1;
  }
  100% {
    transform: translateX(135%) scale(0.75);
    opacity: 0;
  }
}

@keyframes loading-track-glow {
  0% {
    transform: translateX(-40%);
    opacity: 0.3;
  }
  50% {
    transform: translateX(35%);
    opacity: 0.65;
  }
  100% {
    transform: translateX(120%);
    opacity: 0.3;
  }
}
/* ── Shimmer base ────────────────────────────────────────────────────────── */

@keyframes shimmer {
  0%   { background-position: -800px 0; }
  100% { background-position:  800px 0; }
}

.skel {
  display: block;
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.05) 25%,
    rgba(255, 255, 255, 0.10) 50%,
    rgba(255, 255, 255, 0.05) 75%
  );
  background-size: 800px 100%;
  animation: shimmer 1.8s infinite linear;
  flex-shrink: 0;
}

.sk-mt    { margin-top: 0.65rem; }
.sk-mt-sm { margin-top: 0.4rem;  }

/* ── Journal ─────────────────────────────────────────────────────────────── */
/* Mirrors dreams-list: repeat(auto-fill, minmax(280px, 1fr)).               */
/* 2 columns need ≥560px of grid width (~600px screen); 3 need ~860px.       */

.sk-journal-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}

@media (min-width: 600px) {
  .sk-journal-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 860px) {
  .sk-journal-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.sk-journal-card {
  border: 1px solid var(--border);
  border-radius: 16px;   /* matches .dream-card */
  padding: 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;          /* matches .dream-card gap */
}

.sk-journal-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.sk-journal-footer {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.2rem;
}

/* ── Feed ────────────────────────────────────────────────────────────────── */

.sk-feed-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.sk-feed-card {
  border: 1px solid var(--border);
  border-radius: 16px;   /* matches .feed-card */
  padding: 1.25rem;      /* matches .feed-card */
}

.sk-feed-head {
  display: flex;
  align-items: center;
  gap: 0.85rem;          /* matches .feed-author-block */
  margin-bottom: 0.65rem;
}

/* Feed avatar is 48×48 rounded-square (border-radius 14px), not a circle */
.sk-feed-avatar {
  width: 48px;
  height: 48px;
  border-radius: 14px;
  flex-shrink: 0;
}

.sk-feed-meta {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.sk-feed-date {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  align-self: center;
}

.sk-feed-footer {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.85rem;
}

/* ── Profile ─────────────────────────────────────────────────────────────── */

.sk-profile {
  max-width: 900px;
  margin: 0 auto;
}

.sk-profile-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 1.5rem 1rem 1rem;
}

.sk-profile-stats {
  display: flex;
  gap: 0.75rem;
  justify-content: center;
  padding: 0.75rem;
  margin: 0.75rem 0;
}

.sk-stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.5rem 1rem;
}

.sk-profile-btn {
  display: block;
  margin: 0 auto 1.5rem;
}

.sk-profile-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1rem;
  padding: 0 1rem;
}

.sk-profile-card {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
}

@media (max-width: 1200px) {
  .sk-profile-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 380px) {
  .sk-profile-grid {
    grid-template-columns: 1fr;
  }
}

/* ── Dream Detail ────────────────────────────────────────────────────────── */
/* Mirrors .detail-card exactly so the skeleton fills the same space.        */

.sk-detail-card {
  margin-top: 0.75rem;
  padding: 2rem;
  border-radius: 18px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

@media (max-width: 640px) {
  .sk-detail-card {
    padding: 1.5rem;
  }
}

.sk-detail-toolbar {
  display: flex;
  align-items: center;
}

.sk-detail-title-row {
  display: flex;
  flex-direction: column;
}

.sk-detail-author {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.sk-detail-content {
  display: flex;
  flex-direction: column;
}

.sk-detail-ai {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1rem 1.25rem;
  display: flex;
  flex-direction: column;
}

/* ── Insights ────────────────────────────────────────────────────────────── */

.sk-insights {
  max-width: 680px;
  margin: 0 auto;
  padding: 1.5rem 1rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.sk-insights-header {
  margin-bottom: 0.75rem;
}

.sk-insights-card {
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1.1rem 1.25rem;
  display: flex;
  flex-direction: column;
}

.sk-insights-card-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.75rem;
}

.sk-insights-count {
  margin-left: auto;
  flex-shrink: 0;
}

/* ── Settings ────────────────────────────────────────────────────────────── */

.sk-settings {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.sk-settings-section {
  border: 1px solid var(--border);
  border-radius: 16px;
  overflow: hidden;
}

.sk-settings-head {
  padding: 1.25rem 1.25rem 0;
  display: flex;
  flex-direction: column;
}

.sk-settings-body {
  padding: 1rem 1.25rem 1.25rem;
  display: flex;
  flex-direction: column;
}

.sk-toggle-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

.sk-toggle-row:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.sk-toggle-row:first-child {
  padding-top: 0;
}

.sk-toggle-label {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.sk-toggle-switch {
  flex-shrink: 0;
}

/* ── Activity ────────────────────────────────────────────────────────────── */

.sk-activity-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.sk-activity-card {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.85rem 1rem;
}

.sk-activity-body {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.sk-activity-action {
  flex-shrink: 0;
  align-self: center;
}

/* ── Search ──────────────────────────────────────────────────────────────── */

.sk-people-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 0.8rem;
}

.sk-person-card {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.9rem;
}

.sk-dream-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1rem;
}

.sk-search-dream-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
}

/* ── Reduced motion ──────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .skel {
    animation: none;
    background: rgba(255, 255, 255, 0.06);
  }
}

/* ── Legacy aliases (keep existing names working) ────────────────────────── */

.dream-card-skeleton { display: none; }
.profile-skeleton    { display: none; }
.list-skeleton       { display: none; }
.toast {
  position: fixed;
  bottom: calc(env(safe-area-inset-bottom) + 5rem);
  left: 50%;
  transform: translateX(-50%);
  background: rgba(20, 26, 36, 0.95);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: #e8eef8;
  font-size: var(--fs-sm);
  line-height: 1.45;
  padding: 0.7rem 1.2rem;
  border-radius: 14px;
  white-space: normal;
  max-width: min(420px, calc(100vw - 2.5rem));
  text-align: center;
  z-index: 600;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
  cursor: pointer;
  animation: toastIn 220ms cubic-bezier(0.32, 0.72, 0, 1) forwards;
}

/* The -50% has to be repeated in every frame: a transform replaces the one on
   the base rule rather than adding to it, so dropping it would snap the toast
   to the right by half its width for the length of the animation. */
@keyframes toastIn {
  from { opacity: 0; transform: translateX(-50%) translateY(12px) scale(0.96); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
}

.toast.is-leaving {
  animation: toastOut 180ms ease-in forwards;
  pointer-events: none;
}

@keyframes toastOut {
  from { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
  to   { opacity: 0; transform: translateX(-50%) translateY(8px) scale(0.98); }
}

@media (prefers-reduced-motion: reduce) {
  .toast,
  .toast.is-leaving {
    animation: none;
  }
}
/* Voice dictation control. Sits inside the bottom-right of a textarea, so the
   idle state is deliberately quiet — a single mic glyph — and only expands into
   the waveform bar while actually listening. */

.voice-input {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  pointer-events: none;
}

.voice-input > * {
  pointer-events: auto;
}

/* ── Trigger ─────────────────────────────────────────────────────────────── */

.voice-input-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(20, 14, 35, 0.85);
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  cursor: pointer;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: color 0.18s ease, border-color 0.18s ease, background-color 0.18s ease, transform 0.18s ease;
  /* Holding the button is a supported gesture, so suppress the iOS long-press
     callout and text selection that would otherwise fire underneath it. */
  -webkit-touch-callout: none;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}

.voice-input-btn:active:not(:disabled) {
  transform: scale(0.92);
}

.voice-input-btn:focus-visible {
  color: var(--primary);
  border-color: rgba(201, 167, 240, 0.5);
}

@media (hover: hover) and (pointer: fine) {
  .voice-input-btn:hover:not(:disabled) {
    color: var(--primary);
    border-color: rgba(201, 167, 240, 0.5);
  }
}

.voice-input-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.voice-input-btn.is-recording {
  color: #ffd9df;
  border-color: rgba(255, 120, 140, 0.7);
  background: rgba(120, 26, 44, 0.55);
  animation: voicePulse 1.9s ease-in-out infinite;
}

.voice-input-btn.is-busy {
  color: var(--primary);
  border-color: rgba(201, 167, 240, 0.45);
}

@keyframes voicePulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255, 120, 140, 0.32); }
  50%      { box-shadow: 0 0 0 7px rgba(255, 120, 140, 0); }
}

.voice-input-spinner {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid rgba(201, 167, 240, 0.28);
  border-top-color: var(--primary);
  animation: voiceSpin 0.7s linear infinite;
}

@keyframes voiceSpin {
  to { transform: rotate(360deg); }
}

/* ── Live recording strip ────────────────────────────────────────────────── */

.voice-input-live {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  height: 36px;
  padding: 0 0.7rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 120, 140, 0.35);
  background: rgba(22, 12, 20, 0.9);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  animation: voiceStripIn 200ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
}

@keyframes voiceStripIn {
  from { opacity: 0; transform: translateX(8px) scaleX(0.9); }
  to   { opacity: 1; transform: translateX(0) scaleX(1); }
}

.voice-input-cancel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  cursor: pointer;
  transition: color 0.16s ease;
}

.voice-input-cancel:focus-visible {
  color: #ff9fb1;
}

.voice-input-cancel:active {
  transform: scale(0.88);
  transition: transform 70ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .voice-input-cancel:hover { color: #ff9fb1; }
}

/* ── Waveform ────────────────────────────────────────────────────────────── */

.voice-wave {
  display: flex;
  align-items: center;
  gap: 2px;
  height: 20px;
  width: 104px;
}

.voice-wave-bar {
  flex: 1;
  min-width: 2px;
  height: 100%;
  border-radius: 2px;
  background: linear-gradient(180deg, #f0a8bb, var(--primary));
  transform: scaleY(0.08);
  transform-origin: center;
  will-change: transform;
}

/* The native engine reports one amplitude per buffer rather than a spectrum, so
   its bars scroll as a history and are sampled well under frame rate. Easing
   between samples is what keeps that from looking like a strobe. */
.voice-input.is-live .voice-wave-bar {
  transition: transform 70ms linear;
}

.voice-input-clock {
  font-size: var(--fs-micro);
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
  flex-shrink: 0;
}

.voice-input-clock.is-ending {
  color: #ff9fb1;
}

/* ── Live caption ────────────────────────────────────────────────────────── */

/* Sits above the field while recording. On iOS this fills with words as they
   are spoken; on the upload path there is nothing to show until the recording
   is sent, so it carries the stop affordance instead. */
.voice-caption {
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.6rem);
  width: min(320px, calc(100vw - 3.5rem));
  padding: 0.6rem 0.75rem 0.5rem;
  border-radius: 14px;
  border: 1px solid rgba(201, 167, 240, 0.28);
  background: rgba(18, 12, 30, 0.94);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  /* Purely a readout — it must never swallow a tap meant for the field. */
  pointer-events: none;
  animation: voiceCaptionIn 180ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
}

@keyframes voiceCaptionIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.voice-caption-text {
  max-height: 5.2em;
  overflow-y: auto;
  font-size: var(--fs-sm);
  line-height: 1.45;
  color: var(--text);
  scrollbar-width: none;
}

.voice-caption-text::-webkit-scrollbar { display: none; }

.voice-caption-idle {
  color: var(--text-secondary);
  font-style: italic;
}

.voice-caption-hint {
  margin: 0.45rem 0 0;
  padding-top: 0.4rem;
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  font-size: var(--fs-micro);
  color: var(--text-secondary);
}

/* ── First-run affordance ────────────────────────────────────────────────── */

/* People reach for a mic expecting to hold it. Holding does work, but tapping
   is the one-handed path, and nothing on screen said so. */
.voice-hint {
  position: absolute;
  right: calc(100% + 0.4rem);
  top: 50%;
  transform: translateY(-50%);
  white-space: nowrap;
  padding: 0.25rem 0.55rem;
  border-radius: 999px;
  border: 1px solid rgba(201, 167, 240, 0.28);
  background: rgba(18, 12, 30, 0.9);
  color: var(--text-secondary);
  font-size: var(--fs-micro);
  pointer-events: none;
  animation: voiceHintIn 2.4s ease-in-out infinite;
}

@keyframes voiceHintIn {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}

/* The bars are a readout of the user's own voice, not decoration, so they keep
   moving under reduced motion — only the ambient pulse and slide are dropped. */
@media (prefers-reduced-motion: reduce) {
  .voice-input-btn.is-recording { animation: none; }
  .voice-input-live { animation: none; }
  .voice-caption { animation: none; }
  .voice-hint { animation: none; opacity: 1; }
}

/* ── Textarea integration ────────────────────────────────────────────────── */

.voice-field {
  position: relative;
  display: block;
}

.voice-field > textarea {
  display: block;
  width: 100%;
}

.voice-field-affordance {
  position: absolute;
  right: 10px;
  bottom: 10px;
  z-index: 2;
}

/* Keep dictated text clear of the button while it sits over the field. */
.voice-field > textarea {
  padding-bottom: 52px;
}

@media (max-width: 420px) {
  .voice-wave { width: 78px; }
}
.dream-title-input {
  width: 100%;
  padding: 0.9rem 1rem;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-md);
  font-weight: 600;
  margin-bottom: 0.75rem;
  transition: border-color 0.22s ease, box-shadow 0.22s ease;
}

.dream-title-input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(201, 167, 240, 0.18);
}

.dream-title-input::placeholder {
  color: var(--text-secondary);
  font-weight: 400;
}

.dream-date-section {
  margin-bottom: 0.75rem;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.dream-date-section label {
  color: var(--text-secondary);
  font-size: var(--fs-base);
}

.dream-date-input {
  padding: 0.75rem 1rem;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-base);
  width: fit-content;
  max-width: 100%;
  transition: border-color 0.22s ease;
}

.dream-date-input:focus {
  border-color: var(--primary);
}

.dreams-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.25rem;
}

.dreams-year-header {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.5rem;
}

.dreams-year-header:first-child {
  margin-top: 0;
}

.dreams-year-header span {
  font-size: var(--fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-secondary);
  white-space: nowrap;
}

.dreams-year-header::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border);
}

.view-toggle {
  display: inline-flex;
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.04);
}

.view-toggle-btn {
  border: none;
  background: transparent;
  color: var(--text-secondary);
  font-weight: 600;
  padding: 0.55rem 0.9rem;
  min-height: 40px;
}

.view-toggle-btn.active {
  background: rgba(201, 167, 240, 0.18);
  color: var(--text);
}

.journal-calendar-shell {
  display: grid;
  gap: 1rem;
}

.journal-calendar {
  border: 1px solid var(--border);
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.03));
  padding: 1rem;
  box-shadow: var(--shadow-light);
  /* Left to fill the page the columns stretch to ~150px and the month reads as
     a row of letterboxes. Capping it keeps the cells close to square. */
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  /* Clips the incoming month to the card, so it enters from the edge instead of
     briefly hanging outside the border. Nothing here needs to overflow. */
  overflow: hidden;
}

.calendar-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}

.calendar-toolbar h2 {
  margin: 0;
  font-size: var(--fs-md);
}

/* Month arrows. They were ← and → glyphs in a text button: about the size of a
   word, with the standard 0.965 button press that is far too subtle on
   something this small. Now a 44px circle — the iOS minimum — around a centred
   svg chevron, with the chip-tier press and a colour flash so a tap reads. */
.calendar-nav-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  font-size: var(--fs-base);
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

@media (hover: hover) and (pointer: fine) {
  .calendar-nav-btn:hover {
    background: rgba(201, 167, 240, 0.14);
    border-color: rgba(201, 167, 240, 0.4);
    color: var(--primary);
  }
}

.calendar-nav-btn:active {
  transform: scale(0.93);
  background: rgba(201, 167, 240, 0.22);
  border-color: rgba(201, 167, 240, 0.5);
  color: var(--primary);
  transition: transform 70ms ease, background-color 70ms ease, border-color 70ms ease;
}

.calendar-weekdays {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 0.35rem;
  margin-bottom: 0.35rem;
}

.calendar-weekdays span {
  text-align: center;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  font-weight: 600;
}

.calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 0.35rem;
}

.calendar-spacer {
  min-height: 54px;
}

.calendar-day {
  min-height: 54px;
  padding: 0;
  border: none;
  background: none;
  border-radius: 12px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  color: var(--text-secondary);
  -webkit-tap-highlight-color: transparent;
}

/* The dream marker. A night with an entry gets a lit dot rather than a count —
   one dream a night is the norm, and the exact number is in the panel below.
   The dot keeps its slot when empty so numbers never shift between days. */
.calendar-day::after {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: transparent;
  transition: background-color 0.18s ease, box-shadow 0.18s ease;
}

.calendar-day-number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  font-size: var(--fs-sm);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  transition: background-color 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
}

.calendar-day.has-dreams {
  color: var(--text);
}

.calendar-day.has-dreams .calendar-day-number {
  font-weight: 600;
}

.calendar-day.has-dreams::after {
  background: var(--primary);
  box-shadow: 0 0 6px rgba(201, 167, 240, 0.5);
}

.calendar-day.is-today .calendar-day-number {
  color: var(--primary);
  box-shadow: inset 0 0 0 1px rgba(201, 167, 240, 0.5);
}

/* After is-today on purpose — same specificity, so a selected today fills. */
.calendar-day.is-selected .calendar-day-number {
  background: var(--primary);
  color: var(--background);
  box-shadow: none;
  font-weight: 700;
}

/* Month navigation. The grid used to swap instantly, which read as a flicker
   rather than a move — sliding it in from the side the month came from gives
   the arrows a direction. `backwards` fill so no transform is left behind.

   The travel and the fade are two separate animations on purpose. Running them
   as one is what made the first attempt invisible: a hard ease-out spends most
   of its distance in the first few frames, so by the time the month was solid
   enough to look at, it had already stopped moving. Splitting them lets the
   fade finish early and long before the slide does, so the part you actually
   watch is the part that still has somewhere to go. */
@keyframes calendarMonthNext {
  from { transform: translate3d(44px, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

@keyframes calendarMonthPrev {
  from { transform: translate3d(-44px, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

/* The label is a fraction of the grid's width, so matching its travel would
   read as the two racing rather than moving together. */
@keyframes calendarMonthLabelNext {
  from { transform: translate3d(16px, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

@keyframes calendarMonthLabelPrev {
  from { transform: translate3d(-16px, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

.calendar-grid[data-month-direction='next'] {
  animation: calendarMonthNext 380ms cubic-bezier(0.33, 1, 0.68, 1) backwards,
             fadeIn 140ms ease-out backwards;
}

.calendar-grid[data-month-direction='prev'] {
  animation: calendarMonthPrev 380ms cubic-bezier(0.33, 1, 0.68, 1) backwards,
             fadeIn 140ms ease-out backwards;
}

.calendar-toolbar h2[data-month-direction='next'] {
  animation: calendarMonthLabelNext 380ms cubic-bezier(0.33, 1, 0.68, 1) backwards,
             fadeIn 140ms ease-out backwards;
}

.calendar-toolbar h2[data-month-direction='prev'] {
  animation: calendarMonthLabelPrev 380ms cubic-bezier(0.33, 1, 0.68, 1) backwards,
             fadeIn 140ms ease-out backwards;
}

/* Switching over from the list view used to drop the calendar in fully formed. */
.journal-calendar-shell {
  animation: fadeIn 0.24s ease-out backwards;
}

.calendar-day-panel {
  border: 1px solid var(--border);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.03);
  padding: 1rem;
}

/* Keyed on the selected date in the JSX, so picking another day replays this
   instead of silently swapping the text underneath the cursor. A fade rather
   than a slide — the dream cards inside already travel, and stacking the two
   would move them twice as far as anything else on the page. */
.calendar-day-panel-body {
  animation: fadeIn 0.2s ease-out backwards;
}

.calendar-day-panel-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.8rem;
}

.calendar-day-panel-head h3 {
  margin: 0;
  font-size: var(--fs-base);
}

.calendar-day-panel-head p {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
}

.dreams-list.calendar-dreams-list {
  margin-top: 0.25rem;
  grid-template-columns: 1fr;
}

@media (min-width: 501px) {
  .dreams-list.calendar-dreams-list {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1001px) {
  .dreams-list.calendar-dreams-list {
    grid-template-columns: repeat(3, 1fr);
  }
}

.dream-card {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.03) 100%);
  border: 1px solid var(--border);
  padding: 1.2rem;
  box-shadow: var(--shadow-light);
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  border-radius: 16px;
  transition: box-shadow 0.22s ease, border-color 0.22s ease;
  overflow: hidden;
  isolation: isolate;
  cursor: pointer;
  position: relative;
}
@media (hover: hover) and (pointer: fine) {
  .dream-card:hover {
    box-shadow: var(--shadow-soft);
    border-color: rgba(201, 167, 240, 0.4);
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.04) 100%);
  }
}

.dream-card:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
}

.dream-card--pending {
  cursor: default;
  opacity: 0.6;
}

.dream-footer-meta {
  margin-top: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.dream-tag-count {
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border);
  padding: 0.2rem 0.6rem;
  border-radius: 100px;
}

/* meta row: date + visibility + AI badge */
.dream-meta {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: nowrap;
  min-width: 0;
  overflow: hidden;
}

.dream-vis-pill {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.6rem;
  border-radius: 100px;
  border: 1px solid var(--border);
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  white-space: nowrap;
  flex-shrink: 0;
}

.dream-vis--public    { color: #34d399; border-color: rgba(52, 211, 153, 0.3); }
.dream-vis--followers { color: #c9a7f0; border-color: rgba(201, 167, 240, 0.3); }
.dream-vis--mutuals   { color: #f2a8b8; border-color: rgba(242, 168, 184, 0.3); }
.dream-vis--anonymous { color: #f59e0b; border-color: rgba(245, 158, 11, 0.3); }
.dream-vis--private   { color: #f87171; border-color: rgba(248, 113, 113, 0.3); }

.dream-ai-badge {
  font-size: 1.25rem;
  color: var(--accent);
  opacity: 0.9;
  flex-shrink: 0;
  letter-spacing: 0;
}

@media (max-width: 768px) {
  .dream-ai-badge {
    font-size: 1.75rem; /* 1.25rem × (16/14) — restores 20px at 14px base */
  }
}

.dream-chevron {
  font-size: 1.25rem;
  color: var(--text-secondary);
  transition: transform 0.16s ease;
}
@media (hover: hover) and (pointer: fine) {
  .dream-card:hover .dream-chevron {
    color: var(--primary);
  }
}

.dream-title {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--text);
  font-size: var(--fs-md);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  line-clamp: 2;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

.dream-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
}

.dream-date {
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  white-space: nowrap;
  flex-shrink: 0;
}

.dream-content {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  color: var(--text);
  line-height: 1.5;
  font-size: var(--fs-base);
  display: -webkit-box;
  -webkit-box-orient: vertical;
  line-clamp: 4;
  -webkit-line-clamp: 4;
  overflow: hidden;
  white-space: normal;
}

.dream-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.tags-section {
  display: grid;
  gap: 0.75rem;
}

.tags-input {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.tags-input input {
  flex: 1;
  padding: 0.8rem 0.9rem;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
}

.tags-input input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(127, 179, 194, 0.14);
}

.add-tag-btn {
  padding: 0.75rem 1rem;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
  font-weight: 600;
  transition: border-color 0.22s ease, color 0.22s ease;
}
@media (hover: hover) and (pointer: fine) {
  .add-tag-btn:hover {
    border-color: var(--primary);
    color: var(--primary);
  }
}

.tags-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.tag .remove-tag {
  background: none;
  border: none;
  color: inherit;
  cursor: pointer;
  font-weight: 600;
  padding: 0 0.25rem;
}

.dream-textarea {
  width: 100%;
  border-radius: 14px;
  border: 1px solid var(--border);
  padding: 1rem;
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-base);
  line-height: 1.5;
  resize: vertical;
  min-height: 180px;
  transition: border-color 0.22s ease, box-shadow 0.22s ease;
  /* Ensure scrolling happens only within textarea, not the modal */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.dream-textarea:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(201, 167, 240, 0.18);
}

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  backdrop-filter: blur(8px);
  padding: 1.25rem;
  touch-action: none;
}

.modal-content {
  background: #131219;
  border-radius: 20px;
  padding: 1.85rem;
  width: 100%;
  max-width: 580px;
  max-height: calc(100dvh - 2.5rem - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  padding-bottom: 1.85rem;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  box-shadow: var(--shadow-soft);
  backdrop-filter: blur(16px);
  touch-action: pan-y;
}

/* Wrapper that holds the fade gradients outside the scrollable form */
.modal-form-wrap {
  flex: 1 1 auto;
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.modal-form-wrap::before,
.modal-form-wrap::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  height: 3rem;
  pointer-events: none;
  z-index: 1;
  opacity: 1;
  transition: opacity 0.2s ease;
}

.modal-form-wrap::before {
  top: 0;
  background: linear-gradient(to bottom, #131219, transparent);
}

.modal-form-wrap::after {
  bottom: 0;
  background: linear-gradient(to top, #131219, transparent);
}

.modal-form-wrap.at-top::before {
  opacity: 0;
}

.modal-form-wrap.at-bottom::after {
  opacity: 0;
}

/* The form scrolls internally; the page behind never scrolls while modal is open */
.modal-content form {
  flex: 1 1 auto;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: 0;
  touch-action: pan-y;
  scrollbar-width: none;
}

.modal-content form::-webkit-scrollbar {
  display: none;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
}

.close-btn {
  background: none;
  border: 1px solid var(--border);
  width: 38px;
  height: 38px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  font-size: 1.1rem;
  color: var(--text-secondary);
  transition: border-color 0.22s ease, color 0.22s ease, background-color 0.22s ease;
}
@media (hover: hover) and (pointer: fine) {
  .close-btn:hover {
    border-color: var(--primary);
    color: var(--primary);
    background: rgba(255, 255, 255, 0.04);
  }
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
  margin-top: 1.25rem;
}

.visibility-section {
  margin-top: 1rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.03);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.visibility-section .section-label {
  font-weight: 600;
  margin: 0;
  color: var(--text);
}

.visibility-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.visibility-chip {
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 0.4rem 1rem;
  background: var(--surface);
  color: var(--text-secondary);
  font-weight: 600;
  transition: all 0.16s ease;
}

.visibility-chip.active {
  color: var(--text);
}

.visibility-chip.active[data-vis='public'] {
  color: #34d399;
  border-color: rgba(52, 211, 153, 0.5);
  background: rgba(52, 211, 153, 0.1);
  box-shadow: 0 0 0 2px rgba(52, 211, 153, 0.15);
}

.visibility-chip.active[data-vis='followers'] {
  color: #c9a7f0;
  border-color: rgba(201, 167, 240, 0.5);
  background: rgba(201, 167, 240, 0.1);
  box-shadow: 0 0 0 2px rgba(201, 167, 240, 0.15);
}

.visibility-chip.active[data-vis='mutuals'] {
  color: #f2a8b8;
  border-color: rgba(242, 168, 184, 0.5);
  background: rgba(242, 168, 184, 0.1);
  box-shadow: 0 0 0 2px rgba(242, 168, 184, 0.15);
}

.visibility-chip.active[data-vis='anonymous'] {
  color: #f59e0b;
  border-color: rgba(245, 158, 11, 0.5);
  background: rgba(245, 158, 11, 0.1);
  box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.15);
}

.visibility-chip.active[data-vis='private'] {
  color: #f87171;
  border-color: rgba(248, 113, 113, 0.5);
  background: rgba(248, 113, 113, 0.1);
  box-shadow: 0 0 0 2px rgba(248, 113, 113, 0.15);
}

.visibility-chip:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.visibility-helper {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--fs-base);
}

.audience-section,
.tag-people-section {
  margin-top: 1rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.03);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.control-headline {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.section-helper {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--fs-base);
}

.tag-people-input {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.tag-people-input input {
  flex: 1;
  min-width: 220px;
  padding: 0.8rem 0.95rem;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
}

.tag-people-input input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(201, 167, 240, 0.15);
}

.tagged-pill-row {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.tagged-pill {
  display: inline-flex;
  gap: 0.35rem;
  align-items: center;
  padding: 0.35rem 0.8rem;
  border-radius: 100px;
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
  font-size: var(--fs-sm);
}

.tagged-pill button {
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: var(--fs-base);
}

.status-hint {
  color: var(--primary);
}

.ai-hint {
  padding: 10px 0 0 0;
}

.tag-suggestion-list {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  padding: 0.35rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  box-shadow: var(--shadow-light);
  margin-top: 0.35rem;
}

.tag-suggestion-item {
  border: none;
  background: transparent;
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  cursor: pointer;
  transition: background-color 0.15s ease;
}
@media (hover: hover) and (pointer: fine) {
  .tag-suggestion-item:hover {
    background: rgba(201, 167, 240, 0.08);
  }
}

.suggestion-name {
  font-weight: 600;
  color: var(--text);
}

.suggestion-username {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.alert-banner {
  margin: 0.5rem 0;
  padding: 0.75rem 1rem;
  border-radius: 12px;
  border: 1px solid rgba(208, 104, 104, 0.35);
  background: rgba(208, 104, 104, 0.08);
  color: #f9d6d6;
  font-weight: 600;
}

.dreams-loading {
  text-align: center;
  color: var(--text-secondary);
  padding: 3rem 1rem;
  font-size: var(--fs-base);
  animation: fadeIn 0.22s ease-out;
}

.journal-header {
  animation: fadeIn 0.22s ease-out;
}

.journal-header h1 {
  animation: slideInUp 0.22s ease-out 0.03s both;
}

.journal-header .page-subtitle {
  animation: slideInUp 0.22s ease-out 0.05s both;
}

.journal-header .action-group {
  animation: fadeIn 0.24s ease-out 0.08s both;
}


.dreams-list {
  animation: fadeIn 0.24s ease-out 0.1s both;
}

.journal-search-row {
  animation: fadeIn 0.22s ease-out 0.09s both;
}

.journal-search-input {
  width: 100%;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 0.7rem 1rem;
  color: var(--text);
  font-size: var(--fs-base);
  transition: border-color 0.18s ease, background-color 0.18s ease;
  box-sizing: border-box;
}

.journal-search-input::placeholder {
  color: var(--text-secondary);
}

.journal-search-input:focus {
  outline: none;
  border-color: rgba(201, 167, 240, 0.45);
  background: rgba(255, 255, 255, 0.07);
}

.dream-card {
  animation: slideInUp 0.22s ease-out both;
}

@media (max-width: 768px) {
  .modal-overlay {
    padding: 1rem;
  }
}

@media (max-width: 640px) {
  .view-toggle {
    width: 100%;
  }

  .view-toggle-btn {
    flex: 1;
  }

  .dreams-list {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.75rem;
  }

  .calendar-day,
  .calendar-spacer {
    min-height: 46px;
  }

  .calendar-day-panel-head {
    flex-direction: column;
    align-items: flex-start;
  }

  .dream-card {
    padding: 0.85rem;
    gap: 0.45rem;
  }

  .dream-title {
    font-size: var(--fs-base);
    line-clamp: 2;
    -webkit-line-clamp: 2;
  }

  .dream-content {
    font-size: var(--fs-sm);
    line-clamp: 3;
    -webkit-line-clamp: 3;
  }

  .modal-content {
    padding: 1.25rem;
  }

  .modal-actions {
    flex-direction: column-reverse;
    align-items: stretch;
  }
}

@media (max-width: 360px) {
  .dreams-list {
    grid-template-columns: 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  .calendar-grid[data-month-direction],
  .calendar-toolbar h2[data-month-direction],
  .journal-calendar-shell,
  .calendar-day-panel-body {
    animation: none;
  }
}
.reaction-popover {
  position: fixed;
  z-index: 1200;
  pointer-events: none;
  padding-bottom: env(safe-area-inset-bottom);
}

.reaction-popover-card {
  pointer-events: auto;
  width: min(360px, 90vw);
  max-height: calc(100dvh - 160px);
  border-radius: 18px;
  background: rgba(15, 21, 36, 0.98);
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow: 0 22px 50px rgba(6, 8, 18, 0.45);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  position: relative;
}

.reaction-popover-card::after {
  content: '';
  position: absolute;
  width: 16px;
  height: 16px;
  background: rgba(15, 21, 36, 0.98);
  border-left: 1px solid rgba(255, 255, 255, 0.08);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  transform: translate(-50%, 0) rotate(45deg);
  left: var(--pointer-offset, 50%);
}

.reaction-popover.placement-top .reaction-popover-card::after {
  bottom: -8px;
}

.reaction-popover.placement-bottom .reaction-popover-card::after {
  top: -8px;
}

.reaction-popover-head {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.reaction-popover-title {
  margin: 0;
  color: var(--text, #fff);
  font-weight: 600;
  font-size: var(--fs-base);
}

.reaction-popover-subtitle {
  margin: 0;
  color: var(--text-secondary, rgba(255, 255, 255, 0.75));
  font-size: var(--fs-sm);
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.reaction-popover-emoji {
  font-size: 1.15rem;
  display: inline-flex;
  align-items: center;
  color: var(--text, #fff);
}

.reaction-popover-emoji-heart {
  color: var(--primary, #5ac8fa);
}

.reaction-popover-empty {
  margin: 0;
  color: var(--text-secondary, rgba(255, 255, 255, 0.75));
}

.reaction-popover-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  overflow-y: auto;
}

.reaction-popover-row {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: 0.45rem;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.02);
  border: 1px solid rgba(255, 255, 255, 0.05);
}

.reaction-popover-avatar {
  width: 38px;
  height: 38px;
  border-radius: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  font-size: 1rem;
  box-shadow: var(--shadow-light, 0 4px 16px rgba(0, 0, 0, 0.25));
}

.reaction-popover-avatar svg {
  width: 1em;
  height: 1em;
}

.reaction-popover-meta {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.reaction-popover-name {
  color: var(--text, #fff);
  font-weight: 600;
  font-size: var(--fs-base);
}

.reaction-popover-username {
  color: var(--primary, #5ac8fa);
  font-size: var(--fs-xs);
  font-weight: 600;
}
.confirm-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 550;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 0 env(safe-area-inset-bottom);
}

@media (min-width: 480px) {
  .confirm-modal-backdrop {
    align-items: center;
    padding: 1.5rem;
  }
}

.confirm-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px 20px 0 0;
  width: 100%;
  max-width: 420px;
  padding: 1.75rem 1.5rem calc(1.75rem + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

@media (min-width: 480px) {
  .confirm-modal {
    border-radius: 20px;
    padding: 1.75rem 1.5rem;
  }
}

.confirm-modal-title {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  margin: 0;
}

.confirm-modal-message {
  font-size: var(--fs-base);
  color: var(--text-secondary);
  margin: 0;
  line-height: 1.5;
}

.confirm-modal-input-label {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.confirm-modal-input {
  background: var(--surface-hover);
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  padding: 0.65rem 0.85rem;
  font-size: var(--fs-base);
  outline: none;
  transition: border-color 0.15s ease;
}

.confirm-modal-input:focus {
  border-color: var(--primary);
}

.confirm-modal-actions {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
  margin-top: 0.25rem;
}
.dream-detail-page {
  padding-top: calc(88px + env(safe-area-inset-top) + 0.75rem);
}

.dream-detail-page .detail-card {
  margin-top: 0.75rem;
}

.detail-card {
  margin-top: 1.5rem;
  padding: 2rem;
  border-radius: 18px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  box-shadow: var(--shadow-light);
  backdrop-filter: blur(18px);
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  animation: slideInUp 0.24s ease-out 0.05s both;
}

.detail-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  margin-bottom: 0.25rem;
  animation: fadeIn 0.22s ease-out;
}

.detail-back-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.45rem 1.1rem;
  border-radius: 100px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.03);
  color: var(--text);
  font-weight: 600;
  letter-spacing: -0.01em;
  box-shadow: var(--shadow-light);
  transition: border-color 0.18s ease, background-color 0.18s ease, transform 0.18s ease;
}
@media (hover: hover) and (pointer: fine) {
  .detail-back-btn:hover {
    border-color: var(--primary);
    background: rgba(201, 167, 240, 0.12);
    color: var(--primary);
  }
}

.detail-back-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  font-size: 0.9rem;
}

.detail-head {
  display: flex;
  flex-wrap: nowrap;
  gap: 1rem;
  align-items: flex-start;
}

.detail-title-block {
  flex: 1;
  min-width: 240px;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding: 0px;
}

.detail-title {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
}

.detail-title-editable {
  cursor: pointer;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.detail-date-block {
  padding: 0;
  min-width: 160px;
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  align-self: flex-start;
}

.detail-date-pill {
  border: 1px solid var(--border);
  border-radius: 100px;
  padding: 0.45rem 1.1rem;
  background: rgba(255, 255, 255, 0.05);
  color: var(--text-secondary);
  font-weight: 600;
  letter-spacing: 0.02em;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--fs-base);
  margin-bottom: 5px;
}

.detail-date-pill--interactive {
  cursor: pointer;
  background: rgba(201, 167, 240, 0.05);
  color: var(--text);
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}
@media (hover: hover) and (pointer: fine) {
  .detail-date-pill--interactive:hover {
    border-color: var(--primary);
    box-shadow: 0 0 0 2px rgba(201, 167, 240, 0.15);
  }
}

.detail-date-edit--standalone {
  justify-content: flex-end;
}

.edit-hint {
  opacity: 0;
  font-size: var(--fs-sm);
  transition: opacity 0.16s ease;
}
@media (hover: hover) and (pointer: fine) {
  .detail-title-editable:hover .edit-hint, .detail-date-pill--interactive:hover .edit-hint {
    opacity: 1;
  }
}

.detail-title-edit,
.detail-date-edit {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.detail-title-input {
  padding: 0.6rem 0.9rem;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-xl);
  font-weight: 600;
  flex: 1;
  min-width: 200px;
}

.detail-title-input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(201, 167, 240, 0.15);
}

.detail-date-input {
  padding: 0.5rem 0.75rem;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-base);
}

.detail-date-input:focus {
  border-color: var(--primary);
}

.detail-visibility {
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1rem;
  background: rgba(255, 255, 255, 0.02);
}

.detail-hint {
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--fs-base);
}

.detail-audience,
.detail-tagged,
.detail-comments {
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 1rem;
  background: rgba(255, 255, 255, 0.02);
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.detail-share-accordion {
  border: 1px solid var(--border);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.02);
  padding: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.detail-share-toggle {
  border: none;
  background: transparent;
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  text-align: left;
  cursor: pointer;
}

/* Was a `›` glyph rotated 90deg to point down. Flex centres a glyph's inline
   box, not its ink, and `›` sits high in its box with uneven side bearings, so
   it never sat in the middle of the circle — and rotating moved that offset to
   a different edge, which is why it looked wrong both open and closed. An svg
   chevron is centred in its own viewBox, so it lands dead centre and stays
   there when the 180deg flip points it back up. */
.share-toggle-icon {
  font-size: 14px;
  color: var(--text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  transition: transform 0.2s ease;
}

.share-toggle-icon.open {
  transform: rotate(180deg);
}

.detail-share-panel {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.comments-list {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.comment-thread {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.comment-thread.nested {
  gap: 0.4rem;
}

.comment-thread-children {
  margin-left: 1.5rem;
  padding-left: 1rem;
  border-left: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.comment-card-reply {
  background: rgba(255, 255, 255, 0.03);
}

.comment-replies-toggle {
  align-self: flex-start;
  border: none;
  background: transparent;
  color: var(--primary);
  font-weight: 600;
  font-size: var(--fs-base);
  cursor: pointer;
  padding: 0.15rem 0;
}

.comment-card {
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 0.85rem 1rem;
  background: rgba(255, 255, 255, 0.04);
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.comment-meta {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.5rem;
}

.comment-meta-names {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: baseline;
}

.comment-author {
  font-weight: 600;
  color: var(--text);
}

.comment-handle {
  color: var(--text-secondary);
  font-size: var(--fs-sm);
}

.comment-time {
  color: var(--text-secondary);
  font-size: var(--fs-xs);
}

.comment-body {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  margin: 0;
  color: var(--text);
  white-space: pre-wrap;
}

.comment-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.comment-action-links {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.comment-heart-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.05);
  color: var(--text-secondary);
  padding: 0.25rem 0.75rem;
  font-size: var(--fs-base);
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}

.comment-heart-btn svg {
  color: inherit;
}

.comment-heart-btn.active {
  border-color: rgba(201, 167, 240, 0.65);
  background: rgba(201, 167, 240, 0.12);
  color: var(--primary);
  box-shadow: 0 0 12px rgba(56, 132, 255, 0.35);
}

.comment-heart-btn.active svg {
  color: var(--primary);
}

.comment-heart-btn:disabled {
  opacity: 0.6;
  cursor: wait;
}

.comment-heart-count {
  font-size: var(--fs-sm);
}

.comment-reply-context {
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  font-style: italic;
}

.comment-reply-btn,
.comment-report-btn,
.comment-delete-btn {
  border: none;
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  cursor: pointer;
  text-decoration: underline;
}
@media (hover: hover) and (pointer: fine) {
  .comment-reply-btn:hover:not(:disabled) {
    color: var(--primary);
  }
}
@media (hover: hover) and (pointer: fine) {
  .comment-report-btn:hover:not(:disabled) {
    color: var(--primary);
  }
}
@media (hover: hover) and (pointer: fine) {
  .comment-delete-btn:hover:not(:disabled) {
    color: var(--text);
  }
}

.comment-reply-btn:disabled,
.comment-report-btn:disabled,
.comment-delete-btn:disabled {
  opacity: 0.5;
  cursor: wait;
}

.comment-composer {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.reply-context {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.03);
  padding: 0.45rem 0.75rem;
}

.reply-context span {
  color: var(--text-secondary);
  font-size: var(--fs-sm);
}

.reply-context button {
  border: none;
  background: transparent;
  color: var(--primary);
  font-weight: 600;
  cursor: pointer;
  font-size: var(--fs-sm);
}

.comment-composer textarea {
  width: 100%;
  min-height: 50px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  padding: 0.75rem 0.9rem;
  line-height: 1.5;
  resize: vertical;
}

.comment-composer textarea:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(201, 167, 240, 0.15);
}

.comment-composer-actions {
  display: flex;
  justify-content: flex-end;
}

.composer-status {
  margin: 0;
  color: var(--text-secondary);
}

.detail-section-head {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.tag-people-input {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.tag-people-input input {
  flex: 1;
  min-width: 220px;
  padding: 0.75rem 0.9rem;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
}

.tag-people-input input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(201, 167, 240, 0.15);
}

.tagged-pill-row {
  display: flex;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.tagged-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.35rem 0.8rem;
  border-radius: 100px;
  border: 1px solid var(--border);
  background: var(--surface-muted);
  color: var(--text);
}

.tagged-pill button {
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
}

.tag-suggestion-list {
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface);
  padding: 0.35rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  box-shadow: var(--shadow-light);
  margin-top: 0.35rem;
}

.tag-suggestion-item {
  border: none;
  background: transparent;
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
  cursor: pointer;
  transition: background-color 0.15s ease;
}
@media (hover: hover) and (pointer: fine) {
  .tag-suggestion-item:hover {
    background: rgba(201, 167, 240, 0.08);
  }
}

.suggestion-name {
  font-weight: 600;
  color: var(--text);
}

.suggestion-username {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.detail-label {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  margin-bottom: 0.6rem;
}

.detail-visibility-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.detail-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.detail-tags-inline {
  margin: 1rem 0 0.5rem;
}

@media (max-width: 640px) {
  .detail-head {
    flex-direction: column;
    gap: 0.85rem;
  }

  .detail-title-block,
  .detail-date-block {
    width: 100%;
  }
}

.detail-author-block {
  padding: 0.65rem 0 0.1rem;
}

.detail-author-btn {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  text-align: left;
  color: inherit;
}

.detail-author-avatar {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.detail-author-meta {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.detail-author-name {
  font-weight: 600;
  font-size: var(--fs-base);
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.detail-author-handle {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.detail-body {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  padding: 1.25rem;
  border-radius: 16px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.03);
  line-height: 1.5;
  color: var(--text);
  white-space: pre-wrap;
}

.detail-reactions {
  margin: 0.9rem 0 0.4rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}

.detail-reactions .reaction-buttons {
  flex-wrap: wrap;
}

.detail-reactions .reaction-icon {
  font-size: 0.95rem;
}

.detail-reactions .reaction-total {
  color: var(--text-secondary);
}

.detail-reactions .custom-emoji-popover {
  margin-top: 0.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  align-items: center;
}

.detail-reactions .custom-emoji-popover input {
  min-width: 140px;
  padding: 0.5rem 0.8rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
}

.detail-reactions .custom-emoji-popover input:focus {
  border-color: rgba(201, 167, 240, 0.6);
  outline: none;
  box-shadow: 0 0 0 2px rgba(201, 167, 240, 0.2);
}

.reaction-button {
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
  background: transparent;
  color: var(--text);
  padding: 0.2rem 0.6rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
  font-size: var(--fs-base);
  margin-right: 5px;
  transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}

.reaction-button.custom-emoji-trigger {
  border-style: dashed;
  opacity: 0.85;
}
@media (hover: hover) and (pointer: fine) {
  .reaction-button:hover:not(:disabled) {
    border-color: rgba(255, 255, 255, 0.4);
    background: rgba(255, 255, 255, 0.06);
  }
}

.reaction-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.reaction-button.active {
  border-color: rgba(201, 167, 240, 0.65);
  background: rgba(201, 167, 240, 0.12);
  color: var(--primary);
}

.reaction-button.active .reaction-icon {
  color: var(--primary);
}

.clear-reaction {
  font-size: var(--fs-xs);
  padding: 0.2rem 0.55rem;
}

.detail-textarea {
  width: 100%;
  min-height: 180px;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: var(--fs-base);
  padding: 0.9rem 1rem;
  line-height: 1.5;
  margin-bottom: 1rem;
}

.detail-textarea:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(201, 167, 240, 0.15);
}

.detail-tags-editor {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-bottom: 1rem;
}

.detail-tag-input-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

.detail-tag-input-row input {
  flex: 1;
  padding: 0.7rem 0.9rem;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
}

.detail-tag-input-row input:focus {
  border-color: var(--primary);
}

.detail-tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.detail-tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.75rem;
  border-radius: 100px;
  background: var(--surface-muted);
  border: 1px solid var(--border);
}

.detail-tag-remove {
  background: none;
  border: none;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  cursor: pointer;
}

.detail-edit-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
}

.detail-summary {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 1rem 1.25rem;
  background: rgba(201, 167, 240, 0.06);
  margin-top: 0.6rem;
}

.detail-summary-text {
  flex: 1 1 auto;
}

.detail-summary-footer {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.detail-summary-controls {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

@media (min-width: 1000px) {
  .detail-summary-footer {
    flex-direction: row;
    align-items: flex-start;
    gap: 1.25rem;
  }

  .detail-summary-controls {
    flex: 1 1 auto;
  }

  .ai-upgrade-cta {
    flex: 0 0 260px;
    margin-top: 0;
  }
}

.detail-summary h3 {
  margin: 0 0 0.25rem;
}

.detail-insight {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  margin: 0;
  color: var(--text);
}

.ai-disclaimer {
  margin: 0.55rem 0 0;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  line-height: 1.3;
}

.detail-connections {
  margin: 1rem 0 0;
  padding: 0.85rem 1rem;
  background: rgba(216, 182, 255, 0.05);
  border: 1px solid rgba(216, 182, 255, 0.2);
  border-radius: 10px;
}

.detail-connections-label {
  font-size: var(--fs-micro);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--primary);
  margin: 0 0 0.55rem;
  opacity: 0.85;
}

.detail-connections-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.detail-connections-item {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  padding-left: 1rem;
  position: relative;
  line-height: 1.4;
}

.detail-connections-item::before {
  content: '↺';
  position: absolute;
  left: 0;
  color: var(--primary);
  opacity: 0.7;
  font-size: var(--fs-xs);
  top: 0.05em;
}

.ai-privacy-notice {
  margin: 0.75rem 0 0;
  padding: 0.75rem 1rem;
  background: rgba(216, 182, 255, 0.05);
  border-left: 3px solid rgba(157, 111, 212, 0.4);
  border-radius: 6px;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  line-height: 1.3;
}

.detail-insight.muted {
  color: var(--text-secondary);
  font-style: italic;
}

.detail-status-message {
  margin: 0.25rem 0 0.5rem;
  color: var(--primary);
  font-size: var(--fs-base);
  font-weight: 500;
}

.ai-quota-badge {
  margin: 0 0 0.5rem;
  font-size: var(--fs-xs);
  color: var(--text-secondary);
  font-style: italic;
}

.reanalyze-controls {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  position: relative;
}

.reanalyze-controls .ghost-btn {
  transition: background-color 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
@media (hover: hover) and (pointer: fine) {
  .reanalyze-controls .ghost-btn:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.08);
    border-color: var(--primary);
  }
}

/* First-analysis style picker. These classes had no CSS at all, so the picker
   rendered as unstyled text in the page flow and read as a stray expansion
   rather than as the choice it is.

   It stays inline rather than becoming an overlay on purpose: `.detail-card`
   has both a backdrop-filter and a `both`-filled animation, and either one
   makes it the containing block for `position: fixed` descendants — a fixed
   overlay in here would size itself against the card, not the viewport. */
.prompt-selector-modal {
  display: block;
}

.prompt-selector-content {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1rem;
  border-radius: 14px;
  border: 1px solid rgba(201, 167, 240, 0.28);
  background: rgba(201, 167, 240, 0.05);
  animation: slideInUp 0.22s ease-out backwards;
}

.prompt-selector-content h3 {
  margin: 0;
  font-size: var(--fs-base);
}

.prompt-selector-hint {
  margin: 0 0 0.35rem;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

@media (prefers-reduced-motion: reduce) {
  .prompt-selector-content {
    animation: none;
  }
}

/* Sits in the flow rather than hanging off the button. Absolutely positioned it
   did not extend the page's scrollable area, so when the button was near the
   bottom the last options were below everything you could ever scroll to.
   Inline it pushes the page down and the list is always reachable — and it now
   matches the first-analysis picker, which is the same choice in the same
   place. */
.prompt-selector-panel {
  margin-top: 0.25rem;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1rem;
  border-radius: 14px;
  border: 1px solid rgba(201, 167, 240, 0.28);
  background: rgba(201, 167, 240, 0.05);
  animation: slideInUp 0.22s ease-out backwards;
}

@media (prefers-reduced-motion: reduce) {
  .prompt-selector-panel {
    animation: none;
  }
}

/* One column, because each row can open a description underneath it. Two
   columns left the expanded row dragging its neighbour's height with it. */
.prompt-options-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

.prompt-selector-label {
  margin: 0;
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--text);
}

/* Every option is one row of the same rhythm, so the two panels line up with
   each other and the grid does not sit tighter than the button above it. */
/* Confirm sits right of cancel and carries the filled treatment, so the
   committing action is the one the eye lands on and the two are never mistaken
   for each other. Right aligned because it closes the panel. */
.prompt-selector-actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.35rem;
  flex-wrap: wrap;
}

.prompt-selector-actions .ghost-btn,
.prompt-selector-actions .primary-btn {
  padding: 0.55rem 1.1rem;
  font-size: var(--fs-sm);
}

.prompt-selector-actions .primary-btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.prompt-option-btn {
  width: 100%;
  display: flex;
  flex-direction: column;
  text-align: left;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.prompt-option-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
}

.prompt-option-label {
  font-weight: 600;
}

/* Collapsed by default and revealed by selection, so only one description is
   ever open. max-height rather than a height animation: the text is two lines
   at most, and auto height cannot be transitioned. */
.prompt-option-desc {
  display: block;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  color: var(--text-secondary);
  font-size: var(--fs-xs);
  line-height: 1.5;
  transition: max-height 0.22s ease, opacity 0.18s ease, margin-top 0.22s ease;
}

.prompt-option-btn.is-selected .prompt-option-desc {
  max-height: 9rem;
  opacity: 1;
  margin-top: 0.4rem;
}

/* The chosen style. This is a real selected state now — something is picked and
   nothing has run yet — so it is allowed to look selected. */
.prompt-option-btn.is-selected {
  border-color: var(--primary);
  background: rgba(201, 167, 240, 0.12);
}

@media (prefers-reduced-motion: reduce) {
  .prompt-option-desc { transition: none; }
}
@media (hover: hover) and (pointer: fine) {
  .prompt-option-btn:hover:not(:disabled) {
    background: rgba(255, 255, 255, 0.08);
    border-color: var(--primary);
  }
}

.prompt-option-btn:disabled:not(.locked) {
  opacity: 0.5;
  cursor: wait;
}

.prompt-option-btn.locked {
  border-style: dashed;
  border-color: rgba(251, 191, 36, 0.35);
  opacity: 0.6;
  cursor: not-allowed;
  pointer-events: none;
  user-select: none;
}

.prompt-lock-icon {
  font-size: 0.7rem;
  margin-right: 0.35rem;
  color: rgba(251, 191, 36, 0.8);
  vertical-align: middle;
}

.prompt-pro-badge {
  display: inline-block;
  margin-left: 0.4rem;
  font-size: var(--fs-micro);
  font-weight: 600;
  padding: 0.1rem 0.35rem;
  border-radius: 0.25rem;
  background: rgba(251, 191, 36, 0.15);
  border: 1px solid rgba(251, 191, 36, 0.45);
  color: rgba(251, 191, 36, 0.9);
  vertical-align: middle;
  letter-spacing: 0.03em;
}

/* The style saved in Settings leads the list and spans the full width, so it
   reads as the top of the list rather than as whichever cell it happened to
   land in. The tint is what marks it; the tag is what stops the tint being
   read as "already chosen", which is the trap the old separate button fell
   into — it looked selected while being the one thing not yet picked. */
.prompt-option-btn.current-prompt {
  border-color: rgba(255, 255, 255, 0.18);
}

.prompt-current-tag {
  margin-left: auto;
  flex-shrink: 0;
  padding: 0.1rem 0.4rem;
  border-radius: 0.25rem;
  border: 1px solid rgba(201, 167, 240, 0.4);
  background: rgba(201, 167, 240, 0.14);
  color: var(--primary);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.03em;
}

.ai-upgrade-cta {
  border: 1px dashed rgba(251, 191, 36, 0.45);
  border-radius: 10px;
  padding: 0.75rem;
  background: rgba(251, 191, 36, 0.08);
}

.ai-upgrade-cta p {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.ai-upgrade-cta-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.6rem;
}

.detail-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.75rem;
}

.detail-error,
.detail-placeholder {
  margin-top: 2rem;
  padding: 1.25rem;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
}

.danger-btn {
  border-radius: 12px;
  padding: 0.8rem 1.2rem;
  font-weight: 600;
  border: 1px solid rgba(239, 68, 68, 0.4);
  background: rgba(239, 68, 68, 0.15);
  color: #ffe5e5;
  transition: background-color 0.16s ease, transform 0.16s ease;
}
@media (hover: hover) and (pointer: fine) {
  .danger-btn:hover:not(:disabled) {
    background: rgba(239, 68, 68, 0.28);
    border-color: rgba(239, 68, 68, 0.6);
  }
}

.danger-btn:disabled {
  opacity: 0.6;
  cursor: wait;
}

@media (max-width: 768px) {
  /* Nav is sticky on mobile — it occupies flow space, no top padding needed */
  .dream-detail-page {
    padding-top: 0.75rem;
  }
}

@media (max-width: 640px) {
  .detail-card {
    padding: 1.5rem;
  }

  .detail-back-btn {
    width: 100%;
    justify-content: center;
  }

  .comment-thread-children {
    margin-left: 1rem;
    padding-left: 0.75rem;
  }
}

/* ── Report modal ─────────────────────────────────────────────────────────── */
.report-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 500;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 0 env(safe-area-inset-bottom);
}

@media (min-width: 480px) {
  .report-modal-backdrop {
    align-items: center;
    padding: 1.5rem;
  }
}

.report-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px 20px 0 0;
  width: 100%;
  max-width: 480px;
  padding: 1.75rem 1.5rem calc(1.75rem + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

@media (min-width: 480px) {
  .report-modal {
    border-radius: 20px;
    padding: 1.75rem 1.5rem;
  }
}

.report-modal h3 {
  font-size: var(--fs-md);
  font-weight: 600;
  color: var(--text);
  text-transform: capitalize;
}

.report-modal-desc {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  margin: 0;
}

.report-reasons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.report-reason-btn {
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
  min-height: 44px;
}

.report-reason-btn.selected {
  border-color: #f87171;
  color: #f87171;
  background: rgba(248, 113, 113, 0.08);
}

.report-modal-actions {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
  margin-top: 0.25rem;
}

/* Generation placeholder. A button that only changes its label leaves the rest
   of the page looking exactly as it did, which is what reads as frozen — this
   puts the movement where the answer is going to appear. */
.analysis-pending {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  padding-top: 0.15rem;
}

.analysis-pending-line {
  height: 0.7rem;
  border-radius: 999px;
  background: linear-gradient(
    90deg,
    rgba(255, 255, 255, 0.05) 0%,
    rgba(201, 167, 240, 0.16) 50%,
    rgba(255, 255, 255, 0.05) 100%
  );
  background-size: 200% 100%;
  animation: analysisShimmer 1.35s ease-in-out infinite;
}

.analysis-pending-line:nth-child(2) { width: 92%; animation-delay: 0.12s; }
.analysis-pending-line:nth-child(3) { width: 68%; animation-delay: 0.24s; }

@keyframes analysisShimmer {
  from { background-position: 140% 0; }
  to   { background-position: -40% 0; }
}

.analysis-pending-note {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.35rem 0 0;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

/* The bars carry no information, so under reduced motion the spinner in the
   note is left to do the work alone. */
@media (prefers-reduced-motion: reduce) {
  .analysis-pending-line {
    animation: none;
  }
}
.feed-header {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  animation: fadeIn 0.22s ease-out;
}

.feed-header h1 {
  animation: slideInUp 0.22s ease-out 0.03s both;
}

.feed-header-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  animation: slideInUp 0.22s ease-out 0.03s both;
}

/* ── Feed tabs ─────────────────────────────────────────────────────────────── */
.feed-tabs {
  display: flex;
  gap: 0.2rem;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.28rem;
  width: fit-content;
  animation: fadeIn 0.22s ease-out 0.05s both;
}

.feed-tab {
  border: none;
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: 0.38rem 1rem;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 0.18s ease, color 0.18s ease;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 34px;
  white-space: nowrap;
  line-height: 1;
}

.feed-tab.active {
  background: rgba(201, 167, 240, 0.14);
  color: var(--primary);
}
@media (hover: hover) and (pointer: fine) {
  .feed-tab:not(.active):hover {
    background: rgba(255, 255, 255, 0.05);
    color: var(--text);
  }
}

.feed-tab-count {
  font-size: var(--fs-micro);
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-secondary);
  padding: 0.1rem 0.42rem;
  border-radius: 999px;
  font-weight: 500;
}

.feed-tab.active .feed-tab-count {
  background: rgba(201, 167, 240, 0.2);
  color: var(--primary);
}

/* ── Feed list ─────────────────────────────────────────────────────────────── */
.feed-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.25rem;
  animation: fadeIn 0.24s ease-out 0.1s both;
}

.feed-card {
  position: relative;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.06) 0%, rgba(255, 255, 255, 0.03) 100%);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 1.25rem;
  box-shadow: var(--shadow-light);
  transition: box-shadow 0.22s ease, border-color 0.22s ease;
  backdrop-filter: blur(12px);
  animation: slideInUp 0.22s ease-out both;
}
@media (hover: hover) and (pointer: fine) {
  .feed-card:hover {
    box-shadow: var(--shadow-soft);
    border-color: rgba(201, 167, 240, 0.4);
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.04) 100%);
  }
}

.feed-card-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.75rem;
  margin-bottom: 0.65rem;
}

.feed-card-actions {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin-left: auto;
  align-self: center;
}

.feed-card-menu-btn {
  width: 38px;
  height: 38px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-secondary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease;
}
@media (hover: hover) and (pointer: fine) {
  .feed-card-menu-btn:hover {
    border-color: rgba(201, 167, 240, 0.38);
    background: rgba(201, 167, 240, 0.08);
    color: var(--text);
  }
}

.feed-card-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 3;
  min-width: 200px;
  padding: 0.45rem;
  border-radius: 16px;
  border: 1px solid var(--border);
  background: rgba(10, 14, 22, 0.98);
  box-shadow: var(--shadow-soft);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.feed-card-menu-item {
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text);
  text-align: left;
  border-radius: 12px;
  padding: 0.75rem 0.85rem;
  font-weight: 600;
  min-height: 44px;
}
@media (hover: hover) and (pointer: fine) {
  .feed-card-menu-item:hover {
    background: rgba(255, 255, 255, 0.06);
  }
}

.feed-card-menu-item-danger {
  color: #ff9fb1;
}
@media (hover: hover) and (pointer: fine) {
  .feed-card-menu-item-danger:hover {
    background: rgba(255, 138, 171, 0.12);
  }
}

.feed-author-block {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}

.feed-avatar {
  width: 48px;
  height: 48px;
  border-radius: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  box-shadow: var(--shadow-light);
  flex-shrink: 0;
}

.feed-avatar--anon {
  filter: grayscale(1);
}

.feed-avatar svg {
  width: 1.1em;
  height: 1.1em;
}

.feed-author-meta {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.feed-author-name-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.feed-author-handle {
  color: var(--primary);
  font-size: var(--fs-xs);
  font-weight: 600;
  background: rgba(201, 167, 240, 0.10);
  padding: 0.2rem 0.6rem;
  border-radius: 100px;
  width: fit-content;
}

.feed-author-handle.feed-author-link {
  text-decoration: none;
  background: rgba(201, 167, 240, 0.18);
}
@media (hover: hover) and (pointer: fine) {
  .feed-author-handle.feed-author-link:hover {
    box-shadow: 0 0 0 2px rgba(201, 167, 240, 0.2);
  }
}

.feed-visibility {
  color: var(--text-secondary);
  font-size: var(--fs-base);
}

.feed-date {
  color: var(--text-secondary);
  font-size: var(--fs-base);
  height: 38px;
  display: flex;
  align-items: center;
}

.feed-title {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  margin: 0.35rem 0;
  font-size: var(--fs-md);
}

.feed-summary {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  color: var(--primary);
  font-weight: 600;
  margin: 0.25rem 0 0.5rem;
}

.feed-content {
  /* User-authored text: break long unbroken strings instead of overflowing. */
  overflow-wrap: break-word;
  overflow-wrap: anywhere;
  color: var(--text);
  line-height: 1.5;
  margin: 0.35rem 0 0.75rem;
}

.feed-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.feed-reactions {
  margin-top: 1rem;
}

.feed-reactions .reaction-icon {
  font-size: 0.95rem;
}

/* ── Empty + discovery states ──────────────────────────────────────────────── */
.feed-empty-card {
  border: 1px dashed var(--border);
  border-radius: 16px;
  padding: 1.5rem;
  text-align: center;
  color: var(--text);
  background: rgba(255, 255, 255, 0.02);
  margin-top: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  align-items: center;
  box-shadow: var(--shadow-light);
  animation: fadeIn 0.24s ease-out 0.1s both;
}

.feed-empty-card .primary-btn {
  margin-top: 0.5rem;
}

.feed-discovery-nudge {
  margin-top: 1rem;
  border: 1px dashed rgba(201, 167, 240, 0.25);
  border-radius: 14px;
  padding: 0.9rem 1.1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  background: rgba(201, 167, 240, 0.03);
  animation: fadeIn 0.22s ease-out both;
}

.feed-discovery-nudge p {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.feed-discovery-nudge button {
  border: none;
  background: transparent;
  color: var(--primary);
  font-size: var(--fs-sm);
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  padding: 0;
  flex-shrink: 0;
}
@media (hover: hover) and (pointer: fine) {
  .feed-discovery-nudge button:hover {
    text-decoration: underline;
  }
}

/* ── Responsive ────────────────────────────────────────────────────────────── */
@media (max-width: 768px) {
  .feed-list {
    grid-template-columns: 1fr;
  }

  .feed-card-menu {
    min-width: 184px;
  }
}

/* ── Report modal (shared with DreamDetail) ──────────────────────────────── */
.report-modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 500;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0 0 env(safe-area-inset-bottom);
}
@media (min-width: 480px) {
  .report-modal-backdrop { align-items: center; padding: 1.5rem; }
}
.report-modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px 20px 0 0;
  width: 100%;
  max-width: 480px;
  padding: 1.75rem 1.5rem calc(1.75rem + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
@media (min-width: 480px) {
  .report-modal { border-radius: 20px; padding: 1.75rem 1.5rem; }
}
.report-modal h3 { font-size: var(--fs-md); font-weight: 600; color: var(--text); text-transform: capitalize; }
.report-modal-desc { font-size: var(--fs-sm); color: var(--text-secondary); margin: 0; }
.report-reasons { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.report-reason-btn {
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
  min-height: 44px;
}
.report-reason-btn.selected { border-color: #f87171; color: #f87171; background: rgba(248, 113, 113, 0.08); }
.report-modal-actions { display: flex; gap: 0.75rem; justify-content: flex-end; margin-top: 0.25rem; }
.navigation {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  padding-top: env(safe-area-inset-top);
  background: rgba(13, 13, 17, 0.7);
  backdrop-filter: blur(14px) saturate(150%);
  border-bottom: 1px solid var(--border);
  z-index: 100;
  height: calc(88px + env(safe-area-inset-top));
  transition: background-color 0.2s ease, border-color 0.2s ease, height 0.34s cubic-bezier(0.22, 1, 0.36, 1);
  transform: translateZ(0);
  will-change: background-color;
}

.navigation-compact {
  height: 60px;
  background: rgba(10, 14, 18, 0.9);
}

.nav-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 1rem;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  transform: translateZ(0);
}

.nav-logo {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1.75rem;
  font-weight: bold;
  color: var(--text);
  letter-spacing: -0.02em;
  transition: color 0.2s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
  transform: translateZ(0) scale(1);
  transform-origin: left center;
  will-change: transform;
  backface-visibility: hidden;
}

.nav-logo span {
  transition: opacity 0.22s ease, max-width 0.22s ease, transform 0.22s ease;
  max-width: 11rem;
  opacity: 1;
  transform: translateX(0);
  overflow: hidden;
  white-space: nowrap;
  color: var(--text);
  font: 700 1.25rem "Playfair Display", serif;
  margin-bottom:-1px;
}

.nav-logo-icon {
  width: 36px;
  height: 36px;
  border-radius: 10px;
  transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), border-radius 0.3s ease;
  transform: translateZ(0) scale(1);
  transform-origin: center;
  will-change: transform;
  backface-visibility: hidden;
  margin-right: -5px;
}
@media (hover: hover) and (pointer: fine) {
  .nav-logo:hover {
    color: var(--primary);
  }
}

.nav-links {
  display: flex;
  gap: 2rem;
  position: relative;
  align-items: center;
  padding-bottom: 12px;
  margin-top: 15px;
  overflow: visible;
  transform: translateZ(0);
  transition: margin-top 0.3s cubic-bezier(0.22, 1, 0.36, 1), padding-bottom 0.3s cubic-bezier(0.22, 1, 0.36, 1);
}

.nav-links a {
  color: var(--text);
  font-weight: 600;
  transition: color 0.18s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
  padding: 0.35rem 0;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.25rem;
  position: relative;
  transform: translateZ(0);
  will-change: transform;
  backface-visibility: hidden;
}
@media (hover: hover) and (pointer: fine) {
  .nav-links a:hover {
    color: var(--primary);
  }
}

.nav-links a.active {
  color: var(--text);
}

.navigation:not(.navigation-compact) .nav-links a:not(.active) .nav-icon {
  opacity: 0.5;
}

.nav-icon-wrapper {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  min-width: 1.8rem;
  min-height: 1.8rem;
}

.nav-icon {
  font-size: 1.25rem;
  color: currentColor;
  opacity: 1;
  transition: opacity 0.24s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
  transform: translateZ(0) scale(1);
  will-change: transform, opacity;
  backface-visibility: hidden;
}

.nav-tab-label {
  display: inline-flex;
  align-items: center;
  line-height: 1;
  color: var(--text);
  transition: opacity 0.22s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1);
  transform: translateZ(0) translateY(0);
  will-change: transform, opacity;
  backface-visibility: hidden;
}

.nav-activity-indicator {
  position: absolute;
  top: -0.5rem;
  right: -0.5rem;
  transform: none;
  padding: 0.15rem 0.36rem;
  min-width: 0.95rem;
  border-radius: 999px;
  background: var(--primary);
  color: #05070b;
  font-size: 0.58rem;
  font-weight: 600;
  line-height: 1;
  text-align: center;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(5, 10, 14, 0.4);
  z-index: 2;
  scale: 0.9;
}

.navigation-compact .nav-icon-wrapper {
  min-width: 1.6rem;
  min-height: 1.6rem;
}

.navigation-compact .nav-activity-indicator {
  top: -0.25rem;
  right: -0.25rem;
  padding: 0.12rem 0.3rem;
  min-width: 0.85rem;
  font-size: 0.5rem;
}

.navigation-compact .nav-logo {
  transform: translateZ(0) scale(1.08);
}

.navigation-compact .nav-logo span {
  max-width: 0;
  opacity: 0;
  transform: translateX(-5px);
}

.navigation-compact .nav-logo-icon {
  transform: translateZ(0) scale(1);
  border-radius: 6px;
}

.navigation-compact .nav-links {
  margin-top: 0;
  padding-bottom: 0px;
  align-items: center;
}

.navigation-compact .nav-links a {
  flex-direction: column;
  gap: 0.12rem;
  align-items: center;
}

.navigation-compact .nav-icon {
  opacity: 0.18;
  transform: translateZ(0) translateY(-2px) scale(0.88);
  pointer-events: none;
}

.navigation-compact .nav-tab-label {
  transform: translateZ(0) translateY(-2px);
}

@media (max-width: 768px) {
  /* Keep icons visible on mobile even when compact */
  .navigation-compact .nav-icon {
    opacity: 1;
    transform: translateZ(0) scale(1);
    pointer-events: auto;
  }
  .navigation {
    position: fixed;
    top: 0;
    height: calc(74px + env(safe-area-inset-top));
  }

  .navigation.navigation-compact {
    height: calc(48px + env(safe-area-inset-top));
  }

  .nav-container {
    padding: 0 0.75rem;
  }

  .nav-logo {
    font-size: 1rem;
  }

  .nav-logo-icon {
    width: 30px;
    height: 30px;
  }

  .navigation:not(.navigation-compact) .nav-logo {
    transform: translateZ(0) scale(1);
  }

  .navigation.navigation-compact .nav-logo {
    transform: translateZ(0) scale(1);
  }

  .navigation:not(.navigation-compact) .nav-logo-icon {
    transform: translateZ(0) scale(0.78);
  }

  .navigation.navigation-compact .nav-logo-icon {
    transform: translateZ(0) scale(1);
  }

  .nav-links {
    flex: 1;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0 0.25rem 10px;
    overflow-x: auto;
    overflow-y: visible;
    scrollbar-width: none;
  }

  .nav-links::-webkit-scrollbar {
    display: none;
  }

  .navigation:not(.navigation-compact) .nav-links a {
    padding: 0.65rem 0.6rem;
    flex-direction: column;
    gap: 0.25rem;
  }

  .nav-links a {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1 1 auto;
    min-width: 0;
    gap: 0.2rem;
    font-size: var(--fs-sm);
    padding: 0.35rem 0.4rem;
    border-radius: 12px;
    white-space: nowrap;
    flex-direction: row;
  }

  .navigation.navigation-compact .nav-links a {
    padding: 0.25rem 0.3rem;
    gap: 0.15rem;
    flex-direction: row;
    align-items: center;
    min-height: 44px;
  }

  .nav-icon {
    display: block;
    font-size: 1rem;
  }

  .navigation:not(.navigation-compact) .nav-icon {
    font-size: 1.3rem;
  }

  .nav-icon-wrapper {
    min-width: 1.4rem;
    min-height: 1.4rem;
  }

  .nav-tab-label {
    display: none;
    font-size: var(--fs-micro);
    line-height: 1;
  }

  .nav-activity-indicator {
    top: -0.35rem;
    right: -0.35rem;
    transform: none;
    padding: 0.13rem 0.28rem;
    min-width: 0.9rem;
    font-size: 0.55rem;
  }

  .navigation:not(.navigation-compact) .nav-tab-label {
    display: block;
  }
}

@media (max-width: 620px) {
  .nav-links {
    gap: 0.2rem;
  }

  .nav-links a {
    padding: 0.4rem 0.2rem;
  }
}

@media (max-width: 480px) {
  .nav-links a {
    gap: 0.2rem;
    font-size: var(--fs-xs);
    padding: 0.3rem 0.2rem;
  }
}

@media (min-width: 769px) {
  .navigation:not(.navigation-compact) .nav-links a {
    gap: 0.2rem;
  }

  .navigation:not(.navigation-compact) .nav-tab-label {
    margin-top: -0.08rem;
  }

  .navigation-compact .nav-links a {
    gap: 0.35rem;
    align-items: center;
  }

  .navigation-compact .nav-icon {
    opacity: 1;
    transform: translateZ(0) scale(0.92);
    pointer-events: auto;
    font-size: 1rem;
  }

  .navigation-compact .nav-tab-label {
    font-size: var(--fs-sm);
  }

  .nav-logo span {
    font-size: 1.5rem;
    margin-left: 5px;
    margin-bottom: 0;
  }
}

/* ── iOS native: top header ─────────────────────────────────────────────── */

.nav-ios-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: calc(52px + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
  display: flex;
  align-items: center;
  background: rgba(13, 13, 17, 0.7);
  backdrop-filter: blur(12px) saturate(140%);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
  z-index: 100;
  transform: translateY(0px);
  will-change: transform;
}

/* Three-column layout: back | logo | spacer */
.nav-ios-header-side {
  flex: 1;
  display: flex;
  align-items: center;
  min-width: 52px;
}

.nav-ios-header-right {
  justify-content: flex-end;
}

.nav-ios-header-center {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
}

.nav-ios-back-btn {
  background: none;
  color: var(--primary);
  font-size: var(--fs-lg);
  padding: 0 0.75rem;
  min-width: 44px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
}

.nav-ios-logo-icon {
  width: 26px;
  height: 26px;
  border-radius: 7px;
  margin-bottom: 3px;
}

.nav-ios-logo-text {
  font-size: 1.15rem;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--text);
  font-family: 'Prata', serif;
}

/* ── iOS native: bottom tab bar ─────────────────────────────────────────── */

.nav-ios-tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: calc(52px + env(safe-area-inset-bottom));
  padding-top: 15px;
  padding-bottom: env(safe-area-inset-bottom);
  display: flex;
  align-items: flex-start;
  background: rgba(13, 13, 17, 0.7);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  border-top: 1px solid rgba(255, 255, 255, 0.07);
  z-index: 100;
  transform: translateZ(0);
  transition: transform 0.25s cubic-bezier(0.32, 0.72, 0, 1), opacity 0.18s ease;
}

/* `resize: 'native'` shrinks the web view, which would leave this fixed bar
   perched on top of the keyboard. A real UITabBar is covered by the keyboard,
   so slide it away instead — and give the text the room back. */
html.keyboard-open .nav-ios-tabbar {
  transform: translateZ(0) translateY(100%);
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .nav-ios-tabbar { transition: none; }
}

.nav-ios-tab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  color: var(--text-secondary);
  -webkit-tap-highlight-color: transparent;
  transition: color 0.15s ease;
}

.nav-ios-tab .nav-icon-wrapper {
  min-width: 1.9rem;
  min-height: 1.9rem;
  display: flex;
  align-items: center;
  justify-content: center;
}

.nav-ios-tab .nav-icon {
  font-size: 1.6rem;
  transition: transform 0.22s cubic-bezier(0.22, 1, 0.36, 1), color 0.15s ease;
  transform: translateZ(0) scale(1);
}

.nav-ios-tab .nav-tab-label {
  display: none;
}

.nav-ios-tab:not(.active) {
  opacity: 0.45;
}

.nav-ios-tab.active {
  color: var(--text);
}

.nav-ios-tab.active .nav-icon {
  transform: translateZ(0);
}
.offline-indicator {
  background: linear-gradient(90deg, #ff5050 0%, #ff6b6b 100%);
  color: white;
  padding: 0.75rem 1rem;
  text-align: center;
  font-size: var(--fs-sm);
  font-weight: 500;
  box-shadow: 0 2px 8px rgba(255, 80, 80, 0.25);
  position: fixed;
  top: calc(88px + env(safe-area-inset-top));
  left: 0;
  right: 0;
  z-index: 90;
}

@media (max-width: 768px) {
  .offline-indicator {
    top: calc(74px + env(safe-area-inset-top));
  }
}

.offline-indicator-text {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.offline-indicator-text::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: white;
  display: inline-block;
  animation: pulse 2s infinite;
}

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

@media (max-width: 600px) {
  .offline-indicator {
    padding: 0.5rem;
    font-size: var(--fs-xs);
  }
}
/* Hidden everywhere by default. The keyboard-open class is only ever set on the
   native iOS shell, so this never appears on the web build. */
.keyboard-dismiss {
  display: none;
}

html[data-native-platform='ios'].keyboard-open .keyboard-dismiss {
  position: fixed;
  /* `resize: 'native'` shrinks the web view to sit on top of the keyboard, so
     the bottom of the viewport is the top of the keyboard. */
  right: 12px;
  bottom: 12px;
  /* Above the composer modal (1000) and the reaction popover (1200): the dream
     composer is itself a modal with a textarea in it. */
  z-index: 1400;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 38px;
  padding: 0 1rem;
  border-radius: 999px;
  /* Filled rather than another dark translucent pill. It sits over whatever the
     user is writing on an all-dark UI, so a tinted surface with light text read
     as one more piece of chrome — the one control that has to be findable
     without looking for it is the one that should not blend in. */
  border: none;
  background: linear-gradient(135deg, #c9a7f0, #9d6fd4);
  box-shadow: 0 6px 20px rgba(157, 111, 212, 0.45), 0 2px 8px rgba(0, 0, 0, 0.4);
  color: #17112b;
  font-size: var(--fs-sm);
  font-weight: 700;
  -webkit-tap-highlight-color: transparent;
  animation: keyboardDismissIn 160ms cubic-bezier(0.32, 0.72, 0, 1) backwards;
}

.keyboard-dismiss svg {
  font-size: 0.72rem;
  opacity: 0.8;
}

.keyboard-dismiss:active {
  transform: scale(0.93);
  transition: transform 70ms ease;
}

@keyframes keyboardDismissIn {
  from { opacity: 0; transform: translate3d(0, 8px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  html[data-native-platform='ios'].keyboard-open .keyboard-dismiss {
    animation: none;
  }
}
.error-boundary {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  padding: 2rem;
  background: linear-gradient(180deg, #0e0a14 0%, #17112b 55%, #0e0a14 100%);
}

.error-boundary-content {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 3rem;
  max-width: 500px;
  text-align: center;
  backdrop-filter: blur(10px);
}

.error-boundary-content h1 {
  font-size: var(--fs-2xl);
  margin-bottom: 1rem;
  color: var(--error);
}

.error-boundary-content p {
  color: var(--text-secondary);
  margin-bottom: 1.5rem;
  line-height: 1.5;
}

.error-details {
  margin: 1.5rem 0;
  text-align: left;
}

.error-details summary {
  cursor: pointer;
  color: var(--text-secondary);
  padding: 0.5rem;
  user-select: none;
}
@media (hover: hover) and (pointer: fine) {
  .error-details summary:hover {
    color: var(--text);
  }
}

.error-details pre {
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 1rem;
  margin-top: 1rem;
  overflow-x: auto;
  font-size: var(--fs-sm);
  color: var(--error);
  white-space: pre-wrap;
  word-break: break-word;
}

.error-boundary-button {
  background: var(--primary-strong);
  color: white;
  border: none;
  padding: 0.75rem 2rem;
  border-radius: 8px;
  font-size: var(--fs-base);
  font-weight: 600;
  cursor: pointer;
  transition: all 0.2s;
}
@media (hover: hover) and (pointer: fine) {
  .error-boundary-button:hover {
    background: #0052cc;
    transform: translateY(-2px);
  }
}

.error-boundary-button:active {
  transform: translateY(0);
}
.terms-gate {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  padding-bottom: calc(1.5rem + env(safe-area-inset-bottom));
  background: var(--bg);
}

.terms-gate-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 2rem 1.75rem;
  width: 100%;
  max-width: 400px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

.terms-gate-icon img {
  width: 48px;
  height: 48px;
}

.terms-gate-title {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--text);
  margin: 0;
  text-align: center;
}

.terms-gate-desc {
  font-size: var(--fs-base);
  color: var(--text-secondary);
  margin: 0;
  text-align: center;
  line-height: 1.5;
}

.terms-gate-checks {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  width: 100%;
}

.terms-gate-check {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  line-height: 1.5;
  cursor: pointer;
}

.terms-gate-check input[type='checkbox'] {
  margin-top: 0.15rem;
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  accent-color: var(--primary);
  cursor: pointer;
}

.terms-gate-check a {
  color: var(--primary);
  text-decoration: none;
}
@media (hover: hover) and (pointer: fine) {
  .terms-gate-check a:hover {
    text-decoration: underline;
  }
}

.terms-gate-btn {
  width: 100%;
  margin-top: 0.25rem;
}


* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

:root {
  --safe-area-inset-top: env(safe-area-inset-top);
  --safe-area-inset-bottom: env(safe-area-inset-bottom);
  --primary: #c9a7f0;
  --primary-strong: #9d6fd4;
  --accent: #e8c87a;
  --background: #0d0d11;
  --background-secondary: #13121a;
  --surface: rgba(255, 255, 255, 0.04);
  --surface-muted: rgba(255, 255, 255, 0.02);
  --text: #eeeafa;
  --text-secondary: #cdbded;
  --border: rgba(255, 255, 255, 0.07);
  --shadow-soft: 0 20px 60px rgba(0, 0, 0, 0.35);
  --shadow-light: 0 10px 30px rgba(0, 0, 0, 0.28);
  --glow-primary: 0 0 50px rgba(157, 111, 212, 0.22);
  --error: #ff5050;
  --success: #2cd44e;
  --app-background-gradient: linear-gradient(180deg, #0d0d11 0%, #110f1c 55%, #0d0d11 100%);

  /* Type scale. One step per role — if two things are the same size they are
     meant to read as the same rank. Anything not on this scale was drift.
     Note the root shrinks to 14px under 768px, so every step scales with it.

     micro  count and status badges
     xs     timestamps, footnotes, helper text
     sm     secondary text, meta rows, small controls
     base   body copy and standard controls
     md     lead paragraphs, card titles, h3
     lg     sub-section headings
     xl     section headings, h2
     2xl    page titles, h1
     3xl    display

     Sizing a glyph, avatar or emoji is not typography — those keep their own
     font-size values and are deliberately off this scale. */
  --fs-micro: 0.7rem;
  --fs-xs: 0.78rem;
  --fs-sm: 0.85rem;
  --fs-base: 0.95rem;
  --fs-md: 1.1rem;
  --fs-lg: 1.3rem;
  --fs-xl: 1.55rem;
  --fs-2xl: 1.85rem;
  --fs-3xl: 2.25rem;
}

html {
  background: var(--app-background-gradient);
  background-color: #0d0d11;
  min-height: 100%;
  overscroll-behavior: none;
  scroll-behavior: smooth;
  color-scheme: dark;
}

body {
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-weight: 400;
  background: var(--app-background-gradient);
  background-color: #0e0a14;
  background-attachment: scroll;
  position: relative;
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100dvh;
  overscroll-behavior: contain;
}

html[data-native-platform='ios'] {
  overscroll-behavior: auto;
  /* Prevent WKWebView's black background from bleeding through on rubber-band scroll */
  background: var(--background);
  background-color: var(--background);
}

html[data-native-platform='ios'] body {
  overscroll-behavior: auto;
  background-color: var(--background);
}

html.no-overscroll,
html.no-overscroll body {
  overscroll-behavior: none !important;
}

.page-title,
h1 {
  font-family: 'Prata', Georgia, serif;
  font-weight: 600;
  font-style: italic;
}

/* Headings carried no font-size at all, so any heading without a page specific
   rule fell through to the browser default — 2em/1.5em/1.17em, in em, which
   compounds with whatever it is nested in. That was the main reason the same
   rank of heading came out different sizes on different pages. */

h1 { font-size: var(--fs-2xl); }

h2 { font-size: var(--fs-xl); }

h3 { font-size: var(--fs-md); }

.dream-title,
.entry-title,
.card-title {
  font-family: 'Prata', Georgia, serif;
  font-weight: 500;
}

h2, h3, .section-heading {
  font-weight: 500;
  color: #edeef6;
}

p {
  color: #d8d6e8;
}

.pull-refresh-indicator {
  position: fixed;
  top: calc(52px + env(safe-area-inset-top) + 24px);
  left: 50%;
  transform: translate(-50%, calc(-18px + (var(--pull-progress, 0) * 18px)));
  opacity: 0;
  pointer-events: none;
  z-index: 260;
  padding: 0.45rem 0.75rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(14, 10, 20, 0.86);
  color: #d7dfed;
  font-size: var(--fs-sm);
  letter-spacing: 0.01em;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: opacity 160ms ease, transform 160ms ease, border-color 160ms ease;
}

.pull-refresh-indicator.is-visible {
  opacity: 1;
}

.pull-refresh-indicator.is-armed {
  border-color: rgba(201, 167, 240, 0.8);
  color: #eef5ff;
}

.pull-refresh-indicator.is-refreshing {
  border-color: rgba(201, 167, 240, 0.8);
  color: #eef5ff;
  animation: pullRefreshPulse 900ms ease-in-out infinite;
}

@keyframes pullRefreshPulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.55; }
}

@keyframes slideInUp {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Page entrance. `backwards` fill only — a lingering `transform` on a page root
   would make it the containing block for every `position: fixed` modal and
   toast inside it, so the transform must be gone once the animation ends. */

@keyframes pageEnter {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.page-container,
.insights-page,
.home-page {
  animation: pageEnter 200ms ease-out backwards;
}

/* iOS: replace the vertical fade with a directional slide, so a push reads as
   coming from the right and a back gesture as returning from the left — the
   single strongest cue that this is an app rather than a page. The curve is
   UIKit's navigation ease. Tabs keep the plain fade. */

@keyframes pageEnterForward {
  from { opacity: 0; transform: translate3d(20px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes pageEnterBack {
  from { opacity: 0; transform: translate3d(-20px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

html[data-native-platform='ios'] [data-nav-direction='forward'] .page-container,
html[data-native-platform='ios'] [data-nav-direction='forward'] .insights-page {
  animation: pageEnterForward 260ms cubic-bezier(0.32, 0.72, 0, 1) backwards;
}

html[data-native-platform='ios'] [data-nav-direction='back'] .page-container,
html[data-native-platform='ios'] [data-nav-direction='back'] .insights-page {
  animation: pageEnterBack 260ms cubic-bezier(0.32, 0.72, 0, 1) backwards;
}

html[data-native-platform='ios'] [data-nav-direction='tab'] .page-container,
html[data-native-platform='ios'] [data-nav-direction='tab'] .insights-page {
  animation: pageEnter 170ms ease-out backwards;
}

@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

/* Inline activity spinner. Sized from the current font-size so it drops into a
   button label without needing its own dimensions. Static text alone ("Working
   …") reads as a frozen screen; something has to actually move. */

.inline-spinner {
  display: inline-block;
  width: 1em;
  height: 1em;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: 0.75;
  flex-shrink: 0;
  animation: inlineSpin 0.7s linear infinite;
}

@keyframes inlineSpin {
  to { transform: rotate(360deg); }
}

/* Small round controls sit below the 44px minimum a finger actually needs. The
   fix is an invisible overlay rather than a bigger circle: the design keeps the
   size it was drawn at, the target grows, and nothing on the page shifts. */

.voice-input-btn,
.close-btn,
.feed-card-menu-btn {
  position: relative;
}

.voice-input-btn::after,
.close-btn::after,
.feed-card-menu-btn::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

.btn-loading {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
}

/* Reduced motion slows the spinner rather than stopping it — a frozen ring is
   exactly the "is this broken?" signal it exists to prevent. */

@media (prefers-reduced-motion: reduce) {
  .inline-spinner { animation-duration: 2.4s; }
}

@keyframes glowSweep {
  0% { transform: translateX(-120%); opacity: 0; }
  45% { opacity: 0.35; }
  100% { transform: translateX(160%); opacity: 0; }
}

#root {
  min-height: 100dvh;
  position: relative;
  z-index: 2;
}

button {
  font-family: inherit;
  cursor: pointer;
  border: none;
  outline: none;
}

button:focus-visible,
a:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

input, textarea, select {
  font-family: inherit;
  outline: none;
}

a {
  text-decoration: none;
  color: inherit;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 1rem;
}

.app-main--with-nav {
  padding-top: calc(88px + env(safe-area-inset-top));
}

html[data-native-platform='ios'] .app-main--with-nav {
  padding-top: calc(52px + env(safe-area-inset-top));
}

/* Reserve the tab bar's height on iOS, the home indicator's everywhere else. */

html[data-native-platform='ios'] .app-main {
  padding-bottom: calc(49px + env(safe-area-inset-bottom));
}

html:not([data-native-platform='ios']) .app-main {
  padding-bottom: env(safe-area-inset-bottom);
}

/* The keyboard hides the tab bar, so stop holding space for it — otherwise the
   last line of a long entry sits behind a gap that no longer has anything in it. */

html[data-native-platform='ios'].keyboard-open .app-main {
  padding-bottom: 0;
}

.page-container {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px 1.25rem 50px;
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
}

.page-header h1 {
  font-size: var(--fs-3xl);
  letter-spacing: -0.02em;
  color: #eef2fb;
}

.page-subtitle {
  color: var(--text-secondary);
  font-size: var(--fs-base);
}

.action-group {
  display: flex;
  gap: 12px;
  align-items: center;
}

.primary-btn,
.secondary-btn,
.ghost-btn {
  border-radius: 12px;
  padding: 0.8rem 1.2rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  border: 1px solid transparent;
  transition: filter 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease, color 0.25s ease, opacity 0.22s ease;
  background: var(--surface);
  color: var(--text);
  backdrop-filter: blur(10px);
}

.primary-btn {
  background: linear-gradient(135deg, #120d24, #1e1535);
  color: #ede8f5;
  border-color: rgba(255, 255, 255, 0.12);
  box-shadow: 0 10px 30px rgba(14, 10, 20, 0.2);
  position: relative;
  overflow: hidden;
}

.primary-btn::after {
  content: '';
  position: absolute;
  inset: -20%;
  background: linear-gradient(120deg, transparent 0%, rgba(255, 255, 255, 0.28) 45%, transparent 70%);
  transform: translateX(-120%);
  animation: glowSweep 8s ease-in-out infinite;
}

@media (hover: hover) and (pointer: fine) {
  .primary-btn:hover {
    filter: brightness(1.12);
    box-shadow: var(--shadow-soft), 0 0 20px rgba(201, 167, 240, 0.15);
  }
}

.primary-btn:disabled {
  opacity: 0.25;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.secondary-btn {
  background: var(--surface-muted);
  color: var(--text);
  border-color: var(--border);
}

@media (hover: hover) and (pointer: fine) {
  .secondary-btn:hover {
    border-color: var(--primary);
    color: var(--primary);
  }
}

.ghost-btn {
  background: transparent;
  color: var(--text-secondary);
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0.25rem 0.6rem;
  border-radius: 100px;
  color: var(--text-secondary);
  font-size: var(--fs-base);
  border: 1px solid var(--border);
  line-height: 1;
}

.pill-active {
  background: rgba(201, 167, 240, 0.1);
  color: var(--text);
  border-color: var(--primary);
  box-shadow: var(--glow-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem 0.8rem;
}

*:not(input):not(textarea) {
  -webkit-tap-highlight-color: transparent;
}

button, a, [role="button"] {
  touch-action: manipulation;
}

.primary-btn, .secondary-btn, .ghost-btn {
  min-height: 44px;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
}

.card-shell {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 1.5rem;
  box-shadow: var(--shadow-light);
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.16s ease, background-color 0.16s ease;
  backdrop-filter: blur(14px);
}

@media (hover: hover) and (pointer: fine) {
  .card-shell:hover {
    box-shadow: var(--shadow-soft);
    background: rgba(255, 255, 255, 0.07);
    border-color: rgba(255, 255, 255, 0.14);
  }
}

.empty-state {
  text-align: center;
  padding: 3rem 2rem;
  border: 1px dashed var(--border);
  border-radius: 14px;
  color: var(--text-secondary);
  background: var(--surface-muted);
  line-height: 1.7;
}

.empty-subtitle {
  color: var(--text-secondary);
  margin-top: 0.35rem;
}

.app-loading-shell {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
}

.lazy-route-loading {
  min-height: calc(100dvh - 120px - env(safe-area-inset-top) - env(safe-area-inset-bottom));
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem calc(2rem + env(safe-area-inset-bottom));
}

html[data-native-platform='ios'] .lazy-route-loading {
  padding-top: calc(2rem + env(safe-area-inset-top) + 56px);
}

/* On iOS WebKit, transform is unreliable on flex items and the ✦ glyph has a
   larger bounding box than its visual. Collapsing line-height removes the
   oversized box so the glyph overflows symmetrically, then position:relative
   nudges it without triggering the flex+transform bug. */

html:not([data-native-platform='ios']) .dream-ai-badge {
  font-size: 1.25rem;
  margin-top: -0.1rem;
}

html[data-native-platform='ios'] .dream-ai-badge{
  line-height: 0;
  position: relative;
  top: -3px;
}

html[data-native-platform='ios'] .profile-ai-badge {
  line-height: 0;
  position: relative;
  top: -1px;
}

.loading-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
}

.loading-inline {
  padding: 0.35rem 0;
}

.pro-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.2rem 0.42rem;
  border-radius: 5px;
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
  padding-top: 0.3rem;
  color: #fbbf24;
  background: rgba(251, 191, 36, 0.12);
  border: 1px solid rgba(251, 191, 36, 0.35);
  vertical-align: middle;
  line-height: 1;
  flex-shrink: 0;
}

.tag,
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface-muted);
  color: var(--primary-strong);
  padding: 0.35rem 0.75rem;
  border-radius: 100px;
  font-weight: 600;
  font-size: var(--fs-base);
  border: 1px solid var(--border);
}

.reaction-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.5rem 0;
}

.reaction-popover-list,
.modal-content,
.search-results,
.app-loading-shell {
  -webkit-overflow-scrolling: touch;
}

.reaction-chip {
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  color: var(--text);
  padding: 0.3rem 0.85rem;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--fs-base);
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease, transform 0.2s ease;
}

.reaction-chip.active {
  border-color: var(--primary);
  background: rgba(201, 167, 240, 0.12);
  box-shadow: var(--glow-primary);
}

.reaction-chip:focus-visible {
  border-color: var(--primary);
  background: rgba(201, 167, 240, 0.1);
  outline: none;
}

@media (hover: hover) and (pointer: fine) {
  .reaction-chip:hover {
    border-color: var(--primary);
    background: rgba(201, 167, 240, 0.1);
  }
}

.reaction-emoji-icon {
  font-size: 1rem;
  color: var(--accent);
}

.custom-emoji-popover {
  margin-top: 0.5rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: rgba(20, 14, 35, 0.85);
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.emoji-picker-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.emoji-option {
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  width: 44px;
  height: 44px;
  font-size: 1.2rem;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: border-color 0.2s ease, transform 0.2s ease, background-color 0.2s ease;
}

.emoji-option:focus-visible {
  border-color: var(--primary);
  outline: none;
}

@media (hover: hover) and (pointer: fine) {
  .emoji-option:hover { border-color: var(--primary); }
}

.emoji-option.selected {
  border-color: rgba(201, 167, 240, 0.7);
  background: rgba(201, 167, 240, 0.12);
  box-shadow: 0 0 0 1px rgba(201, 167, 240, 0.2);
}

.emoji-input-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}

.emoji-input-row input {
  min-width: 160px;
  padding: 0.5rem 0.85rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.05);
  color: var(--text);
}

.emoji-input-row input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 2px rgba(201, 167, 240, 0.2);
  outline: none;
}

.reaction-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem;
}

.reaction-summary-item {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--text-secondary);
  font-size: var(--fs-sm);
}

.reaction-summary-item .reaction-emoji-icon {
  font-size: 0.85rem;
}

.emoji-clear-btn {
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.55rem 0.75rem;
  border-radius: 10px;
  border: 1px solid rgba(255, 100, 100, 0.25);
  background: rgba(255, 100, 100, 0.06);
  color: #ff9fb1;
  font-size: 0.85rem;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

@media (hover: hover) and (pointer: fine) {
  .emoji-clear-btn:hover {
    background: rgba(255, 100, 100, 0.12);
    border-color: rgba(255, 100, 100, 0.45);
  }
}

.reaction-emoji-text {
  font-size: 1.1rem;
  line-height: 1;
}

.search-highlight {
  background: rgba(232, 200, 122, 0.25);
  color: #f0d58a;
  border-radius: 2px;
  padding: 0 1px;
  font-style: inherit;
  font-weight: inherit;
}

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

.pending-title {
  color: var(--text-secondary);
  font-size: var(--fs-base);
  font-style: italic;
  margin: 0 0 0.4rem;
}

.text-muted {
  color: var(--text-secondary);
}

.surface-row {
  display: grid;
  gap: 1rem;
}

.audience-search-input {
  width: 100%;
  margin-bottom: 0.5rem;
}

.audience-search-input input {
  width: 100%;
  padding: 0.75rem 0.95rem;
  border-radius: 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.audience-search-input input:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(201, 167, 240, 0.12);
}

.audience-result-list {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}

.audience-result {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 0.75rem 1rem;
  background: var(--surface);
  color: var(--text);
  transition: border-color 0.18s ease, background-color 0.18s ease, box-shadow 0.18s ease;
  text-align: left;
}

.audience-result.active {
  border-color: var(--primary);
  background: rgba(201, 167, 240, 0.1);
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.18);
}

.audience-result-meta {
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
}

.result-name {
  font-weight: 600;
  color: var(--text);
}

.result-handle {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.result-status {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.audience-result.active .result-status {
  color: var(--primary);
}

.selected-pill-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-top: 0.65rem;
}

.selected-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.85rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface-muted);
  font-size: var(--fs-sm);
  color: var(--text);
}

.selected-pill button {
  border: none;
  background: transparent;
  color: inherit;
  cursor: pointer;
  font-size: var(--fs-base);
  line-height: 1;
}

@media (hover: hover) and (pointer: fine) {
  .selected-pill button:hover { color: var(--primary); }
}

@media (max-width: 768px) {
  html {
    font-size: 14px;
  }

  /* Prevent iOS auto-zoom on input focus (triggered when font-size < 16px) */
  input,
  textarea,
  select {
    font-size: 16px;
  }

  .app-main.app-main--with-nav {
    padding-top: calc(74px + env(safe-area-inset-top));
  }

  .app-main.app-main--no-nav {
    padding-top: 0;
  }

  .page-container {
    padding: 10px 1.25rem calc(50px + env(safe-area-inset-bottom));
  }

  .page-header {
    flex-direction: column;
    align-items: flex-start;
  }

  .action-group {
    width: 100%;
    justify-content: flex-start;
    flex-wrap: wrap;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── iOS native: suppress active/hover highlights while scrolling ─────────────
 * `is-scrolling` is added to <html> by src/utils/iosTapFix.js as soon as a
 * touch moves more than 4 px. Removed on touchend so intentional taps still
 * receive full visual feedback. Scoped to data-native-platform='ios' so web
 * is completely unaffected.
 *
 * Strategy:
 *   1. Kill all transitions so mid-flight hover animations can't linger.
 *   2. Strip only the visual "highlight" properties (filter, transform,
 *      box-shadow) that change on hover/active. Intentionally leave
 *      background-color and color alone — resetting those causes cards to
 *      flash transparent which looks worse.
 *   3. Restore semantic .active states (selected chips, pills) which are
 *      driven by JS state, not pointer events.
 * --------------------------------------------------------------------------- */

/* 1. Kill transitions on everything during scroll so no highlights linger */

html[data-native-platform='ios'].is-scrolling * {
  transition: none !important;
}

/* 2. Strip pointer-driven visual changes. Split in two now that hover is gated
      behind `hover: hover`: the :active half still matters on every iOS device
      (it stops a press state firing mid flick-scroll), while the :hover half
      only has anything to undo on an iPad driven by a trackpad or mouse. */

html[data-native-platform='ios'].is-scrolling *:active {
  filter: none !important;
  transform: none !important;
  box-shadow: none !important;
  outline: none !important;
  border-color: var(--border) !important;
  text-decoration-color: inherit !important;
}

@media (hover: hover) and (pointer: fine) {
  html[data-native-platform='ios'].is-scrolling *:hover {
    filter: none !important;
    transform: none !important;
    box-shadow: none !important;
    outline: none !important;
    border-color: var(--border) !important;
    text-decoration-color: inherit !important;
  }
}

/* 3. Restore semantic selected states (driven by JS, not pointer) */

html[data-native-platform='ios'].is-scrolling .reaction-chip.active, html[data-native-platform='ios'].is-scrolling .reaction-chip.active:active {
  border-color: var(--primary) !important;
  background-color: rgba(183, 183, 240, 0.12) !important;
  box-shadow: var(--glow-primary) !important;
}

@media (hover: hover) and (pointer: fine) {
  html[data-native-platform='ios'].is-scrolling .reaction-chip.active:hover {
    border-color: var(--primary) !important;
    background-color: rgba(183, 183, 240, 0.12) !important;
    box-shadow: var(--glow-primary) !important;
  }
}

html[data-native-platform='ios'].is-scrolling .audience-result.active, html[data-native-platform='ios'].is-scrolling .audience-result.active:active {
  border-color: var(--primary) !important;
  background-color: rgba(183, 183, 240, 0.1) !important;
}

@media (hover: hover) and (pointer: fine) {
  html[data-native-platform='ios'].is-scrolling .audience-result.active:hover {
    border-color: var(--primary) !important;
    background-color: rgba(183, 183, 240, 0.1) !important;
  }
}

html[data-native-platform='ios'].is-scrolling .pill-active, html[data-native-platform='ios'].is-scrolling .pill-active:active {
  border-color: var(--primary) !important;
  background-color: rgba(183, 183, 240, 0.1) !important;
  box-shadow: var(--glow-primary) !important;
}

@media (hover: hover) and (pointer: fine) {
  html[data-native-platform='ios'].is-scrolling .pill-active:hover {
    border-color: var(--primary) !important;
    background-color: rgba(183, 183, 240, 0.1) !important;
    box-shadow: var(--glow-primary) !important;
  }
}

/* ── Interaction feedback ────────────────────────────────────────────────────
 * Two separate concerns, deliberately kept apart:
 *
 *   Press  — applies on every device. `-webkit-tap-highlight-color` is cleared
 *            globally above, so without these a tap on a phone gives no
 *            feedback at all. The transition lives inside the `:active` rule so
 *            the press reads instantly and the release snaps back.
 *   Hover  — gated behind `hover: hover` + `pointer: fine`. Ungated `:hover`
 *            sticks to whatever a finger last touched until something else is
 *            tapped, which is what `iosTapFix.js` exists to paper over.
 * ------------------------------------------------------------------------- */

.primary-btn:active,
.secondary-btn:active,
.ghost-btn:active,
.danger-btn:active,
.auth-submit:active,
.auth-google-btn:active,
.auth-apple-btn:active,
.request-btn:active,
.follow-action-btn:active,
.moderation-action-btn:active,
.edit-profile-btn:active,
.settings-btn:active,
.add-tag-btn:active,
.close-btn:active,
.report-reason-btn:active,
.feed-card-menu-item:active,
.activity-clear-btn:active,
.prompt-option-btn:active,
.prompt-option:active,
.more-options-toggle:active,
.detail-share-toggle:active,
.voice-input-btn:active {
  transform: scale(0.965);
  transition: transform 80ms ease;
}

/* Cards are large, so they take a much smaller scale — anything more reads as
   the whole page lurching rather than the card acknowledging the tap. */

.card-shell:active,
.feed-card:active,
.dream-card:active,
.profile-dream-card:active,
.tagged-dream-card:active,
.search-dream-card:active,
.person-card:active,
.connections-card:active,
.connections-card-main:active,
.activity-card-main:active,
.audience-result:active,
.stat-button:active {
  transform: scale(0.99);
  transition: transform 80ms ease;
}

.pill:active,
.chip:active,
.reaction-chip:active,
.emoji-option:active,
.visibility-chip:active,
.feed-tab:active,
.dream-tab:active,
.connections-tab:active,
.view-toggle-btn:active,
.filter-toggle .chip:active,
.reaction-button:active,
.comment-heart-btn:active,
.comment-reply-btn:active,
.comment-report-btn:active,
.comment-delete-btn:active,
.selected-pill button:active,
.tagged-pill button:active,
.detail-tag-remove:active,
.avatar-option:active,
.color-swatch:active,
.calendar-day:active,
.nav-ios-tab:active,
.nav-ios-back-btn:active {
  transform: scale(0.93);
  transition: transform 70ms ease;
}

/* Disabled controls must not look pressable. */

.primary-btn:disabled:active,
.secondary-btn:disabled:active,
.ghost-btn:disabled:active,
.danger-btn:disabled:active,
button:disabled:active {
  transform: none;
}

@media (hover: hover) and (pointer: fine) {
  .ghost-btn:hover:not(:disabled),
  .danger-btn:hover:not(:disabled) {
    color: var(--text);
    filter: brightness(1.15);
  }

  .pill:hover,
  .chip:hover,
  .view-toggle-btn:hover,
  .feed-tab:hover,
  .dream-tab:hover,
  .connections-tab:hover {
    border-color: rgba(201, 167, 240, 0.45);
    color: var(--text);
  }

  .feed-card:hover,
  .dream-card:hover,
  .profile-dream-card:hover,
  .tagged-dream-card:hover,
  .search-dream-card:hover,
  .person-card:hover,
  .connections-card:hover,
  .activity-card:hover {
    border-color: rgba(201, 167, 240, 0.28);
    background-color: rgba(255, 255, 255, 0.055);
  }

  .calendar-day:hover:not(.is-selected) .calendar-day-number {
    background: rgba(201, 167, 240, 0.16);
  }

  .avatar-option:hover,
  .color-swatch:hover,
  .report-reason-btn:hover,
  .feed-card-menu-item:hover,
  .prompt-option-btn:hover,
  .audience-result:hover {
    border-color: rgba(201, 167, 240, 0.45);
  }

  .activity-clear-btn:hover,
  .comment-reply-btn:hover,
  .comment-report-btn:hover {
    color: var(--primary);
  }

  .comment-delete-btn:hover {
    color: #ff9fb1;
  }
}

/* Presses are feedback, not decoration, but they still respect the global
   reduced-motion rule above, which zeroes out every transition duration. */

@media (prefers-reduced-motion: reduce) {
  .page-container,
  .insights-page,
  .home-page,
  [data-nav-direction] .page-container,
  [data-nav-direction] .insights-page {
    animation: none;
  }
}

/* Remaining standalone controls and links. Grouped separately from the block
   above only because these are not variants of the shared button classes. */

.auth-back-link:active,
.auth-forgot-link:active,
.auth-password-toggle:active,
.comment-replies-toggle:active,
.detail-author-btn:active,
.detail-back-btn:active,
.detail-title-editable:active,
.detail-date-pill--interactive:active,
.feed-author-link:active,
.feed-card-menu-btn:active,
.legal-back-btn:active,
.memory-patterns-link:active,
.nav-logo:active,
.rc-restore-btn:active,
.tag-suggestion-item:active,
.tagged-view-profile:active,
.emoji-clear-btn:active,
.navigation .nav-links a:active {
  transform: scale(0.94);
  transition: transform 70ms ease;
}

.home-cta-primary:active,
.home-cta-secondary:active {
  transform: scale(0.965);
  transition: transform 80ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .detail-title-editable:hover,
  .detail-date-pill--interactive:hover,
  .feed-author-link:hover,
  .tagged-view-profile:hover,
  .memory-patterns-link:hover,
  .auth-forgot-link:hover,
  .auth-back-link:hover,
  .comment-replies-toggle:hover,
  .rc-restore-btn:hover {
    color: var(--primary);
  }

  .feed-card-menu-btn:hover,
  .auth-password-toggle:hover,
  .detail-back-btn:hover,
  .legal-back-btn:hover {
    color: var(--text);
  }

  .tag-suggestion-item:hover {
    border-color: rgba(201, 167, 240, 0.45);
  }

  .nav-logo:hover {
    filter: brightness(1.15);
  }
}

/* ── Native touch behaviour (iOS shell only) ─────────────────────────────────
 * Without these, a long press anywhere pops WebKit's Copy / Look Up / Share
 * callout and drags start selecting UI text — the clearest tell that an app is
 * a web view. Chrome is locked down; anything the user might genuinely want to
 * copy is opted back in below, and text entry is restored explicitly because
 * inheriting `user-select: none` into a field breaks selection in WKWebView.
 * ------------------------------------------------------------------------- */

html[data-native-platform='ios'] body {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

html[data-native-platform='ios'] input,
html[data-native-platform='ios'] textarea,
html[data-native-platform='ios'] [contenteditable='true'] {
  -webkit-touch-callout: default;
  -webkit-user-select: text;
  user-select: text;
}

/* Real content — a dream, a comment, an analysis — stays long-pressable so it
   can be copied, the way selectable text behaves in a native app. */

html[data-native-platform='ios'] .detail-body,
html[data-native-platform='ios'] .detail-insight,
html[data-native-platform='ios'] .detail-connections-item,
html[data-native-platform='ios'] .comment-body,
html[data-native-platform='ios'] .feed-content,
html[data-native-platform='ios'] .feed-summary,
html[data-native-platform='ios'] .insights-entry-text,
html[data-native-platform='ios'] .profile-bio,
html[data-native-platform='ios'] .legal-page {
  -webkit-touch-callout: default;
  -webkit-user-select: text;
  user-select: text;
}

/* ── Modal motion ────────────────────────────────────────────────────────────
 * Nothing in the app animated on open — sheets and dialogs simply appeared,
 * which is the other big "web view" tell after the long-press callout. The
 * class names are shared across the three stylesheets that define report
 * modals, so styling them once here covers every caller.
 *
 * `backwards` fill again: these end at a transform, and leaving one applied
 * would make the panel a containing block for anything fixed inside it.
 * ------------------------------------------------------------------------- */

@keyframes modalBackdropIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes modalSheetIn {
  from { opacity: 0; transform: translate3d(0, 100%, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes modalDialogIn {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}

.confirm-modal-backdrop,
.report-modal-backdrop,
.modal-overlay,
.crop-modal-backdrop {
  animation: modalBackdropIn 180ms ease-out backwards;
}

.report-modal,
.modal-content,
.crop-modal-card {
  animation: modalDialogIn 220ms cubic-bezier(0.32, 0.72, 0, 1) backwards;
}

/* The confirm modal is a bottom sheet below 480px and a centred dialog above,
   so its entrance has to follow the same breakpoint. */

.confirm-modal {
  animation: modalSheetIn 260ms cubic-bezier(0.32, 0.72, 0, 1) backwards;
}

@media (min-width: 480px) {
  .confirm-modal {
    animation: modalDialogIn 220ms cubic-bezier(0.32, 0.72, 0, 1) backwards;
  }
}

/* Scrolling inside a sheet must not chain to the page behind it. */

.confirm-modal,
.report-modal,
.modal-content,
.crop-modal-card {
  overscroll-behavior: contain;
}

@media (prefers-reduced-motion: reduce) {
  .confirm-modal-backdrop,
  .report-modal-backdrop,
  .modal-overlay,
  .crop-modal-backdrop,
  .confirm-modal,
  .report-modal,
  .modal-content,
  .crop-modal-card {
    animation: none;
  }
}

/* ---------------------------------------------------------------------------
 * Popovers. These appeared fully formed the instant they mounted, which is the
 * most jarring version of the problem — they arrive right under the finger that
 * asked for them. Growing them a little out of their anchor corner ties the
 * panel to the control that opened it.
 * `backwards` fill again, for the same containing-block reason as the modals.
 * ------------------------------------------------------------------------- */

@keyframes popoverIn {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}

.feed-card-menu {
  transform-origin: top right;
  animation: popoverIn 150ms cubic-bezier(0.32, 0.72, 0, 1) backwards;
}

/* Opacity only, deliberately. This card is measured with getBoundingClientRect
   in a layout effect to place itself next to its anchor, and a scale would be
   folded into that measurement and put the popover in the wrong spot. */

.reaction-popover-card {
  animation: fadeIn 150ms ease-out backwards;
}

@media (prefers-reduced-motion: reduce) {
  .feed-card-menu,
  .reaction-popover-card {
    animation: none;
  }
}
