/* ===================== Masonry ===================== */

.masonry-grid {
  columns: 5 272px;
  column-gap: 1.3em;
}

@media (max-width: 1400px) {
  .masonry-grid {
    columns: 4 248px;
  }
}

@media (max-width: 1024px) {
  .masonry-grid {
    columns: 3 216px;
    column-gap: 1.1em;
  }
}

@media (max-width: 720px) {
  .masonry-grid {
    columns: 2 150px;
    column-gap: 0.85em;
  }
}

/* ===================== Post card ===================== */

.post-card {
  break-inside: avoid;
  margin-bottom: 1.3em;
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--sh-2), var(--glass-highlight);
  animation: rise-in var(--dur-slow) var(--ease-out) both;
  transition: transform 0.35s var(--ease-out), box-shadow 0.35s var(--ease-out),
    border-color 0.35s var(--ease-out);
}

/* Gentle stagger so a grid resolves as a cascade rather than one hard pop. */
.masonry-grid .post-card:nth-child(1) { animation-delay: 0.02s; }
.masonry-grid .post-card:nth-child(2) { animation-delay: 0.05s; }
.masonry-grid .post-card:nth-child(3) { animation-delay: 0.08s; }
.masonry-grid .post-card:nth-child(4) { animation-delay: 0.11s; }
.masonry-grid .post-card:nth-child(5) { animation-delay: 0.14s; }
.masonry-grid .post-card:nth-child(6) { animation-delay: 0.17s; }
.masonry-grid .post-card:nth-child(n + 7) { animation-delay: 0.2s; }

.post-card:hover {
  transform: translateY(-6px);
  box-shadow: var(--sh-3), var(--glass-highlight);
  border-color: var(--line-strong);
}

.post-card-media {
  position: relative;
  display: block;
  overflow: hidden;
  /* Shimmer stands in until the image paints, so a slow-loading grid reads as
     loading rather than broken. The image covers it once decoded. */
  background: linear-gradient(90deg, var(--bg-subtle) 25%, var(--surface-2) 37%, var(--bg-subtle) 63%);
  background-size: 200% 100%;
  animation: shimmer 1.4s linear infinite;
}

.post-card-media img {
  width: 100%;
  height: auto;
  position: relative;
  background: var(--bg-subtle);
  transition: transform 0.6s var(--ease-out);
}

.post-card:hover .post-card-media img {
  transform: scale(1.07);
}

/* Bottom scrim keeps the duration badge legible over light imagery. */
.post-card-media::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 46%;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.45), transparent);
  opacity: 0;
  transition: opacity 0.35s var(--ease-out);
  pointer-events: none;
}

.post-card:hover .post-card-media::after {
  opacity: 1;
}

.post-card-badge {
  position: absolute;
  bottom: 0.7em;
  right: 0.7em;
  z-index: 1;
  background: rgba(9, 9, 11, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: var(--text-2xs);
  font-weight: 600;
  padding: 0.32em 0.75em;
  border-radius: var(--r-full);
}

.post-card-body {
  padding: 1em 1.1em 1.15em;
}

.post-card-title {
  display: block;
  font-weight: 600;
  font-size: var(--text-sm);
  letter-spacing: -0.02em;
  margin-bottom: 0.55em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.post-card-title:hover {
  color: var(--brand-text);
}

.post-card-meta {
  display: flex;
  gap: 1em;
  font-size: var(--text-2xs);
  color: var(--ink-muted);
}

.post-card-stat {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
}

/* ===================== Pagination ===================== */

.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1em;
  margin-top: 3.5em;
  font-size: var(--text-sm);
}

.pagination-link {
  font-weight: 600;
  padding: 0.7em 1.35em;
  border-radius: var(--r-full);
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  box-shadow: var(--glass-highlight);
  transition: transform var(--dur) var(--ease-spring), border-color var(--dur) var(--ease-out),
    color var(--dur) var(--ease-out), background var(--dur) var(--ease-out);
}

.pagination-link:not(.disabled):hover {
  transform: translateY(-2px);
  border-color: var(--brand);
  color: var(--ink);
  background: var(--brand-soft);
}

.pagination-link.disabled {
  opacity: 0.35;
  pointer-events: none;
  box-shadow: none;
}

.pagination-status {
  color: var(--ink-muted);
  font-size: var(--text-xs);
}

/* ===================== Post detail ===================== */

.post-detail {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(320px, 1fr);
  gap: 2.25em;
  align-items: start;
  animation: rise-in var(--dur-slow) var(--ease-out) both;
}

@media (max-width: 960px) {
  .post-detail {
    grid-template-columns: 1fr;
    gap: 1.5em;
  }
}

.post-detail-media {
  position: relative;
  background: var(--bg-subtle);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-2xl);
  overflow: hidden;
  box-shadow: var(--sh-3), var(--glass-highlight);
}

.post-detail-media img,
.post-detail-media video {
  width: 100%;
  max-height: 80vh;
  object-fit: contain;
  background: #09090b;
}

.post-detail-info h1 {
  font-size: var(--text-xl);
  margin-bottom: 0.4em;
}

.post-detail-description {
  color: var(--ink-muted);
  white-space: pre-wrap;
  margin-top: 1.1em;
  font-size: var(--text-sm);
  line-height: 1.7;
}

.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45em;
  margin: 1.25em 0;
}

.tag {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-muted);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  padding: 0.4em 0.9em;
  border-radius: var(--r-full);
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
    background var(--dur) var(--ease-out), transform var(--dur) var(--ease-spring);
}

a.tag:hover {
  color: var(--ink);
  background: var(--brand-soft);
  border-color: var(--brand);
  transform: translateY(-1px);
}

.post-detail-stats {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 1.15em;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  margin: 1.4em 0 1.75em;
  padding-bottom: 1.5em;
  border-bottom: 1px solid var(--line);
}

/* ===================== Like button ===================== */

.like-button {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-full);
  padding: 0.55em 1.15em;
  cursor: pointer;
  color: var(--ink);
  font-weight: 600;
  font-size: var(--text-sm);
  box-shadow: var(--glass-highlight);
  transition: transform var(--dur) var(--ease-spring), border-color var(--dur) var(--ease-out),
    color var(--dur) var(--ease-out), background var(--dur) var(--ease-out);
}

.like-button:hover {
  transform: translateY(-2px);
  border-color: var(--pink);
  background: rgba(236, 72, 153, 0.1);
}

.like-button .like-icon {
  /* 2em rather than the inherited 1em: doubled, like the card hearts. */
  font-size: 2em;
  line-height: 1;
  color: var(--ink-muted);
  transition: color var(--dur) var(--ease-out), transform var(--dur) var(--ease-spring);
}

/* Tabular figures: the count is swapped live by likeToggle.js, and
   proportional digits make the button visibly jump on 9 -> 10. */
.like-count {
  font-variant-numeric: tabular-nums;
  min-width: 1ch;
  text-align: left;
}

.like-button:hover .like-icon {
  color: var(--pink);
}

.like-button.liked {
  border-color: var(--pink);
  color: var(--pink);
  background: rgba(236, 72, 153, 0.14);
}

.like-button.liked .like-icon {
  color: var(--pink);
  transform: scale(1.2);
}

.like-button:disabled {
  opacity: 0.55;
  cursor: default;
  transform: none;
}

/* ===================== Comments ===================== */

.comments-section h2 {
  font-size: var(--text-lg);
  margin-bottom: 1em;
}

.comment-form {
  display: flex;
  flex-direction: column;
  gap: 0.75em;
  margin-bottom: 1.75em;
}

.comment-form button {
  align-self: flex-end;
}

.comment-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5em;
}

.comment-item {
  padding: 1em 1.15em;
  border-radius: var(--r-lg);
  background: var(--glass-bg);
  border: 1px solid transparent;
  transition: background var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out);
}

.comment-item:hover {
  background: var(--glass-bg-strong);
  border-color: var(--glass-border);
}

.comment-item-header {
  display: flex;
  align-items: baseline;
  gap: 0.65em;
  font-size: var(--text-sm);
}

.comment-item-header strong a:hover {
  color: var(--brand-text);
}

.comment-item p {
  margin: 0.35em 0 0;
  font-size: var(--text-sm);
  line-height: 1.65;
}

.comment-delete {
  font-size: var(--text-2xs);
  margin-top: 0.5em;
}

/* ===================== Ads ===================== */

.ad-banner {
  position: relative;
  max-width: 480px;
  margin: 1.75em auto;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--glass-border);
  background: var(--bg-subtle);
  box-shadow: var(--sh-1);
  transition: transform var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}

.ad-banner:hover {
  transform: translateY(-3px);
  box-shadow: var(--sh-2);
}

.ad-banner img {
  width: 100%;
  /* The image's own proportions decide the height. */
  height: auto;
  /* contain, never cover: this is somebody's advertisement, and cropping it is
     not ours to do. The old rule paired `cover` with a hard 160px ceiling, so
     anything that was not roughly 3:1 came through as a horizontal slice of its
     own middle -- a 1536x1024 creative rendered as a plain orange stripe,
     because that is what happened to run across the centre of it. */
  object-fit: contain;
  /* A ceiling so a tall creative cannot push the feed down the page; with
     `contain` this letterboxes rather than crops. */
  max-height: 300px;
  background: var(--bg-subtle);
  display: block;
}

.ad-label {
  position: absolute;
  top: 0.65em;
  left: 0.65em;
  z-index: 1;
  background: rgba(9, 9, 11, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.14);
  color: #fff;
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 0.3em 0.75em;
  border-radius: var(--r-full);
}

/* ===================== Composer ===================== */

.composer {
  margin-bottom: 1.75em;
}

.composer summary {
  cursor: pointer;
  font-weight: 700;
  font-size: var(--text-base);
  list-style: none;
}

.composer summary::-webkit-details-marker {
  display: none;
}

.composer[open] summary {
  margin-bottom: 1.5em;
  padding-bottom: 1.2em;
  border-bottom: 1px solid var(--line);
}

.composer .upload-form {
  max-width: 580px;
}

/* ===================== Avatars ===================== */

