docs: sync wikis from Gitea (2026-05-10 00:15 UTC)

This commit is contained in:
gitea-actions[bot]
2026-05-09 19:15:08 -05:00
parent 47183ee5ef
commit 6f8af0d90f
17 changed files with 3331 additions and 1 deletions
+2 -1
View File
@@ -11,6 +11,7 @@ Consolidated backup of all project wikis from [Gitea](https://git.mokoconsulting
- [**Template-Client-WaaS**](Template-Client-WaaS/) — 5 pages
- [**backup-mcp**](backup-mcp/) — 6 pages
- [**client-clarksvillefurs**](client-clarksvillefurs/) — 16 pages
- [**client-waas-clarksvillefurs**](client-waas-clarksvillefurs/) — 16 pages
- [**deploy-mcp**](deploy-mcp/) — 6 pages
- [**joomla-api-mcp**](joomla-api-mcp/) — 6 pages
- [**moko-platform**](moko-platform/) — 53 pages
@@ -18,4 +19,4 @@ Consolidated backup of all project wikis from [Gitea](https://git.mokoconsulting
- [**ssh-mcp**](ssh-mcp/) — 10 pages
---
*Last synced: 2026-05-10 00:09 UTC*
*Last synced: 2026-05-10 00:15 UTC*
+69
View File
@@ -0,0 +1,69 @@
# ClarksvilleFurs.com
Managed Joomla client site for the Clarksville Furs community — a free, all-ages furry community in Clarksville, TN.
## Infrastructure
| Environment | URL | Server |
|---|---|---|
| **Live** | [clarksvillefurs.com](https://clarksvillefurs.com) | DreamHost (iad1-shared-b7-01) |
| **Dev** | [clarksvillefurs.dev.mokoconsulting.tech](https://clarksvillefurs.dev.mokoconsulting.tech) | Moko Dev Server |
| **Monitoring** | [Grafana Dashboard](https://bench.mokoconsulting.tech/d/client-d85a0ed3/) | Moko Bench |
Both environments share the same database. Dev is an open mirror of live (without offline mode).
## Quick Links
| Task | How |
|---|---|
| Deploy to dev | Push to `dev` branch → auto-deploys via workflow |
| Deploy to live | Merge to `main` → auto-deploys dev + live |
| Sync extensions | `deploy_sync_joomla` MCP tool or `sync-servers.yml` workflow |
| Monitor status | [Grafana dashboard](https://bench.mokoconsulting.tech/d/client-d85a0ed3/) |
| Run backup | Akeeba Backup in Joomla admin |
## Platform
- **CMS:** Joomla 6.1.0
- **Template:** MokoOnyx
- **PHP:** 8.4 (web) / 8.2 (CLI)
- **Platform type:** `client` (MokoStandards)
## Documentation
### Site Management
- [Deployment](deployment) — server access, deploy workflow, SFTP configs
- [Content Authoring](content-authoring) — article and page management
- [Brand Reference](brand-reference) — logos, colors, voice
### Content Guides
- [Style Guide](authoring-style-guide) — writing standards
- [Quick Reference](authoring-quick-reference) — common tasks
- [Cross-Post Preview](authoring-cross-post-preview) — social media teasers
- [Ad Schedule](authoring-ad-schedule) — promotion calendar
### SOPs
- [Website Management](authoring-sop-website-management) — admin procedures
- [Moderation](authoring-sop-moderation) — community moderation
### Technical
- [Theme Architecture](theme-architecture) — MokoOnyx template structure
- [CSS Variables](css-variables) — custom theme variables
- [Accessibility](accessibility) — WCAG compliance
- [Migration Plan](migration-plan-events) — events system migration
## MokoStandards
This repo follows the [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home) governance framework.
- [Site Monitoring](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/SITE_MONITORING) — Prometheus + Grafana monitoring
- [Joomla Sync](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/JOOMLA_SYNC) — dev ↔ live file sync
- [Minification](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/MINIFICATION) — CSS/JS build pipeline
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,162 @@
← [Home](Home)
# Accessibility
WCAG 2.1 AA is the baseline target for all text on the CF site. That means
4.5:1 contrast for normal text and 3:1 for large text (≥18pt or ≥14pt bold) or
UI components. This document tracks issues found during live-site audits, the
theme-level mitigations in place, and the content-edit items that can't be
fixed from CSS.
## Resolved in the theme
### Coral-on-sky links fail AA — fixed
Coral `#FF4B3E` on the sky blue backgrounds used across the site measures
2.06:1 to 2.57:1, all below the 4.5:1 AA threshold.
| Fg | Bg | Ratio | Where |
|---|---|---|---|
| Coral | Sky Primary `#9CCEDB` | 2.33:1 | block-color-1, hero-primary |
| Coral | Sky Secondary `#7FB7C6` | 2.06:1 | container-bottom-a, offline page bg |
| Coral | Sky Raw `#a3cde2` | 2.57:1 | `.custom.sky` cards, container-top-b |
**Mitigation:** `user.css` has a scoped override that flips `--link-color` to
ink `#1E1E1E` inside any element with a sky background (selectors cover
`[style*="var(--color-primary)"]`, `[style*="var(--sky)"]`, `.cf-brand-callout`,
`.container-top-b`, `.container-bottom-a`, `.hero-primary`, `.block-color-1`,
`.custom.sky .card`, `.custom.yellow .card`, `.custom.red .card`).
**Hover state** uses coral, which does fail AA against sky. Hover is
time-limited and visual affordance is already established by underline
thickness change. Monitored but not currently a blocker.
### White-on-red fails AA — fixed
White on soft red `#ff7a73` measures 2.53:1. `.custom.red .card-body` now uses
ink text (5.79:1, AA pass) instead of white.
### Muted text invisible on sky — fixed
Mascot Grey `#8F8F8F` on sky backgrounds drops below 2:1. Same scoped override
bumps muted text to `#3a3a3a` inside sky surfaces.
### Light palette drift — fixed
Several Bootstrap palette variables in `light.custom.css` had accidentally held
dark-mode values (`--light: #1B2027`, `--primary-text-emphasis: #7A1E15`,
`--primary-bg-subtle: #3a1511`, etc.). These were silently breaking
`.bg-primary-subtle`, `.text-primary-emphasis`, `.bg-light`, `.bg-dark` utility
classes site-wide. All corrected to proper light-mode values in v02.02.00.
## Known exceptions — acceptable
### Coral on white, small text (3.63:1)
Coral on white background at body text size measures 3.63:1 — above AA-large
(3:1) but below AA-normal (4.5:1). The `.cf-brand-accent` utility and the
decorative `.text-danger` on headings compat rule only apply this color to
large text (`h1``h6`, `.display-*`), where 3.63:1 is AA-pass. Link text with
body font size uses a darker shade via `--link-color: #FF4B3E` + underline for
affordance.
### Coral hover on dark-tint cards (1.05:11.39:1)
Hover state on `.custom.green` links is 1.39:1. Primary affordance is
underline thickness change, which is preserved. Fix available: swap hover
color to ink (11.4:1 AAA). Not applied by default because coral hover is the
site-wide brand convention.
## Known issues — content-edit required
Theme CSS cannot fix these; they must be addressed in Joomla article content
or module configuration.
### Placeholder URLs
Found in article content on about-us, faq, news:
```html
<a href="/YOUR_FACEBOOK_URL">Facebook</a>
```
Either replace with the real Facebook URL or remove the Facebook mention.
### Hardcoded brand-color CTAs
Home page has inline-styled Discord and Telegram CTAs:
```html
```
Telegram's official light cyan fails AA with white text. Options:
1. Swap text to ink: `color: #1E1E1E` (5.09:1, AA pass)
2. Use Telegram's darker brand variant `#0088CC` (5.09:1 with white, AA pass)
3. Use a `.btn-primary` instead and accept that all CTAs look the same
All three require a content edit. Option 2 is most brand-authentic.
### Decorative `.text-danger` on body text
If an editor uses `<p class="text-danger">` to make a paragraph red (as
decoration, not warning), the text renders as soft red `#ff7a73` — 3.14:1
against white. Fails AA for normal text. The compat rule only applies to
headings. For decorative red body text, use `.cf-brand-accent` (coral) instead
— which also fails AA at body size, but is the intended brand color and is
constrained to short spans.
Real semantic danger messages should stay in `.text-danger` and be kept to
large-text usage (alerts, form validation summaries).
## Audit tools
### Style guide preview
Open `/style-guide.html` (at the repo root of any theme package delivery) in
a browser. Contains:
- A Blue Gauntlet section exercising every common element on sky backgrounds
- Contrast audit table computing ratios live for all common color pairs
- Light/dark toggle
- All tinted card variants rendered with sample content
### Browser DevTools
Chrome/Firefox DevTools Accessibility panel shows contrast ratios on hover for
any text element. Fastest way to sanity-check a page before committing.
### WebAIM Contrast Checker
<https://webaim.org/resources/contrastchecker/> — paste in two hex values,
confirms AA/AAA grading.
## Metadata
| Field | Value |
|---|---|
| Document Type | reference |
| Domain | Accessibility |
| Applies To | CF website (clarksvillefurs.com) |
| Jurisdiction | WCAG 2.1 AA |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/accessibility.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-21 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-21 | Claude | Initial creation | Findings from live-site audit at v02.06.00 |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,89 @@
← [Home](Home)
# Authoring Documentation
Documentation for anyone posting Events or News articles on the
Clarksville Furs website. Written for members of the **Event Authors**
Joomla group and the webmaster.
## Who these docs are for
- **Event Authors** — managers and volunteers who create and publish
event listings and news posts through the Joomla admin.
- **Webmaster** — the person responsible for the site, user accounts,
and cross-post integrations.
## Reading order
If you're brand new, read in this order:
1. **[Quick Reference](quick-reference)** — numbered steps to log
in, create an article, attach an image, and publish. One page,
skimmable in under a minute.
2. **[Style Guide](style-guide)** — voice and tone rules, title
format, body length targets, image specs, and what not to do.
3. **[Cross-Post Preview](cross-post-preview)** — how a single
article shows up on Discord, Telegram, and Facebook, and which
fields control what.
4. **[Screencast Script](screencast-script)** — the spoken script
for the recorded walkthrough video. Read this if you want a
scene-by-scene overview of the full workflow before you try it.
5. **[Ad Schedule](ad-schedule)** — promotional posting schedule
for pre-launch (4 weeks) and post-launch (6 months) to drive
traffic to the website.
6. **[SOP — Website Management](sop-website-management)** — user
accounts, content management, events, media, backups, and
emergency procedures.
7. **[SOP — Community Moderation](sop-moderation)** — 4-tier
moderation system, platform-specific procedures, crisis handling,
and moderator self-care.
If you've posted before and just need a refresher, start and stop at
the Quick Reference.
## Related documents
- [Migration Plan — Events](migration-plan-events) — the
upstream plan that defines when and how Events authoring goes live.
- [Content Authoring Guide](content-authoring) — CSS utility
classes available inside article HTML.
- [Brand Reference](brand-reference) — palette, typography, and
design decisions.
- [Deployment Guide](deployment) — how theme changes ship to
dev and production.
## Questions?
Use the [Contact Us](https://clarksvillefurs.com/contact-us) page or ask in #server-announcements on Discord.
---
## Metadata
| Field | Value |
|---|---|
| Document Type | index |
| Domain | Content Authoring |
| Applies To | Event Authors group, Webmaster |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/authoring/README.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-26 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-26 | Claude | Initial creation | Phase 3 authoring docs index |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,138 @@
← [Home](Home)
# Ad Schedule — Pre-Launch and Post-Launch
Promotional posting schedule for Discord, Telegram, and Facebook to
build awareness of the website and drive traffic to
clarksvillefurs.com.
All posts should link to the website as the primary destination — not
to direct chat invites. The goal is to get members and newcomers
interacting with the site, reading the FAQ, and using the events page.
---
## Pre-Launch (4 weeks before [LAUNCH DATE])
### Week 4 (T-28 days)
| Day | Platform | Post |
|---|---|---|
| Monday | Discord, Telegram | **Teaser**: "Something new is coming to Clarksville Furs. Stay tuned." (No link yet) |
| Thursday | Facebook | **Teaser**: Same message, post to the Facebook group |
### Week 3 (T-21 days)
| Day | Platform | Post |
|---|---|---|
| Monday | Discord, Telegram | **Sneak peek**: "Our new website is almost ready. Here's a preview of what's coming — FAQ, events, and a whole new way to stay connected." Screenshot of the FAQ page. |
| Wednesday | Facebook | **Sneak peek**: Same, with screenshot |
| Friday | Discord | **FAQ highlight**: Share one FAQ answer as a teaser — "This and 11 more answers at clarksvillefurs.com/faq (coming soon)" |
### Week 2 (T-14 days)
| Day | Platform | Post |
|---|---|---|
| Monday | Discord, Telegram | **Feature spotlight — Events**: "Soon you'll be able to browse all CF events in one place — and submit your own. clarksvillefurs.com/events" |
| Wednesday | Discord | **Feature spotlight — FAQ**: "Parents asking questions? Friends curious about the fandom? We built a FAQ page that covers it all." |
| Friday | Facebook | **Countdown**: "One week out. The new Clarksville Furs website launches [LAUNCH DATE]." |
### Week 1 (T-7 days)
| Day | Platform | Post |
|---|---|---|
| Monday | All platforms | **Countdown**: "This week. clarksvillefurs.com goes live on [LAUNCH DATE]." |
| Wednesday | Discord, Telegram | **Call to action**: "When the site launches, head to clarksvillefurs.com and explore. Read the FAQ. Check out the events page." |
| Friday | All platforms | **Launch eve**: "Tomorrow. clarksvillefurs.com" |
### Launch Day
| Platform | Post |
|---|---|
| All platforms | **Launch**: "We're live! The new Clarksville Furs website is here. Explore the FAQ, browse upcoming events, and get to know the community. clarksvillefurs.com" |
| Discord (pinned) | **Pinned**: "The Clarksville Furs website is live at clarksvillefurs.com. This is now the best place to find event details, read the FAQ, and learn about the community." |
---
## Post-Launch: Months 16
### Monthly recurring posts
| Frequency | Platform | Post type |
|---|---|---|
| 1st of month | All platforms | **Monthly reminder**: "All upcoming events are on clarksvillefurs.com/events. Browse what's coming up and RSVP." |
| 15th of month | Discord, Telegram | **Submit your own event**: "Did you know members can create their own events? Visit clarksvillefurs.com/events and click Submit Event." |
| Weekly (Mon) | Discord | **FAQ of the week**: Pick one FAQ article and share the intro text with a link. Rotate through all 12 over 3 months. |
### Month 1 — Establish habits
| Week | Platform | Post |
|---|---|---|
| 1 | All platforms | **Welcome post**: "New here? Start at clarksvillefurs.com — our FAQ answers the most common questions, and the events page shows you what's coming up." |
| 2 | Discord, Telegram | **For parents**: "Got a kid who's into furries? Our FAQ has a page just for you: clarksvillefurs.com/faq" |
| 3 | Facebook | **Share prompt**: "Know someone curious about the fandom? Share our FAQ with them: clarksvillefurs.com/faq" |
| 4 | Discord | **Event submission reminder**: "Want to organize a game night, movie night, or meetup? Submit it at clarksvillefurs.com/events" |
### Month 2 — Deepen engagement
| Week | Platform | Post |
|---|---|---|
| 1 | Discord, Telegram | **Highlight a specific FAQ**: "What is a Therian?" intro text + link |
| 2 | Facebook | **Convention planning**: "Thinking about a con trip? Check our events page for group plans: clarksvillefurs.com/events" |
| 3 | Discord | **Feedback ask**: "Been using the website? Tell us what you think — use the Contact Us page: clarksvillefurs.com/contact-us" |
| 4 | All platforms | **Community stat**: "X members and counting. If you haven't visited the site yet, now's a great time: clarksvillefurs.com" |
### Months 36 — Maintain cadence
By month 3, reduce to the monthly recurring schedule (1st and 15th)
plus the weekly FAQ rotation on Discord. Add one-off posts only when:
- A new FAQ article is added
- A major event is coming up
- The website gets a significant update
- A milestone is reached (member count, event count)
---
## Post guidelines
- **Always link to clarksvillefurs.com** — never give out direct
Discord or Telegram invite links as the primary entry point
- **Teasers, not full details** — drive traffic to the website for
complete information
- **Contact goes through the ticket system** — point people to
clarksvillefurs.com/contact-us, not a direct email address
- **Keep it casual** — match the CF voice (warm, direct, inclusive)
- **One exclamation mark max** per post
---
## Metadata
| Field | Value |
|---|---|
| Document Type | schedule |
| Domain | Content Marketing |
| Applies To | Webmaster, Event Authors, Social media managers |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/authoring/ad-schedule.md |
| Version | 00.01.00 |
| Status | Draft |
| Last Reviewed | 2026-04-27 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-27 | Claude | Initial creation | Pre-launch (4 weeks) and post-launch (6 months) promotional schedule |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,238 @@
← [Home](Home)
# Cross-Post Preview
When you publish an article in the **Events** or **News** category, it
automatically cross-posts to three platforms. Each platform pulls
different fields from the article. This page shows you exactly what
goes where so you can tune your intro text and image before hitting
Publish.
## How cross-posting works
Two integrations handle the cross-posts:
| Integration | Destination | Trigger |
|---|---|---|
| **MokoDiscordHook** | Discord — #server-announcements | `onContentAfterSave` fires when an article is saved in a configured category |
| **Perfect Publisher** | Facebook Page + Telegram channel | Rule Engine matches the article category and posts via the FB and Telegram APIs |
You don't need to do anything extra. Save a published article in the
right category and the cross-posts fire automatically.
**Important — teasers, not full details.** Cross-posts should hook the
reader and drive them to the website. Write the intro as a short teaser
that makes people want to click through to clarksvillefurs.com/events
for the full info. Don't put the complete date, time, and location in
the intro — save those for the article body.
## Worked example
Suppose you create this article:
| Field | Value |
|---|---|
| **Title** | Monthly Meetup — Downtown Clarksville |
| **Alias** | monthly-meetup-downtown-clarksville |
| **Category** | Events |
| **Intro text** | Our monthly meetup is back! Grab a lawn chair and come hang — full details on the website. |
| **Intro Image** | `images/events/meetup-heritage-park.jpg` (1200x630, pavilion with picnic tables) |
| **Intro Image Alt** | Pavilion at Heritage Park with picnic tables and string lights |
| **Full article body** | (additional details: directions, parking, what to bring, RSVP link) |
Here's how that article renders on each surface:
---
### Discord — MokoDiscordHook embed
MokoDiscordHook sends a rich embed to #server-announcements. The
embed uses these article fields:
| Embed element | Sourced from |
|---|---|
| **Embed title** | Article title |
| **Embed description** | Intro text (first 12 sentences of the article body, before the "Read more" break) |
| **Embed image** | Intro Image |
| **Embed link** | Full article URL on clarksvillefurs.com |
**What it looks like in Discord:**
```
┌──────────────────────────────────────────┐
│ Monthly Meetup — Downtown Clarksville │
│ │
│ Our monthly meetup is back! Grab a │
│ lawn chair and come hang — full │
│ details on the website. │
│ │
│ │
│ ┌────────────────────────────────────┐ │
│ │ │ │
│ │ [ intro image: pavilion with │ │
│ │ picnic tables and string │ │
│ │ lights ] │ │
│ │ │ │
│ └────────────────────────────────────┘ │
│ │
│ clarksvillefurs.com │
└──────────────────────────────────────────┘
```
**Tips for Discord:**
- Keep the intro under 200 characters for clean embed layout.
- Title truncates around 70 characters — stay under.
- The image renders full-width in the embed. Landscape (1200x630) is
ideal.
- Discord caches embeds aggressively. If you edit the article after
posting, the Discord embed will **not** update.
---
### Telegram — Perfect Publisher message
Perfect Publisher posts to @ClarksvilleFurs as a text message
with a link preview.
| Message element | Sourced from |
|---|---|
| **Message text** | Intro text + article URL |
| **Link preview title** | Article title (from the page's `<meta og:title>`) |
| **Link preview image** | Intro Image (from `<meta og:image>`) |
| **Link preview description** | Meta description, or intro text if meta description is empty |
**What it looks like in Telegram:**
```
Our monthly meetup is back! Grab a lawn
chair and come hang — full details on
the website.
clarksvillefurs.com/events/monthly-meetup-
downtown-clarksville
┌────────────────────────────────┐
│ [ link preview card ] │
│ │
│ Monthly Meetup — Downtown │
│ Clarksville │
│ │
│ [ intro image thumbnail ] │
│ │
│ clarksvillefurs.com │
└────────────────────────────────┘
```
**Tips for Telegram:**
- The intro text becomes the message body — write it as a teaser that
hooks the reader and drives them to the website for full details.
- Telegram generates the link preview from Open Graph meta tags. If the
intro image is missing, Telegram may show no preview or a generic
favicon.
- The link preview caches. If you need to refresh it after editing,
use Telegram's [@webpagebot](https://t.me/webpagebot) to clear the
cache for the URL.
---
### Facebook — Perfect Publisher post
Perfect Publisher creates a post on the linked Facebook Page
(clarksvillefurs) with a link card.
| Post element | Sourced from |
|---|---|
| **Post text** | Intro text (prepended to the link) |
| **Link card title** | Article title (from `<meta og:title>`) |
| **Link card image** | Intro Image (from `<meta og:image>`) |
| **Link card description** | Meta description, or intro text if empty |
| **Link card domain** | clarksvillefurs.com |
**What it looks like on Facebook:**
```
Clarksville Furs
Just now · 🌐
Our monthly meetup is back! Grab a lawn
chair and come hang — full details on
the website.
┌────────────────────────────────────┐
│ │
│ [ large link card image: │
│ pavilion with picnic tables │
│ and string lights ] │
│ │
├────────────────────────────────────┤
│ CLARKSVILLEFURS.COM │
│ Monthly Meetup — Downtown │
│ Clarksville │
│ Our monthly meetup is back! │
│ Grab a lawn chair and come... │
└────────────────────────────────────┘
👍 Like 💬 Comment ↗ Share
```
**Tips for Facebook:**
- The link card image must be at least 600x315 px. The recommended
1200x630 works perfectly.
- Facebook caches link previews aggressively. If you update the image
or title after the first post, use the Facebook Sharing Debugger to
force a re-scrape of the URL.
- The intro text appears *above* the link card. Keep it short and
punchy — two sentences max.
---
## Field-to-surface cheat sheet
| Article field | Website | Discord | Telegram | Facebook |
|---|---|---|---|---|
| Title | Page heading | Embed title | Link preview title | Link card title |
| Intro text | Category listing excerpt | Embed description | Message body | Post text |
| Intro Image | Category listing thumbnail | Embed image | Link preview image | Link card image |
| Intro Image Alt | `alt` attribute on `<img>` | Not displayed | Not displayed | Not displayed (but good practice) |
| Full article body | Full article page | Not included | Not included | Not included |
| Article URL | Canonical link | Embed link | Message link | Link card URL |
| Meta description | `<meta name="description">` | Not used | Link preview fallback | Link card fallback |
**Key takeaway:** The **intro text** and **intro image** are the two
fields that matter most for cross-posts. Get those right and every
platform looks good.
---
## Metadata
| Field | Value |
|---|---|
| Document Type | guide |
| Domain | Content Authoring |
| Applies To | Event Authors group, Webmaster |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/authoring/cross-post-preview.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-26 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-26 | Claude | Initial creation | Phase 3 cross-post field mapping with worked example |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,100 @@
← [Home](Home)
# Quick Reference — Events and News
One-page cheat sheet. If you've posted before and just forgot the
steps, this should get you unblocked in under a minute.
## Log in
1. Go to `clarksvillefurs.com/administrator`
2. Enter your username and password.
3. Complete the 2FA prompt (authenticator app code).
4. You land on the Home Dashboard.
## Create a new article
5. From the Home Dashboard, click **Content > Articles > + New**.
6. Enter the **Title** — use the format described in the
[Style Guide](./style-guide.md#title-format).
7. Set the **Alias** — Joomla auto-generates one from the title. Leave
it unless you need a shorter URL slug.
8. Set the **Category**:
- **Events** for event listings.
- **News** for announcements and updates.
## Write the body
9. Write a 12 sentence intro paragraph. This is the text that
appears in cross-posts to Discord, Telegram, and Facebook — make
it count.
10. Add the rest of the article body. See the
[Style Guide](./style-guide.md#body-length-targets) for length
guidance.
## Attach an image
11. In the **Images** tab (below the editor):
- **Intro Image** — shown in category list views and cross-posts.
- **Full Article Image** — shown at the top of the full article.
12. Click **Select** and upload or pick from the Media Manager.
13. Fill in the **Alt Text** field — describe what's in the image.
See [Style Guide — Image specs](./style-guide.md#image-specs).
## Set the publish date
14. In the **Publishing** tab:
- **Start Publishing** — set the date and time the article should
go live. Use this for scheduling future events.
- Leave **Finish Publishing** blank unless the article should
auto-expire.
## Publish
15. Set **Status** to **Published** (green toggle at the top).
16. Click **Save & Close**.
## Verify
17. Open the site in a new tab and confirm the article appears in the
correct category listing.
18. Check that the intro image renders and the title is correct.
19. Wait 12 minutes, then verify the cross-posts arrived:
- Discord — #server-announcements
- Telegram — @ClarksvilleFurs
- Facebook — linked Facebook Page
If a cross-post didn't arrive, check the article category. Cross-posts
only fire for articles saved in the **Events** or **News** categories.
---
## Metadata
| Field | Value |
|---|---|
| Document Type | guide |
| Domain | Content Authoring |
| Applies To | Event Authors group, Webmaster |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/authoring/quick-reference.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-26 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-26 | Claude | Initial creation | Phase 3 quick-reference cheat sheet |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,245 @@
← [Home](Home)
# Screencast Script — Events and News Walkthrough
**Runtime target:** 58 minutes
**Presenter:** Moko Consulting (to be assigned)
**Format:** Screen recording with voiceover
This is the read-from script for the recorded walkthrough. Screen
directions are in `[BRACKETS]`. Spoken voiceover is the plain text
beneath each direction.
---
## Scene 1 — Intro (0:000:30)
`[SCREEN: CF website homepage, scrolled to show the Events section]`
Hey everyone! This is a quick walkthrough of how to post events and
news on the Clarksville Furs website. By the end of this video you'll
know how to log in, create an article, attach an image, and publish —
plus you'll see how your post automatically shows up on Discord,
Telegram, and Facebook.
Let's jump in.
---
## Scene 2 — Logging in (0:301:15)
`[SCREEN: Browser navigating to clarksvillefurs.com/administrator]`
First, head to clarksvillefurs.com/administrator. This is the Joomla
admin panel — it's where all content management happens.
`[SCREEN: Joomla login form — type username and password]`
Enter your username and password. These were set up for you when your
account was created. If you don't have credentials yet, reach out to
the [Contact Us](https://clarksvillefurs.com/contact-us) page.
`[SCREEN: 2FA prompt — enter authenticator code]`
You'll also need to enter a code from your authenticator app. This
is two-factor authentication — it keeps the site secure even if your
password gets compromised.
`[SCREEN: Home Dashboard loads]`
And we're in. This is the Home Dashboard. You can see quick links to
articles, media, and users. We're going to create a new article.
---
## Scene 3 — Creating the article (1:152:45)
`[SCREEN: Click Content > Articles > + New in the top menu]`
Click **Content**, then **Articles**, then the **New** button. This
opens a blank article editor.
`[SCREEN: Article editor — cursor in Title field]`
Start with the title. For events, we use the format "Event Name — em
dash — Location." So for our monthly meetup, that's "Monthly Meetup —
Downtown Clarksville."
`[SCREEN: Type the title "Monthly Meetup — Downtown Clarksville"]`
Keep it under 70 characters so it doesn't get cut off in Discord
embeds.
`[SCREEN: Click the Category dropdown, select "Events"]`
Next, set the category. Pick **Events** for event listings or **News**
for announcements. This is important — the category controls which
cross-post integrations fire. If you pick the wrong category, your
post won't show up on Discord or Telegram.
`[SCREEN: Click into the editor body area]`
Now write the body. Start with one or two sentences that summarize the
event — the what, when, and where. This intro text is what people see
on Discord, Telegram, and Facebook before they click through, so make
it count.
`[SCREEN: Type intro text: "Come hang out with us this Saturday! We're meeting at the pavilion in Heritage Park, 123 PM. Bring a lawn chair and a good attitude."]`
After the intro, add whatever details people need: directions, parking,
what to bring, an RSVP link. But keep it concise — 50 to 150 words is
plenty for an event listing.
---
## Scene 4 — Adding an image (2:454:00)
`[SCREEN: Click the "Images" tab below the editor]`
Scroll down and click the **Images** tab. You'll see two image slots:
Intro Image and Full Article Image.
`[SCREEN: Click "Select" next to Intro Image]`
The **Intro Image** is the one that matters most. It shows up in the
category listing on the website and in every cross-post. Click
**Select** to open the Media Manager.
`[SCREEN: Media Manager — upload a new image or select an existing one]`
You can upload a new image or pick one that's already in the library.
For best results, use a landscape photo — 1200 by 630 pixels. Keep the
file size under 500 KB. JPG works great for photos.
`[SCREEN: Select the image, return to the Images tab]`
Once you've picked the image, fill in the **Alt Text** field. This is
a short description of what's *in* the image — not the event title.
Something like "Pavilion at Heritage Park with picnic tables and string
lights." Screen readers use this, and it's good practice for
accessibility.
`[SCREEN: Type alt text into the Alt Text field]`
Don't skip the alt text. It takes five seconds and makes the site
better for everyone.
---
## Scene 5 — Publishing options (4:005:00)
`[SCREEN: Click the "Publishing" tab]`
Click the **Publishing** tab. The main field here is **Start
Publishing** — this is when the article goes live on the site.
`[SCREEN: Set Start Publishing to a date a few days from now]`
For events, I like to set this a few days before the event so people
have time to see it and plan. You can also set **Finish Publishing** if
you want the article to automatically disappear after the event date,
but that's optional.
`[SCREEN: Scroll up to the Status toggle at the top]`
Last thing before we save — make sure the **Status** is set to
**Published**. It's the green toggle at the top of the editor. If this
is set to Unpublished, the article exists but nobody can see it.
---
## Scene 6 — Save and verify (5:006:00)
`[SCREEN: Click "Save & Close" in the toolbar]`
Click **Save & Close**. Joomla saves the article and drops you back to
the article list.
`[SCREEN: Open the site frontend in a new tab, navigate to the Events category]`
Let's verify. Open the site in a new tab and navigate to the Events
page. There's our article — title, intro text, and the image we just
uploaded.
`[SCREEN: Click into the full article to show the complete content]`
Click into it to see the full article. Everything looks good.
---
## Scene 7 — Cross-post verification (6:007:00)
`[SCREEN: Switch to Discord — show the channel with the new embed]`
Now let's check the cross-posts. Over in Discord, in the
#server-announcements channel, you can see the embed that fired
automatically when we saved the article. It pulled in the title, the
intro text, the image, and a link back to the full article on the
website.
`[SCREEN: Switch to Telegram — show the channel message]`
Same thing on Telegram. The intro text is the message body, and
there's a link preview card with the title and image.
`[SCREEN: Switch to Facebook — show the page post]`
And on Facebook — the page post has the intro text above a link card
with the image and title.
All three platforms pulled from the same two fields: the **intro text**
and the **intro image**. That's why those two fields matter the most.
---
## Scene 8 — Wrap-up (7:007:30)
`[SCREEN: Back on the CF website Events page]`
That's the whole workflow. To recap:
1. Log in with your credentials and 2FA code.
2. Create a new article — set the title, category, and body.
3. Attach an intro image with alt text.
4. Set the publish date and status.
5. Save, verify on the website, and confirm the cross-posts arrived.
If you get stuck, check the Quick Reference doc — it's a one-page
cheat sheet with all the steps. And if something's not working, reach
out to the [Contact Us](https://clarksvillefurs.com/contact-us) page.
Thanks for watching, and happy posting!
`[SCREEN: Fade to CF logo / end card]`
---
## Metadata
| Field | Value |
|---|---|
| Document Type | script |
| Domain | Content Authoring |
| Applies To | Screencast recording — Moko Consulting presenter |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/authoring/screencast-script.md |
| Version | 00.01.00 |
| Status | Draft |
| Last Reviewed | 2026-04-26 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-26 | Claude | Initial creation | Phase 3 walkthrough script, 8 scenes, ~7 min target |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,488 @@
← [Home](Home)
# SOP — Community Moderation
Standard operating procedures for moderating the Clarksville Furs
community across all platforms: the website, Discord, Telegram, and
Facebook.
Clarksville Furs is an all-ages, family-friendly community. These
procedures exist to keep it that way.
---
## 1. Guiding Principles
- **Safety first** — protect minors, protect vulnerable members,
protect the community's reputation.
- **Assume good intent** — most issues are misunderstandings, not
malice. Educate before you escalate.
- **Consistency** — enforce the same standards everywhere. What's not
okay on Discord is not okay on Telegram, Facebook, or the website.
- **Transparency** — when you take moderation action, explain why.
Members deserve to know what rule was broken.
- **Documentation** — log every moderation action. Patterns matter
more than individual incidents.
---
## 2. Community Guidelines Summary
The full Community Guidelines are published at
`clarksvillefurs.com/community-guidelines`. Key rules for moderators:
1. **All-ages content only** in all public spaces
2. **No harassment, bullying, or targeted behavior**
3. **No hate speech** — racism, homophobia, transphobia, or any
identity-based attacks
4. **No unsolicited sexual content** in any public space
5. **No doxxing** — sharing someone's real name, address, workplace,
or photo without consent
6. **No spam or self-promotion** without moderator approval
7. **Respect pronouns and chosen names**
8. **No drama-baiting** — deliberately provocative posts designed to
start arguments
---
## 3. Moderation Tiers
Not every issue requires the same response. Use the tier system to
match the response to the severity.
### Tier 1 — Gentle reminder (most common)
**When to use:** First-time minor infractions. Off-topic posting,
mild language in a family-friendly channel, accidental oversharing.
**Action:**
1. Send a friendly DM (not a public callout).
2. Explain which guideline was relevant.
3. Ask them to edit or delete the message.
4. No formal record unless it recurs.
**Example script:**
> Hey! Just a heads-up — we keep things family-friendly in the public
> channels. Would you mind editing/removing that message? Thanks!
### Tier 2 — Formal warning
**When to use:** Repeat minor infractions after a Tier 1 reminder, or
a single moderate infraction (heated argument, inappropriate content
that's not extreme, disrespectful behavior).
**Action:**
1. DM the member with a clear statement of what happened and which
rule was broken.
2. Delete or hide the offending content.
3. Log the warning in the moderation log (see Section 7).
4. Inform other moderators so they're aware.
**Example script:**
> Hi — this is a formal warning about [specific behavior] in
> [channel/platform]. This violates our Community Guidelines,
> specifically [rule number/name]. Please review the guidelines at
> clarksvillefurs.com/community-guidelines. Further violations may
> result in a temporary or permanent ban.
### Tier 3 — Temporary ban (24 hours to 30 days)
**When to use:** Serious single infractions or pattern of Tier 2
warnings (3+ warnings in 90 days). Examples: explicit content in a
public channel, targeted harassment, sustained disruptive behavior.
**Action:**
1. Mute or ban the member on the affected platform.
2. DM them with the reason and duration.
3. Log in the moderation log with full context.
4. Notify the moderation team.
5. After the ban expires, send a welcome-back message reminding them
of the guidelines.
**Duration guidelines:**
- First temp ban: 2472 hours
- Second temp ban: 714 days
- Third temp ban: 30 days, with a note that the next step is permanent
### Tier 4 — Permanent ban
**When to use:** Extreme violations (threats, doxxing, CSAM, predatory
behavior toward minors) or failure to reform after multiple Tier 3
bans.
**Action:**
1. Immediately ban on all platforms (Discord, Telegram, Facebook,
website).
2. Do not engage in debate — the decision is final.
3. Log the full incident with screenshots and timestamps.
4. Notify the webmaster and Moko Consulting.
5. If the violation involves a minor or is potentially criminal,
see Section 6.
---
## 4. Platform-Specific Procedures
### 4.1 Discord
- **Roles**: Moderators have the `Content Moderators` role with
permissions to delete messages, mute members, and manage channels.
- **Slow mode**: Enable slow mode (3060 seconds) during heated
conversations instead of immediately banning.
- **Channel locks**: Lock a channel temporarily if a situation is
escalating. Announce: "Channel is paused while mods review. Be
back shortly."
- **DM policy**: Always DM the member before or after taking public
action. Never moderate silently — it breeds distrust.
- **Bot logs**: Check the audit log and bot logs for context before
acting.
### 4.2 Telegram
- **Admin rights**: Moderators have admin rights in the main chat
group.
- **Announcement channel** (@ClarksvilleFurs): Only admins can post.
No moderation needed — it's outbound only.
- **Main chat group**: Apply the same tier system as Discord.
- **Spam bots**: Telegram is prone to join-spam. Use the group's
anti-spam bot and manually remove/ban spam accounts immediately.
### 4.3 Facebook group
- **Admin/Moderator roles**: Moderators have the Moderator role on the
Facebook group.
- **Post approval**: Consider enabling post approval for new members
(first 30 days) to catch spam and inappropriate content before it's
visible.
- **Reporting**: Facebook has its own reporting system. If someone
reports a post, review it promptly — Facebook may act independently
if reports pile up.
- **Non-members**: The group is public, so non-members can see content.
Moderate accordingly — assume parents and employers are reading.
### 4.4 Website (Joomla)
Content Moderators have Joomla admin panel access and can manage
content directly.
- **Admin access**: Content Moderators can log in at
`clarksvillefurs.com/administrator` to manage articles and events.
- **User blocking**: Go to **Users > Manage**, find the user, set
**Block User** to Yes.
- **Content removal**: Unpublish the article or event immediately.
Investigate before permanently deleting — you may need the content
as evidence.
- **Event review**: Event Authors can auto-publish DPCalendar events.
Review recently published events periodically and unpublish anything
that violates Community Guidelines.
- **Protected categories**: Content Moderators cannot edit FAQ, About
Us, Legal, SOP, or News articles. Escalate to a Manager if changes
are needed in those categories.
- **Registration spam**: Check the Community Builder approval queue
regularly. Reject accounts with obviously fake names, disposable
emails, or no profile information.
---
## 5. In-Person Event Moderation
### 5.1 Meetup ground rules
All Clarksville Furs meetups follow the same Community Guidelines as
online spaces. Additionally:
- **All-ages environment** — no alcohol at CF-organized events unless
the venue is 21+ only and the event is explicitly labeled as such.
- **Photography consent** — ask before photographing or filming anyone.
Never photograph minors without explicit parental consent. Fursuiters
may be photographed in public spaces unless they ask not to be.
- **Personal space** — not everyone wants hugs. Ask first. "Can I hug
you?" is always the right question.
- **No weapons** — real or prop. Even if it's part of a costume.
### 5.2 Handling issues at a meetup
If someone is making others uncomfortable or violating guidelines:
1. Pull them aside privately — do not make a scene.
2. Explain the issue calmly and specifically.
3. If they cooperate, move on. No need to escalate.
4. If they refuse or the behavior is serious, ask them to leave.
Be firm but not aggressive: "I need you to head out for today.
We can talk about this later."
5. If they refuse to leave or become threatening, call 911. Do not
physically confront anyone.
6. Log the incident after the event. Follow the tier system for any
online follow-up.
### 5.3 Photography and social media at events
- **Before the event**: Announce in Discord/Telegram that photos will
be taken and may be shared on CF social media.
- **At the event**: Designate a photographer if possible. Ask for
verbal consent before posting photos of identifiable people.
- **Minors**: Never post photos of minors on CF social media without
written parental consent. When in doubt, don't post it.
- **Fursuiters**: Fursuiters in public spaces generally expect to be
photographed, but always respect a "no photos" request.
### 5.4 Venue-specific rules
Some venues have their own rules (no outside food, specific parking,
noise limits). The event organizer should:
1. Visit the venue beforehand or call to confirm rules.
2. Post venue rules in the event description.
3. Remind attendees at the start of the meetup.
4. If a member violates venue rules, address it immediately — losing
a venue relationship hurts the whole community.
---
## 6. Handling Sensitive Situations
### 6.1 A member reports harassment
1. Thank them for reporting — never dismiss or minimize.
2. Ask for screenshots, timestamps, and any witnesses.
3. Do not reveal the reporter's identity to the accused.
4. Investigate promptly (within 24 hours).
5. Take action based on the tier system.
6. Follow up with the reporter to let them know the outcome (without
sharing details of any punishment).
### 6.2 A member is in crisis (self-harm, suicidal ideation)
1. Do not ignore it. Do not dismiss it as attention-seeking.
2. Respond with empathy: "I hear you. I care about you. Can I help
you find support?"
3. Share the 988 Suicide and Crisis Lifeline: **call or text 988**.
4. If you believe there is immediate danger, contact local emergency
services (911).
5. Notify the webmaster privately.
6. Do not share the member's situation publicly or with other members.
### 6.3 A minor is involved
1. Any content involving a minor that is sexual, exploitative, or
predatory is an **immediate Tier 4 permanent ban** on all
platforms.
2. Preserve all evidence (screenshots with timestamps).
3. Contact the webmaster and Moko Consulting immediately.
4. If the content may be illegal (CSAM, grooming), report to the
National Center for Missing & Exploited Children (NCMEC) at
CyberTipline.org and contact local law enforcement.
5. Do not attempt to investigate yourself — let authorities handle it.
---
### 6.4 Content takedown or privacy request
If someone requests removal of content that identifies them (photos,
real name, personal info):
1. Take the request seriously regardless of who posted the content.
2. Remove or edit the content within 24 hours.
3. If the content has cross-posted to Discord/Telegram/Facebook,
delete those posts manually.
4. Notify the original poster that the content was removed and why.
5. No formal moderation action is needed against the poster unless
the content was posted maliciously (doxxing — Tier 4).
### 6.5 Handling media or public attention
If CF receives press coverage, goes viral, or gets attention from
outside the community:
1. Do not respond to journalists or media on behalf of CF without
webmaster approval.
2. Do not engage with trolls or bad-faith actors on social media.
Ignore, mute, or block.
3. If the attention is negative, consider temporarily setting Discord
to slow mode and enabling Facebook post approval.
4. Coordinate any official response through the webmaster.
5. Document the situation for the team so everyone is on the same page.
---
## 7. Reporting to Authorities
If a moderation situation involves potential criminal activity:
1. **Do not delete the evidence.** Screenshot everything with
timestamps and usernames.
2. **Do not confront the individual** — this may cause them to
destroy evidence or flee.
3. Contact local law enforcement (Clarksville Police Department
non-emergency: 931-648-0656) or 911 if there is immediate danger.
4. For online exploitation of minors, file a report at
CyberTipline.org (National Center for Missing & Exploited
Children).
5. Notify the webmaster and Moko Consulting.
---
## 8. Appeals Process
### 8.1 Who can appeal
Any member who receives a Tier 2 warning, Tier 3 temporary ban, or
Tier 4 permanent ban may appeal. Tier 1 reminders are informal and
not appealable.
### 8.2 How to appeal
1. The member contacts the webmaster via the Contact Us page at
clarksvillefurs.com/contact-us (or by email if they are banned
from the website).
2. The appeal must include: what happened (their perspective), why
they believe the action was incorrect or disproportionate, and
what they would do differently.
### 8.3 Review process
1. The webmaster reviews the appeal against the moderation log.
2. If the original moderator is available, get their input — but the
webmaster makes the final call.
3. Possible outcomes:
- **Upheld** — the original action stands. Explain why.
- **Modified** — reduce the severity (e.g., Tier 3 → Tier 2).
Update the moderation log.
- **Overturned** — remove the action entirely. Apologize if
appropriate. Update the moderation log.
4. Respond to the member within 7 days.
5. Appeals are final. There is no second appeal.
### 8.4 Exceptions
Tier 4 bans for threats, CSAM, or predatory behavior toward minors
are **not appealable**. These are safety decisions, not judgment calls.
---
## 9. Ban Evasion
### 9.1 Identifying alt accounts
Signs that a banned member has returned with a new account:
- New account created shortly after a ban
- Same writing style, vocabulary, or topics
- Same city/state in Community Builder profile
- References to events or conversations the new account shouldn't
know about
- Other members report recognizing the person
### 9.2 Handling confirmed evasion
1. Ban the alt account immediately on all platforms.
2. Log it as a new Tier 4 entry referencing the original ban.
3. Do not engage in debate about whether it's really them.
4. If evasion is persistent (3+ attempts), consider IP-based
restrictions on Discord and website registration.
---
## 10. Moderator Onboarding
### 10.1 Checklist for new moderators
When adding a new Content Moderator:
- [ ] Add to the **Content Moderators** Joomla user group
- [ ] Grant Discord moderator role
- [ ] Grant Telegram admin rights in the main chat group
- [ ] Grant Facebook group moderator role
- [ ] Share access to the moderation log
- [ ] Walk through this SOP document — especially Sections 3 (tiers),
5 (in-person), and 6 (sensitive situations)
- [ ] Introduce them to the mod team in the private moderator channel
- [ ] Pair them with an experienced moderator for their first 2 weeks
### 10.2 Moderator expectations
- Check in on at least one platform daily (even just a glance)
- Respond to reported issues within 24 hours
- Log all Tier 2+ actions
- Attend mod team check-ins (monthly or as scheduled)
- Ask for help when unsure — there's no penalty for escalating
### 10.3 Removing a moderator
If a moderator steps down or is removed:
1. Remove from Content Moderators Joomla group (revokes admin access).
2. Remove moderator roles on Discord, Telegram, and Facebook.
3. Revoke access to the moderation log.
4. Thank them for their service (if voluntary departure).
---
## 11. Moderation Log
All Tier 2+ actions must be logged. Use a shared document or
spreadsheet accessible to all moderators.
Each entry should include:
| Field | Description |
|---|---|
| Date | Date and time of the incident |
| Platform | Discord, Telegram, Facebook, Website |
| Member | Username or display name |
| Incident | Brief description of what happened |
| Rule violated | Which community guideline was broken |
| Tier | 2, 3, or 4 |
| Action taken | Warning, mute, temp ban (duration), permanent ban |
| Moderator | Who handled it |
| Notes | Context, screenshots reference, follow-up needed |
---
## 12. Moderator Self-Care
Moderation is emotionally taxing. Take care of yourself:
- **You are not on call 24/7.** If something can wait until tomorrow,
let it wait. Mute the channel and come back fresh.
- **Tag-team difficult situations.** Don't handle a Tier 3 or 4
alone — loop in another moderator.
- **Step away if you're angry.** You'll make better decisions calm.
Mute the conversation, take a walk, come back.
- **Debrief after hard incidents.** Talk to a fellow moderator or the
webmaster. You shouldn't carry it alone.
- **It's okay to ask for help.** If a situation is beyond your
experience, escalate to the webmaster or Moko Consulting.
---
## Metadata
| Field | Value |
|---|---|
| Document Type | SOP |
| Domain | Community Moderation |
| Applies To | Moderators, Content Moderators, Webmaster |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/authoring/sop-moderation.md |
| Version | 00.02.00 |
| Status | Active |
| Last Reviewed | 2026-05-01 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-05-01 | Claude | Expanded: in-person events, appeals, ban evasion, onboarding, privacy/takedown, media handling | Sections 5, 6.46.5, 810 added; renumbered |
| 2026-04-27 | Claude | Initial creation | 4-tier system, platform procedures, crisis handling, mod log, self-care |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,441 @@
← [Home](Home)
# SOP — Website Management
Standard operating procedures for the webmaster and authorized managers
of the Clarksville Furs website (clarksvillefurs.com).
---
## 1. User Account Management
### 1.1 Creating a new user account
1. Log in to the Joomla admin at `clarksvillefurs.com/administrator`.
2. Go to **Users > Manage > + New**.
3. Fill in: name, username, email, and a temporary password.
4. Assign the user to the appropriate group(s):
- **Registered** — can log in and view member-only content
- **Event Authors** — can create and auto-publish DPCalendar events,
edit their own. Cannot post News or edit protected categories
(FAQ, About Us, Legal, SOP).
- **Content Moderators** — inherits Event Authors permissions, plus:
can edit all articles, can access the Joomla admin panel, can
manage content across all unlocked categories.
- **Manager** — full content control including News, FAQ, About Us,
Legal, and SOP categories. Admin panel access.
5. Set **Require Password Reset** to Yes.
6. Click **Save & Close**.
7. Notify the user via the Contact Us system — never send credentials
by Discord, Telegram, or any public channel.
### 1.2 Enabling 2FA for a user
1. The user logs in for the first time with their temporary password.
2. They are prompted to set a new password.
3. Go to **Users > Manage** and open the user's profile.
4. Under **Multi-factor Authentication**, enable **Authenticator App**.
5. The user scans the QR code with their authenticator app and enters
the verification code.
### 1.3 Disabling or removing a user
1. Go to **Users > Manage** and find the user.
2. To temporarily disable: set **Block User** to Yes. The account
remains but cannot log in.
3. To permanently remove: click the user, then **Delete**. This
removes the account but preserves any articles they created.
### 1.4 Community Builder registration approval
New registrations through Community Builder require manual approval.
1. Check the **User Approval Queue** in the Staff Menu.
2. Review the registration: name, email, location, birthday.
3. Approve legitimate registrations. Reject obvious spam (gibberish
names, throwaway emails, empty profiles).
4. Approved users receive a welcome email automatically.
---
## 2. Content Management
### 2.1 Publishing an article
See the [Quick Reference](quick-reference) for the step-by-step
workflow.
### 2.2 Reviewing published content
Event Authors can auto-publish DPCalendar events. Content Moderators
and Managers should periodically review recently published content:
1. Go to **Content > Articles** or **Components > DPCalendar > Events**
and sort by most recent.
2. Review for:
- Accurate date, time, and location (in the body, not the intro)
- Intro text is a teaser that drives traffic to the website
- Intro image is set with alt text
- No personal contact info (emails, phone numbers)
- Tone matches the [Style Guide](style-guide)
3. If changes are needed, edit directly or contact the author.
4. If content violates Community Guidelines, unpublish immediately
and follow the [Moderation SOP](sop-moderation).
### 2.3 Who can post where
| Category | Event Authors | Content Mods | Manager+ |
|---|---|---|---|
| DPCalendar events | Create + publish + edit own | Edit all | Full |
| News | No access | No access | Full |
| FAQ | No access | No access | Full |
| About Us | No access | No access | Full |
| Legal | No access | No access | Full |
| SOP | No access | No access | Full |
News articles are authored by Managers only to maintain editorial
control over official announcements.
### 2.4 Editing an existing article
1. Go to **Content > Articles** and find the article.
2. Click the title to open the editor.
3. Make changes and click **Save & Close**.
4. **Important**: If the article has already cross-posted to Discord,
the Discord embed will NOT update. Telegram and Facebook link
previews can be refreshed using their respective cache-clearing
tools (see [Cross-Post Preview](cross-post-preview)).
### 2.5 Unpublishing or removing an article
1. To hide temporarily: set **Status** to **Unpublished**. The article
stays in the database but is not visible on the site.
2. To remove permanently: set **Status** to **Trashed**, then go to
**Content > Articles**, filter by **Trashed**, select, and
**Empty Trash**.
3. Cross-posts on Discord, Telegram, and Facebook are NOT automatically
removed — delete those manually if needed.
### 2.6 Managing the FAQ
FAQ articles are in the **FAQ** category (ID: 31). To add a new FAQ:
1. Create a new article in the FAQ category.
2. Write a standalone intro paragraph that fully answers the question
(see [Style Guide — Body length targets](style-guide)).
3. Add a readmore break after the intro.
4. Add detailed content below the break.
5. Set the **Ordering** to place it in the right position on the FAQ
page (see the current order by viewing the article list sorted by
ordering).
---
## 3. Events (DPCalendar)
### 3.1 Creating an event
Events on the website use the DPCalendar component, not standard
articles.
1. Go to **Components > DPCalendar > Events > + New**.
2. Fill in: title, start date/time, end date/time, location, and
description.
3. Set the calendar (category) and access level.
4. Add an image if available.
5. Click **Save & Close**.
### 3.2 Member event submissions
Members with the **Event Authors** group can submit and auto-publish
events from the frontend at `clarksvillefurs.com/events/submit`.
Events go live immediately — no approval step. Content Moderators and
Managers should review recently published events periodically (see
Section 2.2).
If an event needs to be taken down, a Content Moderator or Manager
can unpublish it from the admin panel.
### 3.3 Recurring events
For monthly meetups or regular events:
1. Use DPCalendar's **Recurrence** feature.
2. Set the recurrence pattern (e.g., first Saturday of every month).
3. Individual occurrences can be edited without affecting the series.
---
## 4. Cross-Post Management
### 4.1 How cross-posting works
Two integrations automatically share content to social channels:
| Integration | Destination | Trigger |
|---|---|---|
| MokoDiscordHook | #server-announcements | `onContentAfterSave` for configured categories |
| Perfect Publisher | Facebook group + @ClarksvilleFurs Telegram | Rule Engine on category match |
### 4.2 Verifying a cross-post
After publishing an article or event:
1. Wait 12 minutes for the integrations to fire.
2. Check #server-announcements in Discord for the embed.
3. Check @ClarksvilleFurs on Telegram for the message + link preview.
4. Check the Facebook group for the post + link card.
5. If any cross-post is missing, check that the article's category
matches the configured trigger categories.
### 4.3 Troubleshooting cross-posts
| Symptom | Likely cause | Fix |
|---|---|---|
| No Discord embed | Article saved in wrong category, or webhook URL expired | Verify category in article. Check MokoDiscordHook plugin settings for valid webhook URL. |
| Discord embed has wrong image | Intro Image not set, or cached | Set Intro Image in the article's Images tab. Discord caches aggressively — the image on the first post is permanent. |
| No Telegram message | Perfect Publisher rule not matching, or bot token expired | Check Rule Engine rules. Verify bot is still a member of the channel. |
| Telegram preview shows old image | Telegram caches link previews | Use [@webpagebot](https://t.me/webpagebot) to clear cache for the URL. |
| No Facebook post | Page token expired, or Rule Engine rule disabled | Re-authenticate the Facebook Page in Perfect Publisher. Check Rule Engine. |
| Facebook card shows wrong image | Facebook caches og:image | Use the [Facebook Sharing Debugger](https://developers.facebook.com/tools/debug/) to re-scrape the URL. |
### 4.4 What cross-posts cannot do
- Cross-posts do **not** update if you edit the article after
publishing. The Discord embed is permanent. Telegram and Facebook
can be refreshed via cache-clearing tools, but the original post
text does not change.
- Cross-posts do **not** auto-delete if you unpublish or trash the
article. Delete the Discord message, Telegram message, and Facebook
post manually.
- Cross-posts show the **intro text only**, not the full article body.
Write the intro as a teaser (see
[Style Guide](./style-guide.md#body-length-targets)).
---
## 5. Community Builder Management
### 5.1 Required registration fields
New registrations require: first name, last name, username, email,
password, city, state, zip code, country, and birthday.
### 5.2 Profile moderation
Periodically review Community Builder profiles for:
- Inappropriate profile images or avatars
- Offensive usernames or display names
- Spam or promotional content in profile bio fields
- Fake or clearly fabricated profile information
To edit a profile: go to **Components > Community Builder > User
Management**, find the user, click to edit.
### 5.3 Managing profile fields
To add, remove, or change required fields:
1. Go to **Components > Community Builder > Field Management**.
2. Find the field by name.
3. To make a field required: set **Required** to Yes.
4. To show on registration: set **Registration** to Yes.
5. To show on profile: set **Profile** to the desired visibility.
Current required fields: first name, last name, username, email,
password, city, state, zip code, country, birthday.
---
## 6. Menu Management
### 6.1 Menu structure
| Menu | Purpose | Audience |
|---|---|---|
| Main Menu | Primary site navigation | Everyone |
| User Menu | Login, logout, SOPs | Registered users |
| Legal Menu | Terms, Privacy, Community Guidelines | Footer links |
| Staff Menu | Profile, events, drafts, approvals | Staff/moderators |
### 6.2 Adding a menu item
1. Go to **Menus > [Menu Name] > + New**.
2. Set the **Menu Item Type** (Single Article, Category Blog, URL, etc.).
3. Set the **Title** and **Alias** (alias becomes the URL slug).
4. Set **Access** to control who sees the menu item (Public, Registered,
Content Moderators, etc.).
5. Set **Parent Item** to control nesting.
6. Click **Save & Close**.
### 6.3 Reordering menu items
1. Go to **Menus > [Menu Name]**.
2. Click the ordering column header to enable drag-and-drop.
3. Drag items to the desired position.
4. Changes take effect immediately — no save needed.
---
## 7. Media Management
### 7.1 Uploading images
1. Go to **Content > Media** or use the inline media picker in the
article editor.
2. Organize images into folders: `events/`, `news/`, `branding/`.
3. Image requirements:
- Format: JPG for photos, PNG for graphics
- Intro images: 1200 x 630 px, under 500 KB
- Always fill in alt text
4. Do not upload images with personally identifiable information
(license plates, addresses, faces of minors without consent).
### 7.2 Cleaning up unused media
Periodically review the Media Manager for orphaned files:
1. Go to **Content > Media**.
2. Sort by date and review old uploads.
3. Before deleting, search for the filename in article content to
confirm it is not in use.
---
## 8. Backups and Maintenance
### 8.1 Automated backups
The site is backed up daily by the hosting provider. Retention:
daily for 30 days, weekly for 90 days, monthly for 12 months.
### 8.2 Cache clearing
After any significant content change:
1. Go to **System > Maintenance > Clear Cache**.
2. Check all boxes and click **Clear Cache**.
3. Go to **System > Maintenance > Purge Expired Cache**.
### 8.3 Updates
Joomla core, template, and extension updates are managed by Moko
Consulting. Do not install updates without coordination.
### 8.4 Scheduled maintenance checklist
**Weekly:**
- [ ] Review Community Builder approval queue — approve or reject
pending registrations
- [ ] Check recently published events for accuracy and guideline
compliance
- [ ] Glance at the moderation log for patterns
**Monthly:**
- [ ] Review Media Manager for orphaned or oversized files
- [ ] Check cross-post integrations are still firing (publish a test
event, verify all three surfaces, then unpublish)
- [ ] Review user accounts — block any that haven't logged in for
12+ months if desired, or remove obvious spam accounts
- [ ] Clear Joomla cache (**System > Maintenance > Clear Cache**)
**Quarterly:**
- [ ] Review FAQ articles — are answers still accurate? Any new
questions coming up repeatedly in Discord?
- [ ] Review SOP articles — do they still match current permissions
and workflows?
- [ ] Check that 2FA is enabled for all Content Moderators and Managers
- [ ] Verify automated backups are running (check backup logs with
Moko Consulting)
- [ ] Review Community Builder required fields — are they still
appropriate?
---
## 9. Analytics and Reporting
### 9.1 What to check
If analytics are configured (Google Analytics or Tag Manager):
- **Pageviews**: Which pages get the most traffic? FAQ and Events
should be near the top.
- **Referral sources**: Are cross-posts driving traffic from Discord,
Telegram, and Facebook?
- **Search terms**: What are people searching for on the site? Use
this to identify missing FAQ articles.
- **Bounce rate on Events**: If people land on the events page and
leave immediately, the event descriptions may need improvement.
### 9.2 Reporting cadence
- **Monthly**: Glance at top pages and referral sources. No formal
report needed — just awareness.
- **Quarterly**: Share a brief summary with the team: top 5 pages,
where traffic comes from, any FAQ gaps identified.
---
## 10. Emergency Procedures
### 10.1 Site is down
1. Check if the issue is local (try a different browser/device/network).
2. Check the hosting provider's status page.
3. Contact Moko Consulting via the Contact Us system or the emergency
contact in the onboarding documentation.
4. Do not attempt server-level fixes unless you have been trained.
### 10.2 Security incident (defacement, unauthorized access)
1. Do not make changes to the site — preserve evidence.
2. Contact Moko Consulting immediately.
3. If you have admin access, check **Users > Manage** for unfamiliar
accounts.
4. Change your own password immediately from a trusted device.
### 10.3 Spam or inappropriate content
1. Unpublish the content immediately.
2. Block the user account if applicable.
3. Document the incident (screenshot, user details, timestamp).
4. Report to Moko Consulting if the spam came through an automated
vector (registration exploit, comment spam).
---
## Metadata
| Field | Value |
|---|---|
| Document Type | SOP |
| Domain | Website Management |
| Applies To | Webmaster, Content Moderators |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/authoring/sop-website-management.md |
| Version | 00.02.00 |
| Status | Active |
| Last Reviewed | 2026-05-01 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-05-01 | Claude | Expanded: cross-posts, CB profiles, menus, analytics, maintenance checklist | Sections 46, 8.4, 9 added; permissions updated for auto-publish model |
| 2026-04-27 | Claude | Initial creation | User management, content, events, media, backups, emergencies |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,178 @@
← [Home](Home)
# Style Guide — Events and News
Rules for writing articles that sound like Clarksville Furs and look
good across every surface (website, Discord, Telegram, Facebook).
## Voice and tone
Clarksville Furs articles should feel like a friend inviting you to
hang out — not a corporation issuing a press release.
**Be:**
- **Warm** — "We'd love to see you there" over "Attendance is
encouraged."
- **Direct** — short sentences, plain words. Say what's happening,
when, and where.
- **Inclusive** — write for everyone: newcomers, families, kids, people
who've never heard of the fandom. No inside jokes that leave readers
out.
- **Casual** — contractions are fine. "We're" not "We are." First
person plural ("we", "our") for the group.
- **Enthusiastic but not over-the-top** — one exclamation mark per
article is plenty. Let the event speak for itself.
**Don't be:**
- Corporate — no "leverage", "synergy", "stakeholders", "action items."
- Vague — "sometime in June" is not a date. Use `TBA` if it's truly
unknown (see below).
- Edgy — keep it family-friendly. No profanity, no sarcasm that could
land wrong.
## Title format
Use this pattern for event titles:
```
Event Name — Location
```
Examples:
- `Monthly Meetup — Downtown Clarksville`
- `Barnaby TN Ren Fest — Triune, TN`
- `Movie Night — TBA`
For news articles, just use a clear descriptive title:
- `We're Live: Introducing Our New Website`
- `Summer Schedule Update`
Rules:
- Use an em dash ( — ) between event name and location, not a hyphen.
- Title-case the event name.
- Keep it under 70 characters so it doesn't truncate in Discord embeds.
- Don't put the date in the title — it's in the publish date and the
body.
## Body length targets
| Article type | Target length | Notes |
|---|---|---|
| Event listing | 50150 words | Date, time, location, what to expect, how to RSVP |
| News post | 100300 words | What happened or is changing, why it matters, what's next |
| Longer feature | 300600 words | Only when the topic genuinely needs it |
The first 12 sentences are the **intro**. This text appears in
cross-posts and category listings. Write the intro as a **teaser** that
hooks the reader and drives them to the full event page on the website
— do not put the full date, time, and location in the intro. Save
those details for the article body so people click through to
clarksvillefurs.com/events to get the complete picture.
## Image specs
Every Events article should have an **Intro Image** set. This image
appears in:
- The category list view on the website
- Discord embeds (via MokoDiscordHook)
- Facebook link cards (via Perfect Publisher)
- Telegram link previews (via Perfect Publisher)
| Property | Requirement |
|---|---|
| Format | JPG or PNG (JPG preferred for photos) |
| Dimensions | 1200 x 630 px (landscape, 1.91:1 ratio) |
| File size | Under 500 KB |
| Alt text | Required. Describe what's in the image, not the event title. Example: "Furries in costume at a park picnic table" |
Tips:
- Avoid text overlaid on the image — it gets cropped differently on
each platform.
- Use a photo of the venue, the group, or the activity. Generic stock
images feel impersonal.
- If you don't have a photo, use the CF mascot image from the Media
Manager rather than leaving it blank.
## Using TBA for unknown details
If the date, time, or location isn't confirmed yet, use `TBA`
(To Be Announced) as a placeholder:
- **Date unknown:** Set the publish date to today and write "Date: TBA"
in the body. Update the article when the date is confirmed.
- **Location unknown:** Use `TBA` in the title where the location goes:
`Monthly Meetup — TBA`
- **Time unknown:** Write "Time: TBA" in the body.
Always go back and update TBA fields before the event. A stale TBA
looks like nobody's running things.
## Recurring events
For recurring events (monthly meetups, weekly game nights):
- Create a **new article** for each occurrence. Don't edit the old one.
- Use a consistent title pattern: `Monthly Meetup — Downtown Clarksville`
(same name each time, location may change).
- In the body, reference that this is a recurring event:
"Our monthly meetup is back! This month we're at..."
- Set the **Start Publishing** date to a few days before the event so
it shows up in the listing with lead time.
## What NOT to do
- **Don't use HTML in the article body** unless you're using an
approved utility class (see
[Content Authoring Guide](content-authoring)). The editor's
visual mode handles formatting.
- **Don't hardcode brand colors** inline — use `.cf-brand-accent` or
`.cf-brand-callout` instead. See the
[Content Authoring Guide](../content-authoring.md#patterns-to-avoid).
- **Don't leave Alt Text blank** on images. Screen readers need it, and
social platforms use it as fallback text.
- **Don't write a novel.** If your event listing is over 200 words,
you're probably over-explaining. Trust the reader.
- **Don't duplicate the title in the first sentence.** The title is
already displayed above the body.
- **Don't use all caps** for emphasis. Bold a word if you must.
- **Don't link to personal social media accounts** — only official CF
channels.
---
## Metadata
| Field | Value |
|---|---|
| Document Type | guide |
| Domain | Content Authoring |
| Applies To | Event Authors group, Webmaster |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/authoring/style-guide.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-26 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-26 | Claude | Initial creation | Phase 3 voice, title, image, and formatting rules |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,158 @@
← [Home](Home)
# Brand Reference — Clarksville Furs
## Core palette
Nine tokens. Every color on the site should trace back to one of these.
| Token | Hex | Role |
|---|---|---|
| Sky Primary | `#9CCEDB` | Large surfaces, hero washes, block-color-1 |
| Sky Secondary | `#7FB7C6` | Gradient depth, light-mode `--color-primary`, bottom-a container |
| Sky Raw (`--sky`) | `#a3cde2` | Module tints, `.custom.sky` cards, top-b container background |
| Coral Accent | `#FF4B3E` | CTAs, links, focus, `.btn-primary`, brand-accent text |
| Ink Outline | `#1E1E1E` | Body text, linework, light-mode navigation background |
| Mascot White | `#F4F4F4` | Soft surfaces, on-dark button text |
| Mascot Grey | `#8F8F8F` | Muted text, secondary neutral |
| Gold Eye | `#F5C518` | Highlights, warning states, `.custom.yellow` cards |
| Soft Red | `#ff7a73` | `.btn-danger`, `.custom.red` cards — softer than coral, semantic danger |
The Sky Raw token `--sky` is available as a CSS custom property for direct
reference in article HTML, module content, and user extensions. Prefer it over
hardcoding `#a3cde2`.
## Typography
**Primary:** Fredoka (variable weight 300700). Loaded locally from
`/media/templates/site/mokoonyx/fonts/Fredoka-Variable.ttf` via `@font-face` in
`user.css`.
**Secondary:** Nunito (weights 400700). Loaded from Google Fonts for resilience;
bundle locally if performance audits require it.
**Stack:**
```css
--body-font-family: "Fredoka", "Nunito", "Inter",
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
"Helvetica Neue", Arial, "Noto Sans", sans-serif;
```
**Weight scale (per brand guide):**
| Element | Weight | Notes |
|---|---|---|
| `h1``h3`, `.site-title` | 700 | Fredoka, letter-spacing `-0.01em` |
| `h4``h6` | 600 | Fredoka |
| `.lead`, `.callout`, `.subhead` | 500 | Fredoka |
| Body (`p`, `li`, `td`, `dd`) | 400 | Nunito falls back to Fredoka |
| `small`, `.text-muted`, `.meta` | 300 | Nunito |
**Note on `.site-title`:** MokoOnyx's base template ships with an "Osaka" font
loaded via `fonts/osaka.css`. CF overrides this with `!important` in `user.css`
to force Fredoka on site title markers. If the MokoOnyx template is updated and
this class changes, the override may need to follow.
## Design decisions
These are the non-obvious choices that drive the look and won't survive a naïve
"reset to defaults" pass. Read before changing anything in the theme.
### `--color-primary` is Sky Secondary (#7FB7C6) in light mode, not coral
MokoOnyx's offline page uses `--color-primary` as a full-viewport background.
Coral at that scale would be jarring. Sky-secondary reads warm and on-brand at
hero scale. Coral retains its role as the action color via Bootstrap's `--primary`.
### Navigation is ink in light mode, dark-neutral in dark mode
Light mode uses `#1E1E1E` ink as nav background with mascot-white text — structural
brand presence at the top of every page. Dark mode uses `#151B22` neutral dark so
the nav doesn't compete with content for attention. Active link is coral in light,
sky in dark.
### Baseline `--border-radius` is 0.875rem
Matches the template's own offline-card radius. Gives consistent soft-rounded
surfaces across form controls, badges, alerts, dropdowns, popovers, toasts.
Cards use a slightly larger 1rem radius; hero cards use 1.25rem.
### Coral hover on dark-tint cards fails AA
`.custom.green` cards (`#448344`) keep white text (4.61:1 AA pass) but the
coral hover on green links is 1.39:1 — visually invisible. This is documented
in-file. If hover legibility becomes a complaint, swap hover to ink.
### `.custom.red` uses ink text, not white
White on `#ff7a73` is 2.53:1 (AA fail). Ink is 5.79:1 (AA pass) AND reads
warmer, which matches the "Celebrating Individuality" card's intended tone.
This is a deliberate departure from the "white on colored card" convention.
### `--danger` is soft red (#ff7a73), not coral
Bootstrap expects primary and danger to be distinct colors. Coral owns primary
(brand action); soft red owns danger (alarm states). A compatibility rule in
`user.css` keeps `.text-danger` on `h1``h6` and `.display-*` rendering as coral
so existing hero content (which uses `.text-danger` decoratively) still reads as
brand-accent. New decorative uses should prefer `.cf-brand-accent`.
## Accessibility baselines
All non-incidental text on the live site is checked to at least WCAG AA (4.5:1
for normal text, 3:1 for ≥18pt or ≥14pt bold). Known exceptions are documented
in [accessibility.md](accessibility).
**Contrast pairs that pass AA or better:**
| Foreground | Background | Ratio | Grade |
|---|---|---|---|
| Ink `#1E1E1E` | White `#FFFFFF` | 15.3:1 | AAA |
| Ink `#1E1E1E` | Sky Primary `#9CCEDB` | 10.97:1 | AAA |
| Ink `#1E1E1E` | Sky Secondary `#7FB7C6` | 8.22:1 | AAA |
| Ink `#1E1E1E` | Sky Raw `#a3cde2` | 12.1:1 | AAA |
| Ink `#1E1E1E` | Coral `#FF4B3E` | 5.16:1 | AA |
| Ink `#1E1E1E` | Soft Red `#ff7a73` | 5.79:1 | AA |
| Ink `#1E1E1E` | Gold `#F5C518` | 11.5:1 | AAA |
| White `#F4F4F4` | Ink `#1E1E1E` | 15.3:1 | AAA |
| White `#F4F4F4` | Dark Green `#448344` | 4.61:1 | AA |
**Contrast pairs that fail AA (known, documented, handled):**
| Foreground | Background | Ratio | Mitigation |
|---|---|---|---|
| Coral `#FF4B3E` | Sky Primary | 2.33:1 | Scoped override: links on sky containers flip to ink |
| Coral `#FF4B3E` | Sky Secondary | 2.06:1 | Scoped override (same) |
| Coral `#FF4B3E` | White (small text) | 3.63:1 | Only used for large text / headings (AA-large passes) |
| White | Soft Red | 2.53:1 | Not used — `.custom.red` uses ink text instead |
## Metadata
| Field | Value |
|---|---|
| Document Type | reference |
| Domain | Brand |
| Applies To | All client-clarksvillefurs theme and content work |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/brand-reference.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-21 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-21 | Claude | Initial creation | Synthesized from brand guide + theme work |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,184 @@
← [Home](Home)
# Content Authoring Guide
This is for whoever writes articles, modules, and page content in the Joomla
admin. The CF theme adds a small library of utility classes that make it easy
to put on-brand components into articles without touching CSS.
## Quick lookup: "I want to…"
| Goal | Use | Example |
|---|---|---|
| Add a warm welcome/community box | `.cf-brand-callout` | See below |
| Make heading text pop coral | `.cf-brand-accent` | `<span class="cf-brand-accent">Your place.</span>` |
| Tint a feature card sky blue | `.custom.sky` wrapper on a `.card` | See below |
| Tint a feature card red/yellow/green | `.custom.red` / `.custom.yellow` / `.custom.green` | See below |
| Heavy sticker outline around any box | `.cf-sticker` | See below |
## `.cf-brand-callout` — welcome and community boxes
Use for the "💙 Clarksville Furs is an all-ages, family-friendly community"
pattern on the FAQ page and similar. Handles the sky background, ink text,
readable link color (ink with coral hover), and flex layout for an icon +
paragraph.
```html
<div class="cf-brand-callout">
<span class="fs-5">💙</span>
<p class="mb-0 small">
<strong>Clarksville Furs is an all-ages, family-friendly community.</strong>
Find us on <a href="/discord">Discord</a>,
<a href="/telegram">Telegram</a>, and
<a href="https://facebook.com/clarksvillefurs">Facebook</a>.
</p>
</div>
```
**Do not** author this as inline `<div style="background: var(--color-primary)">`.
The utility class handles the contrast scoping automatically — the inline
pattern is legacy and currently works via a selector hack in `user.css` but
should be migrated.
## `.cf-brand-accent` — coral brand-pop text
For the "pop of coral" on big headings that used to be done with `.text-danger`.
```html
<h1 class="display-4 fw-bold">
<span class="cf-brand-accent">Your place.</span> Your pack.
</h1>
```
`.text-danger` on h1h6 and `.display-*` still renders as coral via a
compatibility rule, so existing content doesn't break — but `.cf-brand-accent`
is semantically correct and should be used for all new content.
## `.custom.{sky|red|yellow|green}` — tinted feature cards
Wrap a standard Bootstrap `.card` in a `.mod-custom.custom.{color}` module
wrapper (or any div with `custom.{color}`) to paint it with a brand tint. The
card-body text color auto-flips for legibility.
```html
<div class="mod-custom custom sky">
<div class="card border-0 h-100 rounded-3">
<div class="card-body p-4 text-center">
<i class="fa-solid fa-house fs-2 mb-3 d-block"></i>
<h5 class="card-title fw-bold">Belonging First</h5>
<p class="card-text small">
Every decision starts with one question: will this make someone
feel welcome?
</p>
</div>
</div>
</div>
```
Tint → text-color mapping:
| Class | Card bg | Card body text | AA on body |
|---|---|---|---|
| `.custom.sky` | `#a3cde2` | Ink (black) | 12.1:1 AAA |
| `.custom.red` | `#ff7a73` | Ink (black) | 5.79:1 AA |
| `.custom.yellow` | `#ffd166` | Ink (black) | 13.3:1 AAA |
| `.custom.green` | `#448344` | White | 4.61:1 AA |
Links inside these cards are auto-styled:
- `.custom.sky`, `.custom.red`, `.custom.yellow` — ink links, coral hover
- `.custom.green` — white links, coral hover (hover contrast is low — don't
rely on hover color alone to indicate interactivity)
## `.cf-sticker` — heavy-outline sticker aesthetic
Opt-in mascot-inspired look: thick outline and hard-offset shadow that lifts on
hover. Use sparingly, for feature callouts and stickers where the brand
personality should shout.
```html
<div class="cf-sticker p-4 bg-white">
<h3>Meet-up this Saturday</h3>
<p>Join us at the park — bring snacks, bring friends.</p>
</div>
```
## Patterns to avoid
### Inline hex colors for brand colors
```html
<span style="color: #FF4B3E;">Your place.</span>
<span class="cf-brand-accent">Your place.</span>
```
Hardcoded hexes don't update when the theme does. If the brand ever shifts
(new accent color, tonal correction), utility classes update site-wide in a
single CSS change.
### Inline `style="background: var(--color-primary)"`
Currently works because `user.css` has a scoped override, but it's fragile.
Prefer `.cf-brand-callout` for callout boxes.
### White-on-coral text
```html
<a href="..." style="background: #FF4B3E; color: white;">Join us</a>
<a href="..." class="btn btn-primary">Join us</a>
```
The `.btn-primary` class handles the ink-on-coral contrast correctly. Don't
re-invent it inline.
### Hardcoded brand colors that fail contrast
The home page currently has a Telegram CTA with `style="background: #26A5E4;
color: #fff;"` — white on Telegram's official light cyan measures 2.44:1, fails
AA. Either use ink text (`color: #1E1E1E`, 5.09:1 AA) or switch to Telegram's
darker brand variant `#0088CC`.
## Common edits that need a content pass
When any of these come up in an editor review, expect to fix content, not CSS:
- **Placeholder URLs** like `/YOUR_FACEBOOK_URL`, `YOUR_DISCORD_INVITE_URL`,
`YOUR_TELEGRAM_URL` — real URLs are `/discord` and `/telegram` (server-side
redirects). Facebook needs a real URL or the mention should be removed.
- **Hardcoded brand-color CTAs** without contrast audit — Discord `#5865F2`
with white text is fine (4.50:1), Telegram `#26A5E4` fails.
- **Decorative `.text-danger`** on body text — only on headings does the
compatibility rule keep it coral. On body text it renders as soft red
(correctly, semantically), which may not be the author's intent.
## Metadata
| Field | Value |
|---|---|
| Document Type | guide |
| Domain | Content Authoring |
| Applies To | All Joomla article editors working on the CF site |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/content-authoring.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-21 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-21 | Claude | Initial creation | Covers v02.06.00 theme utility classes |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,260 @@
← [Home](Home)
# CSS Variables Reference
Quick reference for the CSS custom properties that drive the CF theme. The full
theme files (`light.custom.css` and `dark.custom.css`) declare 924+ variables
each, but most are Bootstrap internals that inherit from the tokens below. Edit
the tokens, not the internals.
Base template: [MokoOnyx](https://github.com/mokoconsulting-tech/MokoCassiopeia)
(formerly MokoCassiopeia).
---
## Brand tokens
These are the raw CF brand values. Every other variable in the theme should
trace back to one of these.
| Token | Variable | Light | Dark | Notes |
|---|---|---|---|---|
| Sky Primary | `--accent-color-secondary` (light) / `--color-primary` (dark) | `#9CCEDB` | `#9CCEDB` | Hero washes, large surfaces |
| Sky Secondary | `--color-primary` (light) / `--accent-color-secondary` (dark) | `#7FB7C6` | `#7FB7C6` | Gradient depth, offline page bg |
| Sky Raw | `--sky` | `#a3cde2` | `#a3cde2` | Module tints, `.custom.sky` cards |
| Coral | `--accent-color-primary` | `#FF4B3E` | `#FF4B3E` | CTAs, links, focus rings |
| Ink | `--body-color` (light) | `#1E1E1E` | n/a | Body text, linework |
| Mascot White | `--white` | `#F4F4F4` | `#F4F4F4` | Soft surfaces, on-dark text |
| Mascot Grey | `--muted-color` | `#8F8F8F` | `#8F8F8F` | Secondary text |
| Gold | `--yellow` | `#F5C518` | `#F5C518` | Highlights, warnings |
| Soft Red | `--danger` | `#ff7a73` | `#ff7a73` | Danger states |
**Key light/dark swap:** `--color-primary` is Sky Secondary in light mode but
Sky Primary in dark mode. This is intentional — see
[brand-reference.md](./brand-reference.md#--color-primary-is-sky-secondary-7fb7c6-in-light-mode-not-coral)
for the reasoning.
---
## Bootstrap palette mapping
CF brand tokens mapped to Bootstrap's contextual color system. These drive
`.btn-*`, `.bg-*`, `.text-*`, `.border-*`, `.alert-*`, and `.badge-*` utilities.
| Bootstrap semantic | Light value | Dark value | CF token |
|---|---|---|---|
| `--primary` | `#FF4B3E` (Coral) | `#FF4B3E` | Coral Accent |
| `--secondary` | `#8F8F8F` (Mascot Grey) | `#8F8F8F` | Mascot Grey |
| `--success` | `#4AA664` | `#4AA664` | -- (standard green) |
| `--info` | `#7FB7C6` (Sky Secondary) | `#7FB7C6` | Sky Secondary |
| `--warning` | `#F5C518` (Gold) | `#F5C518` | Gold Eye |
| `--danger` | `#ff7a73` (Soft Red) | `#ff7a73` | Soft Red |
| `--light` | `#F4F4F4` (Mascot White) | `#F4F4F4` | Mascot White |
| `--dark` | `#1E1E1E` (Ink) | `#1E1E1E` | Ink Outline |
**Note:** `--primary` is Coral (the action color), not Sky. `--info` is Sky
Secondary. This is deliberate — Coral is the CTA/interaction color across the
site; Sky is the ambient brand surface.
---
## Dark mode color strategy
The theme supports full light/dark mode switching. Key differences:
| Property | Light | Dark | Why |
|---|---|---|---|
| `--color-primary` | `#7FB7C6` (Sky Secondary) | `#9CCEDB` (Sky Primary) | Lighter sky reads better against dark backgrounds |
| `--body-color` | `#1E1E1E` (Ink) | `#E6EBF1` (Light gray) | Ink is the text color in light; light gray in dark |
| `--body-bg` | `#FFFFFF` | `#0E1318` (Near-black) | |
| `--heading-color` | `#1E1E1E` | `#F4F4F4` (Mascot White) | |
| `--nav-bg-color` | `#1E1E1E` (Ink) | `#151B22` (Dark neutral) | Ink nav is structural in light; neutral in dark so nav doesn't compete with content |
| `--navbar-active-color` | `#FF4B3E` (Coral) | `#FF4B3E` (Coral) | Same — coral stays the active indicator |
| `--link-color` | `#FF4B3E` (Coral) | `#FF4B3E` (Coral) | Same — coral links in both modes |
| `--link-hover-color` | `#E03828` (Darker coral) | `#E03828` | Same |
| `--code-color` | `#FF4B3E` | `#FF7A6F` (Lighter coral) | Softer in dark for readability |
| `--secondary-bg` | `#F4F4F4` | `#151B22` | Card backgrounds, dropdowns |
| `--card-bg` | `#F4F4F4` (via `--secondary-bg`) | `#151B22` | |
| `--border-color` | `#D6D6D6` | `#2b323b` | |
The `--sky` token is mode-invariant (`#a3cde2` in both). This means
`.custom.sky` cards and `--sky`-based surfaces look the same regardless of
mode — the surrounding page contrast changes, not the card itself.
---
## Typography variables
Typography is mode-invariant — defined once in the theme files and reinforced
by `user.css`.
| Variable | Value | Notes |
|---|---|---|
| `--body-font-family` | `'Fredoka', 'Nunito', -apple-system, ...` | Full stack in both theme files + `user.css` |
| `--body-font-size` | `1rem` | |
| `--body-font-weight` | `400` | Nunito for body text |
| `--body-line-height` | `1.5` | |
| `--font-monospace` | `SFMono-Regular, Menlo, Monaco, ...` | Standard monospace stack |
Weight hierarchy is enforced by `user.css`, not the theme files — see
[brand-reference.md](./brand-reference.md#typography).
---
## Border & radius
| Variable | Value | Notes |
|---|---|---|
| `--border-radius` | `0.875rem` | Baseline for all CF components |
| `--border-radius-sm` | `0.5rem` | Badges, small controls |
| `--border-radius-lg` | `1.25rem` | Hero cards |
| `--border-radius-xl` | `1.5rem` | |
| `--border-radius-pill` | `50rem` | Fully rounded (pills, FABs) |
| `--card-border-radius` | `1rem` | Cards slightly larger than baseline |
| `--border-color` | `#D6D6D6` (light) / `#2b323b` (dark) | |
---
## Container color map
MokoOnyx defines several page-region containers. These are the CF color
assignments:
| Container | Light bg | Dark bg | Notes |
|---|---|---|---|
| Header | `light_skybackground.png` | (image) | Background image, not a flat color |
| Below Topbar | `#F4F4F4` (Mascot White) | `#151B22` | Soft neutral strip |
| Top A | `none` (transparent) | `none` | Inherits page bg |
| Top B | `var(--sky)` = `#a3cde2` | `var(--sky)` | Sky-tinted — triggers contrast overrides |
| TOC | `var(--secondary-bg)` | `var(--secondary-bg)` | Sidebar table of contents |
| Sidebar | `#F4F4F4` | `#151B22` | 0.75rem radius |
| Bottom A | `#7FB7C6` (Sky Secondary) | varies | Sky-tinted — triggers contrast overrides |
| Bottom B | `#1E1E1E` (Ink) | `#0E1318` | Dark strip, typically footer area |
**Contrast implications:** Top B and Bottom A use sky backgrounds, which means
links inside them are automatically flipped to ink via the scoped override in
`user.css`. See [accessibility.md](./accessibility.md#coral-on-sky-links-fail-aa--fixed).
---
## Button variants
All buttons use ink (`#1E1E1E`) text for AA contrast. The `.btn-dark` variant
uses Mascot White text instead.
### Solid buttons
| Class | Background | Hover bg | CF token |
|---|---|---|---|
| `.btn-primary` | `#FF4B3E` (Coral) | `#FF6B60` | Coral Accent |
| `.btn-secondary` | `#9CCEDB` (Sky Primary) | `#7FB7C6` | Sky Primary |
| `.btn-success` | `#78D694` | `#9CE3B2` | -- |
| `.btn-info` | `#9CCEDB` (Sky Primary) | `#7FB7C6` | Sky Primary |
| `.btn-warning` | `#F5C518` (Gold) | `#FFD84A` | Gold Eye |
| `.btn-danger` | `#ff7a73` (Soft Red) | `#e5615a` | Soft Red |
| `.btn-light` | `#F4F4F4` (Mascot White) | `#FFFFFF` | Mascot White |
| `.btn-dark` | `#1E1E1E` (Ink) | `#333333` | Ink Outline |
### Outline buttons
Outline variants use the brand color as text/border color and fill on hover:
| Class | Text/border | Hover fill |
|---|---|---|
| `.btn-outline-primary` | Coral `#FF4B3E` | Coral |
| `.btn-outline-secondary` | Sky `#9CCEDB` | Sky |
| `.btn-outline-success` | `#78D694` | Green |
| `.btn-outline-info` | Sky `#9CCEDB` | Sky |
| `.btn-outline-warning` | Gold `#F5C518` | Gold |
| `.btn-outline-danger` | `#c0453e` | Soft Red |
| `.btn-outline-light` | Mascot White | Mascot White |
| `.btn-outline-dark` | `#B8C3CB` | `#B8C3CB` |
All solid buttons have `--btn-border-color: #1E1E1E` (ink outline) for the
sticker/outlined aesthetic. Outline buttons swap to ink border on hover.
---
## Hero system
Two hero variants for banner sections:
| Variant | Background | Overlay | Text color |
|---|---|---|---|
| Primary | Sky Primary `#9CCEDB` | 55% sky gradient | Ink `#1E1E1E` |
| Secondary | Ink `#1E1E1E` | 78% ink overlay | Mascot White `#F4F4F4` |
Hero card dimensions: `max-width: 800px`, `padding: 3rem 2rem`,
`border-radius: 1.25rem`. Alt card is narrower at `600px`.
---
## Block colors
Used for module position color rotation (top-a, top-b, bottom-a, bottom-b):
| Block | Background | Text | Typical use |
|---|---|---|---|
| Block 1 | `var(--secondary-bg)` | `var(--body-color)` | Neutral modules |
| Block 2 | Coral `#FF4B3E` | Mascot White | CTA modules |
| Block 3 | Gold `#F5C518` | Gold | Highlight modules |
| Block 4 | Mascot White `#F4F4F4` | Sky Primary | Light modules |
Additional block overrides:
| Variable | Value | Use |
|---|---|---|
| `--block-highlight-bg` | Gold 18% opacity | Subtle gold wash |
| `--block-cta-bg` | Coral solid | Call-to-action blocks |
| `--block-alert-bg` | Coral 18% opacity | Alert/notice blocks |
---
## Editing guidelines
1. **Edit brand tokens, not internals.** If you need to change a color, find
the brand token it maps to and change that. The 900+ downstream variables
inherit automatically.
2. **Edit in both theme files.** Every color change in `light.custom.css`
likely needs a corresponding change in `dark.custom.css`.
3. **Run a contrast audit** after any color change. See
[accessibility.md](./accessibility.md#audit-tools) for tools.
4. **Bump the file version** in the header comment on every edit.
5. **Clear Joomla cache** after deploying — see
[deployment.md](deployment) for the full workflow.
---
## Metadata
| Field | Value |
|---|---|
| Document Type | reference |
| Domain | CSS Variables |
| Applies To | All CSS changes in light.custom.css, dark.custom.css, user.css |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/css-variables.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-22 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-22 | Claude | Initial creation | Replaces deleted CSS_VARIABLES.md with focused reference |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
+180
View File
@@ -0,0 +1,180 @@
← [Home](Home)
# Deployment
## Environments
| Environment | URL | Purpose |
|---|---|---|
| Development | `clarksvillefurs.dev.mokoconsulting.tech` | Moko internal staging — first stop for all changes |
| Production | `clarksvillefurs.com` | Live site |
Development mirrors production's Joomla version, template, extensions, and
data. Testing on dev first is required for every theme change.
## Theme package deliverables
A theme-only deploy consists of three CSS files and, if changed, the font file:
```
deploy/
├── images/
│ └── branding/
│ ├── logo_full_wide.png
│ ├── mascot.png
│ └── web_logo_full_wide.png
└── media/
└── templates/
└── site/
└── mokoonyx/
├── css/
│ ├── theme/
│ │ ├── light.custom.css
│ │ └── dark.custom.css
│ └── user.css
└── fonts/
└── Fredoka-Variable.ttf
```
## SFTP deployment (manual, current process)
Copy SFTP credentials from `docs/templates/sftp-config.json.template` into a
local, gitignored `sftp-config.json`. Connect via any SFTP client (Transmit,
FileZilla, Cyberduck, rsync over ssh).
**Upload paths** (relative to Joomla web root):
- `/media/templates/site/mokoonyx/css/theme/light.custom.css`
- `/media/templates/site/mokoonyx/css/theme/dark.custom.css`
- `/media/templates/site/mokoonyx/css/user.css`
- `/media/templates/site/mokoonyx/fonts/Fredoka-Variable.ttf` *(only if font file changed)*
- `/images/branding/*.png` *(only if images changed)*
**Note:** The template directory on the server may still be
`/media/templates/site/mokocassiopeia/` if the MokoCassiopeia → MokoOnyx rename
has not yet been completed on that environment. Check the actual directory
name with `ls` on the server; the *file contents* reference `mokoonyx` in
their headers regardless of the current folder name, which is correct
forward-looking metadata.
## Cache busting after deploy
Joomla caches heavily. After uploading CSS, always:
1. Joomla admin → **System → Maintenance → Clear Cache** → check all boxes → Clear Cache
2. Joomla admin → **System → Maintenance → Purge Expired Cache**
3. Verify cache-bust query string on the CSS URL changed (e.g. `?475b76` → new hash)
If the query string didn't change, the template file mod-times weren't
picked up. Touching any file in the template directory (e.g. via SFTP `touch`
or re-saving the template in admin) forces a regeneration.
Hard-refresh the browser (Ctrl+Shift+R / Cmd+Shift+R) to bypass local cache.
## Verification checklist
On the dev environment, after every deploy:
1. Home page loads without console errors
2. Light mode renders as expected (sky header PNG, ink nav, coral CTAs)
3. Dark mode toggle works — CSS vars all resolve, no broken fallbacks
4. Hero "Your place." renders as coral (not washed pink) in light mode
5. `.custom.{sky,red,yellow,green}` cards render with correct tints and readable text
6. FAQ page blue callout at top — links are ink, not coral
7. Footer / `.container-bottom-a` — sky-secondary bg, ink text, link overrides working
8. No FOUC on Fredoka font load (font-display: swap handles this)
9. Contrast spot-checks on any new text/bg pair using browser DevTools
If any check fails, roll back (reupload previous version) before promoting
to production.
## Automated dev → live sync (daily cron)
Dev and live share the same database, so only the filesystem needs syncing.
A cron job on the dev server runs `rsync` daily at **3:00 AM server time** to
push filesystem changes to live.
### How it works
| Component | Location (dev server) |
|---|---|
| Script | `/home/clarksvillefurs/scripts/sync-dev-to-live.sh` |
| SSH key | `~/.ssh/id_sync_to_live` (ed25519, authorized on live) |
| Cron entry | `0 3 * * * /home/clarksvillefurs/scripts/sync-dev-to-live.sh` |
| Log file | `/home/clarksvillefurs/scripts/logs/sync-dev-to-live.log` |
The script uses `rsync -avz --delete` with excludes for environment-specific
files (`configuration.php`, `.htaccess`, `cache/`, `tmp/`, `logs/`,
dev-only files, DreamHost system files). It includes a PID-based lock file
to prevent overlapping runs.
### Manual run
SSH into the dev server and execute directly:
```bash
/home/clarksvillefurs/scripts/sync-dev-to-live.sh
cat /home/clarksvillefurs/scripts/logs/sync-dev-to-live.log
```
### Updating the script
The canonical copy lives in the repo at `scripts/sync-dev-to-live.sh`.
After editing, SCP it to the dev server:
```bash
scp scripts/sync-dev-to-live.sh clarksvillefurs@dev.mokoconsulting.tech:/home/clarksvillefurs/scripts/
ssh clarksvillefurs@dev.mokoconsulting.tech "sed -i 's/\r$//' /home/clarksvillefurs/scripts/sync-dev-to-live.sh"
```
The `sed` command strips Windows line endings (required for bash execution).
## Production promotion (manual)
Only after full dev verification:
1. Upload the same files to production SFTP (or wait for the next automated sync at 3 AM)
2. Run the same cache-clear sequence in production Joomla admin
3. Verify the same checklist in an incognito window against the production URL
4. Tag the git commit with the release version (`git tag v02.06.00 && git push --tags`)
## Rollback
Keep the previous working version of each CSS file in `/deploy/archive/vXX.YY.ZZ/`
before uploading. If production starts throwing errors or visibly breaks:
1. SFTP upload the previous version back into place
2. Clear caches
3. Verify the rollback worked
4. Root-cause the failure on dev before re-attempting
## Metadata
| Field | Value |
|---|---|
| Document Type | guide |
| Domain | DevOps |
| Applies To | All theme and template deployments |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/deployment.md |
| Version | 00.02.00 |
| Status | Active |
| Last Reviewed | 2026-04-26 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-26 | Claude | Added automated dev→live sync section | Cron rsync workflow, script reference, manual run instructions |
| 2026-04-21 | Claude | Initial creation | SFTP workflow, cache-busting, rollback |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,248 @@
← [Home](Home)
# Migration Plan — Events and News
End-to-end plan for enabling Clarksville Furs managers to author event
listings and news posts that automatically cross-post to Discord,
Telegram, and Facebook.
## Goal
Give the **Event Authors** Joomla group a self-service workflow:
create an article in the Events or News category, attach an image,
publish — and have the post appear on all CF social channels within
minutes, with no webmaster intervention.
## Stakeholders
| Role | Responsibility |
|---|---|
| Moko Consulting | Technical implementation, plugin configuration, documentation, training |
| Webmaster | Account provisioning, 2FA setup, day-to-day oversight |
| Event Authors | Article creation and publishing |
---
## Phase 1 — Infrastructure
Set up the Joomla categories, user group, and plugin wiring.
### 1.1 Create content categories
- [ ] **Events** category under `com_content` (published, public access)
- [ ] **News** category under `com_content` (published, public access)
— News (ID: 16) already exists; verify description and alias
### 1.2 Create the Event Authors user group
- [ ] Create Joomla user group **Event Authors** (child of Registered)
- [ ] Grant article-create and article-edit-own permissions on the
Events and News categories
- [ ] Deny publish permission — articles default to Unpublished until
a moderator (or the webmaster) approves, unless the author also
holds a higher group
- [ ] Assign initial members
### 1.3 Configure MokoDiscordHook
MokoDiscordHook fires `onContentAfterSave` and sends a Discord embed.
- [ ] Install / verify MokoDiscordHook plugin is enabled
- [ ] Set the target Discord webhook URL for #server-announcements
- [ ] Configure category trigger: Events category ID, News category ID
- [ ] Embed fields mapped:
- **Title** ← article title
- **Description** ← article intro text
- **Image** ← intro image URL
- **Link** ← full article URL on clarksvillefurs.com
### 1.4 Configure Perfect Publisher
Perfect Publisher posts to Facebook and Telegram via the Rule Engine.
- [ ] Install / verify Perfect Publisher is enabled
- [ ] Connect Facebook group (clarksvillefurs) — verify Page token is valid
- [ ] Connect Telegram channel (@ClarksvilleFurs) — verify
bot token and channel membership
- [ ] Create Rule Engine rules:
- **Rule: Events → FB + Telegram** — category match on Events,
action = publish to FB Page + Telegram channel
- **Rule: News → FB + Telegram** — category match on News,
action = publish to FB Page + Telegram channel
- [ ] Post content mapped:
- **Facebook**: intro text as post body, article URL as link
(link card pulls `og:title`, `og:image`, `og:description`)
- **Telegram**: intro text + article URL as message body
(link preview pulls from Open Graph meta tags)
### 1.5 Verify Open Graph tags
- [ ] Confirm Joomla outputs `og:title`, `og:description`, `og:image`
for articles (MokoOnyx or a plugin handles this)
- [ ] Test with Facebook Sharing Debugger and Telegram @webpagebot
---
## Phase 2 — Dry run
Validate the full pipeline end-to-end before handing off to authors.
### 2.1 Test article pipeline
- [ ] Create a test article in the Events category with:
- Title following style guide format: `Test Event — Downtown Clarksville`
- 12 sentence intro text
- Intro image (1200x630 JPG, with alt text)
- Publish date set to now
- Status = Published
- [ ] Verify article appears on the website Events listing
- [ ] Verify Discord embed arrives in #server-announcements
- Title, description, image, link all correct
- [ ] Verify Telegram message arrives in @ClarksvilleFurs
- Message text, link preview card all correct
- [ ] Verify Facebook post appears on clarksvillefurs group
- Post text, link card image and title all correct
- [ ] Repeat for a News category article
- [ ] Delete or unpublish test articles after verification
### 2.2 Test author permissions
- [ ] Log in as an Event Authors member (not a super admin)
- [ ] Confirm the user can create articles in Events and News
- [ ] Confirm the user cannot edit other users' articles
- [ ] Confirm the user cannot access admin areas beyond Content
### 2.3 Test edge cases
- [ ] Article with no intro image — cross-posts should still work
(no image in embed, but no error)
- [ ] Article with a very long title (70+ characters) — check
truncation on Discord embed
- [ ] Article saved as Unpublished — cross-posts should NOT fire
- [ ] Article edited after publishing — Discord embed does NOT update
(expected; document this for authors)
---
## Phase 3 — Documentation and training
Author the manager-facing documentation and record the walkthrough.
### 3.1 Authoring documentation
All files live under `docs/authoring/`. See the
[Authoring Documentation Index](authoring-README) for the full
list and reading order.
| Document | Purpose |
|---|---|
| [README](authoring-README) | Index, audience, reading order |
| [Quick Reference](authoring-quick-reference) | One-page cheat sheet — log in through publish |
| [Style Guide](authoring-style-guide) | Voice, tone, title format, image specs, don'ts |
| [Cross-Post Preview](authoring-cross-post-preview) | Field-to-surface mapping with worked example |
| [Screencast Script](authoring-screencast-script) | 8-scene spoken script for the walkthrough recording |
### 3.2 Dry-run checklist for docs
Each document must have:
- [ ] Moko HTML-comment file header (Copyright, SPDX, FILE INFORMATION)
- [ ] DEFGROUP: `ClarksvilleFurs.Documentation`
- [ ] INGROUP: `ClarksvilleFurs`
- [ ] VERSION starting at `00.01.00`
- [ ] Metadata table and Revision History table at the bottom
- [ ] Pure Markdown body — no HTML except the file header
- [ ] Placeholder tokens for values TBD:
`[LAUNCH DATE]` (the only remaining placeholder)
### 3.3 Record walkthrough
- [ ] Record the screencast using the
[Screencast Script](authoring-screencast-script)
- [ ] Presenter: Moko Consulting
- [ ] Runtime target: 58 minutes
- [ ] Upload to a location accessible to Event Authors (Google Drive,
YouTube unlisted, or embedded on the site)
- [ ] Link from the authoring README
### 3.4 Onboard first authors
- [ ] Schedule a live walkthrough session with initial Event Authors
- [ ] Share the authoring docs link
- [ ] Have each author create a test article and verify cross-posts
- [ ] Collect feedback and update docs as needed
---
## Phase 4 — Launch
Go live and hand off to the team.
### 4.1 Fill in placeholders
- [ ] Replace `[LAUNCH DATE]` across all authoring docs
- [x] ~~Replace `[CF Discord channel name]`~~#server-announcements
- [x] ~~Replace `[FB Page ID]`~~ → clarksvillefurs (Facebook group)
- [x] ~~Replace `[Telegram channel handle]`~~@ClarksvilleFurs
- [x] ~~Replace `[Webmaster email]`~~ → Contact Us page (clarksvillefurs.com/contact-us)
### 4.2 Publish
- [ ] Merge authoring docs to main branch
- [ ] Enable auto-publish permissions for Event Authors (if dry run
proved they don't need moderator approval)
- [ ] Announce in Discord and Telegram that the Events page is live
- [ ] Monitor first 5 real posts for cross-post issues
### 4.3 Post-launch
- [ ] Review cross-post analytics after 2 weeks
- [ ] Update docs based on author feedback
- [ ] Consider adding a menu item for Events on the main navigation
(currently hidden: `menu_show=0` on item 457)
---
## Constraints
- **MokoDiscordHook**: embed with title, intro text, image, link.
Fires `onContentAfterSave` for configured categories. Does NOT
update embeds if the article is edited after initial save.
- **Perfect Publisher**: native FB Page post + Telegram channel post,
triggered by Rule Engine on category match. Link previews depend
on Open Graph meta tags being present and correct.
- **No invented features**: this plan only uses capabilities that
exist in the installed plugins. If a feature isn't listed here,
it doesn't exist.
---
## Metadata
| Field | Value |
|---|---|
| Document Type | plan |
| Domain | Content Authoring |
| Applies To | Events and News authoring workflow |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/migration-plan-events.md |
| Version | 00.01.00 |
| Status | Draft |
| Last Reviewed | 2026-04-26 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-26 | Claude | Initial creation | 4-phase plan: infrastructure, dry run, documentation, launch |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |
@@ -0,0 +1,151 @@
← [Home](Home)
# Theme Architecture
The CF theme rides on top of MokoOnyx (Joomla 5 template). MokoOnyx provides
everything structural (layout, scaffolding, responsive grid, component behavior).
CF's theme layer only changes colors, fonts, and introduces a small library of
utility classes.
## File roster
Three CSS files make up the CF theme layer. They live under the MokoOnyx
template directory and survive template updates because MokoOnyx's CSS cascade
is ordered to read the `.custom` files after its own `.standard` files.
```
/media/templates/site/mokoonyx/
├── css/
│ ├── theme/
│ │ ├── light.custom.css ← light-mode palette
│ │ └── dark.custom.css ← dark-mode palette
│ ├── user.css ← persistent overrides (fonts, utilities)
│ └── theme/
│ ├── light.standard.css ← template default, do NOT edit
│ └── dark.standard.css ← template default, do NOT edit
└── fonts/
└── Fredoka-Variable.ttf ← brand font
```
## Load order
MokoOnyx loads stylesheets in this order on every page. Later files override
earlier files per CSS cascade rules:
1. `template.base.css` — Bootstrap 5.3 + MokoOnyx layout primitives
2. `fonts/osaka.css` — template's default heading font (overridden later)
3. `theme/light.standard.css` — Bootstrap palette + MokoOnyx variable defaults
4. `theme/dark.standard.css` — same, dark-mode scoped under `:root[data-bs-theme='dark']`
5. `theme/light.custom.css`**CF palette** (this is ours)
6. `theme/dark.custom.css`**CF dark palette** (this is ours)
7. `user.css`**persistent overrides** (this is ours)
8. `a11y-high-contrast.css` — accessibility toggle
9. `bootstrap.css` — Bootstrap component styles (read vars set above)
The CF files sit between the template's defaults and Bootstrap's final component
pass, so our variable values flow into every Bootstrap component that reads them.
## What each CF file is allowed to change
### `light.custom.css` and `dark.custom.css`
**Purpose:** Full color palette for each theme mode. These files are a
comprehensive redeclaration of every MokoOnyx / Bootstrap 5 custom property in
the template's scaffold — 684 variables per file at the time of writing.
**Scope of edits:**
- All `--color-*` brand tokens
- All Bootstrap contextual colors (`--primary`, `--secondary`, `--success`, `--info`, `--warning`, `--danger`, `--light`, `--dark`) and their `-rgb`, `-text-emphasis`, `-bg-subtle`, `-border-subtle` variants
- Typography tokens that should vary by mode (none currently — font stack is mode-invariant and lives in `user.css`)
- All container backgrounds (`--container-top-a-*`, `--container-top-b-*`, `--container-bottom-a-*`, `--container-bottom-b-*`, `--container-sidebar-*`, `--container-toc-*`, `--container-below-topbar-*`)
- Hero variant styling (`--hero-primary-*`, `--hero-secondary-*`, `--hero-card-*`, `--hero-alt-card-*`)
- Block color rotation (`--block-color-1` through `-4`, plus overrides)
- All Bootstrap component defaults (accordion, alert, badge, breadcrumb, card, dropdown, list-group, modal, nav-tabs, nav-pills, offcanvas, pagination, popover, progress, spinner, table, toast, tooltip)
- Button variants (`.btn-primary` through `.btn-dark`, `.btn-outline-*`, `.btn-link`) — live at stylesheet root, not nested, following the MokoOnyx scaffold convention
**Not in scope:** typography, layout, spacing outside Bootstrap's defaults.
Those belong in `user.css`.
### `user.css`
**Purpose:** Persistent non-color overrides. Edits here survive template updates
and color changes without touching the palette files.
**Scope of edits:**
- `@font-face` loading for Fredoka
- `@import` for Nunito from Google Fonts
- Global font-stack override via `:root { --body-font-family }`
- Typography weight hierarchy (per brand guide)
- `.site-title` override to beat Osaka
- Rounded-corner enforcement on `.form-control`, `.form-select`, `.alert`, `.badge`, `.input-group-text`, `.btn`
- `.btn` base sizing (`padding: 0.65rem 1.5rem`) and `.btn-lg` variant
- Opt-in utility classes: `.cf-sticker`, `.cf-brand-callout`, `.cf-brand-accent`
- Tinted card classes: `.custom.sky`, `.custom.red`, `.custom.yellow`, `.custom.green`
- Blue-background contrast override (scoped ink-link treatment inside sky surfaces)
- Decorative `.text-danger` → coral compatibility rule for headings
- `:focus-visible` accessibility outline
- Link underline offset for body text
## Versioning
All three files use zero-padded semver in their `FILE INFORMATION` header
comment. Version is displayed prominently near the top of each file and must be
bumped on every edit.
Current versions (as of last update):
| File | Version |
|---|---|
| `light.custom.css` | 02.04.00 |
| `dark.custom.css` | 02.02.00 |
| `user.css` | 01.05.00 |
## Cache busting
Joomla cache-busts CSS via a query string appended to every asset URL (e.g.
`?475b76`). The cache key is regenerated when any template file changes on
disk. A deploy should always be followed by a template rebuild (Joomla admin →
System → Maintenance → Clear Cache) to make browsers pick up the new version.
## Safe-edit checklist
Before committing any CSS change:
1. Brace balance — count `{` and `}` occurrences, must match
2. File version bumped in header comment
3. No direct hex usage where a `var(--*)` exists — always prefer the token
4. Contrast audit for any color change touching text/background pairs
5. Both light and dark mode tested (toggle in the site header)
6. File header comment still present and valid
## Metadata
| Field | Value |
|---|---|
| Document Type | reference |
| Domain | Theme Architecture |
| Applies To | All CSS changes in this repo |
| Jurisdiction | Moko Consulting |
| Owner | Moko Consulting |
| Repo | mokoconsulting-tech/client-clarksvillefurs |
| Path | ./docs/theme-architecture.md |
| Version | 00.01.00 |
| Status | Active |
| Last Reviewed | 2026-04-21 |
| Reviewed By | Claude |
## Revision History
| Date | Author | Change | Notes |
|---|---|---|---|
| 2026-04-21 | Claude | Initial creation | Based on v02.06.00 theme package |
---
*Repo: [client-clarksvillefurs](https://git.mokoconsulting.tech/ClarksvilleFurs/client-waas-clarksvillefurs) · [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
| Revision | Date | Author | Description |
|---|---|---|---|
| 1.0 | 2026-05-09 | Moko Consulting | Initial version |