/* chan-fe — imageboard-style catalog (4chan-X inspired, light theme)
   Goals:
   - light blue/grey background, dark text, near-invisible grid
   - drop shadow on images only
   - row flexes to hold the tallest (truncated) post
   - vanilla JS, no build step
*/

/* ---------------- 4chan-ish color tokens ---------------- */
:root {
  --bg:           #EEF2FF;            /* 4chan page background */
  --bg-hover:     #c8d0e8;            /* row hover */
  --bg-elev:      #ffffff;            /* control surfaces */
  --fg:           #000;
  --fg-dim:       #555;
  --fg-faint:     #888;
  --toolbar:      #34345C;
  --link:         var(--toolbar);
  --link-visited: #800080;
  --border:       #b7c5d9;
  --border-soft:  #d0d6e6;
  --accent:       #0f4d92;
  --red:          rgb(214, 0, 0);
  --shadow-img:   0 1px 3px rgba(0, 0, 0, 0.25);
  --shadow-img-hover: 0 2px 6px rgba(0, 0, 0, 0.35);

  --font-sans:   Arial, Helvetica, sans-serif;
  /* keep var name for compatibility, but use sans to avoid monospace UI */
  --font-mono:   Arial, Helvetica, sans-serif;

  --card-w:      180px;
  --gap:         4px;
  --per-page:    25;
}

/* Traditional orange/red imageboard palette. Disabling NSFW blur opts into
   this theme as a visible reminder that sensitive media is being shown. */
html.nsfw-theme {
  --bg:           #FFFFEE;
  --bg-hover:     #F0C0B0;
  --bg-elev:      #FFFFEE;
  --fg:           #800000;
  --fg-dim:       #800000;
  --fg-faint:     #9b5b50;
  --toolbar:      #800000;
  --link:         #000080;
  --link-visited: #800080;
  --border:       #D9BFB7;
  --border-soft:  #E8D2C8;
  --accent:       #CC1105;
}

html.nsfw-theme .topbar,
html.nsfw-theme .profile-bio,
html.nsfw-theme .post-block,
html.nsfw-theme .post-preview,
html.nsfw-theme .profile-preview,
html.nsfw-theme .emoji-picker-head,
html.nsfw-theme .compose-modal-head,
html.nsfw-theme .poll-composer-head,
html.nsfw-theme .board-create-head,
html.nsfw-theme .subscribe-modal-head,
html.nsfw-theme .watcher-head,
html.nsfw-theme .config-modal-head {
  background: #F0E1D7;
  border-color: var(--border);
}
html.nsfw-theme .post-block { background: #F0E0D6; }
html.nsfw-theme .post-block.is-op { background: transparent; }
html.nsfw-theme .post-block.is-inline { background: #F0E0D6; }
html.nsfw-theme .post-block.is-linked { background: #F0C0B0; }
html.nsfw-theme .post-block.is-own { border-left-color: rgba(221, 0, 0, .8); }
html.nsfw-theme .post-block.is-replying-to-you { border-left-color: rgba(221, 0, 0, .8); }
html.nsfw-theme .board-title,
html.nsfw-theme .thread-subject,
html.nsfw-theme .auth-dialog-box h2,
html.nsfw-theme .emoji-picker-head h2,
html.nsfw-theme .compose-modal-head h2,
html.nsfw-theme .poll-composer-head h2,
html.nsfw-theme .board-create-head h2,
html.nsfw-theme .subscribe-modal-head h2,
html.nsfw-theme .watcher-title,
html.nsfw-theme .config-modal-head h2 {
  color: #CC1105;
}
html.nsfw-theme .post-reply-to .reply-to-link,
html.nsfw-theme .compose-reply-to .reply-to-link { color: #000080; }
html.nsfw-theme .config-tab.is-active { box-shadow: inset 0 -2px 0 0 #CC1105; }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--bg);            /* #EEF2FF */
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.35;
  min-height: 100vh;
}

a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---------------- topbar ---------------- */
.topbar {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 2px 4px 0;
  background: #D6DAF0;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
  position: sticky;
  top: 0;
  z-index: 10;
}
.brand { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.instance {
  color: var(--fg);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
a.instance:hover { text-decoration: underline; }
/* One wrappable line of bracketed board groups:
 * [/home/twkn/local/likes/][/custom1/custom2/][+]
 * Inline flow (not flex) so long custom-board lists wrap at the <wbr>
 * break points renderBoardNav() inserts after separators. */
.boards {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 14px;
  line-height: 1.5;
}
.board-group { margin-right: 4px; }
.board-sep { color: var(--fg-faint); }

/* ---------------- toolbar (icon buttons to the left of the user pill) ---------------- */
.toolbar {
  display: flex;
  align-items: center;
  gap: 4px;
}
.toolbar-btn {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1;
  background: transparent;
  color: var(--toolbar);
  border: 0;
  padding: 0;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.toolbar-btn:hover:not(:disabled) {
  color: var(--red);
}
.toolbar-btn:disabled {
  color: var(--fg-faint);
  cursor: not-allowed;
}
/* Spin the refresh icon while a fetch is in flight. The class is toggled
 * from render() based on state.loading, so it covers manual refresh clicks
 * and the auto-refresh timer firing in the background. */
@keyframes toolbar-refresh-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.toolbar-btn.is-loading i {
  animation: toolbar-refresh-spin 1s linear infinite;
  transform-origin: 50% 50%;
}
@media (prefers-reduced-motion: reduce) {
  .toolbar-btn.is-loading i { animation-duration: 2.5s; }
}

.toolbar-btn.has-unread {
  color: var(--red);
}

/* ---------------- top loading bar ----------------
 * Thin NProgress-style bar pinned to the very top of the viewport. The fill
 * width is driven from JS (syncLoadingBar) tied to state.loading — it fills
 * toward ~90% while a view load (board/profile/tag/search/thread) is in
 * flight, snaps to 100% the instant the load finishes, then fades out.
 * pointer-events:none + aria-hidden keep it purely decorative. */
#loading-bar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 3px;
  z-index: 1000;
  pointer-events: none;
}
#loading-bar .loading-bar-fill {
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent);
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.25);
  opacity: 0;
  transition: width 300ms ease, opacity 300ms ease;
}
/* Source order matters: when both classes are present during the fade-out,
 * .is-done (declared later) wins so opacity goes to 0. */
#loading-bar.is-loading .loading-bar-fill { opacity: 1; }
#loading-bar.is-done    .loading-bar-fill { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  #loading-bar .loading-bar-fill { transition-duration: 0.01ms; }
}
.board-link {
  font-family: var(--font-mono);
  font-size: 14px;
  padding: 2px 0;
  color: var(--fg);
}
.board-link:hover { color: var(--red); text-decoration: none; }
.board-link.active { color: var(--accent); }

.user-pill,
.auth-pill {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-sans);
  font-size: 12px;
}
.auth-signin {
  font-family: var(--font-sans);
  font-size: 12px;
  background: var(--accent);
  color: white;
  border: 1px solid var(--accent);
  border-radius: 1px;
  padding: 3px 10px;
  cursor: pointer;
}
.auth-signin:hover:not(:disabled) { background: #0a3a72; }
.auth-signin:disabled {
  background: var(--bg-elev);
  color: var(--fg-faint);
  border-color: var(--border);
  cursor: not-allowed;
}
.auth-pill-link {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--fg);
  text-decoration: none;
  font-size: 12px;
  font-weight: 500;
  padding: 2px 4px 2px 2px;
  border-radius: 1px;
}
.auth-pill-link:hover { background: var(--bg-hover); text-decoration: none; }
.auth-avatar {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--bg);
  flex-shrink: 0;
}
.auth-name {
  white-space: nowrap;
  max-width: 140px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.auth-signout {
  font-family: var(--font-sans);
  font-size: 11px;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 2px 7px;
  cursor: pointer;
}
.auth-signout:hover { background: var(--bg-hover); color: var(--fg); }

/* ---------------- auth dialog ---------------- */
.auth-dialog {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 100;
  align-items: flex-start;
  justify-content: center;
  padding-top: 12vh;
}
.auth-dialog.is-open { display: flex; }
.auth-dialog-box {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 2px;
  width: 420px;
  max-width: calc(100% - 24px);
  padding: 14px 16px 16px;
  box-shadow: 0 4px 24px rgba(0,0,0,0.4);
}
.auth-dialog-box h2 {
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0 0 8px;
}
.auth-steps {
  margin: 0 0 10px;
  padding-left: 18px;
  font-size: 12px;
  color: var(--fg);
  line-height: 1.45;
}
.auth-steps li { margin-bottom: 2px; }
.auth-steps b { color: var(--fg); font-weight: 600; }
.auth-dialog-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border-soft);
}
.auth-open {
  font-family: var(--font-sans);
  font-size: 12px;
  background: var(--accent);
  color: white;
  border: 1px solid var(--accent);
  border-radius: 1px;
  padding: 4px 10px;
  cursor: pointer;
}
.auth-open:hover { background: #0a3a72; }
.auth-instance-row {
  margin-bottom: 12px;
}
.auth-instance-row label {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  margin-bottom: 3px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.auth-instance-row input[type="text"] {
  width: 100%;
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--border);
  padding: 5px 8px;
  border-radius: 3px;
}
.auth-instance-link {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-dim);
}
.auth-form label {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  margin-bottom: 3px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.auth-form input[type="text"] {
  width: 100%;
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 5px 7px;
  box-sizing: border-box;
  outline: none;
  word-break: break-all;
}
.auth-form input[type="text"]:focus { border-color: var(--accent); }
.auth-form-row {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}
.auth-submit {
  font-family: var(--font-sans);
  font-size: 12px;
  background: var(--accent);
  color: white;
  border: 1px solid var(--accent);
  border-radius: 1px;
  padding: 4px 12px;
  cursor: pointer;
}
.auth-submit:hover { background: #0a3a72; }
.auth-cancel {
  font-family: var(--font-sans);
  font-size: 12px;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 4px 12px;
  cursor: pointer;
}
.auth-cancel:hover { background: var(--bg-hover); }
.auth-error {
  font-family: var(--font-mono);
  font-size: 11px;
  color: #b00;
  margin-top: 8px;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ---------------- catalog wrap ---------------- */
.catalog-wrap { max-width: 1500px; margin: 0 auto; padding: 10px 12px; }
.catalog-header { margin-bottom: 4px; }
.board-title {
  font-family: var(--font-sans);
  color: #AF0A0F;
  text-shadow: 1px 1px 1px rgba(105, 10, 15, 0.6);
  font-size: 28px;
  font-weight: 400;
  letter-spacing: -2px;
  text-align: center;
  margin: 4px 0 2px 0;
}
.catalog-meta {
  color: var(--fg-dim);
  font-size: 11px;
  font-family: var(--font-mono);
  text-align: center;
}
/* Full user@instance handle for a custom-board (/g/<name>) catalog, shown
 * between the board-title and catalog-meta. Mirrors .profile-acct but centered
 * to match the catalog header. */
.board-acct {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  text-align: center;
  margin: 2px 0 4px;
  word-break: break-all;
}

/* ---------------- start thread row (its own line, centered) ---------------- */
.start-thread-row {
  display: flex;
  justify-content: center;
  gap: 8px;
  padding: 6px 0 8px;
}
.profile-follow.is-following {
  background: var(--bg-elev);
  color: var(--fg);
  border-color: var(--border);
}
.profile-follow.is-following:hover:not(:disabled) { background: #6a0a0f; color: #fff; border-color: #6a0a0f; }
.profile-moderation { position: relative; }
.profile-moderation-btn { min-width: 28px; }
.profile-moderation-menu {
  position: absolute; top: calc(100% + 3px); right: 0; z-index: 40;
  min-width: 175px; padding: 3px; background: var(--bg-elev);
  border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,.25);
}
.profile-moderation-menu button {
  display: block; width: 100%; padding: 5px 8px; border: 0; background: transparent;
  color: var(--fg); font: 12px var(--font-sans); text-align: left; cursor: pointer;
}
.profile-moderation-menu button:hover { background: var(--bg-hover); }
.profile-moderation-menu button:disabled { color: var(--fg-faint); cursor: default; }

/* ---------------- account menu (multi-account switcher) ---------------- */
/* .user anchors the dropdown the same way .profile-moderation does. */
.user { position: relative; display: flex; align-items: center; gap: 4px; }
.account-menu-btn[hidden],
.account-signin-btn[hidden] { display: none; }
.account-menu {
  position: absolute; top: calc(100% + 3px); right: 0; z-index: 40;
  min-width: 200px; padding: 3px; background: var(--bg-elev);
  border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,.25);
}
.account-menu[hidden] { display: none; }
.account-menu-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 5px 8px; border: 0; background: transparent; color: var(--fg);
  font: 12px var(--font-sans); text-align: left; cursor: pointer; white-space: nowrap;
}
.account-menu-item i { width: 14px; text-align: center; color: var(--fg-dim); }
.account-menu-item:hover { background: var(--bg-hover); }
.account-menu-item.is-active { font-weight: 600; }
.account-menu-sep { height: 1px; margin: 3px 0; background: var(--border-soft); }

/* ---------------- controls (search left, filter + sort right) ---------------- */
.catalog-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;   /* search hugs the left, filter/sort the right */
  gap: 12px;
  padding: 4px 0 8px;
  border-bottom: 1px solid var(--border-soft);
  margin-bottom: -1px;
}
.catalog-controls.is-search-hidden {
  justify-content: flex-end;
}
.start-thread {
  font-family: var(--font-sans);
  font-size: 12px;
  background: var(--accent);
  color: white;
  border: 1px solid var(--accent);
  border-radius: 1px;
  padding: 4px 12px;
  cursor: pointer;
}
.start-thread:hover:not(:disabled) { background: #0a3a72; }
.start-thread:disabled {
  background: var(--bg-elev);
  color: var(--fg-faint);
  border-color: var(--border);
  cursor: not-allowed;
}
.catalog-controls-right {
  display: flex;
  align-items: center;
  gap: 8px;
}
.catalog-controls-right[hidden] { display: none; }
.catalog-media-filter {
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 3px 6px;
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
}
.catalog-media-filter:hover { color: var(--accent); border-color: var(--accent); }
.catalog-media-filter.is-active { color: #fff; background: var(--accent); border-color: var(--accent); }
.catalog-media-filter[hidden] { display: none; }
/* Search box: input with a magnifying-glass submit button embedded on the
   right. Same proportions as the Filter input so the two flank the bar. */
.catalog-search {
  position: relative;
  display: flex;
  align-items: center;
}
.catalog-search-input {
  font-family: var(--font-sans);
  font-size: 12px;
  background: var(--bg-elev);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 3px 28px 3px 6px;   /* leave room for the embedded button */
  width: 220px;
  outline: none;
}
.catalog-search-input:focus { border-color: var(--accent); }
.catalog-search-btn {
  position: absolute;
  right: 3px;
  top: 50%;
  transform: translateY(-50%);
  background: transparent;
  border: 0;
  padding: 2px 4px;
  font-size: 12px;
  line-height: 1;
  color: var(--fg-dim);
  cursor: pointer;
}
.catalog-search-btn:hover:not(:disabled) { color: var(--accent); }
.catalog-search-btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* Section labels in a search-results catalog span the full grid width. */
.search-section-label {
  grid-column: 1 / -1;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  text-transform: lowercase;
  letter-spacing: 0.04em;
  padding: 6px 0 2px;
  border-bottom: 1px dotted var(--border-soft);
  margin-bottom: 2px;
}
.search-hashtags { grid-column: 1 / -1; }
.search-hashtag-links {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  padding: 2px 4px 5px;
}
.search-hashtag {
  color: var(--link);
  font: 12px var(--font-mono);
}
.search-hashtag:hover { color: var(--red); }
.catalog-filter {
  font-family: var(--font-sans);
  font-size: 12px;
  background: var(--bg-elev);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 3px 6px;
  width: 200px;
  outline: none;
}
.catalog-filter:focus { border-color: var(--accent); }
.catalog-sort {
  font-family: var(--font-sans);
  font-size: 11px;
  color: var(--fg-dim);
}
.catalog-sort select {
  font-family: var(--font-sans);
  font-size: 11px;
  background: var(--bg-elev);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 2px 4px;
  margin-left: 4px;
}

/* ---------------- catalog grid (4chan-X) ---------------- */
.catalog {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--card-w), 1fr));
  /* Size each row independently to its tallest card. `1fr` made every row
     adopt the height of the tallest card in the entire catalog. */
  grid-auto-rows: max-content;
  gap: var(--gap) var(--gap); /* row-gap col-gap */
}
.catalog.is-search {
  grid-auto-rows: max-content;
}

.empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: 60px 0;
  color: var(--fg-faint);
  font-family: var(--font-mono);
  font-size: 12px;
}

/* ---------------- thread card (4chan-X style, near-invisible) ---------------- */
.thread-card {
  display: flex;
  flex-direction: column;
  position: relative;
  cursor: pointer;
  background: transparent;       /* invisible card */
  border: 0;
  padding: 4px;
  min-width: 0;                  /* allow text truncation */
}
.thread-card:hover {
  z-index: 7;
  background: transparent;       /* no hover bg — only the image reacts */
}
.thread-activity {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 6;
  padding: 5px 6px;
  color: var(--fg-dim);
  background: var(--bg);
  font-family: var(--font-mono);
  font-size: 10px;
  line-height: 1.35;
  text-align: left;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.08s ease;
}
.thread-card:hover .thread-activity {
  opacity: 1;
  pointer-events: auto;
}
.thread-activity-line {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.thread-activity-line i { width: 1.3em; text-align: center; }
.thread-activity-line a { color: var(--link); text-decoration: none; }
.thread-activity-line a:hover { text-decoration: underline; }

/* thumb: image (natural aspect) or avatar+banner composite */
.thread-thumb {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100px;
  max-height: 320px;
  overflow: visible;             /* drop shadow shows outside */
  background: transparent;
}
.thread-thumb img {
  display: block;
  max-width: 100%;
  max-height: 320px;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(var(--shadow-img));
  transition: filter 0.06s ease;
}
.thread-card:hover .thread-thumb img {
  filter: drop-shadow(var(--shadow-img-hover));
}

/* avatar+banner composite (imageless OP) */
.thread-thumb.is-avatar-banner {
  aspect-ratio: 4 / 3;
  max-height: none;
  background: var(--bg-elev);
  filter: drop-shadow(var(--shadow-img));
  transition: filter 0.06s ease;
  position: relative;
}
.thread-thumb.is-avatar-banner.is-anonymous,
.post-media.is-avatar-banner.is-anonymous {
  background: #d9f2d9;
}
.thread-thumb.is-avatar-banner.is-anonymous .thumb-avatar,
.post-media.is-avatar-banner.is-anonymous .thumb-avatar {
  border-color: #9acb9a;
}
.anonymous-mode [data-anon-masked="1"] {
  pointer-events: none;
  cursor: default;
  text-decoration: none;
}
.thread-card:hover .thread-thumb.is-avatar-banner {
  filter: drop-shadow(var(--shadow-img-hover));
}
.thread-thumb .banner-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: brightness(0.55) saturate(0.9);
  border-radius: 0;            /* shadow comes from parent filter */
}
.thread-thumb .thumb-avatar {
  position: relative;
  z-index: 1;
  width: 55%;
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid rgba(255,255,255,0.4);
  box-shadow: 0 2px 6px rgba(0,0,0,0.4);
}
.post-media.is-avatar-banner .thumb-avatar {
  position: relative;
  z-index: 1;
  width: 55%;
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid rgba(255,255,255,0.4);
  box-shadow: 0 2px 6px rgba(0,0,0,0.4);
}
.thread-thumb .thumb-avatar-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elev);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 32px;
  font-weight: 600;
}

/* catalog video thumbnail */
.thread-thumb-video {
  display: block;
  max-width: 100%;
  max-height: 320px;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(var(--shadow-img));
  transition: filter 0.06s ease;
}
.thread-card:hover .thread-thumb-video {
  filter: drop-shadow(var(--shadow-img-hover));
}

/* Action overlay pinned to the bottom of the thumb, revealed on card hover.
   Reuses .post-action buttons (so toggleLike/toggleRepost work) but restyles
   them for legibility over a thumbnail. */