.avatar {
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  /* The global `img { max-width: 100% }` can shrink an avatar's width to fit a
     narrow parent while its fixed height stays put -- which turns a 96px circle
     into a 68x96 oval. Pinning the ratio and letting height follow means a
     squeezed avatar stays circular instead of stretching. */
  aspect-ratio: 1;
  height: auto;
}

.avatar-initials {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 700;
  letter-spacing: -0.03em;
}

.avatar-sm {
  width: 34px;
  height: 34px;
  font-size: 0.9rem;
}

.avatar-md {
  width: 56px;
  height: 56px;
  font-size: 1.3rem;
}

.avatar-lg {
  width: 96px;
  height: 96px;
  font-size: 2.2rem;
}

.avatar-xl {
  width: 152px;
  height: 152px;
  font-size: 3.1rem;
  border: 5px solid var(--bg);
  box-shadow: var(--sh-3);
}

.avatar-edit {
  margin-top: 1.4em;
  padding-top: 1.2em;
  border-top: 1px solid var(--line);
}

.avatar-edit summary,
.category-edit summary,
.report-box summary {
  cursor: pointer;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--ink-muted);
  transition: color var(--dur) var(--ease-out);
}

.avatar-edit summary:hover,
.category-edit summary:hover {
  color: var(--brand-text);
}

.avatar-edit-form {
  display: flex;
  gap: 0.8em;
  align-items: center;
  margin-top: 1em;
  flex-wrap: wrap;
}

/* ===================== Profile ===================== */

.fb-cover {
  height: 260px;
  /* Square corners and full bleed: the cover is meant to reach the edges of the
     page column, and a rounded corner is exactly what stops it touching them. */
  border-radius: 0;
  background: var(--gradient-aurora);
  background-size: 180% 180%;
  position: relative;
  overflow: hidden;
  box-shadow: var(--sh-2);
  animation: cover-drift 18s ease-in-out infinite alternate;
}

@keyframes cover-drift {
  from {
    background-position: 0% 50%;
  }
  to {
    background-position: 100% 50%;
  }
}

/* Light bloom plus a soft vignette so the flat gradient gains depth.
   Suppressed when a real photo is set -- the overlay would just wash it out. */
.fb-cover::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(circle at 18% 14%, rgba(255, 255, 255, 0.4), transparent 52%),
    radial-gradient(circle at 84% 88%, rgba(9, 9, 11, 0.34), transparent 58%);
}

.fb-cover.has-image {
  background: var(--bg-subtle);
  animation: none;
}

.fb-cover.has-image::after {
  background: linear-gradient(to bottom, rgba(9, 9, 11, 0.12), rgba(9, 9, 11, 0.35));
}

/* Below the desktop breakpoints the cover has TWO ancestors adding side padding
   -- .shell and .page-container -- so reaching the screen edge means cancelling
   both. Each rule mirrors the padding set for that same width in layout.css;
   change one there and this has to follow. */
@media (max-width: 1080px) {
  .fb-cover {
    /* .shell gains 0 8px here. */
    margin-left: -8px;
    margin-right: -8px;
  }
}

@media (max-width: 1024px) {
  .fb-cover {
    /* ...and .page-container gains 1.25em. */
    margin-left: calc(-1.25em - 8px);
    margin-right: calc(-1.25em - 8px);
  }
}

@media (max-width: 560px) {
  .fb-cover {
    /* .page-container drops to 1em. */
    margin-left: calc(-1em - 8px);
    margin-right: calc(-1em - 8px);
  }
}

.fb-cover-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Cover editing */

.cover-edit {
  position: absolute;
  right: 1em;
  bottom: 1em;
  z-index: 2;
}

.cover-edit summary {
  list-style: none;
  cursor: pointer;
}

.cover-edit summary::-webkit-details-marker {
  display: none;
}

.cover-edit-button {
  display: inline-block;
  padding: 0.5em 1.1em;
  border-radius: var(--r-full);
  background: rgba(9, 9, 11, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 600;
  transition: background var(--dur) var(--ease-out), transform var(--dur) var(--ease-spring);
}

.cover-edit-button:hover {
  background: rgba(9, 9, 11, 0.78);
  transform: translateY(-2px);
}

.cover-edit-panel {
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.6em);
  width: min(340px, 78vw);
  padding: 1.1em;
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--glass-border);
  box-shadow: var(--sh-3);
}

.cover-edit-panel .field-hint {
  margin-top: 0.6em;
}

.cover-edit-panel form + form {
  margin-top: 0.9em;
  padding-top: 0.9em;
  border-top: 1px solid var(--line);
}

@media (max-width: 560px) {
  .cover-edit {
    right: 0.6em;
    bottom: 0.6em;
  }
}

.fb-identity-bar {
  position: relative;
  margin: -76px 0 2em;
  /* Pulled in from 1.9em. Against a cover that now runs to both corners, the old
     indent left the avatar and the name floating well inside the page. */
  padding: 0 0.5em;
  display: flex;
  align-items: flex-end;
  gap: 1.4em;
  flex-wrap: wrap;
}

.fb-identity-info {
  padding-bottom: 0.75em;
  min-width: 0;
}

.fb-identity-info h1 {
  font-size: var(--text-xl);
  margin-bottom: 0.25em;
  display: flex;
  align-items: center;
  gap: 0.6em;
  flex-wrap: wrap;
}

.fb-layout {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 1.75em;
  align-items: start;
}

@media (max-width: 900px) {
  .fb-layout {
    grid-template-columns: 1fr;
  }
  .fb-identity-bar {
    padding: 0 0.5em;
    margin-top: -64px;
  }
  .fb-cover {
    height: 190px;
  }
}

.fb-sidebar {
  position: sticky;
  top: 6.5rem;
  /* Bio and stats start closer to the column edge, in line with the identity
     block above them. */
  padding-left: 8px;
}

.fb-sidebar h2 {
  font-size: var(--text-base);
  margin-bottom: 1em;
}

.fb-sidebar-stats {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6em;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.fb-sidebar-stats li strong {
  color: var(--ink);
  font-weight: 700;
}

@media (max-width: 900px) {
  .fb-sidebar {
    position: static;
  }
}

.fb-feed {
  display: flex;
  flex-direction: column;
  gap: 1.2em;
}

.fb-composer summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 0.85em;
}

.fb-composer summary::-webkit-details-marker {
  display: none;
}

.fb-composer-placeholder {
  flex: 1;
  padding: 0.8em 1.3em;
  border-radius: var(--r-full);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-weight: 500;
  transition: background var(--dur) var(--ease-out), color var(--dur) var(--ease-out),
    border-color var(--dur) var(--ease-out);
}

.fb-composer summary:hover .fb-composer-placeholder {
  background: var(--brand-soft);
  border-color: var(--brand);
  color: var(--ink);
}

.fb-composer[open] summary {
  margin-bottom: 1.5em;
  padding-bottom: 1.2em;
  border-bottom: 1px solid var(--line);
}

.fb-post-card {
  padding: 1.5em;
  transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out),
    border-color 0.3s var(--ease-out);
}

.fb-post-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--sh-3), var(--glass-highlight);
  border-color: var(--line-strong);
}

.fb-post-header {
  display: flex;
  align-items: center;
  gap: 0.8em;
  margin-bottom: 1em;
}

.fb-post-header strong {
  display: block;
  font-size: var(--text-sm);
}

.fb-post-header .field-hint {
  margin-top: 0;
}

.fb-post-title {
  font-weight: 700;
  font-size: var(--text-lg);
  letter-spacing: -0.028em;
  margin-bottom: 0.4em;
}

.fb-post-title a:hover {
  color: var(--brand-text);
}

.fb-post-description {
  color: var(--ink-muted);
  font-size: var(--text-sm);
  margin-bottom: 1.1em;
  white-space: pre-wrap;
  line-height: 1.7;
}

.fb-post-media {
  display: block;
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--bg-subtle);
  margin-bottom: 1.1em;
}

.fb-post-media img {
  width: 100%;
  max-height: 540px;
  object-fit: cover;
  display: block;
  transition: transform 0.6s var(--ease-out);
}

.fb-post-media:hover img {
  transform: scale(1.04);
}

.fb-post-stats {
  display: flex;
  gap: 1.4em;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  padding-top: 1em;
  border-top: 1px solid var(--line);
}

/* ===================== Policies ===================== */

.policy-layout {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  gap: 1.75em;
  align-items: start;
}

@media (max-width: 860px) {
  .policy-layout {
    grid-template-columns: 1fr;
  }
}

.policy-nav {
  position: sticky;
  top: 6.5rem;
}

@media (max-width: 860px) {
  .policy-nav {
    position: static;
  }
}

.policy-nav h2 {
  font-size: var(--text-2xs);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
  margin-bottom: 1em;
}

.policy-nav-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2em;
}

.policy-nav-list a {
  display: block;
  padding: 0.6em 0.85em;
  border-radius: var(--r-md);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-muted);
  transition: background var(--dur) var(--ease-out), color var(--dur) var(--ease-out);
}

.policy-nav-list a:hover {
  background: var(--glass-bg-strong);
  color: var(--ink);
}

.policy-nav-list a.active {
  background: var(--brand-soft);
  color: var(--ink);
}

.policy-doc {
  max-width: 76ch;
}

.policy-meta {
  margin-top: -0.4em;
  margin-bottom: 1.8em;
  padding-bottom: 1.2em;
  border-bottom: 1px solid var(--line);
}

/* Legal text is long-form reading, so it gets a looser measure and rhythm
   than the rest of the app. */
.policy-body {
  font-size: var(--text-sm);
  line-height: 1.8;
  color: var(--ink-muted);
}

.policy-body h2 {
  font-size: var(--text-base);
  color: var(--ink);
  margin-top: 2em;
  margin-bottom: 0.6em;
}

.policy-body h2:first-child {
  margin-top: 0;
}

.policy-body h3 {
  font-size: var(--text-sm);
  color: var(--ink);
  margin-top: 1.5em;
}

.policy-body ul,
.policy-body ol {
  padding-left: 1.4em;
  margin-bottom: 1.2em;
}

.policy-body li {
  margin-bottom: 0.5em;
}

.policy-body strong {
  color: var(--ink);
}

