/* Shared listing-card / directory UI components — used by every page that
   renders bot/channel/group cards (home, detail, category, guides) or the
   breadcrumb+footer chrome below the homepage. One file, cached once by the
   browser (see topbar.css/theme.css for the same reasoning), instead of the
   near-identical <style> blocks that used to be copy-pasted into every page
   template. That copy-pasting had already drifted in two places fixed here:
     - vote buttons had hover/active color feedback on the homepage only;
       detail/category/guide pages had the same buttons with no feedback.
     - the 18+ badge used a dark-mode-aware color on the homepage but a
       hardcoded light-mode-only color on the detail page.
   Page-specific layout (hero, sidebar, forms, article typography) stays
   inline in each page's own <style> block — this file is only the pieces
   that are reused, or that benefit from being cached across page views
   (a visitor browsing several listing pages in a row now downloads this
   once instead of on every single navigation).

   Borderless by design: every surface below gets its definition from
   --shadow-sm/-md (cards/popovers) or a tinted --badge-bg fill one step
   away from --surface (pills/chips/buttons) — never a 1px stroke. Where a
   fill alone wouldn't read as distinct from its container (a chip sitting
   on a card that's already --surface-colored), the chip uses --badge-bg
   specifically so it stays visible without a border. */

.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: .9rem; }

.listing { border-radius: 1.1rem; padding: 1.1rem; display: flex; gap: .8rem; background: var(--surface); align-items: stretch; box-shadow: var(--shadow-sm); transition: transform .15s ease, box-shadow .15s ease; }
.listing:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
a.listing { color: inherit; text-decoration: none; }
.listing:active { background: var(--badge-bg); }