.thread-thumb-foot {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 4;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 3px;
  padding: 5px 4px 4px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0));
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.08s ease;
}
.thread-card:hover .thread-thumb-foot {
  opacity: 1;
  pointer-events: auto;
}
.thread-thumb-foot .post-action {
  font-size: 10px;
  padding: 1px 4px;
  gap: 3px;
  color: #fff;
  background: rgba(0, 0, 0, 0.45);
}
.thread-thumb-foot .post-action:hover:not(:disabled) {
  background: rgba(0, 0, 0, 0.7);
  color: var(--red);
}
.thread-thumb-foot .post-action.is-liked { color: var(--red); }
.thread-thumb-foot .post-action.is-reposted { color: #5fe06a; }
.thread-thumb-foot .post-action.is-watching,
.thread-thumb-foot .post-action.is-watching:hover:not(:disabled) { color: var(--red); }

/* legacy fallback for no media URL */
.thread-thumb-placeholder {
  width: 100%;
  height: 100%;
  min-height: 120px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background:
    repeating-linear-gradient(
      45deg,
      #1a1c20,
      #1a1c20 8px,
      #15171b 8px,
      #15171b 16px
    );
  color: var(--fg-dim);
  font-family: var(--font-mono);
  filter: drop-shadow(var(--shadow-img));
}
.thread-thumb-placeholder .label {
  letter-spacing: 1px;
  text-transform: uppercase;
  font-size: 9px;
  color: #aaa;
}

/* stats badge (top-right of thumb) — 4chan style: "R: N / I: N" */
.thread-stats {
  position: absolute;
  top: 4px;
  right: 4px;
  background: rgba(255,255,255,0.85);
  color: var(--red);
  font-family: var(--font-mono);
  font-size: 10px;
  padding: 1px 4px;
  border-radius: 1px;
  z-index: 2;
  letter-spacing: 0.3px;
}
.thread-stats b { color: #b00; font-weight: 600; }

.thread-badge {
  position: absolute;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 9px;
  padding: 1px 4px;
  border-radius: 1px;
  letter-spacing: 0.4px;
  line-height: 1.2;
}
.thread-badge.nsfw {
  top: 4px;
  left: 4px;
  background: rgba(180, 30, 30, 0.9);
  color: white;
  text-transform: uppercase;
}
.thread-badge.spoiler {
  bottom: 4px;
  left: 4px;
  right: 4px;
  background: rgba(0,0,0,0.75);
  color: #fff;
  font-style: italic;
  text-align: center;
}
/* Board admin buttons (shown only on boards the user moderates) */
.start-thread.board-delete { background: #7a1010; border-color: #7a1010; }
.start-thread.board-delete:hover { background: #9a1414; border-color: #9a1414; }

/* Group-post marker (status.group / group account cards); links to /g/… */
.thread-badge.board {
  top: 4px;
  left: 4px;
  background: rgba(0, 102, 0, 0.9);
  color: white;
  text-transform: uppercase;
  text-decoration: none;
}
a.thread-badge.board:hover { background: #060; color: #fff; }
/* NSFW owns the top-left corner; stack the board badge under it. */
.thread-badge.board.below-nsfw { top: 20px; }

/* Inline /boardname/ chip on a group thread's OP info row */
.post-board-chip {
  font-family: var(--font-mono);
  font-size: 9px;
  padding: 1px 4px;
  border-radius: 1px;
  letter-spacing: 0.4px;
  vertical-align: 1px;
  background: #006600;
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
}
.post-board-chip:hover { background: #060; color: #fff; text-decoration: none; }

/* NSFW blur overlay — sits above the image, below badges and toggle btn */
.nsfw-blur-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  background: rgba(0, 0, 0, 0.15); /* fallback tint when backdrop-filter unsupported */
  pointer-events: none;
}
.nsfw-revealed .nsfw-blur-overlay {
  display: none;
}

/* Toggle button — top-right corner, opposite the NSFW badge */
.nsfw-toggle-btn {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 3;
  background: none;
  border: none;
  padding: 2px 3px;
  cursor: pointer;
  color: var(--toolbar);
  font-size: 11px;
  line-height: 1;
  border-radius: 1px;
}
.nsfw-toggle-btn.is-revealed {
  color: var(--fg-faint);
}

/* Top-right control cluster on catalog thumbs (hide thread + NSFW toggle).
   Hover-revealed and styled like the footer overlay so the controls (the blur
   toggle especially) stay legible over any thumbnail. */
.thread-thumb-top {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 5;
  display: flex;
  gap: 3px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.08s ease;
}
.thread-card:hover .thread-thumb-top {
  opacity: 1;
  pointer-events: auto;
}
.thread-thumb-top .post-action,
.thread-thumb-top .nsfw-toggle-btn {
  position: static;
  font-size: 11px;
  line-height: 1;
  padding: 2px 5px;
  color: #fff;
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 1px;
  cursor: pointer;
}
.thread-thumb-top .post-action:hover:not(:disabled),
.thread-thumb-top .nsfw-toggle-btn:hover {
  background: rgba(0, 0, 0, 0.75);
  color: var(--red);
}
.thread-thumb-top .post-action { border: 0; }
.thread-thumb-top .nsfw-toggle-btn:hover { color: #fff; }

/* Wrapper for NSFW images in thread view (provides positioning context) */
.nsfw-img-wrap {
  position: relative;
  display: inline-block;
  line-height: 0;
}

/* text info: stats line + subject + body (centered, 4chan-X style) */
.thread-info {
  position: relative;
  padding: 5px 4px 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  text-align: center;          /* 4chan centers card text */
}
.thread-stats-text {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  color: #000;
  letter-spacing: 0.5px;
}
.thread-stats-text .sep {
  color: var(--fg-faint);
  font-weight: 400;
  margin: 0 3px;
}
.thread-subject {
  font-size: 13px;
  font-weight: 700;
  color: #0F4D92;              /* 4chan subject/link dark blue */
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}
.thread-subject a {
  color: inherit;
  cursor: pointer;
}
.thread-subject a:hover { text-decoration: underline; }

/* Poster name when used as the subject line (no summary/extracted h1). */
.thread-subject.is-poster,
.thread-subject.is-poster a {
  color: #117743;                 /* 4chan green name */
}

/* Poster name shown below the summary subject in catalog cards. */
.thread-poster-name {
  font-size: 12px;
  font-weight: 700;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}
.thread-poster-name a {
  color: #117743;                 /* 4chan green name */
  text-decoration: none;
}
.thread-poster-name a:hover {
  text-decoration: underline;
}

/* Subject line in thread view (OP only). Rendered inline inside .post-head
   matching 4chan's inline subject in the postInfo row. */
.post-subject {
  font-size: 14px;
  font-weight: 700;
  color: #0F0C5D;                 /* 4chan navy subject color */
}

.custom-emoji {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  vertical-align: -0.22em;
  object-fit: contain;
}

.thread-body {
  font-size: 12px;
  font-weight: 400;
  line-height: 1.35;
  color: #000;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
  margin-top: 1px;
}
/* Content links render (mentions/hashtags/urls) but stay inert so the whole
   card remains one click target that opens the thread; keep them looking like
   the surrounding snippet text rather than standout links. */
.thread-body a {
  pointer-events: none;
  color: inherit;
  text-decoration: none;
}
/* Keep the clamped snippet compact — no big default <p> gaps. */
.thread-body p { margin: 0; }

/* No meta line / no handle in catalog cards — 4chan doesn't have them */

/* ---------------- catalog infinite-scroll footer ---------------- */
.catalog-sentinel {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 16px 0 24px;
  clear: both;
}
.catalog-load-more {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--link);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 1px;
  padding: 4px 14px;
  cursor: pointer;
}
.catalog-load-more:hover:not(:disabled) { background: var(--bg-hover); }
.catalog-load-more:disabled { color: var(--fg-faint); cursor: default; }

/* ---------------- thread view ---------------- */
.catalog.is-thread { display: block; }

/* ---------------- about page ---------------- */
.catalog.is-about { display: block; max-width: 720px; }

.about-header {
  margin-bottom: 18px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-soft);
}
.about-title {
  font-family: var(--font-sans);
  font-size: 24px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0 0 2px;
}
.about-uri {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-faint);
  margin-bottom: 6px;
}
.about-tagline {
  font-size: 13px;
  color: var(--fg);
  margin: 6px 0 0;
}

.about-block {
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 2px;
  padding: 10px 14px 12px;
  margin-bottom: 10px;
}
.about-block h2 {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0 0 8px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--border-soft);
}

.about-html { font-size: 13px; line-height: 1.5; color: var(--fg); }
.about-html p { margin: 0 0 0.5em; }
.about-html p:last-child { margin-bottom: 0; }
.about-html a { color: var(--link); }
.about-html ul { margin: 0; padding-left: 20px; }

.about-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.about-stat {
  background: var(--bg);
  border: 1px solid var(--border-soft);
  border-radius: 2px;
  padding: 8px 10px;
  text-align: center;
}
.about-stat-value {
  font-family: var(--font-mono);
  font-size: 18px;
  font-weight: 700;
  color: var(--fg);
}
.about-stat-label {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--fg-faint);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-top: 2px;
}

.about-config {
  margin: 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 14px;
  font-family: var(--font-mono);
  font-size: 12px;
}
.about-config dt { color: var(--fg-faint); }
.about-config dd { margin: 0; color: var(--fg); word-break: break-word; }
.about-config a { color: var(--link); }

.contact-card {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 8px;
}
.contact-avatar {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.2));
}
.contact-info { min-width: 0; }
.contact-name {
  font-size: 14px;
  font-weight: 700;
  color: var(--fg);
}
.contact-handle {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  margin-bottom: 4px;
}
.contact-note {
  font-size: 12px;
  line-height: 1.4;
  color: var(--fg-dim);
}
.contact-note p { margin: 0; }

.contact-fields { margin-top: 4px; }

/* ---------------- profile bio (/user/ view) ---------------- */
.profile-bio {
  margin: 4px auto 8px;
  max-width: 640px;
  padding: 10px 12px;
  background: #D6DAF0;            /* match a post (4chan reply bg) */
  border: 1px solid #B7C5D9;
  border-radius: 2px;
}
.profile-card {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.profile-avatar {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.2));
}
.profile-info { min-width: 0; flex: 1; }
.profile-display-name {
  font-size: 15px;
  font-weight: 700;
  color: #117743;                 /* 4chan green name (matches catalog/replies) */
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.profile-display-name .custom-emoji { vertical-align: -2px; }
.profile-badge { color: var(--fg-dim); font-size: 12px; }
.profile-acct {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  margin-bottom: 4px;
  word-break: break-all;
}
.profile-stats {
  display: flex;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--fg-dim);
  margin-bottom: 6px;
}
.profile-stat { cursor: default; }
.profile-note {
  font-size: 12px;
  line-height: 1.4;
  color: var(--fg-dim);
  word-break: break-word;
}
.profile-note p { margin: 0 0 4px; }
.profile-note p:last-child { margin-bottom: 0; }
.profile-note a { color: var(--link); }
.profile-note.is-collapsed {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.profile-fields {
  margin: 6px 0 0;
  font-size: 12px;
}
.profile-fields dt {
  font-weight: 700;
  color: var(--fg-dim);
  margin-top: 4px;
}
.profile-fields dd {
  margin: 0;
  color: var(--fg);
  word-break: break-word;
}
.profile-fields dd a { color: var(--link); }
.profile-fields dd.is-verified { color: #1a7f37; }
.profile-show-more {
  display: inline-block;
  margin-top: 4px;
  padding: 0;
  background: none;
  border: none;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--link);
  cursor: pointer;
}
.profile-show-more:hover { text-decoration: underline; }
/* The explicit display above otherwise overrides the [hidden] attribute, so
   the note's "[show more]" toggle would show even when it has nothing to
   reveal. Restore hidden's intent explicitly. */
.profile-show-more[hidden] { display: none; }
.profile-bio-toggle { display: block; }
.profile-extra { margin-top: 2px; }

/* ---- 4chan-style navigation bars (top & bottom of thread view) ---- */
.navLinks {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--fg);
  margin: 4px 0;
  clear: both;
}
.navLinks a {
  color: var(--link);
  text-decoration: none;
}
.navLinks a:hover {
  color: var(--red);
  text-decoration: underline;
}
.navLinksTop {
  padding-bottom: 3px;
  border-bottom: 1px solid var(--border-soft);
  margin-bottom: 8px;
}
.navLinks .brackets-wrap::before { content: "["; }
.navLinks .brackets-wrap::after  { content: "]"; }
.navLinks .brackets-wrap a {
  color: var(--link);
  text-decoration: none;
}
.navLinks .brackets-wrap a:hover {
  color: var(--red);
  text-decoration: underline;
}
/* Floating [Top] bar for catalog views: fixed and centered at the bottom of
   the viewport, shown by app.js once the user scrolls a screen down. Threads
   keep their own in-flow [Top] nav instead. */
.scroll-top-bar {
  position: fixed;
  bottom: 14px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 4px;
  padding: 4px 10px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}
.scroll-top-bar a {
  color: var(--link);
  text-decoration: none;
}
.scroll-top-bar a:hover {
  color: var(--red);
  text-decoration: underline;
}
.navLinksBot {
  margin: 4px 0;
  position: relative; /* anchor for .qr-link-container-bottom */
  border-style: solid;
  border-width: 1px 0;
  border-color: var(--border-soft);
  padding: 3px 0;
}
/* 4chan trick: pull the "Reply to OP" out of flow and pin it to the
   horizontal center, while the [Index][Catalog][Top][Update] links
   stay in normal flow on the left of the same row. */
.navLinksBot > .qr-link-container-bottom {
  width: 200px;
  position: absolute;
  left: -100px;
  margin-left: 50%;
  text-align: center;
}
.thread-section {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  color: var(--fg);
  border-bottom: 1px solid var(--border-soft);
  padding-bottom: 3px;
  margin: 20px 0 8px;
}

/* Thread wrapper: OP + replies flowing (4chan style) */
.thread-wrapper {
  /* replies-wrap sits below OP; no nesting indentation */
}
.replies-wrap {
  margin-top: 4px;
}

.post-block {
  background: #D6DAF0;            /* 4chan reply bg */
  border: 1px solid #B7C5D9;
  border-radius: 0;
  padding: 3px 6px 5px;
  margin: 0 0 6px;
  width: fit-content;
  max-width: calc(100% - 8px);
  display: flow-root;
  overflow: visible;
  position: relative;
}
.post-block.is-op {
  padding: 0;
  margin: 0 0 8px;
  border: none;
  background: transparent;
  width: fit-content;            /* shrink to content so the action row doesn't
                                    stretch all the way to the right edge of
                                    the page (match reply containers) */
  max-width: 100%;
}
.post-block.is-op .post-body {
  margin-left: 0;                /* avatar banner already provides left
                                    gutter via its own 20px right margin;
                                    no need for an extra 40px gap */
}
.post-block.is-op .post-foot {
  width: 100%;
}
.post-block.is-op .post-foot-primary {
  margin-left: 0;
}
.post-block.is-op .post-reactions {
  justify-content: flex-start;  /* OPs: reaction chips align left to match
                                    the action row */
}