.policy-body a {
  color: var(--brand-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.policy-body .policy-note {
  padding: 0.95em 1.1em;
  background: rgba(251, 191, 36, 0.08);
  border-left: 3px solid var(--warning);
  border-radius: var(--r-md);
  margin: 1.5em 0;
}

.policy-card {
  align-items: flex-start;
}

.policy-edit-form {
  max-width: 900px;
}

.policy-body-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--text-xs);
  line-height: 1.7;
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4em 1.4em;
  margin-bottom: 1.2em;
  font-weight: 600;
}

.footer-links a:hover {
  color: var(--brand-text);
}

/* ===================== Two-factor ===================== */

.totp-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.6rem;
  letter-spacing: 0.45em;
  text-align: center;
  padding-left: 0.45em;
}

.twofa-setup,
.twofa-intro,
.recovery-panel {
  max-width: 520px;
}

.twofa-setup h2,
.recovery-panel h2 {
  font-size: var(--text-base);
  margin-top: 1.5em;
}

.twofa-setup h2:first-child {
  margin-top: 0;
}

.twofa-qr {
  width: 240px;
  height: 240px;
  border-radius: var(--r-lg);
  /* White plate: QR codes need light quiet-zone contrast to scan reliably,
     and the app's default surface is near-black. */
  background: #fff;
  padding: 12px;
  margin: 1em 0;
  box-shadow: var(--sh-2);
}

.twofa-manual-key {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--text-base);
  letter-spacing: 0.1em;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-md);
  padding: 0.8em 1em;
  word-break: break-all;
  user-select: all;
}

.twofa-manage-form + .twofa-manage-form {
  margin-top: 1.75em;
  padding-top: 1.5em;
  border-top: 1px solid var(--line);
}

.recovery-codes {
  list-style: none;
  padding: 1.2em;
  margin: 1.2em 0;
  background: var(--glass-bg-strong);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-lg);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5em 1.5em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--text-sm);
  letter-spacing: 0.05em;
  user-select: all;
}

@media (max-width: 480px) {
  .recovery-codes {
    grid-template-columns: 1fr;
  }
  .totp-input {
    font-size: 1.3rem;
    letter-spacing: 0.3em;
  }
}

/* ===================== People results ===================== */

.results-heading {
  font-size: var(--text-base);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: var(--text-2xs);
  margin-bottom: 1em;
}

.people-results {
  margin-bottom: 2.5em;
}

.people-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
  gap: 0.85em;
}

.person-card {
  display: flex;
  align-items: center;
  gap: 0.9em;
  padding: 1em 1.15em;
  border-radius: var(--r-lg);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--sh-1), var(--glass-highlight);
  animation: rise-in var(--dur-slow) var(--ease-out) both;
  transition: transform var(--dur) var(--ease-spring), border-color var(--dur) var(--ease-out),
    background var(--dur) var(--ease-out), box-shadow var(--dur) var(--ease-out);
}

.person-card:hover {
  transform: translateY(-3px);
  border-color: var(--brand);
  background: var(--brand-soft);
  box-shadow: var(--sh-2);
}

.person-card .avatar {
  transition: transform var(--dur) var(--ease-spring);
}

.person-card:hover .avatar {
  transform: scale(1.06);
}

.person-card-info {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  min-width: 0;
}

.person-card-name {
  display: flex;
  align-items: center;
  gap: 0.45em;
  flex-wrap: wrap;
  font-weight: 700;
  font-size: var(--text-sm);
  letter-spacing: -0.02em;
}

.person-card-meta {
  font-size: var(--text-2xs);
  color: var(--ink-muted);
}

.person-card-bio {
  font-size: var(--text-xs);
  color: var(--ink-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.no-post-results {
  margin-top: 0;
}

/* ===================== Creator links ===================== */

.creator-links {
  display: flex;
  flex-direction: column;
  gap: 0.55em;
  margin-top: 1.4em;
  padding-top: 1.3em;
  border-top: 1px solid var(--line);
}

.creator-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6em;
  padding: 0.75em 1.05em;
  border-radius: var(--r-md);
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  font-size: var(--text-sm);
  font-weight: 600;
  transition: border-color var(--dur) var(--ease-out), background var(--dur) var(--ease-out),
    transform var(--dur) var(--ease-spring), box-shadow var(--dur) var(--ease-out);
}

.creator-link:hover {
  border-color: var(--brand);
  background: var(--brand-soft);
  transform: translateX(3px);
  box-shadow: var(--sh-1);
}

.creator-link-arrow {
  opacity: 0.45;
  font-size: 0.85em;
  transition: opacity var(--dur) var(--ease-out), transform var(--dur) var(--ease-out);
}

.creator-link:hover .creator-link-arrow {
  opacity: 1;
  transform: translate(2px, -2px);
}

/* ===================== NSFW ===================== */

/* Blur the image itself, not just an overlay: a viewer with CSS partly disabled
   must not get an unobstructed preview. The veil on top is the second layer. */
/* No CSS blur here any more. The image these rules apply to is already the
   server-side censored derivative, so filtering it again would smear an image
   that is 24px of source to begin with. More importantly, a CSS filter was never
   a control -- the real file was still downloaded and one devtools click removed
   it. The scale just crops the soft edges the blur leaves behind. */
.post-card.is-nsfw .post-card-media img,
.fb-post-media.is-nsfw img,
.post-detail-media.is-nsfw img,
.post-detail-media.is-nsfw video {
  transform: scale(1.06);
}

.post-card.is-nsfw:hover .post-card-media img {
  transform: scale(1.12);
}

.nsfw-veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
  padding: 12px;
  /* .feed-media-link sets line-height: 0 to kill the inline gap under its image.
     That inherits straight into this overlay and collapsed the badge to 6px tall,
     so the veil restores a real line box for its own text. */
  line-height: 1.35;
  /* Deep enough that white text clears 4.5:1 even over a bright photograph:
     0.68 of this laid over pure white still lands around #6b6478. */
  background: rgba(20, 12, 40, 0.68);
  color: #fff;
}

/* The centrepiece: one large faded disc carrying the 18+ mark, replacing the old
   stack of a small badge, a heading and a chrome button. A circle reads as
   "blocked" from across the page in a way three lines of small text never did.

   Sized from a variable so one component serves a 620px feed card and a 200px
   grid tile without a second set of rules. */
.nsfw-veil-ring {
  --veil-ring: 118px;
  /* flex: none matters. The parent is a column flex container, and without this
     it shrinks the height and turns the circle into an oval -- the same way an
     avatar got squashed here once before. */
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Explicit height rather than aspect-ratio, for that same reason. */
  width: var(--veil-ring);
  height: var(--veil-ring);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  border: 2px solid rgba(255, 255, 255, 0.4);
  box-shadow: 0 2px 14px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.22);
}

/* Scoped to the ring deliberately: the row thumbnails in postRow.ejs still use a
   bare .nsfw-veil-badge and must keep the original chrome pill. */
.nsfw-veil-ring .nsfw-veil-badge {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  box-shadow: none;
  font-size: calc(var(--veil-ring) * 0.3);
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.01em;
  color: rgba(255, 255, 255, 0.94);
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.6);
}

/* Per-context sizes. The grid tile is the tightest box on the site, so it is the
   one whose circle has to be held back. */
.post-detail-media .nsfw-veil-ring {
  --veil-ring: 148px;
}

.fb-post-media .nsfw-veil-ring {
  --veil-ring: 104px;
}

.post-card-media .nsfw-veil-ring {
  --veil-ring: 76px;
}

/* The prompt sits on the fade rather than inside a chrome button. The button
   looked like it would reveal something, and there is nothing here to reveal --
   the censored derivative is all that was ever sent. */
.nsfw-veil-hint {
  font-size: var(--text-sm);
  font-weight: bold;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
}

/* On the cards the whole tile is the link, so the text just follows the tile's
   hover. On the post page the hint IS the link and needs its own affordance. */
.post-card:hover .nsfw-veil-hint,
.feed-card-media:hover .nsfw-veil-hint,
.fb-post-media:hover .nsfw-veil-hint {
  text-decoration: underline;
}

a.nsfw-veil-hint {
  cursor: pointer;
  text-decoration: none;
}

a.nsfw-veil-hint:hover {
  text-decoration: underline;
}

.post-card:hover .nsfw-veil-ring,
.feed-card-media:hover .nsfw-veil-ring,
.fb-post-media:hover .nsfw-veil-ring,
.post-detail-media:hover .nsfw-veil-ring {
  background: rgba(255, 255, 255, 0.18);
  border-color: rgba(255, 255, 255, 0.55);
}

.badge-nsfw {
  display: inline-block;
  /* Red through to deeper red, not brand-blue through to red: pairing the chrome
     colour with a warning colour made the badge read as a gradient accident. Both
     ends clear 4.8:1 against the white text. */
  background: linear-gradient(to bottom, #d0345e 0%, var(--badge-nsfw-bg) 100%);
  color: #fff;
  font-size: 0.6rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  padding: 0.22em 0.6em;
  border-radius: var(--r-full);
  vertical-align: middle;
}

.nsfw-gate {
  text-align: center;
}

.nsfw-gate-badge {
  display: inline-block;
  font-size: 1.5rem;
  font-weight: 800;
  letter-spacing: 0.01em;
  background: var(--gradient-brand);
  color: #fff;
  width: 4rem;
  height: 4rem;
  line-height: 4rem;
  border-radius: 50%;
  margin-bottom: 0.9em;
  box-shadow: var(--sh-brand-lg);
}

.nsfw-consent {
  display: flex;
  align-items: flex-start;
  gap: 0.7em;
  text-align: left;
  font-size: var(--text-sm);
  margin-bottom: 1.3em;
  cursor: pointer;
}

.nsfw-consent input {
  width: auto;
  margin-top: 0.28em;
  flex-shrink: 0;
}

/* Yes/No on the age re-confirmation step. Stacked on narrow screens so neither
   answer is easier to hit by accident than the other. */
.nsfw-confirm-actions {
  display: flex;
  flex-direction: column;
  gap: 0.7em;
  margin-top: 1.4em;
}

.nsfw-confirm-actions form {
  margin: 0;
}

.nsfw-confirm-actions button,
.nsfw-confirm-actions .button-secondary {
  width: 100%;
}

.nsfw-explore-search {
  flex-basis: 100%;
  max-width: 440px;
}

/* ===================== Report ===================== */

.report-box {
  margin-top: 1.75em;
  padding-top: 1.4em;
  border-top: 1px solid var(--line);
}

.report-box summary:hover {
  color: var(--danger);
}

.report-box form {
  margin-top: 1em;
  display: flex;
  flex-direction: column;
  gap: 0.75em;
}

/* ===================== Follow ===================== */

.follow-button.following {
  background: var(--gradient-brand);
  color: #fff;
  border-color: transparent;
  box-shadow: var(--sh-brand);
}

.follow-button.following:hover {
  color: #fff;
  background: var(--gradient-brand);
}

/* Status line on the author's own unpublished posts. Uses text plus colour, never
   colour alone, so the state is legible without relying on hue. */
.submission-status {
  margin: 0.5em 0 0.9em;
  padding: 0.6em 0.9em;
  border-radius: var(--r-sm);
  font-size: var(--text-sm);
  font-weight: 600;
  border: 1px solid var(--line);
}

.submission-status.is-pending {
  background: rgba(250, 204, 21, 0.1);
  border-color: rgba(250, 204, 21, 0.32);
  color: #facc15;
}

.submission-status.is-rejected {
  background: rgba(248, 113, 113, 0.1);
  border-color: rgba(248, 113, 113, 0.32);
  color: #f87171;
}

/* Approval warning inside the composer, before someone spends time on a post. */
.composer-approval-note {
  margin: 0 0 1em;
  padding: 0.7em 0.95em;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--line);
}

