{"release_id":"01a1c502-4ad1-0000-ec62-adc54d3c69aa","chunk_id":"01a1c502-4c84-7a80-b7be-985228984087","file":"129.COKs2i4_.mjs","mappings":"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","names":["SIZE_NICHES","BJU_2015","num","n","LOCALE_INFO","locale","hub","$.derived","albumHubForNiche","$$props","themeStyle","nicheThemeStyle","getModeAccent","nicheAvatarUrl","getAvatarUrl","isStaff","modRemove","postId","t","res","j","invalidateAll","onMount","activeMode","accentOverride","$.user_effect","nicheAccentEntry","nicheAccentSpec","isSubscribed","$.state","$.proxy","memberCount","subscribing","$.set","chatModalOpen","chatViewerIsMember","chatMemberCount","toggleSubscribe","wasSubscribed","$.get","goto","shareToastVisible","shareToastText","shareNiche","url","shareOrCopy","result","redditShareUrl","div","root","div_1","div_2","section","$.child","div_3","div_4","div_5","img","root_1","$.template_effect","$.set_attribute","DuelAvatar","$$anchor","$$render","consequent","alternate","div_6","$.sibling","node","p_1","div_7","h1","span","root_3","$0","$.set_text","text_2","consequent_1","span_1","root_4","consequent_2","p_2","root_5","consequent_3","p_3","node_3","div_8","span_2","strong","span_3","strong_1","span_4","root_6","a","text_10","text_11","consequent_4","div_9","button","text_12","$.reset","node_5","a_1","root_8","text_13","$.append","button_1","root_9","text_14","consequent_5","alternate_1","consequent_6","button_2","text_15","node_7","a_2","root_10","text_16","consequent_7","div_10","div_11","a_3","text_18","node_8","div_12","root_11","PostComposer","node_9","consequent_8","section_1","root_12","div_13","h2","span_5","text_20","p_4","consequent_9","alternate_2","div_14","button_3","root_15","text_24","$.delegated","a_4","root_16","consequent_10","alternate_3","button_4","node_12","text_19","div_15","root_17","p","PostCard","consequent_11","alternate_4","nav","root_19","h2_1","ul","r","li","root_20","a_5","text_28","span_6","p_5","root_21","$.index","part","a_6","root_23","lhref","a_7","root_24","consequent_12","consequent_13","alternate_5","d","p_6","root_26","consequent_15","p_7","root_27","a_8","text_33","$1","text_34","albumHubPath","consequent_16","p_8","node_17","a_9","root_29","text_35","a_10","root_30","text_36","a_11","root_31","text_37","consequent_17","consequent_18","consequent_19","alternate_6","text_27","consequent_20","div_16","root_33","consequent_21","aside","node_19","div_17","section_2","h2_2","p_9","div_18","div_19","span_7","div_20","root_34","span_8","a_12","text_45","consequent_22","section_3","p_10","a_13","JoinNicheChatModal","consequent_23","$.set_style","$.set_class","text","text_5","text_8","$4","text_41"],"sources":["../../../../../../src/lib/niche-seo.ts","../../../../../../src/routes/n/[slug]/+page.svelte"],"sourcesContent":["import { BJU_2015 } from '$lib/data/size-stats';\n\n/**\n * Which niches search engines may index, and what their pages say to them.\n * One rule for the niche page's noindex, the sitemap and every \"related\n * niches\" link, so a niche is either indexable everywhere or nowhere.\n */\n\n/** A niche below this many posts is a thin page; it stays out of the index\n *  and the sitemap until the community fills it. */\nexport const NICHE_INDEX_MIN_POSTS = 5;\n\n/**\n * Niches whose name or description reads as minors, animals or other people's\n * images. Whatever moderation decides about them (RAT-547), they never go in\n * front of a search engine. The pattern catches new niches named the same way;\n * a false positive only costs a noindex.\n */\nconst RISKY_SLUGS = new Set([\n\t'teenmonstercock',\n\t'young',\n\t'animal',\n\t'porn-trade',\n\t'girlsnudes',\n\t'exposing-fakes',\n\t'arab',\n\t'black',\n\t'ratemypet',\n\t'pets',\n\t// Photos taken \"around other people\", and women posted by whoever: both can\n\t// be pictures of someone who never agreed to be in them.\n\t'public',\n\t'girls'\n]);\nconst RISKY_TEXT =\n\t/\\b(teens?|teenage|young|youth|boys?|underage|minors?|kids?|child(ren)?|school|jailbait|animals?|bestiality|zoo|pets?|incest|porn[\\s-]?trade|exposing)\\b|girls?\\s*nudes/i;\n\nexport type NicheLike = {\n\tslug: string;\n\tname: string;\n\tdescription: string | null;\n\tpostCount: number;\n\tisHibernated: boolean;\n};\n\nexport function isRiskyNiche(n: Pick<NicheLike, 'slug' | 'name' | 'description'>): boolean {\n\treturn RISKY_SLUGS.has(n.slug) || RISKY_TEXT.test(`${n.name} ${n.description ?? ''}`);\n}\n\nexport function isNicheIndexable(n: NicheLike): boolean {\n\treturn !n.isHibernated && n.postCount >= NICHE_INDEX_MIN_POSTS && !isRiskyNiche(n);\n}\n\n/** Niches about size: their pages point at the size tools (RAT-577), the\n *  answer to \"how do I compare?\" that a feed of photos can't give. */\nexport const SIZE_NICHES = new Set(['averagedicks', 'cockcompare', 'tinydick', 'hung']);\n\n/** The study the calculator and stats pages use, for the two niches whose\n *  copy is about size. */\nconst AVG_IN = BJU_2015.erectLength.meanIn.toFixed(1);\nconst AVG_CM = BJU_2015.erectLength.meanCm.toFixed(1);\nconst STUDY_MEN = BJU_2015.source.sampleSize.toLocaleString('en-US');\n\n/**\n * Hand-written search copy for niches that answer a search people make: the\n * title and description aim at it, `h1` replaces the niche name as the page\n * heading, and `intro` is a line or two in the searcher's words under it. Each\n * one is written for its niche; a template filled with the name is what the\n * rest get, and what search engines learn to discount. Niches named for porn\n * searches (bbc, bwc, college) are left to that plain template on purpose.\n */\nexport const NICHE_SEARCH: Record<\n\tstring,\n\t{ title: string; description: string; h1: string; intro: string }\n> = {\n\tcockcompare: {\n\t\ttitle: 'Cock Compare — Side by Side, the Crowd Picks | RateMyD',\n\t\tdescription:\n\t\t\t\"Cock compare on RateMyD: post your cock next to someone else's and let thousands of members vote on the winner. No edits, no filters. Free to join, 18+.\",\n\t\th1: 'cock compare',\n\t\tintro:\n\t\t\t\"the biggest community on RateMyD. post yours next to someone else's and let the members vote, or take it to a 1v1 duel where the AI names the winner.\"\n\t},\n\tuncut: {\n\t\ttitle: 'Rate My Uncut Cock — Uncut Dicks, Posted & Rated | RateMyD',\n\t\tdescription:\n\t\t\t'Rate my uncut cock: post your uncut dick, get rated by thousands of members who appreciate foreskin and compare with other uncut guys. Free to join, 18+.',\n\t\th1: 'uncut cock rating',\n\t\tintro:\n\t\t\t'uncut and proud of it. post yours, get rated by members who prefer foreskin, and see how you compare with other uncut guys.'\n\t},\n\tsph: {\n\t\ttitle: 'SPH Rating — Small Penis Humiliation, by Consent | RateMyD',\n\t\tdescription:\n\t\t\t'SPH rating on RateMyD: post your small dick for the humiliation you asked for, or book a real SPH rater for a private 1:1 chat. Consensual and 18+ only.',\n\t\th1: 'sph rating',\n\t\tintro:\n\t\t\t'small penis humiliation, asked for and given by consent. post yours and let the community take it apart, or book an SPH rater to do it one-on-one.'\n\t},\n\taveragedicks: {\n\t\ttitle: 'Average Dick Pics — Compare Yours with Other Guys | RateMyD',\n\t\tdescription: `Average dick pics on RateMyD: post yours, compare it with other average dicks and duel for the vote. The average erect penis is ${AVG_IN} inches (${AVG_CM} cm).`,\n\t\th1: 'average dicks',\n\t\tintro: `most dicks are average, and that's the point here. across ${STUDY_MEN} men the mean is ${AVG_IN} inches erect (${AVG_CM} cm); post yours and compare with guys around the same size.`\n\t},\n\t'curved-cocks': {\n\t\ttitle: 'Curved Dick Pics — Upward, Downward, Sideways | RateMyD',\n\t\tdescription:\n\t\t\t'Curved dick pics on RateMyD: upward, downward or sideways, post your curved cock, compare the bend with other guys and get rated. Free to join, 18+.',\n\t\th1: 'curved dicks',\n\t\tintro:\n\t\t\t'up, down or to the side: a curve is common and nothing to hide. post yours, see how other guys bend, and get rated.'\n\t},\n\tbulge: {\n\t\ttitle: 'Rate My Bulge — Bulge Pics, Compared & Rated | RateMyD',\n\t\tdescription:\n\t\t\t'Rate my bulge: post your bulge in briefs, jeans or gym shorts, compare it against other guys and let the members vote. Free to join, 18+.',\n\t\th1: 'rate my bulge',\n\t\tintro:\n\t\t\t'the tease before the reveal. post your bulge in briefs, jeans or gym shorts and let the members rate it against the rest.'\n\t},\n\ttinydick: {\n\t\ttitle: 'Small Dick Rating — Tiny Dick Pics, Posted & Rated | RateMyD',\n\t\tdescription:\n\t\t\t\"Small dick rating on RateMyD: post your tiny dick, get honest ratings from the community and compare with others. After humiliation instead? That's SPH. 18+.\",\n\t\th1: 'small dick rating',\n\t\tintro:\n\t\t\t\"small, tiny or micro, all welcome. post yours for an honest rating, compare with guys your size, and see you're far from the only one.\"\n\t},\n\thung: {\n\t\ttitle: 'Hung — The Big Ones, 8 Inches and Up | RateMyD',\n\t\tdescription:\n\t\t\t'Hung on RateMyD: the big ones, 8 inches and up. Post yours, compare against the biggest on the site and let the members vote. Free to join, 18+.',\n\t\th1: 'hung',\n\t\tintro: `for the outliers. the average erect penis is ${AVG_IN} inches and 7 is already bigger than 99 in 100 men; this is where the ones past that compare.`\n\t},\n\tbushcomparison: {\n\t\ttitle: 'Bush Compare — Natural, Trimmed or Shaved | RateMyD',\n\t\tdescription:\n\t\t\t'Bush compare on RateMyD: natural, trimmed or shaved, post yours and compare with other guys. Grooming is one of the six things the AI rating scores. 18+.',\n\t\th1: 'bush compare',\n\t\tintro:\n\t\t\t'natural, trimmed or shaved. grooming is one of the six things the AI dick rating scores, so post yours, compare with other guys and see what works.'\n\t},\n\tballs: {\n\t\ttitle: 'Rate My Balls — Ball Pics, Compared & Rated | RateMyD',\n\t\tdescription:\n\t\t\t'Rate my balls: post your ball pics, compare size and hang with other guys and let the members rate them. A RateMyD community, free to join, 18+.',\n\t\th1: 'rate my balls',\n\t\tintro:\n\t\t\t'balls, and what they swing from. post yours, compare size and hang with other guys, and let the members rate them.'\n\t},\n\tgay: {\n\t\ttitle: 'Gay Dick Rating — Get Rated by Gay Guys | RateMyD',\n\t\tdescription:\n\t\t\t'Gay dick ratings on RateMyD: post a pic, get rated by men, and rate theirs in the gay niche.',\n\t\th1: 'gay dick rating',\n\t\tintro: 'post a pic, get rated by men, rate theirs.'\n\t}\n};\n\nconst clean = (s: string | null | undefined) => (s ?? '').replace(/\\s+/g, ' ').trim();\n\nfunction clip(s: string, max: number): string {\n\treturn s.length <= max ? s : `${s.slice(0, max - 1).trimEnd()}…`;\n}\n\n/** Title, description and heading for a niche page. */\nexport function nicheSeo(n: NicheLike & { memberCount: number }): {\n\ttitle: string;\n\tdescription: string;\n\th1: string;\n\tnoindex: boolean;\n} {\n\tconst noindex = !isNicheIndexable(n);\n\tconst curated = NICHE_SEARCH[n.slug];\n\tif (curated) return { ...curated, noindex };\n\n\tconst name = clip(clean(n.name) || n.slug, 40);\n\tconst counts = `${n.postCount.toLocaleString('en-US')} posts from ${n.memberCount.toLocaleString('en-US')} members`;\n\tconst about = clean(n.description);\n\treturn {\n\t\ttitle: `${name} — Post, Compare & Get Rated | RateMyD`,\n\t\tdescription: clip(`${name} on RateMyD: ${counts}.${about ? ` ${about}` : ''}`, 158),\n\t\th1: name,\n\t\tnoindex\n\t};\n}\n","<script lang=\"ts\">\n\timport { t, lhref, locale, LOCALE_INFO } from '$lib/i18n';\n\timport { SIZE_NICHES } from '$lib/niche-seo';\n\timport { albumHubForNiche, albumHubPath } from '$lib/album-hubs';\n\timport { onMount } from 'svelte';\n\timport { goto } from '$app/navigation';\n\timport { activeMode, accentOverride, nicheAccentSpec, getModeAccent } from '$lib/stores/activeMode';\n\timport { shareOrCopy } from '$lib/share';\n\timport PostComposer from '$lib/components/post/PostComposer.svelte';\n\timport PostCard from '$lib/components/post/PostCard.svelte';\n\timport DuelAvatar from '$lib/components/duel/DuelAvatar.svelte';\n\timport JoinNicheChatModal from '$lib/components/niche/JoinNicheChatModal.svelte';\n\timport { getAvatarUrl } from '$lib/avatar';\n\timport { nicheThemeStyle, nicheAccentEntry } from '$lib/niche-theme';\n\timport { invalidateAll } from '$app/navigation';\n\n\tlet { data } = $props();\n\tconst num = (n: number) => n.toLocaleString(LOCALE_INFO[locale()].hreflang);\n\tconst hub = $derived(albumHubForNiche(data.niche.slug));\n\tconst themeStyle = $derived(nicheThemeStyle(data.niche.accent, data.niche.bgPattern, getModeAccent('niches').hex));\n\tconst nicheAvatarUrl = $derived(getAvatarUrl(data.niche.avatarPath));\n\tconst isStaff = $derived(data.viewerRole === 'owner' || data.viewerRole === 'moderator');\n\n\t// niche staff: soft-remove a post from the niche (server checks the role)\n\tasync function modRemove(postId: string) {\n\t\tif (!confirm(t('remove this post from the niche? the author keeps nothing, it disappears everywhere.'))) return;\n\t\tconst res = await fetch(`/api/niches/${data.niche.slug}/mod/remove-post`, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: { 'content-type': 'application/json' },\n\t\t\tbody: JSON.stringify({ postId })\n\t\t});\n\t\tif (!res.ok) {\n\t\t\tconst j = await res.json().catch(() => ({}));\n\t\t\talert(j.error ?? t('could not remove'));\n\t\t\treturn;\n\t\t}\n\t\tawait invalidateAll();\n\t}\n\n\tonMount(() => {\n\t\tactiveMode.set('niches');\n\t\treturn () => {\n\t\t\tactiveMode.set(null);\n\t\t\taccentOverride.set(null);\n\t\t};\n\t});\n\t// the niche's own colour takes over the site chrome while we're here\n\t$effect(() => {\n\t\tconst e = nicheAccentEntry(data.niche.accent);\n\t\taccentOverride.set(e ? nicheAccentSpec(e.key, e.base, e.dark) : null);\n\t});\n\n\t// Subscribe toggle: optimistic + POST/DELETE.\n\tlet isSubscribed = $state(data.isSubscribed);\n\tlet memberCount = $state(data.niche.memberCount);\n\tlet subscribing = $state(false);\n\n\t$effect(() => {\n\t\tisSubscribed = data.isSubscribed;\n\t\tmemberCount = data.niche.memberCount;\n\t});\n\n\t// RAT-342: after a successful subscribe, prompt the user to join\n\t// the niche's default group chat. Chat-membership is opt-in —\n\t// independent from the niche subscription itself.\n\tlet chatModalOpen = $state(false);\n\tlet chatViewerIsMember = $state(data.defaultRoom?.viewerIsMember ?? false);\n\tlet chatMemberCount = $state(data.defaultRoom?.memberCount ?? 0);\n\tlet joiningChat = $state(false);\n\n\t$effect(() => {\n\t\tchatViewerIsMember = data.defaultRoom?.viewerIsMember ?? false;\n\t\tchatMemberCount = data.defaultRoom?.memberCount ?? 0;\n\t});\n\n\tasync function toggleSubscribe() {\n\t\tif (subscribing) return;\n\t\tsubscribing = true;\n\t\tconst wasSubscribed = isSubscribed;\n\t\tisSubscribed = !wasSubscribed;\n\t\tmemberCount += wasSubscribed ? -1 : 1;\n\t\ttry {\n\t\t\tconst res = await fetch(`/api/niches/${data.niche.slug}/subscribe`, {\n\t\t\t\tmethod: wasSubscribed ? 'DELETE' : 'POST'\n\t\t\t});\n\t\t\tif (!res.ok) {\n\t\t\t\tisSubscribed = wasSubscribed;\n\t\t\t\tmemberCount += wasSubscribed ? 1 : -1;\n\t\t\t\t// RAT-272 follow-up: send unauthed users to the proper sign-in\n\t\t\t\t// flow with a return path, not /rate (which is the rating\n\t\t\t\t// upload page and confused users who just wanted to subscribe).\n\t\t\t\tif (res.status === 401) {\n\t\t\t\t\tgoto(`/auth/sign-in?next=${encodeURIComponent(`/n/${data.niche.slug}`)}`);\n\t\t\t\t}\n\t\t\t} else if (!wasSubscribed && data.defaultRoom && !chatViewerIsMember) {\n\t\t\t\t// Fresh subscribe → pop the join-chat prompt. Skipped on\n\t\t\t\t// unsubscribe and when the user is already in the chat.\n\t\t\t\tchatModalOpen = true;\n\t\t\t}\n\t\t} catch {\n\t\t\tisSubscribed = wasSubscribed;\n\t\t\tmemberCount += wasSubscribed ? 1 : -1;\n\t\t} finally {\n\t\t\tsubscribing = false;\n\t\t}\n\t}\n\n\tasync function joinChat() {\n\t\tif (joiningChat || !data.defaultRoom) return;\n\t\tjoiningChat = true;\n\t\ttry {\n\t\t\tconst res = await fetch(`/api/niches/${data.niche.slug}/join-chat`, {\n\t\t\t\tmethod: 'POST'\n\t\t\t});\n\t\t\tif (res.ok) {\n\t\t\t\tconst body = (await res.json()) as { code: string; memberCount: number };\n\t\t\t\tchatViewerIsMember = true;\n\t\t\t\tchatMemberCount = body.memberCount;\n\t\t\t\tchatModalOpen = false;\n\t\t\t\tgoto(`/g/${body.code}`);\n\t\t\t}\n\t\t} catch {\n\t\t\t// silent\n\t\t} finally {\n\t\t\tjoiningChat = false;\n\t\t}\n\t}\n\n\n\t// RAT-272 follow-up: native share sheet (Web Share API) where supported,\n\t// clipboard fallback elsewhere. shareOrCopy() must be invoked SYNC inside\n\t// the click handler so iOS Safari activation carries through.\n\tlet shareToastVisible = $state(false);\n\tlet shareToastText = $state('');\n\tfunction shareNiche() {\n\t\tconst url = `${window.location.origin}/n/${data.niche.slug}`;\n\t\t// Fire-and-track — sheet/clipboard happens synchronously; the toast\n\t\t// updates once the promise resolves.\n\t\tshareOrCopy({\n\t\t\turl,\n\t\t\ttitle: t('/n/{slug} on ratemyd', { slug: data.niche.slug }),\n\t\t\ttext: `${data.niche.description}`\n\t\t}).then((result) => {\n\t\t\tif (result === 'shared') shareToastText = t('shared');\n\t\t\telse if (result === 'copied') shareToastText = t('link copied');\n\t\t\telse shareToastText = t('could not share');\n\t\t\tshareToastVisible = true;\n\t\t\tsetTimeout(() => (shareToastVisible = false), 1800);\n\t\t});\n\t}\n\n\t// Reddit submit URL — opens reddit's submit page prefilled with the niche\n\t// link + a starter title. growth hook → niche-owners pull in audience.\n\tconst redditShareUrl = $derived(\n\t\t`https://reddit.com/submit?title=${encodeURIComponent(`new community: /n/${data.niche.slug}`)}&url=${encodeURIComponent(`https://ratemyd.app/n/${data.niche.slug}`)}`\n\t);\n</script>\n\n<!-- pt-24: the navbar is fixed and 4rem tall, so pt-16 was zero distance. -->\n<!-- per-niche accent + repeating background: the owner's customization.\n     --accent-color feeds the site-wide --color-accent, so every bg-accent /\n     text-accent inside picks it up; the pattern sits on a fixed layer behind. -->\n<div class=\"niche-theme\" style={themeStyle}>\n<div class=\"niche-bg\" aria-hidden=\"true\"></div>\n<div class=\"relative mx-auto grid max-w-5xl grid-cols-1 gap-6 px-5 pt-24 pb-10 lg:grid-cols-[minmax(0,1fr)_280px]\">\n\n\t<!-- LEFT: niche header + composer + feed -->\n\t<div class=\"min-w-0\">\n\n\t\t<!-- niche header (Stage 1 primitive).\n\t\t\t RAT-282: full-bleed on mobile — edge-to-edge, square corners, just a\n\t\t\t bottom hairline as the divider. Restores to a rounded card on sm+\n\t\t\t where the centered column + sidebar make a floating card read right. -->\n\t\t<section\n\t\t\tclass=\"-mx-5 mt-4 border-b border-border bg-surface overflow-hidden\n\t\t\t\tsm:mx-0 sm:mt-0 sm:mb-5 sm:rounded-2xl sm:border\n\t\t\t\t{data.niche.isHibernated ? 'opacity-70' : ''}\"\n\t\t>\n\t\t\t<div>\n\t\t\t\t<div class=\"px-5 pt-5 pb-5\">\n\t\t\t\t\t<div class=\"flex items-start gap-4\">\n\t\t\t\t\t\t<!-- RAT-282: same gradient avatar as the discovery cards +\n\t\t\t\t\t\t\t user avatars, seeded from the slug. Replaces the flat\n\t\t\t\t\t\t\t colored square; the colored header gradient went with it. -->\n\t\t\t\t\t\t{#if nicheAvatarUrl}\n\t\t\t\t\t\t\t<img src={nicheAvatarUrl} alt=\"\" class=\"h-16 w-16 shrink-0 rounded-2xl object-cover\" />\n\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t<DuelAvatar nickname={data.niche.slug} link={false} size={64} />\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t<div class=\"flex-1 min-w-0\">\n\t\t\t\t\t\t\t<p class=\"font-mono text-[11px] tracking-[0.12em] text-muted\">/n/{data.niche.slug}</p>\n\t\t\t\t\t\t\t<div class=\"flex items-center gap-2 flex-wrap\">\n\t\t\t\t\t\t\t\t<h1 class=\"font-display font-bold text-2xl tracking-tight\">{data.heading}</h1>\n\t\t\t\t\t\t\t\t{#if data.niche.isHibernated}\n\t\t\t\t\t\t\t\t\t<span class=\"font-mono text-[10px] tracking-[0.18em] uppercase text-muted\">{t('hibernated')}</span>\n\t\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\t\t{#if data.viewerRole}\n\t\t\t\t\t\t\t\t\t<span class=\"rounded-md bg-accent/15 px-2 py-0.5 font-mono text-[10px] tracking-[0.14em] uppercase text-accent\">{data.viewerRole === 'owner' ? t('owner') : data.viewerRole === 'moderator' ? t('moderator') : data.viewerRole}</span>\n\t\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t{#if data.searchIntro}\n\t\t\t\t\t\t\t\t<p class=\"mt-2 max-w-xl text-sm leading-relaxed text-text\">{data.searchIntro}</p>\n\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\t<p class=\"text-sm text-muted mt-2 max-w-xl leading-relaxed\">{data.niche.description}</p>\n\t\t\t\t\t\t\t<div class=\"mt-3 flex items-center gap-4 text-xs text-muted flex-wrap\">\n\t\t\t\t\t\t\t\t<span><strong class=\"text-text\">{num(memberCount)}</strong> {memberCount === 1 ? t('member') : t('members')}</span>\n\t\t\t\t\t\t\t\t<span><strong class=\"text-text\">{data.niche.postCount}</strong> {t('posts')}</span>\n\t\t\t\t\t\t\t\t{#if data.founder?.nickname}\n\t\t\t\t\t\t\t\t\t<span>{t('founded by')} <a href={`/u/${data.founder.nickname}`} class=\"text-accent hover:underline no-underline\">@{data.founder.nickname}</a></span>\n\t\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"flex gap-2 mt-4 flex-wrap\">\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonclick={toggleSubscribe}\n\t\t\t\t\t\t\tdisabled={subscribing}\n\t\t\t\t\t\t\tclass=\"flex-1 py-2.5 rounded-lg font-semibold text-sm transition-colors\n\t\t\t\t\t\t\t\t{isSubscribed ? 'bg-surface-2 border border-border text-text' : 'bg-accent text-bg hover:bg-accent/90'}\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{isSubscribed ? t('✓ subscribed') : t('subscribe')}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t{#if data.defaultRoom}\n\t\t\t\t\t\t\t{#if chatViewerIsMember}\n\t\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\t\thref={`/g/${data.defaultRoom.code}`}\n\t\t\t\t\t\t\t\t\tclass=\"inline-flex items-center gap-1.5 px-4 py-2.5 rounded-lg border border-border bg-surface-2 text-text text-xs font-semibold hover:border-border-strong no-underline transition-colors\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" />\n\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t\t{t('open chat')}\n\t\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t\t{:else}\n\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\tonclick={() => (chatModalOpen = true)}\n\t\t\t\t\t\t\t\t\tclass=\"inline-flex items-center gap-1.5 px-4 py-2.5 rounded-lg border border-accent/40 bg-accent/10 text-accent text-xs font-semibold hover:bg-accent/15 transition-colors\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t<path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\" />\n\t\t\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t\t\t{t('join chat')}\n\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t\t<!-- Secondary share action next to the green subscribe CTA.\n\t\t\t\t\t\t\t Neutral surface (no off-theme coral) so it reads as the\n\t\t\t\t\t\t\t quieter of the paired buttons. -->\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\tonclick={shareNiche}\n\t\t\t\t\t\t\tclass=\"inline-flex items-center gap-1.5 px-4 py-2.5 rounded-lg border border-border bg-surface-2 text-muted text-xs font-semibold hover:text-text hover:border-border-strong transition-colors\"\n\t\t\t\t\t\t\ttitle={t('copy link')}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t<circle cx=\"18\" cy=\"5\" r=\"3\"/>\n\t\t\t\t\t\t\t\t<circle cx=\"6\" cy=\"12\" r=\"3\"/>\n\t\t\t\t\t\t\t\t<circle cx=\"18\" cy=\"19\" r=\"3\"/>\n\t\t\t\t\t\t\t\t<line x1=\"8.59\" y1=\"13.51\" x2=\"15.42\" y2=\"17.49\"/>\n\t\t\t\t\t\t\t\t<line x1=\"15.41\" y1=\"6.51\" x2=\"8.59\" y2=\"10.49\"/>\n\t\t\t\t\t\t\t</svg>\n\t\t\t\t\t\t\t{t('share')}\n\t\t\t\t\t\t</button>\n\t\t\t\t\t\t{#if data.viewerRole === 'owner'}\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={`/n/${data.niche.slug}/manage`}\n\t\t\t\t\t\t\t\tclass=\"inline-flex items-center gap-1.5 px-4 py-2.5 rounded-lg border border-border bg-surface-2 text-text text-xs font-semibold hover:border-border-strong no-underline transition-colors\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{t('manage')}\n\t\t\t\t\t\t\t</a>\n\t\t\t\t\t\t{/if}\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<!-- Grow this niche: reddit share hook, always visible -->\n\t\t\t\t\t<div class=\"mt-4 pt-4 border-t border-border\">\n\t\t\t\t\t\t<div class=\"text-[10px] text-muted uppercase tracking-widest mb-2\">{t('grow this niche')}</div>\n\t\t\t\t\t\t<a\n\t\t\t\t\t\t\thref={redditShareUrl}\n\t\t\t\t\t\t\ttarget=\"_blank\"\n\t\t\t\t\t\t\trel=\"noopener noreferrer\"\n\t\t\t\t\t\t\tclass=\"inline-flex items-center gap-2 px-3 py-1.5 rounded-md border border-border text-xs text-muted hover:text-text hover:border-border-strong no-underline transition-colors\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{t('share /n/{slug} on reddit', { slug: data.niche.slug })}\n\t\t\t\t\t\t\t<svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" fill=\"none\"><path d=\"M3 5h4M5 3l2 2-2 2\" stroke=\"currentColor\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>\n\t\t\t\t\t\t</a>\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</section>\n\n\t\t<!-- composer (only if authed + not banned + niche not hibernated) -->\n\t\t{#if data.canPost && !data.niche.isHibernated}\n\t\t\t<div class=\"-mx-5 sm:mx-0 sm:mb-5\">\n\t\t\t\t<PostComposer\n\t\t\t\t\tnicheContext={data.niche\n\t\t\t\t\t\t? { id: data.niche.id, slug: data.niche.slug, name: data.niche.name }\n\t\t\t\t\t\t: undefined}\n\t\t\t\t/>\n\t\t\t</div>\n\t\t{/if}\n\n\t\t<!-- feed -->\n\t\t{#if data.posts.length === 0}\n\t\t\t<!-- empty feed: the site's hero voice, in the niche's colour -->\n\t\t\t<section class=\"-mx-5 border-b border-border bg-surface px-6 py-10 sm:mx-0 sm:rounded-2xl sm:border\">\n\t\t\t\t<div class=\"eyebrow-x\">/n/{data.niche.slug} · {t('day one')}</div>\n\t\t\t\t<h2 class=\"empty-h\">{t('nothing here')}<br /><span>{t('yet.')}</span></h2>\n\t\t\t\t<p class=\"mt-3 max-w-md text-sm leading-relaxed text-muted\">\n\t\t\t\t\t{#if data.canPost}\n\t\t\t\t\t\t{data.niche.memberCount === 1 ? t(\"it's just you so far.\") : t('{n} people are in, nobody has posted.', { n: num(data.niche.memberCount) })} {t('the first post sets the tone for everyone who comes after. make it a good one.')}\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t{data.niche.memberCount === 1 ? t('1 person is in and the feed is empty.') : t('{n} people are in and the feed is empty.', { n: num(data.niche.memberCount) })} {t('sign in and be the one who starts it.')}\n\t\t\t\t\t{/if}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"mt-6 flex flex-wrap items-center gap-2\">\n\t\t\t\t\t{#if data.canPost}\n\t\t\t\t\t\t<button type=\"button\" class=\"empty-cta\" onclick={() => { window.scrollTo({ top: 0, behavior: 'smooth' }); document.querySelector<HTMLTextAreaElement>('textarea')?.focus(); }}>{t('post the first thing')}</button>\n\t\t\t\t\t{:else}\n\t\t\t\t\t\t<a href={`/auth/sign-in?next=${encodeURIComponent(`/n/${data.niche.slug}`)}`} class=\"empty-cta no-underline\">{t('sign in to post')}</a>\n\t\t\t\t\t{/if}\n\t\t\t\t\t<button type=\"button\" class=\"empty-alt\" onclick={shareNiche}>{t('invite people')}</button>\n\t\t\t\t</div>\n\t\t\t</section>\n\t\t{:else}\n\t\t\t<div class=\"-mx-5 flex flex-col sm:mx-0 sm:gap-4\">\n\t\t\t\t{#each data.posts as p (p.id)}\n\t\t\t\t\t<PostCard post={p} viewerLoggedIn={!!data.viewerNickname} viewerId={data.viewerId} onModRemove={isStaff ? modRemove : null} />\n\t\t\t\t{/each}\n\t\t\t</div>\n\t\t{/if}\n\n\t\t<!-- more niches: server-rendered links, the way search engines reach the\n\t\t\t other communities (the discovery tab loads in the browser) -->\n\t\t{#if data.related.length > 0}\n\t\t\t<nav\n\t\t\t\taria-labelledby=\"more-niches\"\n\t\t\t\tclass=\"-mx-5 mt-6 border-t border-border px-5 pt-6 sm:mx-0 sm:rounded-2xl sm:border sm:bg-surface sm:p-5\"\n\t\t\t>\n\t\t\t\t<h2 id=\"more-niches\" class=\"text-xs font-bold tracking-wider text-muted uppercase\">{t('more niches')}</h2>\n\t\t\t\t<ul class=\"mt-3 flex flex-wrap gap-2\">\n\t\t\t\t\t{#each data.related as r (r.slug)}\n\t\t\t\t\t\t<li>\n\t\t\t\t\t\t\t<a\n\t\t\t\t\t\t\t\thref={`/n/${r.slug}`}\n\t\t\t\t\t\t\t\tclass=\"inline-flex items-center gap-1.5 rounded-full border border-border bg-bg px-3 py-1.5 text-xs font-semibold text-text no-underline transition-colors hover:border-accent/50\"\n\t\t\t\t\t\t\t\t>{r.name}<span class=\"font-normal text-muted\">{num(r.memberCount)}</span></a\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t</li>\n\t\t\t\t\t{/each}\n\t\t\t\t</ul>\n\t\t\t\t{#if SIZE_NICHES.has(data.niche.slug)}\n\t\t\t\t\t<p class=\"mt-4 text-xs leading-relaxed text-muted\">\n\t\t\t\t\t\t{#each t('how do you measure up? the {calc} gives your percentile, and the {cmp} puts you next to the average.').split(/(\\{calc\\}|\\{cmp\\})/) as part, i (i)}{#if part === '{calc}'}<a href={lhref('/tools/penis-size-calculator')} class=\"font-semibold text-text hover:text-accent\">{t('dick size calculator')}</a\n\t\t\t\t\t\t\t>{:else if part === '{cmp}'}<a href={lhref('/tools/penis-size-visualizer')} class=\"font-semibold text-text hover:text-accent\">{data.niche.slug === 'cockcompare' ? t('cock size comparison') : t('penis size comparison')}</a\n\t\t\t\t\t\t\t>{:else}{part}{/if}{/each}\n\t\t\t\t\t</p>\n\t\t\t\t{/if}\n\t\t\t\t{#if data.niche.slug === 'sph'}\n\t\t\t\t\t<!-- RAT-617: what this community is about, explained and for sale -->\n\t\t\t\t\t<p class=\"mt-4 text-xs leading-relaxed text-muted\">\n\t\t\t\t\t\t<a href=\"/sph\" class=\"font-semibold text-text hover:text-accent\">SPH, explained</a> ·\n\t\t\t\t\t\t<a href=\"/sph/clips\" class=\"font-semibold text-text hover:text-accent\">SPH clips</a> ·\n\t\t\t\t\t\t<a href=\"/sph/captions\" class=\"font-semibold text-text hover:text-accent\">SPH captions</a> ·\n\t\t\t\t\t\t<a href=\"/sph/joi\" class=\"font-semibold text-text hover:text-accent\">SPH JOI</a>\n\t\t\t\t\t</p>\n\t\t\t\t{/if}\n\t\t\t\t{#if hub}\n\t\t\t\t\t<!-- RAT-608: the shop for what this community posts about -->\n\t\t\t\t\t<p class=\"mt-4 text-xs leading-relaxed text-muted\">\n\t\t\t\t\t\t{t('paid photo sets from creators')}:\n\t\t\t\t\t\t<a href={albumHubPath(hub)} class=\"font-semibold text-text hover:text-accent\">{hub.name} →</a>\n\t\t\t\t\t</p>\n\t\t\t\t{/if}\n\t\t\t\t<p class=\"mt-4 text-xs leading-relaxed text-muted\">\n\t\t\t\t\t<!-- RAT-591: \"rate my cock\" points at the homepage that ranks for it,\n\t\t\t\t\t\t the AI words at the rater itself -->\n\t\t\t\t\t{#each t('new here? {cock} with the {ai}, or {raters}.').split(/(\\{cock\\}|\\{ai\\}|\\{raters\\})/) as part, i (i)}{#if part === '{cock}'}<a href=\"/\" class=\"font-semibold text-text hover:text-accent\">{t('rate my cock')}</a\n\t\t\t\t\t\t>{:else if part === '{ai}'}<a href=\"/rate\" class=\"font-semibold text-text hover:text-accent\">{t('AI dick rater')}</a\n\t\t\t\t\t\t>{:else if part === '{raters}'}<a href=\"/r\" class=\"font-semibold text-text hover:text-accent\">{t('get rated by real raters')}</a\n\t\t\t\t\t\t>{:else}{part}{/if}{/each}\n\t\t\t\t</p>\n\t\t\t</nav>\n\t\t{/if}\n\t</div>\n\n\t{#if shareToastVisible}\n\t\t<div class=\"fixed bottom-6 left-1/2 -translate-x-1/2 px-4 py-2 rounded-lg bg-surface-2 border border-border text-sm shadow-soft z-50\">\n\t\t\t{shareToastText}\n\t\t</div>\n\t{/if}\n\n\t<!-- RIGHT: sidebar -->\n\t<aside class=\"hidden lg:block\">\n\t\t<div class=\"sticky top-20 space-y-4\">\n\n\t\t\t<section class=\"rounded-2xl border border-border bg-surface p-4\">\n\t\t\t\t<h2 class=\"mb-3 text-xs font-bold uppercase tracking-wider text-muted\">{t('about this niche')}</h2>\n\t\t\t\t<p class=\"text-xs text-muted leading-relaxed\">{data.niche.description}</p>\n\t\t\t\t<div class=\"border-t border-border mt-3 pt-3 text-[11px] text-muted space-y-1\">\n\t\t\t\t\t<div><span class=\"text-text\">{t('created')}</span> · {new Date(data.niche.createdAt).toLocaleDateString()}</div>\n\t\t\t\t\t{#if data.founder?.nickname}\n\t\t\t\t\t\t<div><span class=\"text-text\">{t('founder')}</span> · <a href={`/u/${data.founder.nickname}`} class=\"text-accent hover:underline no-underline\">@{data.founder.nickname}</a></div>\n\t\t\t\t\t{/if}\n\t\t\t\t</div>\n\t\t\t</section>\n\n\t\t\t<section class=\"rounded-2xl border border-border bg-surface p-4 text-xs text-muted\">\n\t\t\t\t<p class=\"leading-relaxed\">{t(\"subscribe to get this niche's posts in your /f Niches tab (coming soon). post here to reach all {n} subscribers.\", { n: num(memberCount) })}</p>\n\t\t\t\t<a href=\"/n\" class=\"mt-2 inline-block font-semibold text-accent hover:underline\">{t('browse all niches →')}</a>\n\t\t\t</section>\n\n\t\t</div>\n\t</aside>\n</div>\n\n<!-- RAT-342: join-to-chat modal. Shown after a fresh subscribe + on\n\t the standalone \"join chat\" pill when the viewer isn't yet in the\n\t default room. Click-outside / Esc close. -->\n{#if data.defaultRoom}\n\t<JoinNicheChatModal\n\t\topen={chatModalOpen}\n\t\tslug={data.niche.slug}\n\t\tnicheName={data.niche.name}\n\t\tmemberCount={chatMemberCount}\n\t\troomCode={data.defaultRoom.code}\n\t\tonClose={() => (chatModalOpen = false)}\n\t\tonJoined={() => { chatViewerIsMember = true; }}\n\t/>\n{/if}\n</div>\n\n<style>\n\t.eyebrow-x { font-family: var(--font-display); font-size: 11px; font-weight: 700; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-accent); }\n\t.empty-h { font-family: var(--font-display); font-weight: 700; font-size: clamp(2rem, 6vw, 3rem); line-height: 0.95; letter-spacing: -0.04em; margin-top: 8px; }\n\t.empty-h span { color: var(--color-accent); }\n\t.empty-cta { display: inline-flex; align-items: center; padding: 11px 20px; border-radius: 12px; border: none; background: var(--color-accent); color: #0a0a0a; font-family: var(--font-display); font-size: 14px; font-weight: 700; cursor: pointer; }\n\t.empty-alt { display: inline-flex; align-items: center; padding: 11px 18px; border-radius: 12px; background: var(--color-surface-2); border: 1px solid var(--color-border); color: var(--color-text); font-family: var(--font-display); font-size: 14px; font-weight: 700; cursor: pointer; }\n\t.niche-theme { position: relative; min-height: 100vh; }\n\t.niche-bg {\n\t\tposition: fixed;\n\t\tinset: 0;\n\t\tz-index: 0;\n\t\tpointer-events: none;\n\t\tbackground-image: var(--niche-bg-image, none);\n\t\tbackground-size: var(--niche-bg-size, auto);\n\t\tbackground-attachment: fixed;\n\t}\n</style>\n"],"version":3}