.post-hide-btn {
  position: absolute;
  left: -22px;
  top: 3px;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  color: var(--fg-faint);
  font-size: 14px;
  line-height: 1;
}

.post-stub {
  margin: 0 -21px 6px;
}
.post-restore-link,
.post-restore-link:visited {
  color: var(--fg-dim);
  text-decoration: none;
  font-size: 14px;
}
.post-restore-link:hover {
  color: var(--red);
  text-decoration: none;
}

.post-head {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--fg-dim);
  margin-bottom: 4px;
  line-height: 1.5;
}
.post-head .avatar {
  width: 20px;
  height: 20px;
  border-radius: 3px;          /* 4chan uses slightly squared avatars */
  object-fit: cover;
  vertical-align: middle;
  margin-right: 4px;
}
.post-head .poster-name {
  color: #117743;                 /* 4chan green name */
  font-weight: 700;
  text-decoration: none;
}
.post-head .poster-name:hover {
  text-decoration: underline;
}
.post-head .opname {
  color: #0f0c5d;                 /* OP gets a different shade (4chan does this) */
}
.post-head .post-datetime {
  font-size: 14px;
  color: var(--fg-dim);
  margin: 0 6px;
}
.post-head .post-no {
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--fg-dim);
  cursor: pointer;
  text-decoration: none;
}
.post-head .post-no:hover {
  color: var(--accent);
  text-decoration: underline;
}
.post-head .post-id {
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--link);
  cursor: pointer;
  text-decoration: none;
}
.post-head .post-id:hover {
  color: var(--red);
  text-decoration: underline;
}

/* ---- 4chan-style reply reference links ---- */
.post-head-reply-from {
  margin-left: 8px;
  font-family: var(--font-mono);
  font-size: 14px;
}
.post-head-reply-from .reply-from-link {
  color: var(--toolbar);
  text-decoration: none;
  margin-right: 6px;
  white-space: nowrap;   /* keep each >>ref atomic */
  display: inline-block; /* atomic inline boxes have soft-wrap opportunities between them, so the group wraps when the row fills up */
}
.post-head-reply-from .reply-from-link:hover {
  color: #202047;
  text-decoration: underline;
}

.post-reply-to {
  margin: 0 40px 0;
  font-family: var(--font-mono);
  font-size: 14px;
  line-height: 1.35;
}
.post-reply-to .reply-to-link {
  color: var(--red);
  text-decoration: underline;
}
.post-reply-to .reply-to-link:hover {
  color: #ff2a2a;
}

/* ---- "you" indicators on post blocks in the thread view ---- */
/* A post authored by the signed-in user. Dashed left border.
 * Never applied to OPs — they aren't "replies" in the conversation
 * sense the user is tracking their own involvement in. */
.post-block.is-own {
  border-left: 3px dashed rgba(221, 0, 0, .8);
  padding-left: 4px;            /* compensate for the 2px thicker border */
}
/* A reply to one of the signed-in user's posts. Solid left border.
 * Also excluded for OPs (OPs don't have a parent in the thread). */
.post-block.is-replying-to-you {
  border-left: 3px solid rgba(221, 0, 0, .8);
  padding-left: 4px;
}
.post-block.is-dm {
  background-color: #dbf0d6;
  border-color: #aecfa8;
}
.post-dm-badge {
  position: absolute;
  top: 4px;
  right: 6px;
  color: #4a7a44;
  font-size: 13px;
  line-height: 1;
  pointer-events: none;
}
/* The post block is width:fit-content, so on short posts its right edge sits
   right where the badge floats. Reserve room on the head's first line so the
   No./post-id/reply-from links never slide under the badge. */
.post-block.has-vis-badge .post-head { padding-right: 24px; }
.post-reply-to .post-mentions-toggle {
  margin-left: 2px;
  color: var(--red);
  vertical-align: center;
}
.post-mentions-toggle {
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1;
  color: var(--red);
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  display: inline-block;
  transition: transform 0.1s ease;
  vertical-align: baseline;
}
.post-mentions-toggle:hover { color: #ff2a2a; }
.post-mentions-toggle:focus-visible { outline: 1px dotted var(--red); outline-offset: 2px; }
.post-mentions-toggle.is-open { transform: rotate(90deg); }
.post-mentions-toggle i { display: inline-block; }
/* Inline toggle for posts without a reply-to line (rare OPs with mentions) */
.post-body > .post-mentions-toggle {
  margin-right: 2px;
  font-size: 12px;
}

/* ---- media in thread view ---- */
.post-media {
  margin: 4px 16px 8px 0;
  float: left;
  clear: left;
}
.post-media .file-info {
  display: block;
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--fg-dim);
  margin-bottom: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 420px;
}
.post-media .file-info .file-link {
  color: var(--link);
  text-decoration: underline;
}
.post-media .file-info .file-link:hover {
  color: var(--red);
}

/* OP image: constrained (4chan style — not full width) */
.post-media .op-image {
  max-width: 250px;
  max-height: 250px;
  display: block;
  cursor: pointer;
  filter: drop-shadow(var(--shadow-img));
}

/* Reply thumbnail: small, expands on click (4chan-x behavior) */
.post-media .reply-thumb {
  max-width: 125px;
  max-height: 125px;
  display: block;
  filter: drop-shadow(var(--shadow-img));
  cursor: pointer;
}
.post-media .reply-thumb.expanded {
  max-width: 100%;
  max-height: 600px;
}

/* 4chan-x overlay image (hover preview) — the expanded image that pops
 * up next to the cursor when hovering a post thumbnail. The JS sets
 * style.left / style.top imperatively based on the pointer position, so
 * the element needs `position: fixed` (or absolute relative to a fixed
 * ancestor) for those to take effect; otherwise the image just flows
 * with the document and the inline coordinates are silently ignored,
 * causing the overlay to spawn at whatever natural Y the rest of the
 * body content leaves for it. */
.post-overlay-img,
.post-overlay-video {
  position: fixed;
  z-index: 150;
  pointer-events: none;
  max-width: calc(100vw - 16px);
  max-height: calc(100vh - 16px);
  width: auto;
  height: auto;
  object-fit: contain;
  box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.3);
}

/* Video attachments (collapsed muted preview + expanded player) */
.post-media.post-media-video {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.post-media.post-media-video .file-info {
  display: flex;
  align-items: baseline;
  gap: 8px;
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}

.post-video-collapsed-media {
  display: block;
  cursor: pointer;
  background: #000;
  filter: drop-shadow(var(--shadow-img));
}

.post-video-player {
  display: block;
  max-width: min(100%, 760px);
  max-height: min(72vh, 700px);
  width: auto;
  height: auto;
  background: #000;
  filter: drop-shadow(var(--shadow-img));
}
.post-video-player[hidden] {
  display: none !important;
}

.post-video-contract {
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--link);
  text-decoration: none;
  cursor: pointer;
}
.post-video-contract:hover {
  color: var(--red);
  text-decoration: underline;
}
.post-video-contract[hidden] {
  display: none !important;
}

.post-video-fallback {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-faint);
  background: var(--bg);
  border: 1px dashed var(--border);
}
.post-video-fallback.is-op {
  width: 250px;
  height: 180px;
}
.post-video-fallback.is-reply {
  width: 125px;
  height: 95px;
}