/* ===================== Creator toolbox (profile sidebar) ===================== */

/* Sticks to the side as the feed scrolls, so a creator's links stay reachable
   instead of scrolling away at the top. Only on wide screens: on a phone the
   sidebar stacks above the feed and sticking it would eat the screen. */
.creator-toolbox {
  margin-top: 1.4em;
  padding-top: 1.3em;
  border-top: 1px solid var(--line);
}

@media (min-width: 901px) {
  .creator-toolbox {
    position: sticky;
    top: 5.5rem;
  }
}

.creator-toolbox-title {
  font-size: var(--text-sm);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--ink-muted);
  margin-bottom: 0.9em;
}

/* ===================== Creator catalogue (foot of the front page) ============ */

/* Its own banded background so it reads as a distinct section rather than more
   feed. The first version sat on the page background with 4%-white cards, which
   was very nearly invisible against near-black. */

/* Faint aurora drifting behind the cards. Purely decorative, so it is removed
   entirely for anyone who has asked for reduced motion (see the media query at
   the end of this block). */

/* Flex, not grid. A grid with auto-fill leaves empty column slots when there are
   only one or two creators, so a new site looks broken rather than small. Flex
   with a fixed basis lets a lone card sit at its natural size, centred. */
.creator-grid {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: stretch;
  gap: 1.15em;
}

.creator-card {
  position: relative;
  flex: 0 1 250px;
  display: flex;
  flex-direction: column;
  padding: 1.75em 1.3em 1.3em;
  border-radius: var(--r-xl);
  /* Solid surface with a real border: the glass treatment used on post cards
     disappears here, because this section already sits on a lighter band. */
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: var(--sh-2);
  transition: transform 0.35s var(--ease-spring), border-color 0.35s var(--ease-out),
    box-shadow 0.35s var(--ease-out);
}

.creator-card:hover {
  transform: translateY(-6px);
  border-color: var(--brand);
  box-shadow: var(--sh-3), 0 0 0 1px var(--brand-ring);
}

/* --- Podium treatment for the top three ------------------------------------ */
/* Rank is meaningless without a visual hierarchy: a plain numbered list reads as
   an arbitrary order. Gold/silver/bronze is instantly understood, and the medal
   colour is carried by the badge, the ring and the top edge together. */
.creator-card:nth-child(1) { --medal: #fbbf24; --medal-soft: rgba(251, 191, 36, 0.16); }
.creator-card:nth-child(2) { --medal: #cbd5e1; --medal-soft: rgba(203, 213, 225, 0.14); }
.creator-card:nth-child(3) { --medal: #d97757; --medal-soft: rgba(217, 119, 87, 0.14); }

.creator-card:nth-child(-n + 3) {
  border-color: var(--medal);
  background: linear-gradient(180deg, var(--medal-soft) 0%, transparent 38%), var(--surface);
}

.creator-card:nth-child(-n + 3) .creator-rank {
  background: var(--medal);
  color: #18181b;
  box-shadow: 0 4px 14px -2px var(--medal);
}

.creator-card:nth-child(-n + 3) .avatar {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--medal);
}

/* Rank sits on the card edge as a badge rather than as faint corner text. */
.creator-rank {
  position: absolute;
  top: -0.75em;
  left: 50%;
  transform: translateX(-50%);
  min-width: 2.3em;
  padding: 0.3em 0.7em;
  text-align: center;
  font-size: var(--text-2xs);
  font-weight: 800;
  letter-spacing: 0.02em;
  color: #fff;
  background: var(--gradient-brand);
  border-radius: var(--r-full);
  box-shadow: var(--sh-brand-lg);
}

.creator-card-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.65em;
  margin-bottom: 1.1em;
  text-align: center;
}

.creator-card-head .avatar {
  width: 68px;
  height: 68px;
  font-size: 1.5rem;
  transition: transform 0.35s var(--ease-spring);
}

.creator-card:hover .creator-card-head .avatar {
  transform: scale(1.06);
}

.creator-card-name {
  font-weight: 700;
  font-size: var(--text-base);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.creator-card-head:hover .creator-card-name {
  color: var(--brand-text);
}

/* Three even columns so the numbers line up across cards instead of wrapping
   raggedly at different points. */
.creator-card-stats {
  list-style: none;
  padding: 0.95em 0;
  margin: 0 0 1.05em;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.3em;
  text-align: center;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  font-size: var(--text-2xs);
  color: var(--ink-muted);
}

.creator-card-stats strong {
  display: block;
  font-size: var(--text-lg);
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--ink);
  line-height: 1.15;
}

/* Pushed to the bottom so cards of different link counts still line up. */
.creator-card-links {
  margin-top: auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4em;
}

.creator-chip {
  font-size: var(--text-2xs);
  font-weight: 600;
  padding: 0.4em 0.85em;
  border-radius: var(--r-full);
  border: 1px solid var(--line-strong);
  background: var(--bg-subtle);
  transition: border-color var(--dur) var(--ease-out), color var(--dur) var(--ease-out),
    background var(--dur) var(--ease-out), transform var(--dur) var(--ease-spring);
}

.creator-chip:hover {
  color: #fff;
  border-color: transparent;
  background: var(--gradient-brand);
  transform: translateY(-2px);
}

@media (max-width: 560px) {
  .creator-card {
    flex: 1 1 100%;
  }
}

/* The drifting aurora is decoration, not information -- it goes entirely when
   reduced motion is requested, rather than merely slowing down. */
@media (prefers-reduced-motion: reduce) {
}

/* ===================== Tag cloud & sort bar ===================== */

.tag-cloud {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6em;
}

.tag-cloud-item {
  display: inline-flex;
  align-items: baseline;
  gap: 0.35em;
  padding: 0.45em 1em;
  border-radius: var(--r-full);
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  font-weight: 600;
  color: var(--ink-muted);
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
    background var(--dur) var(--ease-out), transform var(--dur) var(--ease-spring);
}

.tag-cloud-item:hover {
  color: var(--ink);
  border-color: var(--brand);
  background: var(--brand-soft);
  transform: translateY(-2px);
}

.tag-cloud-item.is-following {
  border-color: var(--brand);
  color: var(--ink);
}

.tag-cloud-hash {
  color: var(--brand-text);
  font-weight: 800;
}

.tag-cloud-count {
  font-size: 0.72em;
  opacity: 0.62;
}

/* Size carries the post count. Set as classes rather than inline styles because
   the CSP has no 'unsafe-inline' for style. */
.tag-size-1 { font-size: var(--text-xs); }
.tag-size-2 { font-size: var(--text-sm); }
.tag-size-3 { font-size: var(--text-base); }
.tag-size-4 { font-size: var(--text-lg); }
.tag-size-5 { font-size: var(--text-xl); }

.sort-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
  margin-bottom: 2em;
}

.sort-chip {
  padding: 0.5em 1.1em;
  border-radius: var(--r-full);
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--ink-muted);
  transition: color var(--dur) var(--ease-out), border-color var(--dur) var(--ease-out),
    background var(--dur) var(--ease-out);
}

.sort-chip:hover {
  color: var(--ink);
  border-color: var(--line-strong);
}

.sort-chip.active {
  color: #fff;
  border-color: transparent;
  background: var(--gradient-brand);
}

/* The directory reuses the catalogue card but not its podium colouring: on page
   three, a gold border would mean "third from the top of this page". */
.creator-grid.is-directory {
  justify-content: flex-start;
}

.creator-grid.is-directory .creator-card:nth-child(-n + 3) {
  border-color: var(--line-strong);
  background: var(--surface);
}

.creator-grid.is-directory .creator-card:nth-child(-n + 3) .creator-rank {
  background: var(--gradient-brand);
  color: #fff;
  box-shadow: var(--sh-brand-lg);
}

.creator-grid.is-directory .creator-card:nth-child(-n + 3) .avatar {
  box-shadow: none;
}

/* Compact like button for the grid cards. The full-size one on the post page is
   a primary action; here it sits in a metadata row and must not dominate it. */
.like-button-sm {
  padding: 0.3em 0.7em;
  font-size: var(--text-2xs);
  gap: 0.35em;
  box-shadow: none;
}

.like-button-sm:hover {
  transform: none;
}

.like-button-sm .like-icon {
  /* Doubled, to match the feed card's heart. */
  font-size: 2em;
  line-height: 1;
}

/* ===================== Post gallery (extra media) ===================== */

.post-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0.85em;
  margin-top: 0.85em;
}

.post-gallery-item {
  margin: 0;
  overflow: hidden;
  border-radius: var(--r-lg);
  border: 1px solid var(--glass-border);
  background: var(--bg-subtle);
  box-shadow: var(--sh-2);
}