.l-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.l-head { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.l-name { font-weight: 800; font-size: 1.05rem; color: var(--text); text-decoration: none; }
.l-name:hover { text-decoration: underline; }
.l-user { color: var(--tg); font-weight: 600; text-decoration: none; font-size: .82rem; display: block; margin-top: .05rem; }
.l-user:hover { text-decoration: underline; color: var(--tg-dark); }
.l-desc { color: var(--text-secondary); font-size: .84rem; margin: .4rem 0 .5rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* Base size (46px) matches cardHtml()'s output as used by the category and
   guide pages. cardHtml() is one shared function also used for the
   homepage's server-rendered cards, so per-page size differences (home's
   cards read at 48px, the detail page's own header avatar at 64px, its
   "similar listings" avatars at 48px) stay as small size-only overrides in
   each page's own <style> block, scoped by ancestor — never a bare `.avatar`
   redeclaration that silently drops the shared radius/font rules below.
   The inset shadow is a subtle rim so an image avatar never blends into a
   similarly-toned background — not a border, so it stays even here. */
.avatar { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; font-weight: 800; color: #fff; object-fit: cover; box-shadow: inset 0 0 0 1px rgba(255,255,255,.25); width: 46px; height: 46px; border-radius: .85rem; font-size: 1rem; }

.l-type { font-size: .62rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; padding: .2em .6em; border-radius: 1em; vertical-align: middle; }
.l-type.bot { background: color-mix(in srgb, var(--tg) 18%, var(--surface)); color: var(--tg-dark); }
.l-type.channel { background: var(--badge-bg); color: var(--text-secondary); }
.l-type.group { background: color-mix(in srgb, var(--tg-dark) 20%, var(--surface)); color: var(--tg-dark); }
/* Was a hardcoded pink (#d6335a) marking 18+ listings — flattened to the
   same neutral badge treatment as everything else (no color anywhere),
   distinguished by uppercase/weight alone instead of a warning hue. */
.l-adult { font-size: .62rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; padding: .2em .6em; border-radius: 1em; background: var(--badge-bg); color: var(--text-secondary); vertical-align: middle; }

.badge.tag { background: var(--badge-bg); color: var(--text-secondary); border-radius: 1em; font-weight: 600; margin: 0 .25rem .25rem 0; font-size: .72rem; }
/* Flattened back to the plain neutral badge fill per "only use 2 colors" —
   was tinted per-category via --cat-hue (see hueOf() in server.js and its
   client-side mirror in index.html); that plumbing still sets --cat-hue
   inline on every card/badge, it's just unconsumed here now. */
.category-badge { background: var(--badge-bg); color: var(--text-secondary); font-weight: 800; text-transform: uppercase; letter-spacing: .04em; padding: .2em .6em; border-radius: 1em; text-decoration: none; }
.category-badge:hover { text-decoration: underline; }
.rating-badge { color: var(--text-secondary); }

.l-actions { display: flex; align-items: center; gap: .5rem; margin-top: auto; padding-top: .6rem; flex-wrap: wrap; }
/* Same hover/active feedback everywhere a vote button appears — previously
   only the homepage's inline <style> had these states. Fill (--badge-bg),
   not a stroke, is what separates the button from the --surface card behind
   it; hover/active swap the fill/text color instead of adding a border. */
.vote-btn { display: inline-flex; align-items: center; gap: .3rem; min-height: var(--tap); border: 0; background: var(--badge-bg); border-radius: 2rem; padding: .3rem .75rem; font-weight: 700; color: var(--text-secondary); font-size: .8rem; cursor: pointer; transition: background .15s ease, color .15s ease; }
.vote-btn svg { width: 16px; height: 16px; flex: 0 0 16px; }
.vote-btn:disabled { opacity: .5; cursor: default; }
/* Like/dislike used to differ by hue (pink vs. blue-gray) — both neutral
   now, so the two states read apart by icon direction and fill intensity
   (active = deeper tint) instead of color. */
.vote-btn.like-btn:hover { background: color-mix(in srgb, var(--text) 12%, var(--badge-bg)); color: var(--text); }
.vote-btn.like-btn.active { background: color-mix(in srgb, var(--text) 20%, var(--badge-bg)); color: var(--text); }
.vote-btn.dislike-btn:hover { background: color-mix(in srgb, var(--text) 12%, var(--badge-bg)); color: var(--text); }
.vote-btn.dislike-btn.active { background: color-mix(in srgb, var(--text) 20%, var(--badge-bg)); color: var(--text); }

/* Base = the small pill used inside cards (home/category/guide grids), which
   set their own background via an inline style attribute per listing's own
   markup. .open-btn-lg is the bigger standalone CTA on the detail page,
   which has no per-instance inline style, so it carries its own color. */
.open-btn { display: inline-flex; align-items: center; min-height: var(--tap); border-radius: 2rem; font-size: .8rem; padding: .3rem 1rem; font-weight: 700; text-decoration: none; white-space: nowrap; }
.open-btn-lg { min-height: var(--tap); background: var(--tg); color: #fff; border-radius: 2rem; font-weight: 700; padding: .45rem 1.1rem; text-decoration: none; font-size: .9rem; white-space: nowrap; }
.open-btn-lg:hover { background: var(--tg-dark); color: #fff; }

/* No persistent top navbar — removed twice by explicit request. Brand mark
   (the "T" square) is a shared primitive still used by the footer's brand
   column below, kept minimal on its own. */
.brand-mark { width: 2rem; height: 2rem; border-radius: .6rem; background: var(--tg); color: #fff; font-weight: 800; font-size: 1.05rem; display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; }

/* Breadcrumb + footer chrome shared by every page below the homepage. Uses
   the theme tokens (var(--muted)/var(--text-secondary)) instead of the
   hardcoded grays (#9aabb9, #7b8ea0, #8aa0b3...) those blocks used to carry,
   which read slightly wrong against the dark-mode surface. */
.breadcrumb-nav { font-size: .82rem; color: var(--muted); margin: 1.2rem 0 0; display: flex; gap: .4rem; flex-wrap: wrap; }
.breadcrumb-nav a { color: var(--text-secondary); text-decoration: none; font-weight: 600; }
.breadcrumb-nav a:hover { color: var(--tg-dark); text-decoration: underline; }

/* Structured, multi-column footer — replaces the earlier single centered
   line of middot-separated links, which read as a placeholder rather than a
   finished site. Built once as siteFooterHtml() in server.js (index.html
   carries its own hand-synced copy, same convention as the header) and used
   on every page. */
footer.site-footer { border-top: 1px solid var(--border); margin-top: 2.5rem; padding-top: 2.2rem; color: var(--muted); font-size: .85rem; }
.site-footer-inner { max-width: 1180px; margin: 0 auto; padding: 0 1rem; display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: 1.6rem 1rem; }
@media (max-width: 640px) { .site-footer-inner { grid-template-columns: 1fr 1fr; } }
.footer-brand-row { display: flex; align-items: center; gap: .5rem; margin-bottom: .6rem; }
.footer-brand-row .brand-mark { width: 1.7rem; height: 1.7rem; font-size: .88rem; border-radius: .5rem; }
.footer-brand-word { font-weight: 800; color: var(--text); font-size: 1rem; }
.footer-brand p { margin: 0; line-height: 1.55; max-width: 24rem; }
.footer-col h3 { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; font-weight: 700; color: var(--text-secondary); margin: 0 0 .8rem; }
.footer-col a { display: block; color: var(--muted); text-decoration: none; margin-bottom: .55rem; font-weight: 600; }
.footer-col a:hover { color: var(--tg-dark); text-decoration: underline; }
.site-footer-bottom { max-width: 1180px; margin: 2rem auto 0; padding: 1.1rem 1rem; border-top: 1px solid var(--border); text-align: center; font-size: .78rem; }

/* ---- Detail page: main content card + related-listings list ----
   .detail-content/.detail-card had a border and no shadow at all before —
   removing the border without adding a shadow would leave them with zero
   definition against the page background, so both pick up --shadow-sm here. */
.detail-content { background: var(--surface); border-radius: 1rem; padding: 1.6rem; margin: 0 0 2rem; color: var(--text-secondary); box-shadow: var(--shadow-sm); }
.detail-content h2 { font-size: 1.05rem; font-weight: 800; color: var(--text); border-left: 4px solid var(--tg); padding: .1rem 0 .1rem .7rem; margin: 1.4rem 0 .6rem; }
.detail-content h2:first-child { margin-top: 0; }
.detail-content p, .detail-content li { font-size: .92rem; line-height: 1.6; }
.detail-content ul, .detail-content ol { padding-left: 1.3rem; margin: 0; }
.detail-content li { margin-bottom: .3rem; }
/* FAQ accordion items: a fill (not a border) marks the tappable region, and
   deepens further on hover/open instead of swapping a border color. */
.detail-content details { background: var(--badge-bg); border-radius: .7rem; padding: 0; margin-bottom: .6rem; transition: background .15s; overflow: hidden; }
.detail-content details:hover { background: color-mix(in srgb, var(--badge-bg) 70%, var(--border-strong)); }
.detail-content details[open] { background: color-mix(in srgb, var(--tg) 10%, var(--badge-bg)); }
.detail-content summary { font-weight: 700; color: var(--text); cursor: pointer; list-style: none; padding: .75rem .9rem; display: flex; justify-content: space-between; align-items: center; gap: .75rem; }
.detail-content summary::-webkit-details-marker { display: none; }
.detail-content summary::after { content: '+'; flex: 0 0 auto; width: 1.4rem; height: 1.4rem; border-radius: 50%; background: var(--surface); color: var(--tg-dark); font-size: 1rem; font-weight: 800; line-height: 1.4rem; text-align: center; transition: transform .15s, background .15s; }
.detail-content details[open] summary::after { content: '−'; background: var(--tg); color: #fff; }
.detail-content details p { margin: 0; padding: 0 .9rem .8rem; color: var(--text-secondary); }

.detail-card { background: var(--surface); border-radius: 1rem; padding: 1.6rem; margin: 1.2rem 0 1rem; box-shadow: var(--shadow-sm); }
.detail-title { font-size: 1.35rem; font-weight: 800; color: var(--text); margin-bottom: .3rem; display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.detail-stats { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin-bottom: .2rem; }
.detail-user { color: var(--tg); font-weight: 600; text-decoration: none; font-size: .9rem; }
.detail-user:hover { text-decoration: underline; }
.detail-desc { margin: .8rem 0; color: var(--text-secondary); font-size: .92rem; line-height: 1.55; }
.share-btn { display: inline-flex; align-items: center; gap: .35rem; min-height: var(--tap); border: 0; background: var(--badge-bg); border-radius: .7rem; padding: .4rem .7rem; font-weight: 700; color: var(--text-secondary); font-size: .85rem; cursor: pointer; white-space: nowrap; transition: background .15s ease, color .15s ease; }
.share-btn svg { width: 15px; height: 15px; }
.share-btn:hover { background: color-mix(in srgb, var(--tg) 16%, var(--badge-bg)); color: var(--tg-dark); }

h2.section-h { font-size: 1.05rem; font-weight: 800; color: var(--text); margin: 0 0 .9rem; }
/* Secondary/supplementary content (related listings) reads as a plain
   divided list instead of stacking more shadowed cards under the main
   content card -- repeating that treatment for every related item is what
   made the page feel like "boxes everywhere". Rows are separated by a hover
   fill and a little extra padding instead of a divider line. */
.similar-list { background: var(--surface); border-radius: 1rem; box-shadow: var(--shadow-sm); overflow: hidden; }
.similar-item { display: flex; gap: .75rem; align-items: flex-start; padding: 1rem; text-decoration: none; color: inherit; transition: background .15s ease; }
.similar-item:hover { background: var(--badge-bg); }
.similar-item:hover .l-name { text-decoration: underline; }

/* ---- Category page: related-categories chip list ---- */
.other-cats { margin: 2.5rem 0 2rem; }
.other-cats h2 { font-size: 1.05rem; font-weight: 800; color: var(--text); margin-bottom: .8rem; }
.other-cats-list { display: flex; flex-wrap: wrap; gap: .5rem; }
.other-cats-list a { background: var(--badge-bg); color: var(--text-secondary); border-radius: 2rem; padding: .35rem .9rem; font-size: .84rem; font-weight: 600; text-decoration: none; transition: background .15s ease; }
.other-cats-list a:hover { background: color-mix(in srgb, var(--tg) 12%, var(--badge-bg)); }
.other-cats-list a span { opacity: .7; }

/* ---- Guides: cross-guide nav chips + guides-index list cards ---- */
.guide-nav { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1.5rem 0 .5rem; }
.guide-nav a { background: var(--badge-bg); color: var(--text-secondary); border-radius: 2rem; padding: .35rem .9rem; font-size: .82rem; font-weight: 600; text-decoration: none; transition: background .15s ease, color .15s ease; }
.guide-nav a.active { background: var(--tg); color: #fff; }
.guide-card { display: block; background: var(--surface); border-radius: 1rem; padding: 1.2rem 1.4rem; margin-bottom: 1rem; text-decoration: none; transition: box-shadow .15s ease, transform .15s ease; box-shadow: var(--shadow-sm); }
.guide-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.guide-card h2 { font-size: 1.1rem; font-weight: 800; color: var(--text); margin: 0 0 .3rem; }
.guide-card p { color: var(--text-secondary); font-size: .88rem; margin: 0; }

/* ---- Home: category-silo preview grid (the "Popular categories" section) ---
   Left accent bar + emoji chip used the per-category --cat-hue rainbow
   before; flattened to the single --tg accent + neutral fill per "only use
   2 colors" — see components.css's .category-badge comment above. */
.cat-silo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: .8rem; margin: .2rem 0 1.6rem; }
.cat-silo-card { display: flex; gap: .7rem; align-items: flex-start; background: var(--surface); border-radius: .9rem; padding: .85rem .9rem; text-decoration: none; color: inherit; box-shadow: var(--shadow-sm); border-left: 4px solid var(--tg); transition: box-shadow .15s ease, transform .15s ease; }
.cat-silo-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.cat-silo-emoji { font-size: 1.15rem; line-height: 1; flex: 0 0 auto; width: 2.1rem; height: 2.1rem; display: inline-flex; align-items: center; justify-content: center; border-radius: .7rem; background: var(--badge-bg); }
.cat-silo-body { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.cat-silo-name { font-weight: 700; color: var(--text); font-size: .92rem; }
.cat-silo-count { color: var(--muted); font-weight: 500; }
.cat-silo-blurb { color: var(--text-secondary); font-size: .8rem; line-height: 1.35; }