.post-media.post-media-audio {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
.audio-placeholder {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: var(--bg);
  border: 1px dashed var(--border);
  color: var(--fg-dim);
  font-size: 22px;
}
.audio-placeholder.is-op {
  width: 250px;
  height: 140px;
}
.audio-placeholder.is-reply {
  width: 125px;
  height: 80px;
}
.audio-mime-label {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
}
.post-audio-player {
  display: block;
  height: 30px;
  margin: 6px 0 4px;
}

.post-body {
  font-size: 14px;
  line-height: 1.5;
  color: var(--fg);
  overflow-wrap: anywhere;
  margin: 0 40px 13px;
  display: flow-root;          /* avoid the preceding media float without
                                  clipping enlarged inline emoji */
  overflow: visible;
}
.post-body p { margin: 0 0 0.5em 0; }
.post-body p:last-child { margin-bottom: 0; }
.post-body img {
  max-width: 100%;
  max-height: 480px;
  display: block;
  margin: 4px 0;
  filter: drop-shadow(var(--shadow-img));
}
.post-body img.custom-emoji {
  max-width: none;
  max-height: none;
  display: inline-block;
  margin: 0;
  filter: none;
}
.post-body a { color: var(--link); }

/* ---- inline media embeds (4chan-x style) in post bodies ---- */
.media-embed {
  display: block;
  margin: 4px 0;
}
.media-embed-line {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: var(--font-mono);
  font-size: 12px;
}
.media-embed-icon { color: var(--fg-dim); }
.media-embed[data-kind="youtube"] .media-embed-icon { color: #ff0000; }
.media-embed[data-kind="peertube"] .media-embed-icon { color: #f1680d; }
.media-embed-link {
  color: var(--link);
  word-break: break-all;
  min-width: 0;
}
.media-embed-link:hover { text-decoration: underline; }
.media-embed-toggle {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  white-space: nowrap;
}
.media-embed-toggle:hover { color: var(--link); text-decoration: underline; }
.media-embed-container { display: block; margin-top: 6px; }
.media-embed-container[hidden] { display: none; }
.media-embed-container iframe,
.media-embed-container video {
  max-width: 100%;
  max-height: 70vh;
  display: block;
  border: 0;
}
.media-embed-container audio { width: 100%; max-width: 560px; }

/* ---- polls ---- */
.post-poll {
  margin: 0 40px 13px;
  font-size: 14px;
  /* The post block is width:fit-content, so the poll needs an explicit width or
     it collapses to its longest option label and the result bars get squished.
     Pin a sensible width (capped to the available space on narrow screens). */
  width: 320px;
  max-width: 100%;
  /* Flow with the post text instead of as a block. The OP image is floated
     left; a block-level poll would place its box up beside the float (under
     the image) rather than after the text. inline-block makes it wrap to the
     next line below the floated image, sitting under the post content. */
  display: inline-block;
}
.post-poll .poll-options {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  /* The post-block is width:fit-content, so a flex container with width:auto
     resolves to shrink-to-fit and ignores .post-poll's declared width — the
     option rows then collapse to their longest label and the result bars get
     squished. Fill the parent so the bars span the full poll width. */
  width: 100%;
}
.post-poll .poll-option { margin: 0; }
/* Interactive (still votable) */
.poll-choice {
  display: flex;
  align-items: center;
  gap: 6px;
  width: 100%;             /* see .post-poll .poll-options: fill the poll width */
  padding: 3px 6px;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--bg-elev);
  cursor: pointer;
}
.poll-choice:hover { background: var(--bg-hover); }
.poll-choice input { margin: 0; cursor: pointer; }
/* Results view */
.poll-result {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;             /* see .post-poll .poll-options: fill the poll width */
  padding: 3px 6px;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--bg-elev);
}
.poll-result-bar {
  position: absolute;
  inset: 0 auto 0 0;
  background: #c5cdea;
  z-index: 0;
  transition: width 0.3s ease;
}
.poll-result.is-leading .poll-result-bar { background: #a9b6e4; }
.poll-result.is-own .poll-result-bar { background: rgb(214, 186, 208); }
.poll-result-label,
.poll-result-pct { position: relative; z-index: 1; }
.poll-result-pct { font-variant-numeric: tabular-nums; color: var(--fg); opacity: 0.8; }
.poll-check { color: var(--accent); }
.poll-vote-btn {
  margin-top: 6px;
  padding: 2px 12px;
  font-size: 13px;
  border: 1px solid var(--border);
  border-radius: 3px;
  background: var(--bg-elev);
  cursor: pointer;
}
.poll-vote-btn:hover:not(:disabled) { background: var(--bg-hover); }
.poll-vote-btn:disabled { opacity: 0.6; cursor: default; }
.poll-footer {
  margin-top: 5px;
  font-size: 12px;
  color: var(--fg);
  opacity: 0.65;
}
/* OP polls align flush-left like the OP body/action row. */
.post-block.is-op .post-poll { margin-left: 0; }
/* A poll post needs the body column at least as wide as the poll (320px) so the
   inline-block poll has room to sit beside the floated OP image, under the
   text. Without this, a short-text post leaves the poll wrapping below the
   image. Scoped via :has() so only posts that actually contain a poll widen —
   compact / inline-quote posts are unaffected. */
.post-block:has(.post-poll) .post-body { min-width: 320px; }
.post-body blockquote {
  display: block;
  border-left: none;
  margin-block-start: 1em;
  margin-block-end: 1em;
  margin-inline-start: 40px;
  margin-inline-end: 40px;
  padding: 0;
  unicode-bidi: isolate;
  color: #789922;                  /* 4chan greentext color */
  font-weight: 400;
}
.post-body blockquote a {
  color: var(--red);               /* >>reply links in red like 4chan */
  text-decoration: none;
}
.post-body blockquote a:hover {
  text-decoration: underline;
}
.post-body code, .post-body pre {
  font-family: var(--font-mono);
  background: var(--bg);
  padding: 1px 4px;
  border-radius: 1px;
  font-size: 13px;
}
.post-block .spoiler {
  color: var(--fg-faint);
  font-style: italic;
  font-size: 13px;
  margin-bottom: 4px;
}
/* ---- emoji reactions row (above .post-foot) ---- */
.post-reactions {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  align-items: center;
  margin: 2px 0 0;
  justify-content: flex-end;
  clear: both;                     /* sit below floated .post-media, not beside it */
  min-height: 0;                   /* allow flex shrink when empty */
}
.post-reactions:empty { display: none; }   /* no row at all when no reactions */
.post-reaction-btn {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  background-color: var(--bg);
  border: 0;
  border-radius: 0;
  padding: 2px 8px 2px 6px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  line-height: 1.2;
  user-select: none;
}
.post-reaction-btn:hover:not(:disabled) {
  background: var(--bg-hover);
  color: var(--red);
}
.post-reaction-btn:hover:not(:disabled) .post-reaction-count { color: var(--red); }
.post-reaction-btn:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}
.post-reaction-btn.is-mine {
  background: #fff0f0;
  color: #b30000;
}
.post-reaction-btn.is-mine:hover:not(:disabled) {
  background: #ffe2e2;
  color: var(--red);
}
.post-reaction-emoji {
  display: inline-block;
  width: 1.1em;
  height: 1.1em;
  vertical-align: -0.22em;
  object-fit: contain;
  flex-shrink: 0;
}
.post-reaction-emoji-unicode {
  display: inline-block;
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
  font-size: 14px;
  line-height: 1;
  flex-shrink: 0;
}
.post-reaction-count {
  font-variant-numeric: tabular-nums;
  color: var(--fg-faint);
}
.post-reaction-btn.is-mine .post-reaction-count {
  color: #b30000;
  font-weight: 700;
}

.post-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  width: 100%;
  margin-top: 6px;
  clear: both;                     /* sit below floated .post-media, not beside it */
}
.post-foot-owner,
.post-foot-primary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.post-foot-primary { margin-left: auto; }
.post-action {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  background: transparent;
  border: 0;
  border-radius: 1px;
  padding: 2px 6px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  line-height: 1;
}
.post-action:hover:not(:disabled) {
  background: var(--bg-hover);
  color: var(--red);
}
.post-action.is-liked {
  color: var(--red);
}
.post-action.is-liked:hover:not(:disabled) {
  color: #b30000;
}
.post-action.is-reposted {
  color: #0f6f00;
}
.post-action.is-reposted:hover:not(:disabled) {
  color: #0c5900;
}
.post-action.is-bookmarked {
  color: #9a7200;
}
.post-action.is-bookmarked:hover:not(:disabled) {
  color: #7d5d00;
}
.post-action.is-watching,
.post-action.is-watching:hover:not(:disabled) {
  color: var(--red);
}
.post-action-delete:hover:not(:disabled) {
  color: #b30000;
}
.post-action-count {
  font-variant-numeric: tabular-nums;
}
.post-foot .ext { margin-left: auto; color: var(--fg-dim); }

/* ---- inline/stacked toggled post previews (4chan-x-ish) ---- */
.inline-stack {
  margin: 8px 0 2px 12px;
  padding-left: 8px;
  border-left: 1px dashed #B7C5D9;
}
.inline-stack.is-reply-to-stack {
  margin-top: 4px;
  margin-bottom: 4px;
}
/* Quote post: a nested block under the content, distinguished from a reply-to
   expansion by a solid border and a small label. */
.inline-stack.is-quote-stack {
  margin-top: 6px;
  border-left-style: solid;
}
.inline-stack.is-quote-stack::before {
  content: "\21AA quote";
  display: block;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--fg-faint);
  margin-bottom: 2px;
}
.inline-post + .inline-post {
  margin-top: 6px;
}
.post-block.is-inline {
  max-width: calc(100% - 8px);
  background: #dbe2f8;
}

.post-block.is-new-reply {
  outline: 2px solid var(--red);
  outline-offset: 1px;
}

/* A post whose No. link has been followed — clicked in-thread, or opened via a
   permalink to a reply. Painted permanently so the linked-to post stays easy
   to spot. Placed after is-op/is-dm/is-inline so it wins the background. */
.post-block.is-linked {
  background: rgb(214, 186, 208);
}

/* 4chan-x style "unread line": marks where posts new since the last visit or
   refresh begin in a thread. */
.replies-wrap > .unread-line {
  border: none;
  border-top: 1px solid var(--red);
  margin: -3px 0 3px;
  width: 100%;
}

/* ---- >>reply links (quotelinks) inside post bodies ---- */
.post-body .quotelink {
  color: var(--red);
  text-decoration: underline;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: inherit;
}
.post-body .quotelink:hover {
  color: #f00;
}

/* ---- post avatar (same as post-head) ---- */
.post-media.is-avatar-banner {
  float: left;
  clear: left;
  margin: 4px 20px 4px 0;
  width: 200px;
  height: 150px;
  aspect-ratio: 4 / 3;
  max-height: none;
  background: var(--bg-elev);
  filter: drop-shadow(var(--shadow-img));
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}
.post-media.is-avatar-banner .banner-bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  filter: brightness(0.55) saturate(0.9);
}
.post-media.is-avatar-banner .thumb-avatar {
  position: relative;
  z-index: 1;
  width: 55%;
  aspect-ratio: 1;
  border-radius: 50%;
  object-fit: cover;
  border: 2px solid rgba(255,255,255,0.4);
  box-shadow: 0 2px 6px rgba(0,0,0,0.4);
}
/* Thread-view OP composite and the profile card avatar open the gallery
   lightbox on click. Not the anonymous placeholder — that click is a no-op. */
.post-media.is-avatar-banner:not(.is-anonymous) .thumb-avatar,
.post-media.is-avatar-banner:not(.is-anonymous) .banner-bg,
#profile-bio .profile-avatar {
  cursor: pointer;
}
.post-media.is-avatar-banner .thumb-avatar-fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elev);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 32px;
  font-weight: 600;
}

/* ---- greentext (text lines starting with >, not links) ---- */
/* Not scoped to .post-body: the catalog card body and hover preview format
   content through the same pipeline and need the same green. */
.greentext {
  color: #789922;
}

/* ---- post preview popup (4chan-x hover preview) ---- */
.post-preview {
  display: none;
  position: fixed;
  z-index: 200;
  max-width: 500px;
  max-height: 400px;
  overflow: auto;
  background: #D6DAF0;
  border: 2px solid #B7C5D9;
  box-shadow: 2px 2px 6px rgba(0,0,0,0.25);
  pointer-events: none;
  padding: 6px 8px;
  font-size: 13px;
  line-height: 1.4;
}
.post-preview.is-visible {
  display: block;
}
.post-preview .ppv-head {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--fg-dim);
  margin-bottom: 4px;
}
.post-preview .ppv-head .ppv-name {
  color: #117743;
  font-weight: 700;
}
.post-preview .ppv-head .ppv-id {
  color: var(--red);
  font-family: var(--font-mono);
}
.post-preview .ppv-body {
  color: var(--fg);
  word-break: break-word;
}
.post-preview .ppv-body p { margin: 0 0 0.5em; }
.post-preview .ppv-body p:last-child { margin-bottom: 0; }

/* ---- profile hover card (shares the post-preview look) ---- */
.profile-preview {
  display: none;
  position: fixed;
  z-index: 200;
  width: 320px;
  max-width: 90vw;
  max-height: 400px;
  overflow: hidden;
  background: #D6DAF0;
  border: 2px solid #B7C5D9;
  box-shadow: 2px 2px 6px rgba(0,0,0,0.25);
  pointer-events: none;
  padding: 8px 10px;
  font-size: 13px;
  line-height: 1.4;
}
.profile-preview.is-visible { display: block; }
/* Compact tweaks for the reused .profile-card markup inside the popup. */
.profile-preview .profile-card { gap: 10px; }
.profile-preview .profile-avatar { width: 56px; height: 56px; }
.profile-preview .profile-display-name { font-size: 14px; }
.profile-preview .profile-note {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Pointer-following account list for likes, reposts and emoji reactions. */
.activity-hover {
  display: none;
  position: fixed;
  z-index: 161;
  width: max-content;
  min-width: 150px;
  max-width: min(280px, calc(100vw - 16px));
  max-height: min(360px, calc(100vh - 16px));
  overflow: hidden auto;
  padding: 5px 7px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.3);
  font: 11px var(--font-mono);
  pointer-events: none;
}
.activity-hover.is-visible { display: block; }
.activity-hover-title {
  margin-bottom: 4px;
  padding-bottom: 3px;
  color: var(--fg-dim);
  border-bottom: 1px dashed var(--border-soft);
  font-weight: 700;
}
.activity-hover-account {
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
  padding: 2px 0;
}
.activity-hover-account-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.activity-hover-name { color: #117743; font-weight: 700; }
.activity-hover-handle { color: var(--fg-faint); margin-left: 4px; }
.activity-hover-state { color: var(--fg-faint); padding: 3px 0; }

/* ---- emoji picker (4chan-x style, no border-radius) ---- */
.emoji-picker {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 130;
  align-items: flex-start;
  justify-content: center;
  padding-top: 8vh;
}
.emoji-picker[hidden] { display: none !important; }
.emoji-picker.is-open { display: flex; }
.emoji-picker-box {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  width: 420px;
  max-width: calc(100% - 24px);
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 24px rgba(0,0,0,0.4);
}
.emoji-picker-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 12px;
  border-bottom: 1px solid var(--border-soft);
  background: #D6DAF0;
}
.emoji-picker-head h2 {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.emoji-picker-close,
.emoji-picker-refresh {
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 3px 6px;
  cursor: pointer;
}
.emoji-picker-close:hover,
.emoji-picker-refresh:hover { background: var(--bg-hover); color: var(--fg); }

.emoji-picker-search-row {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--border-soft);
  background: var(--bg);
}
.emoji-picker-search {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--bg-elev);
  color: var(--fg);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 4px 6px;
  outline: none;
}
.emoji-picker-search:focus { border-color: var(--accent); }
.emoji-picker-status {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  white-space: nowrap;
  flex-shrink: 0;
}