.post-gallery-item img,
.post-gallery-item video {
  display: block;
  width: 100%;
  max-height: 42vh;
  object-fit: cover;
  background: #09090b;
}

/* No CSS blur: like the cover, a blurred item is already the server-side
   censored file, so filtering it again would only smear it further. */
.post-gallery-item.is-nsfw img {
  transform: scale(1.04);
}

/* Author's own controls on the post page. Set apart from the report box so a
   destructive action is not mistaken for one of the ordinary ones. */
.owner-actions {
  margin-top: 1.75em;
  padding-top: 1.4em;
  border-top: 1px solid var(--line);
}

/* Delete sits at the end of the stats row rather than beside the counts. */
.fb-post-delete {
  margin-left: auto;
}

/* ===================== Horizontal post row ===================== */

.post-row {
  margin-top: 3.5em;
}

.post-row-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1em;
  margin-bottom: 1.1em;
}

.post-row-head h2 {
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.post-row-controls {
  display: flex;
  gap: 0.4em;
  flex-shrink: 0;
}

.post-row-arrow {
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  color: var(--ink);
  border-radius: var(--r-full);
  border: 1px solid var(--glass-border);
  background: var(--glass-bg);
  transition: border-color var(--dur) var(--ease-out), background var(--dur) var(--ease-out),
    opacity var(--dur) var(--ease-out);
}

.post-row-arrow:hover {
  border-color: var(--brand);
  background: var(--brand-soft);
}

/* Dimmed rather than removed: a control that disappears shifts the ones beside it. */
.post-row-arrow.is-disabled {
  opacity: 0.3;
  pointer-events: none;
}

.post-row-track {
  display: flex;
  gap: 0.9em;
  overflow-x: auto;
  /* Snap so the strip always comes to rest on a card edge rather than mid-image. */
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* Room for the cards' hover lift, which would otherwise be clipped by the
     scroll container. */
  padding: 0.4em 0.2em 1em;
  margin: -0.4em -0.2em 0;
}

.post-row-track::-webkit-scrollbar {
  display: none;
}

/* Visible focus ring: the strip is keyboard-scrollable, so it must show when it
   holds focus. */
.post-row-track:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 4px;
  border-radius: var(--r-lg);
}

.row-card {
  flex: 0 0 auto;
  width: 210px;
  scroll-snap-align: start;
}

.row-card-media {
  position: relative;
  display: block;
  aspect-ratio: 3 / 4;
  overflow: hidden;
  border-radius: var(--r-lg);
  border: 1px solid var(--glass-border);
  background: var(--bg-subtle);
  box-shadow: var(--sh-2);
  transition: transform 0.3s var(--ease-out), border-color 0.3s var(--ease-out),
    box-shadow 0.3s var(--ease-out);
}

.row-card-media:hover {
  transform: translateY(-5px);
  border-color: var(--brand);
  box-shadow: var(--sh-3);
}

.row-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.5s var(--ease-out);
}

.row-card-media:hover img {
  transform: scale(1.06);
}

/* Scrim so the title stays readable over any image. */
.row-card-overlay {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-direction: column;
  gap: 0.2em;
  padding: 2.2em 0.85em 0.8em;
  background: linear-gradient(to top, rgba(9, 9, 11, 0.92) 25%, transparent);
  color: #fff;
}

.row-card-title {
  font-size: var(--text-sm);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.row-card-stats {
  font-size: var(--text-2xs);
  opacity: 0.8;
}

.row-card-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(9, 9, 11, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.25);
  color: #fff;
  font-size: 0.9rem;
  padding-left: 3px;
}

.row-card-veil {
  position: absolute;
  top: 0.6em;
  left: 0.6em;
}

@media (max-width: 560px) {
  .row-card {
    width: 148px;
  }
  /* Arrows are redundant where the strip is swiped directly. */
  .post-row-controls {
    display: none;
  }
}

/* ===================== Feed (one post per row) ===================== */

/* The reading column. Capped rather than fluid: a 1200px-wide photo card forces
   the eye across the whole screen for every post, which reads worse than a
   narrower column even though the screen has the room. */
.post-feed {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: none;
  margin: 0;
}

.feed-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  overflow: hidden;
}

/* ---- Head ---- */

.feed-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.5rem 0.85rem;
  /* The same title bar the rail modules wear. The feed card was the one module on
     the page without one, which made the rail look like a different system rather
     than the same one. */
  background: var(--gradient-titlebar);
  border-bottom: 1px solid var(--line);
}

.feed-author {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

.feed-author.is-gone { cursor: default; }

.feed-author-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.feed-author-name {
  font-weight: 650;
  font-size: var(--text-sm);
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.feed-author:hover .feed-author-name { color: var(--brand-text); }

.feed-author-time {
  font-size: var(--text-2xs);
  color: var(--ink-muted);
}

.feed-card-head-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}

.feed-icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--ink-muted);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

.feed-icon-button:hover {
  color: var(--ink);
  background: var(--bg-subtle);
  border-color: var(--line);
}

.feed-icon-button.is-copied {
  color: var(--success);
  border-color: var(--success);
}

/* ---- Media ---- */

.feed-card-media {
  position: relative;
  display: block;
  /* Explicit, not left to `auto`. With an aspect-ratio set and the height capped
     below what that ratio wants, an auto width shrinks to preserve the ratio --
     a 9:16 phone video ended up 395px wide inside a 618px card, adrift against the
     left edge. Pinning the width keeps the frame full-bleed and moves the
     letterboxing inside the image, where object-fit centres it. */
  width: 100%;
  background: #000;
  /* Tall portrait photos would otherwise push the next post a full screen away.
     Capped by viewport height so the cap scales with the window instead of being
     a fixed pixel guess. */
  max-height: 78vh;
  overflow: hidden;
}

.feed-media-link {
  display: block;
  position: relative;
  line-height: 0;
  /* Fills the ratio box the script sets on the parent, so the image occupies the
     reserved space instead of sitting at natural height inside a taller box. */
  height: 100%;
}

.feed-card-media img {
  display: block;
  width: 100%;
  height: 100%;
  max-height: 78vh;
  /* `contain`, not `cover`: this is the post's actual photo at its real shape, not
     a thumbnail cropped to a grid cell. Letterboxing against black is the honest
     result for an image whose aspect does not match the column. */
  object-fit: contain;
  object-position: center;
}

/* Only the active slide is laid out; the rest are removed from flow so the card
   is the height of one photo, not the sum of three. */
.feed-card-media.has-slides .feed-slide { display: none; }
.feed-card-media.has-slides .feed-slide.is-active { display: block; }

.feed-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 62px;
  height: 62px;
  border-radius: var(--r-full);
  background: rgba(9, 9, 11, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff;
  pointer-events: none;
}

.feed-duration,
.feed-slide-count {
  position: absolute;
  bottom: 0.6rem;
  right: 0.6rem;
  padding: 0.16rem 0.5rem;
  border-radius: var(--r-full);
  background: rgba(9, 9, 11, 0.72);
  color: #fff;
  font-size: var(--text-2xs);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}

.feed-slide-count {
  top: 0.6rem;
  bottom: auto;
}

.feed-slide-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-radius: var(--r-full);
  background: rgba(9, 9, 11, 0.62);
  color: #fff;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

.feed-slide-prev { left: 0.55rem; }
.feed-slide-next { right: 0.55rem; }

.feed-card-media:hover .feed-slide-nav,
.feed-slide-nav:focus-visible { opacity: 1; }

/* Hover does not exist on a touchscreen, so there the arrows are always visible --
   otherwise a phone user has no way to reach photos 2 and 3. */
@media (hover: none) {
  .feed-slide-nav { opacity: 1; }
}

.feed-slide-nav:hover { background: rgba(9, 9, 11, 0.85); }

.feed-slide-dots {
  position: absolute;
  bottom: 0.6rem;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 0.3rem;
  pointer-events: none;
}

.feed-dot {
  width: 6px;
  height: 6px;
  border-radius: var(--r-full);
  background: rgba(255, 255, 255, 0.38);
  transition: background var(--dur-fast) var(--ease-out);
}

.feed-dot.is-active { background: #fff; }

/* ---- Actions ---- */

.feed-card-actions {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  /* Even top and bottom. It was 0.55rem against 0.2rem, which pushed every control
     in the row 3px above the row's optical centre. */
  padding: 0.4rem 0.6rem;
  /* Wraps because the platform marks share this row. A creator with all eight
     linked adds ~264px of icons to a row that is already near full on a phone;
     without this the row would push the card sideways instead of using a second
     line. With one or two platforms nothing moves. */
  flex-wrap: wrap;
}

.feed-action {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.55rem;
  border: 1px solid transparent;
  border-radius: var(--r-full);
  background: transparent;
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

.feed-action:hover { color: var(--ink); background: var(--bg-subtle); }
.feed-action.is-static { cursor: default; }
.feed-action.is-static:hover { color: var(--ink-muted); background: transparent; }

/* The heart is deliberately the largest thing in the row, but at 2.1em against
   the others' 1em it had no relationship to them at all -- it read as a mistake
   rather than emphasis. Lifting the rest to 1.35em keeps the heart clearly
   dominant while putting them on the same scale. */
.feed-action span[aria-hidden],
.feed-action .save-icon {
  font-size: 1.35em;
  line-height: 1;
}

.feed-action svg { width: 19px; height: 19px; }

.feed-action .like-icon {
  font-size: 2.1em;
  line-height: 1;
  transition: transform var(--dur-fast) var(--ease-spring);
}

/* The row is sized by its tallest item, so the enlarged heart would otherwise
   push the whole action bar down. Pulling the line box back keeps the bar the
   height it was while the glyph itself grows. */
.feed-action.like-button {
  padding-top: 0;
  padding-bottom: 0;
}

.feed-action.liked { color: var(--pink); }
.feed-action.liked .like-icon { transform: scale(1.15); }

/* ---- Body ---- */

.feed-card-body {
  /* 0.15rem left the title crammed against the action row; the caption block needs
     the same breathing room above it that it has below. */
  padding: 0.5rem 0.85rem 0.9rem;
}

.feed-card-title {
  display: block;
  font-weight: 650;
  font-size: var(--text-base);
  color: var(--ink);
  text-decoration: none;
}

.feed-card-title:hover { color: var(--brand-text); }

.feed-card-text {
  margin: 0.3rem 0 0;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  /* Long descriptions are clamped: the feed is a list, and the post page is where
     the full text belongs. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.feed-card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.55rem;
}

.feed-tag {
  font-size: var(--text-2xs);
  color: var(--brand-text);
  text-decoration: none;
}

.feed-tag:hover { text-decoration: underline; }

/* On a phone the card runs edge to edge, the way a native feed does. The negative
   margin cancels .page-container's horizontal padding, which is 1em below 860px --
   both elements inherit the body font size, so the two ems are the same length. */
@media (max-width: 620px) {
  .post-feed { gap: 1rem; }

  .feed-card {
    border-radius: 0;
    border-left: none;
    border-right: none;
    margin-inline: -1em;
  }
}

/* ===================== Stories ===================== */

.story-strip {
  max-width: none;
  margin: 0 0 10px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  padding: 8px 10px;
}

/* Scrolls sideways once there are more authors than fit; the scrollbar is hidden
   because the rings themselves are the affordance. */
.story-rail {
  display: flex;
  gap: 0.9rem;
  overflow-x: auto;
  padding: 0.2rem 0.1rem 0.5rem;
  scrollbar-width: none;
}

.story-rail::-webkit-scrollbar { display: none; }

.story-ring {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  flex: 0 0 auto;
  width: 72px;
  padding: 0;
  border: none;
  background: none;
  color: var(--ink-muted);
  cursor: pointer;
}

/* The gradient ring is a padded background behind the avatar, so it reads as a
   border without a border property fighting the avatar's own radius. */
.story-ring-frame {
  display: block;
  width: 68px;
  height: 68px;
  padding: 3px;
  border-radius: 50%;
  background: var(--gradient-brand);
  line-height: 0;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 1px 2px rgba(0, 0, 0, 0.25);
}

.story-ring:hover .story-ring-frame,
.story-ring:focus-visible .story-ring-frame {
  background: linear-gradient(to bottom, #3f9aa2 0%, #2b7880 100%);
}

.story-ring-frame .avatar {
  display: block;
  /* Sized here rather than inheriting avatar-lg's 96px, which is wider than the
     ring's own column. */
  width: 60px;
  height: 60px;
  font-size: 24px;
  border: 2px solid #fff;
}

.story-ring-name {
  font-size: var(--text-2xs);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- Viewer ---- */

.story-viewer {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(4, 4, 6, 0.94);
}

.story-viewer[hidden] { display: none; }

/* Stops the page behind from scrolling under the viewer on a phone. */
body.story-open { overflow: hidden; }

.story-viewer-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(430px, 100vw);
  height: min(92vh, 100dvh);
  background: #000;
  border-radius: var(--r-lg);
  overflow: hidden;
}

.story-progress {
  display: flex;
  gap: 3px;
  padding: 0.55rem 0.6rem 0;
  /* Above the tap targets, or the bar would be unclickable and, more importantly,
     invisible behind them. */
  position: relative;
  z-index: 3;
}

.story-progress-track {
  flex: 1;
  height: 2.5px;
  border-radius: var(--r-full);
  background: rgba(255, 255, 255, 0.28);
  overflow: hidden;
}

.story-progress-fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: var(--r-full);
  background: #fff;
}

.story-progress-fill.is-done { width: 100%; }

/* 5s matches the image dwell time in stories.js. A video's bar runs the same
   animation; it is a progress hint, not a scrubber. */
.story-progress-fill.is-running {
  animation: story-fill 5s linear forwards;
}

@keyframes story-fill {
  from { width: 0; }
  to   { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .story-progress-fill.is-running { animation: none; width: 100%; }
}

.story-viewer-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.6rem 0.7rem;
  position: relative;
  z-index: 3;
  color: #fff;
}

.story-viewer-author {
  font-weight: 650;
  font-size: var(--text-sm);
}

.story-viewer-time {
  font-size: var(--text-2xs);
  color: rgba(255, 255, 255, 0.7);
}

.story-close {
  margin-left: auto;
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  border-radius: var(--r-full);
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
}

.story-close:hover { background: rgba(255, 255, 255, 0.2); }

.story-stage {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  /* min-height: 0 lets the flex child shrink; without it a tall image pushes the
     caption out of the viewer entirely. */
  min-height: 0;
  margin-top: -3.2rem;
}

.story-media {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.story-caption {
  position: relative;
  z-index: 3;
  margin: 0;
  padding: 0.8rem 0.9rem 1.1rem;
  color: #fff;
  font-size: var(--text-sm);
  text-align: center;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75), transparent);
}

.story-caption[hidden] { display: none; }

/* Half the viewer each, sitting under the header and caption so those stay
   clickable. */
.story-tap {
  position: absolute;
  top: 3.2rem;
  bottom: 3.5rem;
  width: 50%;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  z-index: 2;
}

.story-tap-prev { left: 0; }
.story-tap-next { right: 0; }

@media (max-width: 620px) {
  .story-strip { padding-inline: 0.15rem; }

  .story-viewer-inner {
    width: 100vw;
    height: 100dvh;
    border-radius: 0;
  }
}

/* ===================== Notifications page ===================== */

.notif-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.notif {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 6px;
  border-bottom: 1px solid #eef0f3;
}

.notif:last-child { border-bottom: none; }

/* Unread rows are tinted and flagged with a left bar, so the distinction survives
   for a reader who cannot separate the two background tints. */
.notif.is-unread {
  background: #f3f0fb;
  border-left: 3px solid var(--brand);
  padding-left: 5px;
}

.notif-avatar {
  flex: 0 0 auto;
  line-height: 0;
}

.notif-avatar .avatar {
  width: 30px;
  height: 30px;
  font-size: 14px;
  border: 1px solid var(--line);
}

.notif-text {
  flex: 1;
  min-width: 0;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  line-height: 1.45;
}

.notif-actor,
.notif-post {
  font-weight: bold;
  color: var(--brand-text);
}

.notif-actor:hover,
.notif-post:hover { text-decoration: underline; }

.notif-time {
  color: var(--ink-muted);
  font-size: var(--text-2xs);
  white-space: nowrap;
}

.notif-thumb {
  flex: 0 0 auto;
  line-height: 0;
}

.notif-thumb img {
  width: 40px;
  height: 40px;
  object-fit: cover;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}

.notif-footer {
  margin-top: 8px;
  text-align: center;
}

/* ===================== Models ===================== */

.model-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.model-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
}

/* The number leads, so it gets the width of two digits reserved -- otherwise the
   avatars step sideways when the list crosses #9. */
.model-rank {
  flex: 0 0 auto;
  min-width: 26px;
  text-align: center;
  font-size: var(--text-lg);
  font-weight: bold;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

.model-rank-1 { color: #9a6b00; }
.model-rank-2 { color: #5a6472; }
.model-rank-3 { color: #8a4b21; }

.model-avatar { flex: 0 0 auto; line-height: 0; }

.model-avatar .avatar {
  width: 46px;
  height: 46px;
  font-size: 20px;
  border: 1px solid var(--line);
}

.model-body {
  flex: 1;
  min-width: 0;
}

.model-name {
  font-weight: bold;
  font-size: var(--text-base);
  color: var(--brand-text);
}

.model-name:hover { text-decoration: underline; }

.model-bio {
  margin: 1px 0 0;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.model-stats {
  margin: 2px 0 0;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.model-visit { flex: 0 0 auto; }

/* ---- Admin ---- */

.model-admin-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
}

.model-admin-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 0;
  border-bottom: 1px solid #eef0f3;
}

.model-admin-row:last-child { border-bottom: none; }

.model-admin-row .avatar {
  width: 30px;
  height: 30px;
  font-size: 14px;
  border: 1px solid var(--line);
}

.model-admin-name {
  font-weight: bold;
  font-size: var(--text-sm);
}

.model-admin-name a { color: var(--brand-text); }
.model-admin-name a:hover { text-decoration: underline; }

/* Pushes the controls to the right and lets the name column absorb the slack. */
.model-admin-stats { margin-left: auto; white-space: nowrap; }

.model-rank-form {
  display: flex;
  align-items: center;
  gap: 4px;
}

.model-rank-input {
  width: 56px;
  padding: 3px 5px;
  border: 1px solid #a8b0bd;
  border-radius: var(--r-sm);
  font-family: inherit;
  font-size: var(--text-sm);
  text-align: center;
}

.model-admin-pool { margin-top: 10px; }

@media (max-width: 620px) {
  /* The controls wrap under the name rather than squeezing it to nothing. */
  .model-admin-row { flex-wrap: wrap; }
  .model-admin-stats { margin-left: 0; flex-basis: 100%; }
  .model-visit { display: none; }
}

/* ===================== Profile photo settings ===================== */

.photo-settings h2 {
  margin: 0 0 8px;
  font-size: var(--text-base);
}

.photo-setting {
  display: flex;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid #eef0f3;
}

.photo-setting:first-of-type { border-top: none; }

.photo-setting-preview {
  flex: 0 0 auto;
  line-height: 0;
}

.photo-setting-preview .avatar {
  width: 64px;
  height: 64px;
  font-size: 28px;
  border: 1px solid var(--line);
}

/* The cover preview keeps the 4:1 shape it will be cropped to, so what is shown
   here is what the profile will use. */
.photo-setting-cover {
  display: block;
  width: 128px;
  height: 32px;
  object-fit: cover;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
}

.photo-setting-cover.is-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-subtle);
  color: var(--ink-muted);
  font-size: var(--text-2xs);
  line-height: 1;
}

.photo-setting-body {
  flex: 1;
  min-width: 0;
}

.photo-setting-body strong { font-size: var(--text-sm); }

.photo-setting-body .field-hint { margin: 1px 0 6px; }

.photo-setting-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 4px;
}

.photo-setting-form input[type='file'] {
  flex: 1;
  min-width: 0;
  font-size: var(--text-xs);
}

/* Save beside Cancel on the author's edit form. Cancel is a link, not a button,
   so the two need aligning against each other rather than sitting on the baseline
   an inline-flex button and an inline anchor would otherwise pick separately. */
.form-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 10px;
}

/* ===================== Save button ===================== */

/* Pushes save and share to the right-hand end of the action row, away from the
   counts they are not part of. */
.feed-action-spacer { flex: 1; }

.save-icon {
  font-size: 1.05em;
  line-height: 1;
  filter: grayscale(1) opacity(0.65);
  transition: filter var(--dur-fast) var(--ease-out);
}

.feed-action:hover .save-icon { filter: grayscale(0.3) opacity(1); }

/* Saved state drops the greyscale entirely, so the icon reads as "on" without
   relying on colour alone -- the label and title change too. */
.save-button.saved .save-icon { filter: none; }

/* ===================== Lightbox ===================== */

.is-zoomable { cursor: zoom-in; }

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 40px 12px;
  background: rgba(4, 4, 6, 0.92);
}