.emoji-picker-body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 4px;
  min-height: 0;
  max-height: 56vh;
}
.emoji-picker-body .empty {
  padding: 30px 12px;
  text-align: center;
  color: var(--fg-faint);
  font-family: var(--font-mono);
  font-size: 12px;
}

.emoji-picker-section {
  margin-bottom: 4px;
}
.emoji-picker-section-title {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 700;
  color: var(--fg-faint);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  padding: 6px 4px 2px;
  border-bottom: 1px dashed var(--border-soft);
  margin-bottom: 4px;
}
.emoji-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: 2px;
}
.emoji-picker-cell {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 4px 2px 3px;
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--fg-dim);
  min-height: 56px;
  text-align: center;
  line-height: 1.1;
  user-select: none;
}
.emoji-picker-cell:hover {
  background: var(--bg-hover);
  color: var(--fg);
  border-color: var(--border);
}
.emoji-picker-cell:active {
  background: #c0c8e0;
}
.emoji-picker-cell-img,
.emoji-picker-cell-unicode {
  display: block;
  width: 24px;
  height: 24px;
  object-fit: contain;
  flex-shrink: 0;
}
.emoji-picker-cell-unicode {
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
  font-size: 22px;
  line-height: 24px;
  text-align: center;
}
.emoji-picker-cell-name {
  width: 100%;
  font-size: 9px;
  color: var(--fg-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0 2px;
}
.emoji-picker-cell:hover .emoji-picker-cell-name { color: var(--fg-dim); }
.emoji-picker-favorites { margin-bottom: 2px; }
.emoji-picker-favorites-edit {
  display: block;
  margin: 3px auto 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--link);
  font: 10px var(--font-mono);
  text-decoration: underline;
  cursor: pointer;
}
.emoji-picker-cell.is-editing {
  border-style: dotted;
  border-color: var(--fg-faint);
}
.emoji-picker-cell.is-editing > :not(.emoji-picker-cell-edit-prompt) {
  filter: grayscale(1);
  opacity: 0.18;
}
.emoji-picker-cell.is-replacing {
  border-color: var(--accent);
  background: var(--bg-hover);
}
.emoji-picker-cell-edit-prompt {
  position: absolute;
  inset: 2px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--fg-dim);
  font-size: 9px;
  line-height: 1.15;
  text-align: center;
  white-space: normal;
}

.emoji-picker-help {
  padding: 4px 10px 6px;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--fg-faint);
  border-top: 1px solid var(--border-soft);
  background: var(--bg);
  min-height: 14px;
}
.emoji-picker-help code {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  padding: 0 3px;
}

/* ---- compose modal (4chan-x style, no border-radius) ---- */
.compose-modal {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 120;
  align-items: flex-start;
  justify-content: center;
  padding-top: 8vh;
}
.compose-modal[hidden] { display: none !important; }
.compose-modal.is-open { display: flex; }
.compose-modal-box {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  width: 520px;
  max-width: calc(100% - 24px);
  max-height: 84vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 24px rgba(0,0,0,0.4);
}
.compose-modal-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 12px;
  border-bottom: 1px solid var(--border-soft);
  background: #D6DAF0;
}
.compose-modal-head h2 {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.compose-modal-close {
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 3px 6px;
  cursor: pointer;
}
.compose-modal-close:hover { background: var(--bg-hover); color: var(--fg); }

.compose-form {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 1 auto;
}
.compose-reply-to {
  font-family: var(--font-mono);
  font-size: 14px;
  line-height: 1.35;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border-soft);
  background: var(--bg);
}
.compose-reply-to .reply-to-link {
  color: var(--red);
  text-decoration: underline;
}
.compose-reply-to .reply-to-link:hover { color: #ff2a2a; }

.compose-subject {
  font-family: var(--font-sans);
  font-size: 14px;
  background: var(--bg-elev);
  color: var(--fg);
  border: 0;
  border-bottom: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 8px 12px;
  outline: none;
  box-sizing: border-box;
}
.compose-subject:focus { background: #fff; }

.compose-content {
  flex: 1 1 auto;
  min-height: 140px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.45;
  background: var(--bg-elev);
  color: var(--fg);
  border: 0;
  border-bottom: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 10px 12px;
  outline: none;
  resize: vertical;
  box-sizing: border-box;
}
.compose-content:focus { background: #fff; }

/* ---- compose autocomplete (typeahead for :emoji: and @mention) ----
 * Rendered as a position:fixed dropdown attached to document.body, placed
 * at the caret by getCaretCoordinates(). */
.compose-autocomplete {
  position: fixed;
  z-index: 200;                 /* above the compose modal (z-index 120) */
  min-width: 220px;
  max-width: 320px;
  max-height: 240px;
  overflow-y: auto;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
  font-family: var(--font-sans);
  font-size: 13px;
  padding: 2px;
}
.compose-autocomplete[hidden] { display: none; }
.compose-autocomplete-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 3px 8px;
  cursor: pointer;
  color: var(--fg);
  border-radius: 0;
}
.compose-autocomplete-row.is-active,
.compose-autocomplete-row:hover {
  background: var(--bg-hover);
}
.compose-autocomplete-emoji {
  width: 18px;
  height: 18px;
  object-fit: contain;
  flex: 0 0 auto;
}
.compose-autocomplete-label {
  font-family: var(--font-mono);
  font-size: 12px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.compose-autocomplete-avatar {
  width: 20px;
  height: 20px;
  object-fit: cover;
  flex: 0 0 auto;
}
.compose-autocomplete-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.2;
}
.compose-autocomplete-name {
  font-size: 13px;
  color: var(--fg);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.compose-autocomplete-name .custom-emoji { vertical-align: -2px; height: 14px; width: 14px; }
.compose-autocomplete-acct {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.compose-attachments {
  list-style: none;
  margin: 0;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border-soft);
  background: var(--bg);
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.compose-attachments:empty,
.compose-attachments[hidden] { display: none; }
.compose-attachment {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 4px 2px 4px;
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-dim);
  max-width: 220px;
}
.compose-attachment.is-uploading { opacity: 0.6; }
.compose-attachment.is-failed { border-color: var(--red); color: var(--red); flex-wrap: wrap; }
.compose-attachment-thumb {
  width: 24px;
  height: 24px;
  object-fit: cover;
  background: var(--bg);
  flex-shrink: 0;
}
.compose-attachment-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 140px;
}
.compose-attachment-error {
  flex-basis: 100%;
  white-space: normal;
  word-break: break-word;
  line-height: 1.25;
}
.compose-attachment-remove {
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1;
  color: var(--fg-dim);
  background: transparent;
  border: 0;
  padding: 0 2px;
  cursor: pointer;
}
.compose-attachment-remove:hover { color: var(--red); }

.compose-status {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-dim);
  padding: 4px 10px 0;
  min-height: 16px;
}
.compose-status.is-error { color: #b00; }
.compose-status.is-uploading { color: var(--accent); }

.compose-toolbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px 8px;
  background: var(--bg);
}
.compose-nsfw {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-family: var(--font-sans);
  font-size: 11px;
  color: var(--fg-dim);
  cursor: pointer;
  user-select: none;
  margin-right: 4px;
  padding: 2px 4px;
  border: 1px solid var(--border-soft);
  border-radius: 0;
  background: var(--bg-elev);
}
.compose-nsfw:hover { background: var(--bg-hover); }
.compose-nsfw input { margin: 0; cursor: pointer; }
.compose-nsfw input:checked + span { color: #b30000; font-weight: 700; }

.compose-toolbar-btn {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 4px 6px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.compose-toolbar-btn:hover:not(:disabled) {
  background: var(--bg-hover);
  color: var(--fg);
  border-color: var(--border);
}
.compose-toolbar-btn:disabled { opacity: 0.4; cursor: not-allowed; }

/* Visibility scope picker (Public / Followers / Direct). */
.compose-visibility { position: relative; display: inline-flex; }
.compose-visibility-menu {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 0;
  margin: 0;
  padding: 2px;
  list-style: none;
  min-width: 140px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  box-shadow: 0 2px 12px rgba(0,0,0,0.3);
  z-index: 10;
}
.compose-visibility-menu li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--fg);
  padding: 5px 8px;
  cursor: pointer;
  white-space: nowrap;
}
.compose-visibility-menu li:hover { background: var(--bg-hover); }
.compose-visibility-menu li.is-selected { font-weight: 700; }
.compose-visibility-menu li i { width: 16px; text-align: center; color: var(--fg-dim); }

/* Direct messages get the same green hue used for DMs in thread view. */
.compose-modal.compose-is-direct .compose-modal-box {
  background: #dbf0d6;
  border-color: #aecfa8;
}
.compose-modal.compose-is-direct .compose-modal-head {
  background: #cfe8c9;
}
.compose-modal.compose-is-direct .compose-modal-head h2 { color: #2f6b29; }
.compose-modal.compose-is-direct .compose-toolbar { background: #d4ecce; }
.compose-modal.compose-is-direct .compose-visibility-btn {
  color: #2f6b29;
  border-color: #aecfa8;
}

/* ---- multi-attachment gallery ---- */
/* "Gallery" link centered under a multi-attachment post's thumbnail. */
.post-gallery-link {
  display: block;
  text-align: center;
  margin-top: 4px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--link);
  text-decoration: none;
  cursor: pointer;
}
.post-gallery-link:hover { color: var(--red); text-decoration: underline; }
.post-gallery-link i { margin-right: 4px; }
/* In the flex video/audio media boxes, stretch so text-align can center it. */
.post-media-video .post-gallery-link,
.post-media-audio .post-gallery-link { align-self: stretch; }

.gallery-modal {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 130;
  align-items: center;
  justify-content: center;
  padding: 4vh 16px;
}
.gallery-modal[hidden] { display: none !important; }
.gallery-modal.is-open { display: flex; }
.gallery-modal-box {
  position: relative;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  width: 1000px;
  max-width: 100%;
  height: 92vh;
  display: flex;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.5);
}
.gallery-modal-close {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 2;
  font-size: 14px;
  line-height: 1;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  padding: 4px 7px;
  cursor: pointer;
}
.gallery-modal-close:hover { background: var(--bg-hover); color: var(--fg); }

/* Left column of thumbnails. */
.gallery-thumbs {
  flex: 0 0 132px;
  overflow-y: auto;
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--bg);
  border-right: 1px solid var(--border-soft);
}
.gallery-thumb {
  display: block;
  width: 116px;
  height: 116px;
  padding: 0;
  border: 1px solid var(--border-soft);
  background: var(--bg-elev);
  cursor: pointer;
  overflow: hidden;
  flex: 0 0 auto;
}
.gallery-thumb:hover { border-color: var(--border); }
.gallery-thumb.is-active { border-color: var(--accent); outline: 1px solid var(--accent); }
.gallery-thumb-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.gallery-thumb-video { position: relative; display: block; width: 100%; height: 100%; }
.gallery-thumb-play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 1em;
  height: 1em;
  font-size: 22px;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
  pointer-events: none;
}