.lightbox[hidden] { display: none; }

/* Stops the page scrolling behind the viewer. */
body.lightbox-open { overflow: hidden; }

.lightbox-stage {
  margin: 0;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* min-width lets the flex child shrink instead of forcing the arrows off screen
     on a narrow window. */
  min-width: 0;
}

.lightbox-image {
  max-width: 100%;
  max-height: calc(100vh - 80px);
  object-fit: contain;
  border-radius: var(--r-md);
}

.lightbox-nav,
.lightbox-close {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: var(--r-full);
  background: rgba(9, 9, 11, 0.62);
  color: #fff;
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}

.lightbox-nav:hover,
.lightbox-close:hover { background: rgba(9, 9, 11, 0.88); }

.lightbox-nav[hidden] { display: none; }

.lightbox-close {
  position: absolute;
  top: 12px;
  right: 12px;
  font-size: 1.7rem;
}

.lightbox-count {
  position: absolute;
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
  padding: 2px 10px;
  border-radius: var(--r-full);
  background: rgba(9, 9, 11, 0.72);
  color: #fff;
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 620px) {
  /* The arrows overlay the image on a phone rather than taking width from it. */
  .lightbox { padding: 48px 6px; }
  .lightbox-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
  }
  .lightbox-prev { left: 8px; }
  .lightbox-next { right: 8px; }
}

/* ===================== Verified tick ===================== */

/* Sized in em so it tracks whatever text it sits beside -- the same partial is
   used at 11px in the rail and at heading size on a profile. */
.verified-tick {
  display: inline-block;
  margin-left: 0.25em;
  color: var(--brand);
  font-size: 0.85em;
  line-height: 1;
  vertical-align: baseline;
}

/* ===================== Creator search ===================== */

.creator-search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 10px;
}

.creator-search input[type='search'] {
  flex: 1;
  min-width: 0;
  padding: 4px 8px;
  border: 1px solid #a8b0bd;
  border-radius: var(--r-sm);
  font-family: inherit;
  font-size: var(--text-sm);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12);
}

/* ===================== Tag results in search ===================== */

.tag-results {
  margin-bottom: 14px;
  padding: 8px 10px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
}

.tag-results h2 {
  margin: 0 0 6px;
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: #464d5a;
}

/* ===================== Chat ===================== */

.chat-list { list-style: none; margin: 0; padding: 0; }

.chat-list-item { border-bottom: 1px solid #eef0f3; }
.chat-list-item:last-child { border-bottom: none; }

.chat-list-link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 4px;
  color: inherit;
}

.chat-list-item.is-unread .chat-list-link { background: #eef4f3; }
a.chat-list-link:hover { background: var(--bg-subtle); }

/* The presence dot sits over the avatar, so status reads at a glance without
   adding a line of text to every row. */
.chat-avatar { position: relative; flex: 0 0 auto; line-height: 0; }

.presence-dot {
  position: absolute;
  right: -1px;
  bottom: -1px;
  width: 11px;
  height: 11px;
  border-radius: var(--r-full);
  background: #9aa3b2;
  border: 2px solid #fff;
}

.presence-dot.is-online { background: var(--success); }

.chat-list-body { flex: 1; min-width: 0; }

.chat-list-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

.chat-list-name { font-weight: bold; font-size: var(--text-sm); }
.chat-list-time { font-size: var(--text-2xs); color: var(--ink-muted); white-space: nowrap; }

.chat-list-preview {
  display: block;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chat-you { font-weight: bold; }

.chat-unread-pill {
  flex: 0 0 auto;
  min-width: 18px;
  padding: 0 5px;
  border-radius: var(--r-full);
  background: linear-gradient(to bottom, #d94a5c 0%, #b0173f 100%);
  border: 1px solid #8d1233;
  color: #fff;
  font-size: 10px;
  font-weight: bold;
  line-height: 16px;
  text-align: center;
}

.sidebar-badge.is-chat {
  background: linear-gradient(to bottom, #d94a5c 0%, #b0173f 100%);
  border: 1px solid #8d1233;
  color: #fff;
}

/* ---- Thread ---- */

.chat-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  margin-bottom: 8px;
}

.chat-head-back {
  font-size: 1.5rem;
  line-height: 1;
  color: var(--brand-text);
  /* Only useful on a phone, where the list is a separate screen. */
  display: none;
}

.chat-head-user { display: flex; align-items: center; gap: 8px; color: inherit; flex: 1; min-width: 0; }
.chat-head-text { display: flex; flex-direction: column; min-width: 0; }
.chat-head-name { font-weight: bold; font-size: var(--text-sm); }
.chat-head-status { font-size: var(--text-2xs); color: var(--ink-muted); }

.chat-menu { position: relative; flex: 0 0 auto; }
.chat-menu > summary { cursor: pointer; padding: 2px 8px; font-size: 1.2rem; list-style: none; }
.chat-menu > summary::-webkit-details-marker { display: none; }

.chat-menu-panel {
  position: absolute;
  right: 0;
  top: 100%;
  z-index: 20;
  width: 260px;
  padding: 8px 10px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-2);
}

.chat-messages {
  /* Its own scroll region so the composer stays put while the transcript moves. */
  height: 52vh;
  overflow-y: auto;
  padding: 8px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
}

.chat-msg { display: flex; margin-bottom: 6px; }
.chat-msg.is-mine { justify-content: flex-end; }

.chat-bubble {
  max-width: 78%;
  padding: 6px 9px;
  border-radius: var(--r-lg);
  background: #eef0f3;
  border: 1px solid var(--line);
  font-size: var(--text-sm);
  /* Long unbroken strings (a pasted URL) must wrap rather than widen the bubble
     past the thread. */
  overflow-wrap: anywhere;
}

.chat-msg.is-mine .chat-bubble {
  background: #e2ecec;
  border-color: #b6cfd1;
}

.chat-text { display: block; }
.chat-deleted { color: var(--ink-muted); }

.chat-media {
  display: block;
  max-width: 100%;
  max-height: 260px;
  border-radius: var(--r-md);
  margin-bottom: 4px;
}

.chat-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
  font-size: var(--text-2xs);
  color: var(--ink-muted);
}

.chat-delete {
  padding: 0 3px;
  border: none;
  background: none;
  color: var(--ink-muted);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
}

.chat-delete:hover { color: var(--danger); }

.chat-typing,
.chat-seen {
  margin: 4px 2px 0;
  font-size: var(--text-2xs);
  color: var(--ink-muted);
}

.chat-seen { text-align: right; }
.chat-typing[hidden], .chat-seen[hidden] { display: none; }

/* ---- Composer ---- */

.chat-composer {
  display: flex;
  align-items: flex-end;
  gap: 6px;
  padding: 8px;
  margin-top: 8px;
}

.chat-composer textarea {
  flex: 1;
  min-width: 0;
  resize: none;
  padding: 5px 8px;
  border: 1px solid #a8b0bd;
  border-radius: var(--r-md);
  font-family: inherit;
  font-size: var(--text-sm);
  line-height: 1.4;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12);
}

.chat-attach { cursor: pointer; font-size: 1.15rem; padding: 4px; }
.chat-attach input[type='file'] { display: none; }

.chat-emoji { position: relative; }
.chat-emoji > summary { cursor: pointer; font-size: 1.15rem; padding: 4px; list-style: none; }
.chat-emoji > summary::-webkit-details-marker { display: none; }

.chat-emoji-panel {
  position: absolute;
  bottom: 100%;
  left: 0;
  z-index: 20;
  width: 232px;
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 6px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-2);
}

.chat-emoji-btn {
  width: 30px;
  height: 28px;
  padding: 0;
  border: none;
  background: none;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  border-radius: var(--r-sm);
}

.chat-emoji-btn:hover { background: var(--bg-subtle); }

.chat-blocked { margin-top: 8px; text-align: center; }
.chat-attach-name { margin: 4px 2px 0; }
.chat-attach-name[hidden] { display: none; }

@media (max-width: 620px) {
  /* On a phone the thread is the whole screen, so the back link earns its place
     and the transcript takes the height the composer does not need. */
  .chat-head-back { display: block; }
  .chat-messages { height: 60vh; }
  .chat-bubble { max-width: 86%; }
}

/* Follow and Message side by side on a profile, rather than the follow button
   sitting alone as it did when it was the only action. */
.profile-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

/* ---- Profile: photo / video folders -------------------------------------
   Tabs in the era's idiom: a chrome strip sitting on a baseline, with the
   active one raised out of it and joined to the content below. The count rides
   inside the tab so a visitor can see there are videos before clicking. */
.profile-tabs {
  display: flex;
  gap: 3px;
  align-items: flex-end;
  margin: 0 0 12px;
  padding: 0 2px;
  border-bottom: 1px solid var(--line-strong);
}