/* Center stage: expanded media + file link underneath. */
.gallery-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  padding: 12px;
  gap: 8px;
}
.gallery-stage {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.gallery-stage-img,
.gallery-stage-video {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.gallery-stage-audio {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.gallery-fileinfo {
  flex: 0 0 auto;
  text-align: center;
  white-space: normal;
}

/* Iconographic placeholder for audio / PDF / undisplayable files. */
.gallery-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  height: 100%;
  color: var(--fg-faint);
  background: var(--bg);
}
.gallery-placeholder i { font-size: 30px; }
.gallery-placeholder-ext {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.5px;
  color: var(--fg-dim);
}
.gallery-stage-placeholder {
  min-width: 220px;
  min-height: 220px;
  border: 1px solid var(--border-soft);
}
.gallery-stage-placeholder i { font-size: 64px; }
.gallery-stage-placeholder .gallery-placeholder-ext { font-size: 14px; }

.compose-spacer { flex: 1; }
.compose-count {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-faint);
  font-variant-numeric: tabular-nums;
  padding: 0 4px;
}
.compose-count.is-over { color: var(--red); font-weight: 700; }

.compose-submit {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 700;
  background: var(--accent);
  color: white;
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: 5px 14px;
  cursor: pointer;
}
.compose-submit:hover:not(:disabled) { background: #0a3a72; }
.compose-submit:disabled {
  background: var(--bg-elev);
  color: var(--fg-faint);
  border-color: var(--border);
  cursor: not-allowed;
}
.compose-submit.is-loading { opacity: 0.6; cursor: progress; }

/* A toolbar button whose feature is currently attached (e.g. a poll). */
.compose-toolbar-btn.is-active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.compose-toolbar-btn.is-active:hover:not(:disabled) { background: #0a3a72; color: #fff; }

/* ---- compose poll chip (shown when a poll is attached) ---- */
.compose-poll-chip {
  display: flex;
  align-items: stretch;
  gap: 4px;
  padding: 6px 10px;
  border-bottom: 1px solid var(--border-soft);
  background: var(--bg);
}
.compose-poll-chip[hidden] { display: none; }
.compose-poll-chip-edit {
  flex: 1 1 auto;
  text-align: left;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 4px 8px;
  cursor: pointer;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.compose-poll-chip-edit:hover { background: var(--bg-hover); border-color: var(--border); }
.compose-poll-chip-edit i { color: var(--accent); margin-right: 4px; }
.compose-poll-chip-remove {
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 4px 8px;
  cursor: pointer;
}
.compose-poll-chip-remove:hover { background: var(--bg-hover); color: #b00; border-color: var(--border); }

/* ---- poll composer dialog (sits above the compose modal) ---- */
.poll-composer {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 140;
  align-items: flex-start;
  justify-content: center;
  padding-top: 10vh;
}
.poll-composer[hidden] { display: none !important; }
.poll-composer.is-open { display: flex; }
.poll-composer-box {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  width: 380px;
  max-width: calc(100% - 24px);
  max-height: 80vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
.poll-composer-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 12px;
  border-bottom: 1px solid var(--border-soft);
  background: #D6DAF0;
}
.poll-composer-head h2 {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0;
  flex: 1;
}
.poll-composer-close {
  font-size: 14px;
  color: var(--fg-dim);
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 4px 6px;
}
.poll-composer-close:hover { background: var(--bg-hover); color: var(--fg); }
.poll-composer-body {
  padding: 12px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.poll-composer-options {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.poll-composer-option {
  display: flex;
  align-items: center;
  gap: 6px;
}
.poll-composer-option-input {
  flex: 1 1 auto;
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 5px 8px;
  outline: none;
  box-sizing: border-box;
}
.poll-composer-option-input:focus { background: #fff; border-color: var(--accent); }
.poll-composer-option-remove {
  font-size: 12px;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 5px 8px;
  cursor: pointer;
  flex-shrink: 0;
}
.poll-composer-option-remove:hover:not(:disabled) { background: var(--bg-hover); color: #b00; }
.poll-composer-option-remove:disabled { opacity: 0.35; cursor: not-allowed; }
.poll-composer-add {
  align-self: flex-start;
  font-family: var(--font-sans);
  font-size: 13px;
  color: var(--accent);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 4px 10px;
  cursor: pointer;
}
.poll-composer-add:hover:not(:disabled) { background: var(--bg-hover); }
.poll-composer-add:disabled { opacity: 0.4; cursor: not-allowed; }
.poll-composer-settings {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 4px;
  border-top: 1px solid var(--border-soft);
  font-family: var(--font-sans);
  font-size: 13px;
}
.poll-composer-multiple {
  display: flex;
  align-items: center;
  gap: 6px;
  cursor: pointer;
}
.poll-composer-duration-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.poll-composer-duration {
  font-family: var(--font-sans);
  font-size: 13px;
  padding: 4px 6px;
  border: 1px solid var(--border);
  border-radius: 0;
  background: var(--bg-elev);
  color: var(--fg);
}
.poll-composer-status { font-size: 12px; min-height: 14px; color: var(--fg-dim); }
.poll-composer-status.is-error { color: #b00; }
.poll-composer-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border-top: 1px solid var(--border-soft);
  background: var(--bg);
}
.poll-composer-spacer { flex: 1 1 auto; }
.poll-composer-remove {
  font-family: var(--font-sans);
  font-size: 12px;
  color: #b00;
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 5px 12px;
  cursor: pointer;
}
.poll-composer-remove:hover { background: var(--bg-hover); }
.poll-composer-cancel {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 5px 12px;
  cursor: pointer;
}
.poll-composer-cancel:hover { background: var(--bg-hover); }
.poll-composer-save {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: 5px 14px;
  cursor: pointer;
}
.poll-composer-save:hover { background: #0a3a72; }

/* ---- create-board dialog (opened from the [+] in the board nav) ---- */
.board-create {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 140;
  align-items: flex-start;
  justify-content: center;
  padding-top: 10vh;
}
.board-create[hidden] { display: none !important; }
.board-create:not([hidden]) { display: flex; }
.board-create-box {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  width: 380px;
  max-width: calc(100% - 24px);
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
.board-create-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 12px;
  border-bottom: 1px solid var(--border-soft);
  background: #D6DAF0;
}
.board-create-head h2 {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0;
  flex: 1;
}
.board-create-close {
  font-size: 14px;
  color: var(--fg-dim);
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 4px 6px;
}
.board-create-close:hover { background: var(--bg-hover); color: var(--fg); }
.board-create-form {
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-family: var(--font-sans);
  font-size: 13px;
}
.board-create-form input {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 5px 8px;
  outline: none;
  box-sizing: border-box;
}
.board-create-form input:focus { background: #fff; border-color: var(--accent); }
.board-create-form input:disabled { color: var(--fg-dim); background: var(--bg-hover); }
.board-create-form textarea {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 5px 8px;
  outline: none;
  resize: vertical;
}
.board-create-form textarea:focus { background: #fff; border-color: var(--accent); }
.board-create-optional { color: var(--fg-dim); font-weight: 400; }
.board-create-hint { color: var(--fg-dim); font-size: 12px; }
.board-create-status { font-size: 12px; min-height: 1em; }
.board-create-status.is-error { color: #b00; }
.board-create-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding-top: 4px;
}
.board-create-cancel {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 5px 12px;
  cursor: pointer;
}
.board-create-cancel:hover { background: var(--bg-hover); }
.board-create-save {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: 5px 14px;
  cursor: pointer;
}
.board-create-save:hover:not(:disabled) { background: #0a3a72; }
.board-create-save:disabled { opacity: 0.5; cursor: not-allowed; }

/* ---- subscribe (Mitra monero-subscription) modal ---- */
.subscribe-modal {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 140;
  align-items: flex-start;
  justify-content: center;
  padding-top: 10vh;
}
.subscribe-modal[hidden] { display: none !important; }
.subscribe-modal:not([hidden]) { display: flex; }
.subscribe-modal-box {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  width: 380px;
  max-width: calc(100% - 24px);
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
.subscribe-modal-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 12px;
  border-bottom: 1px solid var(--border-soft);
  background: #D6DAF0;
}
.subscribe-modal-head h2 {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0;
  flex: 1;
}
.subscribe-modal-close {
  font-size: 14px;
  color: var(--fg-dim);
  background: transparent;
  border: 0;
  cursor: pointer;
  padding: 4px 6px;
}
.subscribe-modal-close:hover { background: var(--bg-hover); color: var(--fg); }
.subscribe-modal-body {
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-family: var(--font-sans);
  font-size: 13px;
}
.subscribe-modal-body .empty { color: var(--fg-dim); text-align: center; padding: 8px 0; }
.subscribe-price {
  font-size: 16px;
  font-weight: 700;
}
.subscribe-price .price-subtext { font-size: 13px; font-weight: 400; color: var(--fg-dim); }
.subscribe-status-line { color: var(--fg-dim); }
.subscribe-pay-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
}
.subscribe-pay-row input[type="number"] {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  padding: 5px 8px;
  outline: none;
  width: 90px;
  box-sizing: border-box;
}
.subscribe-pay-row input[type="number"]:focus { background: #fff; border-color: var(--accent); }
.subscribe-pay-amount { margin-left: auto; }
.subscribe-modal-status { font-size: 12px; min-height: 1em; color: var(--fg-dim); }
.subscribe-modal-status.is-error { color: #b00; }
.subscribe-modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding-top: 2px;
}
.subscribe-modal-actions button {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: 5px 14px;
  cursor: pointer;
}
.subscribe-modal-actions button.secondary {
  font-weight: 400;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border);
}
.subscribe-modal-actions button:hover:not(:disabled) { background: #0a3a72; }
.subscribe-modal-actions button.secondary:hover:not(:disabled) { background: var(--bg-hover); }
.subscribe-modal-actions button:disabled { opacity: 0.5; cursor: not-allowed; }
.subscribe-invoice { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.subscribe-invoice .payment-header { width: 100%; text-align: center; }
.subscribe-invoice .payment-address {
  font-family: var(--font-mono, monospace);
  font-size: 11px;
  word-break: break-all;
  text-align: center;
  width: 100%;
  color: var(--fg);
}
.subscribe-invoice .invoice-status { color: var(--fg-dim); font-size: 12px; text-align: center; }
.subscribe-invoice .qr-wrapper {
  width: min(220px, 100%);
  margin: 0 auto;
}
.subscribe-invoice .qr-wrapper svg { width: 100%; height: auto; display: block; }
.start-thread.profile-subscribe { background: #2a6b2a; border-color: #2a6b2a; }
.start-thread.profile-subscribe:hover:not(:disabled) { background: #1a4f1a; border-color: #1a4f1a; }

/* ---- 4chan-x style watcher panel ---- */
.watcher-panel {
  position: fixed;
  z-index: 118;
  width: min(430px, calc(100vw - 8px));
  max-height: 72vh;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--bg-elev);
  box-shadow: 0 3px 12px rgba(0,0,0,0.25);
}

.watcher-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 5px;
  background: #D6DAF0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 12px;
}
.watcher-title { font-weight: 700; color: #0F4D92; }
.watcher-status { margin-left: auto; color: var(--fg-faint); font-size: 11px; }
.watcher-refresh,
.watcher-close {
  color: var(--fg-dim);
  text-decoration: none;
  line-height: 1;
}
.watcher-refresh:hover,
.watcher-close:hover { color: var(--red); }
.watcher-close { font-size: 16px; margin-left: 2px; }

.watcher-tabs {
  display: flex;
  border-bottom: 1px solid var(--border-soft);
  background: #f4f6ff;
}

.watcher-tab {
  border: 0;
  border-right: 1px solid var(--border-soft);
  background: transparent;
  color: var(--fg-dim);
  font-size: 12px;
  padding: 3px 7px;
  cursor: pointer;
}
.watcher-tab.is-active {
  background: var(--bg-elev);
  color: var(--fg);
  font-weight: 700;
}
.watcher-tab.has-unread {
  color: var(--red);
}

.watcher-toolbar {
  border-bottom: 1px solid var(--border-soft);
  padding: 3px 5px;
}
.watcher-toggle-current {
  font-size: 11px;
  border: 1px solid var(--border);
  background: var(--bg-elev);
  color: var(--fg);
  padding: 1px 6px;
  cursor: pointer;
}
.watcher-toggle-current:hover { background: var(--bg-hover); }

.watcher-content {
  max-height: calc(72vh - 62px);
  overflow: auto;
}
.watcher-inline-emoji {
  width: 14px;
  height: 14px;
  vertical-align: text-bottom;
  margin: 0 2px;
  transform-origin: center center;
  transition: transform .1s linear;
}
.watcher-pane[hidden] { display: none !important; }
.watcher-pane.is-active {
  display: block;
  width: 100%;
}

.watcher-row {
  display: flex;
  align-items: center;
  gap: 5px;
  width: 100%;
  padding: 2px 5px;
  border-bottom: 1px solid #eef2ff;
  font-size: 12px;
  line-height: 1.35;
}
.watcher-row:last-child { border-bottom: 0; }
.watcher-row.is-unread { background: #fff1f1; }

/* Unread notifications use color only. Keeping borders, padding and font
   weight identical prevents the line from shifting when it becomes read. */
.watcher-row-notif.is-unread {
  background: transparent;
}
.watcher-row-notif.is-unread .watcher-age,
.watcher-row-notif.is-unread .watcher-notif-user,
.watcher-row-notif.is-unread .watcher-notif-verb { color: var(--red); }
.watcher-row-notif:hover { background: #f4f6ff; }
.watcher-markread a { color: var(--fg-faint); }

.watcher-remove {
  color: var(--fg-dim);
  text-decoration: none;
  font-weight: 700;
  min-width: 10px;
  text-align: center;
}
.watcher-remove:hover { color: var(--red); }

.watcher-link {
  color: var(--fg);
  text-decoration: none;
  flex: 1;
  width: 100%;
  min-width: 0;
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
}
.watcher-link:hover { text-decoration: underline; }

.watcher-age {
  color: #4b5a79;
  flex: 0 0 auto;
}
.watcher-unread {
  color: var(--red);
  flex: 0 0 auto;
  min-width: 22px;
  text-align: right;
}
/* Notification line holds two links: the actor handle and the verb. The handle
   absorbs truncation (ellipsis) so the verb ("replied to (you)") stays readable. */
.watcher-sum {
  color: var(--fg);
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 5px;
}
.watcher-notif-user {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.watcher-notif-verb {
  flex: 0 0 auto;
  white-space: nowrap;
}
.watcher-notif-user,
.watcher-notif-verb {
  color: var(--fg);
  text-decoration: none;
}
a.watcher-notif-user:hover,
a.watcher-notif-verb:hover { text-decoration: underline; }
.watcher-request-actions {
  display: inline-flex;
  flex: 0 0 auto;
  gap: 3px;
}
.watcher-request-actions button {
  padding: 0 3px;
  border: 1px solid var(--border-soft);
  background: var(--bg-elev);
  color: var(--fg);
  font: 10px var(--font-sans);
  cursor: pointer;
}
.watcher-request-actions button:hover:not(:disabled) { background: var(--bg-hover); }
.watcher-request-actions button:disabled { color: var(--fg-faint); cursor: default; }

/* Emoji hover magnification (site-wide custom emoji + reaction emoji) */
.custom-emoji,
.post-reaction-emoji,
.watcher-inline-emoji {
  position: relative;
  transform-origin: center center;
  transition: transform .1s linear;
}
.custom-emoji:hover,
.post-reaction-emoji:hover,
.watcher-inline-emoji:hover {
  transform: scale(3);
  transition-delay: .2s;
  z-index: 1000;
}

.watcher-pager {
  border-top: 1px solid var(--border-soft);
  padding: 2px 0;
  text-align: center;
  font-size: 12px;
  line-height: 1.35;
}
.watcher-pager a {
  color: var(--link);
  text-decoration: none;
}
.watcher-pager a:hover { text-decoration: underline; }
.watcher-pager a.is-disabled {
  color: var(--fg-faint);
  pointer-events: none;
  text-decoration: none;
}

/* ---- config modal (tabbed, matches compose-modal aesthetic) ---- */
.config-modal {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  z-index: 125;             /* above compose (120) so the cog always wins */
  align-items: flex-start;
  justify-content: center;
  padding-top: 8vh;
}
.config-modal[hidden] { display: none !important; }
.config-modal.is-open { display: flex; }

.config-modal-box {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 0;
  width: 560px;
  max-width: calc(100% - 24px);
  max-height: 84vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
}
.config-modal-head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px 8px 6px 12px;
  border-bottom: 1px solid var(--border-soft);
  background: #D6DAF0;
}
.config-modal-head h2 {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  color: #0F4D92;
  margin: 0;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.config-modal-close {
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1;
  color: var(--fg-dim);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 3px 6px;
  cursor: pointer;
}
.config-modal-close:hover { background: var(--bg-hover); color: var(--fg); }

.config-modal-body {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 1 auto;
}
.config-tabs {
  display: flex;
  flex-direction: row;
  align-items: stretch;
  border-bottom: 1px solid var(--border-soft);
  background: var(--bg-elev);
  font-family: var(--font-sans);
  font-size: 12px;
}
.config-tab {
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 1.2;
  color: var(--fg-dim);
  background: transparent;
  border: 0;
  border-right: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 8px 14px;
  cursor: pointer;
  text-align: center;
}
.config-tab:hover { background: var(--bg-hover); color: var(--fg); }
.config-tab.is-active {
  color: var(--fg);
  background: var(--bg);
  font-weight: 700;
  box-shadow: inset 0 -2px 0 0 #0F4D92;
}

.config-panels {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  background: var(--bg);
}
.config-panel {
  padding: 14px 16px 16px;
}
.config-panel[hidden] { display: none; }
.config-panel:not(.is-active) { display: none; }
.config-panel.is-active { display: block; }

.config-group {
  margin-bottom: 16px;
}
.config-group:last-child { margin-bottom: 0; }
.config-group-title {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 700;
  color: var(--fg);
  margin-bottom: 4px;
}
.config-group-desc {
  font-family: var(--font-sans);
  font-size: 11px;
  color: var(--fg-dim);
  margin-bottom: 10px;
  line-height: 1.4;
}
.config-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}
.config-row:last-child { margin-bottom: 0; }
.moderation-list { font: 12px var(--font-sans); }
.moderation-list-item { display: flex; align-items: center; gap: 8px; padding: 4px 0; border-bottom: 1px solid var(--border-soft); }
.moderation-list-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.moderation-list-remove { border: 0; background: transparent; color: var(--fg-dim); cursor: pointer; padding: 2px 5px; }
.moderation-list-remove:hover { color: var(--red); }
.moderation-list-remove:disabled { color: var(--fg-faint); cursor: not-allowed; opacity: 0.55; }
.profile-config-form { font-family: var(--font-sans); }
.profile-config-field { display: flex; flex-direction: column; gap: 3px; margin-bottom: 10px; font-size: 11px; color: var(--fg-dim); }
.profile-config-field > span { font-weight: 600; text-transform: uppercase; letter-spacing: .4px; }
.profile-config-field input[type="text"],
.profile-config-field textarea,
.profile-field-row input {
  box-sizing: border-box; width: 100%; padding: 5px 6px; color: var(--fg);
  background: var(--bg-elev); border: 1px solid var(--border-soft); border-radius: 0;
  font: 12px var(--font-sans); outline: none;
}
.profile-config-field textarea { resize: vertical; min-height: 80px; }
.profile-config-field input:focus,
.profile-config-field textarea:focus,
.profile-field-row input:focus { border-color: var(--accent); }
.profile-config-images { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.profile-config-field input[type="file"] { max-width: 100%; font: 11px var(--font-sans); color: var(--fg-dim); }
.profile-config-fields { display: flex; flex-direction: column; gap: 5px; margin-bottom: 8px; }
.profile-field-row { display: grid; grid-template-columns: minmax(80px, .7fr) minmax(120px, 1.3fr) 24px; gap: 5px; align-items: center; }
.profile-field-remove { border: 0; background: transparent; color: var(--fg-dim); cursor: pointer; padding: 3px; }
.profile-field-remove:hover { color: var(--red); }
.profile-field-add { padding: 4px 7px; color: var(--fg); background: var(--bg-elev); border: 1px solid var(--border-soft); font: 11px var(--font-sans); cursor: pointer; }
.profile-field-add:hover:not(:disabled) { background: var(--bg-hover); }
.profile-field-add:disabled { color: var(--fg-faint); cursor: default; }
@media (max-width: 520px) {
  .profile-config-images { grid-template-columns: 1fr; gap: 0; }
  .profile-field-row { grid-template-columns: 1fr 1fr 22px; }
}
.config-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--fg);
  cursor: pointer;
  user-select: none;
}
.config-toggle input[type="checkbox"] {
  margin: 0;
  cursor: pointer;
}
.config-toggle.is-forced { color: var(--fg-faint); cursor: not-allowed; }
.config-toggle.is-forced input { cursor: not-allowed; }
.config-field {
  display: inline-flex;
  flex-direction: column;
  gap: 3px;
  font-family: var(--font-sans);
  font-size: 11px;
  color: var(--fg-dim);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.config-field-label { font-weight: 600; }
.config-field input[type="number"] {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--border-soft);
  border-radius: 0;
  padding: 3px 6px;
  width: 90px;
  outline: none;
}
.config-field input[type="number"]:focus {
  border-color: var(--accent);
}
.config-field-hint {
  font-family: var(--font-sans);
  font-size: 11px;
  color: var(--fg-faint);
  font-style: italic;
}
.config-save {
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 700;
  background: var(--accent);
  color: white;
  border: 1px solid var(--accent);
  border-radius: 0;
  padding: 4px 12px;
  cursor: pointer;
}
.config-save:hover { background: #0a3a72; }
.config-save-status {
  font-family: var(--font-sans);
  font-size: 11px;
  color: #117743;
  font-style: italic;
  min-height: 1em;
}
.config-save-status.is-error { color: var(--red); }

/* ---- floating, draggable, non-blocking panel modals ---------------------- *
 * makePanelModal() in app.js adds .draggable-panel to a modal's root overlay
 * to turn it from a dimmed, full-screen, click-capturing backdrop into a
 * transparent, click-through layer: the page underneath stays fully
 * interactive (no click-outside-to-close), and only the panel box itself
 * catches pointer events. The box is positioned absolutely and moved by
 * dragging its header; coordinates are set imperatively in JS. The compound
 * selectors keep specificity above each modal's base rules. */
.compose-modal.draggable-panel,
.config-modal.draggable-panel,
.subscribe-modal.draggable-panel,
.board-create.draggable-panel,
.emoji-picker.draggable-panel,
.poll-composer.draggable-panel {
  background: transparent;
  align-items: flex-start;
  justify-content: flex-start;
  padding: 0;
  pointer-events: none;
}
.compose-modal.draggable-panel > .compose-modal-box,
.config-modal.draggable-panel > .config-modal-box,
.subscribe-modal.draggable-panel > .subscribe-modal-box,
.board-create.draggable-panel > .board-create-box,
.emoji-picker.draggable-panel > .emoji-picker-box,
.poll-composer.draggable-panel > .poll-composer-box {
  pointer-events: auto;
  position: absolute;
  left: 0;
  top: 8vh;
  margin: 0;
}
/* The header bar is the drag handle. */
.compose-modal.draggable-panel .compose-modal-head,
.config-modal.draggable-panel .config-modal-head,
.subscribe-modal.draggable-panel .subscribe-modal-head,
.board-create.draggable-panel .board-create-head,
.emoji-picker.draggable-panel .emoji-picker-head,
.poll-composer.draggable-panel .poll-composer-head {
  cursor: grab;
  touch-action: none;
  user-select: none;
}
/* While a drag is in progress, show the grabbing cursor everywhere and
 * suppress text selection, so the pointer reads as "holding" the panel. */
body.is-panel-dragging { cursor: grabbing !important; user-select: none !important; }
body.is-panel-dragging .compose-modal-head,
body.is-panel-dragging .config-modal-head,
body.is-panel-dragging .subscribe-modal-head,
body.is-panel-dragging .board-create-head,
body.is-panel-dragging .emoji-picker-head,
body.is-panel-dragging .poll-composer-head { cursor: grabbing; }