.profile-tab {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 26px;
  background: linear-gradient(to bottom, #f4f2ee 0%, #e6e2da 100%);
  border: 1px solid var(--line-strong);
  border-bottom: 0;
  border-radius: var(--r-md) var(--r-md) 0 0;
  font-size: var(--text-sm);
  font-weight: bold;
  color: var(--ink-muted);
  text-decoration: none;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
  /* Pulls the tab down onto the strip's border so the active one can cover it. */
  margin-bottom: -1px;
}

.profile-tab:hover {
  background: linear-gradient(to bottom, #ffffff 0%, #efece6 100%);
  color: var(--ink);
}

/* The active tab is white and one pixel taller, and its bottom edge is the same
   colour as the panel behind it -- that gap in the baseline is what makes it
   read as the open folder rather than just a highlighted button. */
.profile-tab.is-active {
  background: var(--surface);
  color: var(--brand-text);
  padding-bottom: 8px;
  box-shadow: inset 0 2px 0 var(--brand);
}

.profile-tab-count {
  font-size: var(--text-xs);
  font-weight: bold;
  color: #fff;
  background: var(--line-strong);
  border-radius: var(--r-full);
  padding: 1px 7px;
  text-shadow: none;
  min-width: 20px;
  text-align: center;
}

.profile-tab.is-active .profile-tab-count {
  background: var(--brand);
}

@media (max-width: 560px) {
  .profile-tabs {
    /* Three tabs plus counts do not fit a narrow phone; let them scroll rather
       than wrap into a second row that breaks the baseline. */
    overflow-x: auto;
    -ms-overflow-style: none;
    scrollbar-width: none;
  }
  .profile-tabs::-webkit-scrollbar {
    display: none;
  }
  .profile-tab {
    flex: 0 0 auto;
  }
}

/* Video marker on the profile timeline. .fb-post-media is the positioning
   context already, since the NSFW veil is absolutely placed inside it. */
.fb-post-play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: var(--r-full);
  background: rgba(0, 0, 0, 0.5);
  border: 2px solid rgba(255, 255, 255, 0.75);
  color: #fff;
  /* The image sets line-height: 0 on some of these containers; the icon is an
     SVG so it is unaffected, but the box needs its own line box regardless. */
  line-height: 0;
  pointer-events: none;
}

.fb-post-media:hover .fb-post-play {
  background: rgba(0, 0, 0, 0.66);
  border-color: #fff;
}

.fb-post-duration {
  position: absolute;
  right: 8px;
  bottom: 8px;
  background: rgba(0, 0, 0, 0.72);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: bold;
  padding: 1px 7px;
  border-radius: var(--r-md);
  pointer-events: none;
}

/* ---- Tag editor -----------------------------------------------------------
   Wraps the plain tags field in a box of chips. The original input is still
   what the form submits; this only sits in front of it. */
.tag-editor {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  min-height: 34px;
  padding: 5px 8px;
  background: #fff;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.09);
  /* The whole box behaves like one field, so the caret is the right cursor
     anywhere in it. */
  cursor: text;
}

.tag-editor:focus-within {
  border-color: var(--brand);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.09), 0 0 0 2px var(--brand-ring);
}

/* display: contents so the chips are flex children of .tag-editor itself and
   wrap alongside the text field, rather than being trapped in one inline box. */
.tag-editor-list {
  display: contents;
}

.tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 2px 3px 2px 8px;
  background: var(--gradient-brand);
  border: 1px solid var(--purple);
  border-radius: var(--r-md);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: bold;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.4);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28);
}

.tag-chip-remove {
  background: none;
  background-image: none;
  border: 0;
  border-radius: var(--r-sm);
  box-shadow: none;
  padding: 0 4px;
  color: rgba(255, 255, 255, 0.82);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  text-shadow: none;
}

.tag-chip-remove:hover {
  background: rgba(255, 255, 255, 0.24);
  color: #fff;
}

/* Beats input[type='text'] from base.css, which is one class *and* one
   attribute and would otherwise put a second border inside the box. */
.tag-editor input.tag-editor-entry {
  flex: 1 1 130px;
  min-width: 130px;
  margin: 0;
  padding: 2px 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  font: inherit;
  color: var(--ink);
}

.tag-editor input.tag-editor-entry:hover,
.tag-editor input.tag-editor-entry:focus {
  border: 0;
  box-shadow: none;
  outline: none;
}

.tag-editor-count {
  margin-left: auto;
  font-size: var(--text-xs);
  color: var(--ink-muted);
  white-space: nowrap;
}

.tag-editor-count.is-full {
  color: var(--danger);
  font-weight: bold;
}

/* Kept in the DOM as the form's value, just not shown once the editor is up. */
.tag-editor-source {
  display: none;
}

/* ---- Upload progress ------------------------------------------------------
   Only ever shown by uploadProgress.js; the markup does not exist without it. */
.upload-progress {
  margin-top: 1em;
  padding: 10px 12px;
  background: var(--bg-subtle);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}

.upload-progress-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1em;
  margin-bottom: 7px;
}

.upload-progress-label {
  font-size: var(--text-sm);
  font-weight: bold;
  color: var(--ink);
  /* A long filename must not push the percentage off the row. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.upload-progress-percent {
  font-size: var(--text-sm);
  font-weight: bold;
  color: var(--brand-text);
  /* Tabular figures, or the number jitters sideways as it counts up. */
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}

.upload-progress-track {
  position: relative;
  height: 10px;
  overflow: hidden;
  background: #fff;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-full);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.14);
}

.upload-progress-bar {
  width: 0;
  height: 100%;
  background: var(--gradient-brand);
  border-radius: var(--r-full);
  transition: width 0.18s linear;
}

/* Once the bytes are sent there is no honest percentage left to show -- the
   server is working and cannot say how far along it is. A moving stripe says
   "still going" without inventing a number. */
.upload-progress.is-indeterminate .upload-progress-bar {
  width: 100%;
  background: repeating-linear-gradient(
    -45deg,
    var(--violet) 0 12px,
    var(--purple) 12px 24px
  );
  background-size: 34px 100%;
  animation: upload-stripe 0.9s linear infinite;
}

@keyframes upload-stripe {
  from {
    background-position: 0 0;
  }
  to {
    background-position: 34px 0;
  }
}

.upload-progress-note {
  margin: 7px 0 0;
}

.upload-progress.is-error {
  background: #fdf2f2;
  border-color: var(--danger);
}

.upload-progress.is-error .upload-progress-label {
  color: var(--danger);
}

@media (prefers-reduced-motion: reduce) {
  .upload-progress-bar {
    transition: none;
  }
  .upload-progress.is-indeterminate .upload-progress-bar {
    animation: none;
  }
}

/* ---- Tag suggestions ------------------------------------------------------
   Sits under the tag editor. Built entirely by tagInput.js, so it does not
   exist without JavaScript. */
.tag-suggestions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  margin-top: 7px;
}

.tag-suggestions-label {
  font-size: var(--text-xs);
  font-weight: bold;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--ink-muted);
  margin-right: 3px;
}

.tag-suggestions-list {
  /* contents, so the buttons wrap in the parent's flex row rather than being
     boxed together on one line. */
  display: contents;
}

/* Deliberately quieter than a chosen tag: these are offers, not selections, and
   a row of brand-coloured buttons would read as though they were already on. */
.tag-suggestion {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  background: linear-gradient(to bottom, #ffffff 0%, #f1efea 100%);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  color: var(--ink-muted);
  font-size: var(--text-xs);
  font-weight: bold;
  cursor: pointer;
  box-shadow: none;
  text-shadow: 0 1px 0 #fff;
}

.tag-suggestion:hover {
  background: linear-gradient(to bottom, #ffffff 0%, #e6eeee 100%);
  border-color: var(--brand);
  color: var(--brand-text);
}

.tag-suggestion-count {
  font-size: 0.6rem;
  font-weight: bold;
  color: #fff;
  background: var(--line-strong);
  border-radius: var(--r-full);
  padding: 0 5px;
  text-shadow: none;
  font-variant-numeric: tabular-nums;
}

.tag-suggestion:hover .tag-suggestion-count {
  background: var(--brand);
}

/* Click count on a creator link. Shown only to the profile owner and admins --
   it is their own performance figure, not something a visitor needs. */
.creator-link-clicks {
  margin-left: auto;
  margin-right: 6px;
  padding: 1px 7px;
  background: var(--brand);
  color: #fff;
  border-radius: var(--r-full);
  font-size: var(--text-xs);
  font-weight: bold;
  font-variant-numeric: tabular-nums;
  text-shadow: none;
}

/* ---- Creator platform marks on a post -------------------------------------
   Filled chips in each brand's colour rather than outlined boxes: a row of
   identical white squares reads as a toolbar, and the whole point of these is
   to be recognised without being read. */
.post-links {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
  margin-left: 8px;
}

.post-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 34px: below about 32 a thumb lands between two chips as often as on one. */
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 9px;
  line-height: 0;
  /* The inner highlight and the drop shadow together lift the chip off the card
     without a border, which at this size would eat into the glyph. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    0 1px 2px rgba(9, 9, 11, 0.22);
  transition: transform 0.13s ease, box-shadow 0.13s ease, filter 0.13s ease;
}

.post-link:hover {
  transform: translateY(-2px);
  filter: brightness(1.08);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.28),
    0 4px 8px rgba(9, 9, 11, 0.28);
}

.post-link:active {
  transform: translateY(0);
  filter: brightness(0.95);
  box-shadow: inset 0 2px 4px rgba(9, 9, 11, 0.3);
}

.post-link svg {
  display: block;
}

/* Brand fills, flat rather than glossy. A lighter top stop looked better in
   isolation and quietly broke the thing it sat on: white on the highlight of the
   OnlyFans, Fansly and Instagram gradients measured 2.8, 2.9 and 2.1 to one,
   under the 3:1 a graphic needs to stay legible. The inset highlight below
   already gives the chip its lift.

   Two colours are off their published value for the same reason: OnlyFans blue
   is deepened to #0092CC (3.5:1 against white), and Linktree keeps its real
   bright green with a dark glyph instead of a white one (9:1). */
.post-link-onlyfans  { background: #0092cc; }
.post-link-fansly    { background: #0092ff; }
.post-link-patreon   { background: #ff424d; }
.post-link-linktree  { background: #43e660; }
/* Instagram is a gradient because that is its identity, but it runs pink to
   purple only -- the yellow end of the real mark cannot carry a white glyph. */
.post-link-instagram { background: linear-gradient(135deg, #e1306c 0%, #a02fa0 100%); }
.post-link-twitter   { background: #0f1419; }
.post-link-tiktok    { background: #010101; }
.post-link-website   { background: #14464c; }

/* On the post page and the profile the marks follow the byline rather than
   sitting in an action row. */
.post-detail .post-links,
.fb-post-card .post-links {
  margin-left: 0;
  margin-bottom: 0.9em;
}
