@meith/web 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +165 -0
- package/app/(auth)/layout.tsx +6 -0
- package/app/(auth)/login/page.tsx +106 -0
- package/app/(auth)/login/verify/page.tsx +55 -0
- package/app/(auth)/register/page.tsx +83 -0
- package/app/(auth)/reset/confirm/page.tsx +45 -0
- package/app/(auth)/reset/page.tsx +22 -0
- package/app/(auth)/verify/page.tsx +44 -0
- package/app/(auth)/verify/resend/page.tsx +51 -0
- package/app/(board)/[slug]/feed.xml/route.ts +48 -0
- package/app/(board)/[slug]/new/page.tsx +112 -0
- package/app/(board)/[slug]/page.tsx +403 -0
- package/app/(board)/discover/[view]/page.tsx +115 -0
- package/app/(board)/discover/page.tsx +5 -0
- package/app/(board)/layout.tsx +22 -0
- package/app/(board)/member/[id]/page.tsx +187 -0
- package/app/(board)/member/[id]/reputation/page.tsx +195 -0
- package/app/(board)/member/by-name/[name]/page.tsx +32 -0
- package/app/(board)/messages/[id]/page.tsx +103 -0
- package/app/(board)/messages/compose/page.tsx +60 -0
- package/app/(board)/messages/layout.tsx +5 -0
- package/app/(board)/messages/page.tsx +179 -0
- package/app/(board)/modcp/forums/page.tsx +59 -0
- package/app/(board)/modcp/ip/page.tsx +158 -0
- package/app/(board)/modcp/layout.tsx +5 -0
- package/app/(board)/modcp/log/page.tsx +98 -0
- package/app/(board)/modcp/page.tsx +112 -0
- package/app/(board)/moderation/layout.tsx +5 -0
- package/app/(board)/moderation/page.tsx +111 -0
- package/app/(board)/moderation/reports/page.tsx +193 -0
- package/app/(board)/moderation/warn/page.tsx +158 -0
- package/app/(board)/notifications/layout.tsx +5 -0
- package/app/(board)/notifications/page.tsx +144 -0
- package/app/(board)/notifications/preferences/page.tsx +65 -0
- package/app/(board)/online/page.tsx +119 -0
- package/app/(board)/page.tsx +195 -0
- package/app/(board)/plugins/[key]/[[...path]]/page.tsx +72 -0
- package/app/(board)/privacy/page.tsx +12 -0
- package/app/(board)/report/page.tsx +71 -0
- package/app/(board)/rules/page.tsx +12 -0
- package/app/(board)/search/[token]/page.tsx +130 -0
- package/app/(board)/search/page.tsx +289 -0
- package/app/(board)/stats/page.tsx +202 -0
- package/app/(board)/subscriptions/layout.tsx +5 -0
- package/app/(board)/subscriptions/page.tsx +142 -0
- package/app/(board)/terms/page.tsx +12 -0
- package/app/(board)/thread/[slug]/edit/page.tsx +107 -0
- package/app/(board)/thread/[slug]/feed.xml/route.ts +42 -0
- package/app/(board)/thread/[slug]/page.tsx +707 -0
- package/app/(board)/thread/[slug]/poll/page.tsx +41 -0
- package/app/(board)/thread/[slug]/post/[postId]/history/page.tsx +160 -0
- package/app/(board)/thread/[slug]/reply/page.tsx +136 -0
- package/app/(board)/unsubscribe/page.tsx +73 -0
- package/app/(board)/usercp/avatar/page.tsx +56 -0
- package/app/(board)/usercp/contacts/page.tsx +141 -0
- package/app/(board)/usercp/email/confirm/page.tsx +52 -0
- package/app/(board)/usercp/layout.tsx +23 -0
- package/app/(board)/usercp/options/page.tsx +56 -0
- package/app/(board)/usercp/page.tsx +71 -0
- package/app/(board)/usercp/profile/page.tsx +81 -0
- package/app/(board)/usercp/security/page.tsx +238 -0
- package/app/(board)/usercp/security/verify/page.tsx +92 -0
- package/app/(board)/usercp/signature/page.tsx +67 -0
- package/app/admin/antispam/page.tsx +155 -0
- package/app/admin/api/marketplace/screenshot/route.ts +68 -0
- package/app/admin/api/plugins/[key]/[...path]/route.ts +27 -0
- package/app/admin/api-tokens/page.tsx +129 -0
- package/app/admin/content/announcements/page.tsx +110 -0
- package/app/admin/content/attachments/page.tsx +199 -0
- package/app/admin/content/navigation/page.tsx +123 -0
- package/app/admin/content/page.tsx +170 -0
- package/app/admin/forums/[id]/page.tsx +96 -0
- package/app/admin/forums/[id]/permissions/page.tsx +108 -0
- package/app/admin/forums/page.tsx +45 -0
- package/app/admin/groups/[id]/page.tsx +133 -0
- package/app/admin/groups/memberships/page.tsx +56 -0
- package/app/admin/groups/page.tsx +104 -0
- package/app/admin/groups/promotions/page.tsx +143 -0
- package/app/admin/layout.tsx +86 -0
- package/app/admin/log/page.tsx +116 -0
- package/app/admin/page.tsx +206 -0
- package/app/admin/plugins/[key]/[[...path]]/page.tsx +276 -0
- package/app/admin/plugins/browse/page.tsx +70 -0
- package/app/admin/plugins/page.tsx +165 -0
- package/app/admin/security/page.tsx +124 -0
- package/app/admin/settings/page.tsx +190 -0
- package/app/admin/system/page.tsx +303 -0
- package/app/admin/themes/[key]/page.tsx +110 -0
- package/app/admin/themes/browse/page.tsx +70 -0
- package/app/admin/themes/page.tsx +163 -0
- package/app/admin/users/[id]/merge/page.tsx +136 -0
- package/app/admin/users/[id]/page.tsx +208 -0
- package/app/admin/users/mail/page.tsx +68 -0
- package/app/admin/users/page.tsx +260 -0
- package/app/admin/users/prune/page.tsx +186 -0
- package/app/api/health/route.ts +11 -0
- package/app/api/metrics/route.ts +66 -0
- package/app/api/plugins/[key]/[...path]/route.ts +27 -0
- package/app/api/read/all/route.ts +15 -0
- package/app/api/read/forum/[id]/route.ts +29 -0
- package/app/api/read/thread/[id]/route.ts +40 -0
- package/app/api/ready/route.ts +63 -0
- package/app/api/system/tick/route.ts +77 -0
- package/app/api/v1/[...path]/route.ts +208 -0
- package/app/api/v1/openapi.json/route.ts +12 -0
- package/app/apple-icon.ts +11 -0
- package/app/atom.xml/route.ts +7 -0
- package/app/attachment/[id]/route.ts +10 -0
- package/app/attachment/[id]/thumb/route.ts +10 -0
- package/app/auth/passkey/options/route.ts +145 -0
- package/app/auth/passkey/verify/route.ts +241 -0
- package/app/auth/resume/route.ts +55 -0
- package/app/auth/sso/[provider]/callback/route.ts +173 -0
- package/app/auth/sso/[provider]/go/route.ts +57 -0
- package/app/auth/sso/[provider]/route.ts +105 -0
- package/app/avatar/[id]/route.ts +31 -0
- package/app/brand/icon-192.png/route.ts +7 -0
- package/app/brand/icon-512.png/route.ts +7 -0
- package/app/brand/icon-maskable.png/route.ts +7 -0
- package/app/demo/stripe/[[...path]]/route.ts +27 -0
- package/app/error.tsx +15 -0
- package/app/feed.xml/route.ts +7 -0
- package/app/forumdisplay.php/page.tsx +11 -0
- package/app/group/[id]/badge/[scheme]/route.ts +26 -0
- package/app/icon.ts +13 -0
- package/app/install/page.tsx +221 -0
- package/app/jump/page.tsx +28 -0
- package/app/layout.tsx +124 -0
- package/app/logo/[scheme]/route.ts +24 -0
- package/app/manifest.ts +43 -0
- package/app/member.php/page.tsx +11 -0
- package/app/memberlist.php/page.tsx +11 -0
- package/app/not-found.tsx +14 -0
- package/app/opengraph-image.ts +11 -0
- package/app/redirect/page.tsx +44 -0
- package/app/robots.txt/route.ts +35 -0
- package/app/showthread.php/page.tsx +11 -0
- package/app/sitemap/[page]/route.ts +64 -0
- package/app/sitemap.xml/route.ts +31 -0
- package/app/twitter-image.ts +11 -0
- package/app/viewforum.php/page.tsx +11 -0
- package/app/viewtopic.php/page.tsx +11 -0
- package/bin/forum-web.mjs +241 -0
- package/components.json +21 -0
- package/instrumentation.ts +18 -0
- package/next.config.mjs +182 -0
- package/package.json +99 -0
- package/postcss.config.mjs +7 -0
- package/proxy.ts +160 -0
- package/src/components/account/active-sessions.tsx +87 -0
- package/src/components/account/avatar-form.tsx +119 -0
- package/src/components/account/credential-proof-form.tsx +76 -0
- package/src/components/account/logout-form.tsx +14 -0
- package/src/components/account/notification-forms.tsx +157 -0
- package/src/components/account/passkey-enrol.tsx +81 -0
- package/src/components/account/passkey-proof-button.tsx +47 -0
- package/src/components/account/push-device-form.tsx +193 -0
- package/src/components/account/relation-forms.tsx +69 -0
- package/src/components/account/reputation-forms.tsx +124 -0
- package/src/components/account/security-activity.tsx +46 -0
- package/src/components/account/sign-in-methods.tsx +166 -0
- package/src/components/account/subscription-forms.tsx +151 -0
- package/src/components/account/two-factor-forms.tsx +226 -0
- package/src/components/account/usercp-forms.tsx +387 -0
- package/src/components/account/usercp-nav.tsx +14 -0
- package/src/components/account/usercp-shell.tsx +34 -0
- package/src/components/admin/admin-forms.tsx +92 -0
- package/src/components/admin/admin-nav.tsx +52 -0
- package/src/components/admin/admin-undo.tsx +32 -0
- package/src/components/admin/api-token-forms.tsx +89 -0
- package/src/components/admin/badge-forms.tsx +97 -0
- package/src/components/admin/branding-forms.tsx +102 -0
- package/src/components/admin/content-forms.tsx +712 -0
- package/src/components/admin/form-bits.tsx +11 -0
- package/src/components/admin/forum-forms.tsx +524 -0
- package/src/components/admin/forum-tree.tsx +454 -0
- package/src/components/admin/group-forms.tsx +646 -0
- package/src/components/admin/mail-test-card.tsx +90 -0
- package/src/components/admin/marketplace-forms.tsx +30 -0
- package/src/components/admin/marketplace-listing.tsx +123 -0
- package/src/components/admin/navigation-forms.tsx +229 -0
- package/src/components/admin/navigation-tree.tsx +442 -0
- package/src/components/admin/oklch-picker.tsx +180 -0
- package/src/components/admin/plugin-forms.tsx +225 -0
- package/src/components/admin/settings-form.tsx +148 -0
- package/src/components/admin/system-forms.tsx +169 -0
- package/src/components/admin/theme-changes.tsx +354 -0
- package/src/components/admin/theme-forms.tsx +636 -0
- package/src/components/admin/theme-palette.tsx +119 -0
- package/src/components/admin/theme-preview.tsx +461 -0
- package/src/components/admin/user-bulk-toolbar.tsx +99 -0
- package/src/components/admin/user-forms.tsx +488 -0
- package/src/components/auth/auth-page.tsx +45 -0
- package/src/components/auth/form-controls.tsx +117 -0
- package/src/components/auth/login-form.tsx +47 -0
- package/src/components/auth/passkey-client.ts +171 -0
- package/src/components/auth/passkey-second-factor.tsx +69 -0
- package/src/components/auth/passkey-sign-in.tsx +61 -0
- package/src/components/auth/register-form.tsx +136 -0
- package/src/components/auth/resend-verification-form.tsx +34 -0
- package/src/components/auth/reset-confirm-form.tsx +43 -0
- package/src/components/auth/reset-request-form.tsx +35 -0
- package/src/components/auth/second-factor-form.tsx +51 -0
- package/src/components/auth/sso-buttons.tsx +47 -0
- package/src/components/board/live-region.tsx +74 -0
- package/src/components/board/search-off-notice.tsx +18 -0
- package/src/components/board/section-page.tsx +114 -0
- package/src/components/content/attachment-field.tsx +51 -0
- package/src/components/content/composer-field.ts +31 -0
- package/src/components/content/composer-ids.ts +6 -0
- package/src/components/content/composer-intents.tsx +27 -0
- package/src/components/content/composer-recovery.tsx +215 -0
- package/src/components/content/edit-post-form.tsx +121 -0
- package/src/components/content/markdown-editor.tsx +590 -0
- package/src/components/content/markdown-syntax.ts +53 -0
- package/src/components/content/mention-token.ts +23 -0
- package/src/components/content/multiquote-button.tsx +32 -0
- package/src/components/content/multiquote-selection.tsx +105 -0
- package/src/components/content/multiquote.ts +125 -0
- package/src/components/content/new-thread-form.tsx +169 -0
- package/src/components/content/poll-edit-form.tsx +96 -0
- package/src/components/content/poll.tsx +89 -0
- package/src/components/content/quote-in-place.tsx +51 -0
- package/src/components/content/reply-form.tsx +113 -0
- package/src/components/content/thanks-button.tsx +65 -0
- package/src/components/content/thread-rating.tsx +143 -0
- package/src/components/install/install-form.tsx +497 -0
- package/src/components/legal/legal-document.tsx +22 -0
- package/src/components/messages/message-forms.tsx +152 -0
- package/src/components/moderation/inline-moderation-form.tsx +158 -0
- package/src/components/moderation/modcp-nav.tsx +15 -0
- package/src/components/moderation/modcp-shell.tsx +41 -0
- package/src/components/moderation/queue-form.tsx +96 -0
- package/src/components/moderation/report-forms.tsx +120 -0
- package/src/components/moderation/signature-lock-form.tsx +83 -0
- package/src/components/moderation/thread-surgery-form.tsx +96 -0
- package/src/components/moderation/thread-tools-form.tsx +137 -0
- package/src/components/moderation/warning-forms.tsx +125 -0
- package/src/components/profile/custom-field.tsx +79 -0
- package/src/components/shell/appearance-icons.tsx +35 -0
- package/src/components/shell/board-notice.tsx +21 -0
- package/src/components/shell/copy-record.ts +20 -0
- package/src/components/shell/copy.tsx +17 -0
- package/src/components/shell/crash-notice.tsx +86 -0
- package/src/components/shell/demo-banner.tsx +49 -0
- package/src/components/shell/group-name-style.tsx +6 -0
- package/src/components/shell/measure.ts +1 -0
- package/src/components/shell/notification-menu.tsx +361 -0
- package/src/components/shell/offline-notice.tsx +29 -0
- package/src/components/shell/onboarding-banner.tsx +39 -0
- package/src/components/shell/page-shell.tsx +167 -0
- package/src/components/shell/panel-list.tsx +95 -0
- package/src/components/shell/panel-nav.tsx +40 -0
- package/src/components/shell/panel-overview.tsx +81 -0
- package/src/components/shell/panel-page.tsx +96 -0
- package/src/components/shell/panel-pagination.tsx +28 -0
- package/src/components/shell/panel-shell.tsx +31 -0
- package/src/components/shell/theme-runtime-style.tsx +6 -0
- package/src/components/shell/theme-switcher.tsx +97 -0
- package/src/components/shell/timezone-probe.tsx +45 -0
- package/src/components/shell/view-tabs.tsx +60 -0
- package/src/config.ts +13 -0
- package/src/server/absent-services.ts +29 -0
- package/src/server/admin-actions.ts +171 -0
- package/src/server/admin-settings-actions.ts +83 -0
- package/src/server/admin-undo-actions.ts +70 -0
- package/src/server/admin-undo.ts +75 -0
- package/src/server/admin.ts +112 -0
- package/src/server/announcements.ts +82 -0
- package/src/server/antispam.ts +310 -0
- package/src/server/api/content.ts +486 -0
- package/src/server/api/http.ts +119 -0
- package/src/server/api/members.ts +109 -0
- package/src/server/api/messages.ts +113 -0
- package/src/server/api/registry.ts +30 -0
- package/src/server/api/search.ts +98 -0
- package/src/server/api/subscriptions.ts +106 -0
- package/src/server/api-auth.ts +66 -0
- package/src/server/api-token-actions.ts +85 -0
- package/src/server/api-tokens-admin.ts +95 -0
- package/src/server/appearance-actions.ts +39 -0
- package/src/server/attachment-download.ts +43 -0
- package/src/server/attachment-embed.ts +63 -0
- package/src/server/attachment-upload-actions.ts +92 -0
- package/src/server/attachments.ts +257 -0
- package/src/server/auth-actions.ts +479 -0
- package/src/server/auth-config.ts +61 -0
- package/src/server/auth-events.ts +92 -0
- package/src/server/auth-form-state.ts +14 -0
- package/src/server/auth-mail.ts +104 -0
- package/src/server/avatars.ts +83 -0
- package/src/server/board-latest-actions.ts +7 -0
- package/src/server/board-latest.tsx +103 -0
- package/src/server/board-offline.ts +23 -0
- package/src/server/board-url.ts +14 -0
- package/src/server/brand-assets.ts +151 -0
- package/src/server/brand-mark.tsx +110 -0
- package/src/server/branding-actions.ts +53 -0
- package/src/server/branding.ts +101 -0
- package/src/server/cache-targets.ts +13 -0
- package/src/server/code-highlighting.ts +33 -0
- package/src/server/container.ts +402 -0
- package/src/server/content-actions.ts +459 -0
- package/src/server/content-admin-actions.ts +492 -0
- package/src/server/content-admin.ts +95 -0
- package/src/server/content-security-policy.ts +35 -0
- package/src/server/context.ts +32 -0
- package/src/server/cookies.ts +139 -0
- package/src/server/credential-proof-actions.ts +42 -0
- package/src/server/credential-proof.ts +35 -0
- package/src/server/current-location.ts +19 -0
- package/src/server/demo-stripe.ts +104 -0
- package/src/server/demo-uploads.ts +28 -0
- package/src/server/demo.ts +80 -0
- package/src/server/discovery.ts +104 -0
- package/src/server/embeds.ts +113 -0
- package/src/server/error-notice.tsx +41 -0
- package/src/server/federation-actions.ts +113 -0
- package/src/server/federation.ts +138 -0
- package/src/server/feed-builder.ts +72 -0
- package/src/server/feed-routes.ts +122 -0
- package/src/server/fixture-actor-source.ts +62 -0
- package/src/server/fixture-forum-repo.ts +59 -0
- package/src/server/fixture-member-profile-repo.ts +30 -0
- package/src/server/fixture-post-repo.ts +108 -0
- package/src/server/fixture-thread-repo.ts +98 -0
- package/src/server/form-state-reporter.ts +34 -0
- package/src/server/form-values.ts +23 -0
- package/src/server/forum-admin-actions.ts +353 -0
- package/src/server/forum-admin.ts +98 -0
- package/src/server/group-admin-actions.ts +341 -0
- package/src/server/group-admin.ts +98 -0
- package/src/server/group-badge-actions.ts +61 -0
- package/src/server/group-badge.ts +62 -0
- package/src/server/group-identity.ts +104 -0
- package/src/server/i18n-catalogs.ts +42 -0
- package/src/server/i18n.ts +69 -0
- package/src/server/image-upload.ts +109 -0
- package/src/server/inline-moderation-actions.ts +129 -0
- package/src/server/install-actions.ts +124 -0
- package/src/server/install.ts +281 -0
- package/src/server/legacy-redirect.ts +83 -0
- package/src/server/legal.ts +43 -0
- package/src/server/location-header.ts +37 -0
- package/src/server/mail-brand.ts +43 -0
- package/src/server/mail-health.ts +41 -0
- package/src/server/mail-send.ts +44 -0
- package/src/server/mail-test-actions.ts +67 -0
- package/src/server/mail-test.ts +56 -0
- package/src/server/markdown-pipeline.ts +31 -0
- package/src/server/marketplace-actions.ts +47 -0
- package/src/server/marketplace-admin.ts +260 -0
- package/src/server/mention-actions.ts +21 -0
- package/src/server/mention-search.ts +35 -0
- package/src/server/message-actions.ts +110 -0
- package/src/server/messages.ts +141 -0
- package/src/server/modcp.ts +125 -0
- package/src/server/moderation-actions.ts +165 -0
- package/src/server/navigation-admin-actions.ts +217 -0
- package/src/server/navigation.ts +112 -0
- package/src/server/nonce.ts +13 -0
- package/src/server/notification-actions.ts +84 -0
- package/src/server/notification-audience.ts +10 -0
- package/src/server/notification-menu-actions.ts +82 -0
- package/src/server/notification-menu.ts +96 -0
- package/src/server/notifications.ts +93 -0
- package/src/server/onboarding-actions.ts +27 -0
- package/src/server/onboarding.ts +89 -0
- package/src/server/page-metadata.ts +14 -0
- package/src/server/passkey-challenge.ts +42 -0
- package/src/server/plugin-admin-actions.ts +232 -0
- package/src/server/plugin-admin.ts +276 -0
- package/src/server/plugin-host.ts +143 -0
- package/src/server/plugin-pages.ts +192 -0
- package/src/server/plugin-panel.ts +49 -0
- package/src/server/plugin-routes.ts +298 -0
- package/src/server/plugin-view.tsx +58 -0
- package/src/server/poll-actions.ts +104 -0
- package/src/server/poll-scope.ts +52 -0
- package/src/server/post-notifications.ts +71 -0
- package/src/server/post-scope.ts +86 -0
- package/src/server/presence.ts +177 -0
- package/src/server/profile-fields.ts +112 -0
- package/src/server/push-actions.ts +113 -0
- package/src/server/push.ts +40 -0
- package/src/server/redirect-back.ts +15 -0
- package/src/server/registration.ts +7 -0
- package/src/server/relation-actions.ts +89 -0
- package/src/server/relations.ts +45 -0
- package/src/server/reply-core.ts +173 -0
- package/src/server/report-actions.ts +165 -0
- package/src/server/report-scope.ts +21 -0
- package/src/server/reputation-actions.ts +146 -0
- package/src/server/reputation-target.ts +49 -0
- package/src/server/reputation.ts +70 -0
- package/src/server/request-fingerprint.ts +65 -0
- package/src/server/safe-path.ts +16 -0
- package/src/server/same-origin.ts +45 -0
- package/src/server/search-page.ts +313 -0
- package/src/server/search.ts +45 -0
- package/src/server/secret-auth.ts +20 -0
- package/src/server/see-other.ts +11 -0
- package/src/server/seed-board.ts +417 -0
- package/src/server/session-actions.ts +78 -0
- package/src/server/session-cookies.ts +124 -0
- package/src/server/session-key.ts +17 -0
- package/src/server/settings.ts +47 -0
- package/src/server/signatures.ts +62 -0
- package/src/server/sso-handshake.ts +79 -0
- package/src/server/stats.ts +63 -0
- package/src/server/subscription-actions.ts +161 -0
- package/src/server/surgery-actions.ts +180 -0
- package/src/server/syndication.ts +77 -0
- package/src/server/system-admin-actions.ts +134 -0
- package/src/server/system-admin.ts +90 -0
- package/src/server/test-container.ts +114 -0
- package/src/server/theme-admin-actions.ts +242 -0
- package/src/server/theme-admin.ts +203 -0
- package/src/server/theme-runtime.ts +89 -0
- package/src/server/theme-style.ts +279 -0
- package/src/server/theme.ts +52 -0
- package/src/server/thread-core.ts +207 -0
- package/src/server/thread-rating-actions.ts +55 -0
- package/src/server/thread-tool-actions.ts +154 -0
- package/src/server/two-factor-actions.ts +178 -0
- package/src/server/two-factor.ts +86 -0
- package/src/server/upgrade-notice.ts +41 -0
- package/src/server/user-admin-actions.ts +572 -0
- package/src/server/user-admin.ts +165 -0
- package/src/server/usercp-actions.ts +263 -0
- package/src/server/usercp-mail.ts +120 -0
- package/src/server/viewer-preferences.ts +64 -0
- package/src/server/warning-actions.ts +122 -0
- package/src/styles/globals.css +969 -0
- package/src/theme/contract.fixture.ts +793 -0
- package/src/view/account-copy.ts +351 -0
- package/src/view/admin-content-copy.ts +66 -0
- package/src/view/admin-copy.ts +106 -0
- package/src/view/admin-forum-tree-copy.ts +40 -0
- package/src/view/admin-group-copy.ts +80 -0
- package/src/view/admin-log.ts +58 -0
- package/src/view/admin-nav.ts +164 -0
- package/src/view/admin-navigation-copy.ts +58 -0
- package/src/view/admin-panel-copy.ts +194 -0
- package/src/view/admin-settings.ts +173 -0
- package/src/view/admin-theme-copy.ts +229 -0
- package/src/view/admin-user-copy.ts +96 -0
- package/src/view/attachments.ts +51 -0
- package/src/view/auth-copy.ts +147 -0
- package/src/view/board-index.ts +167 -0
- package/src/view/board-latest.ts +101 -0
- package/src/view/breadcrumb.ts +50 -0
- package/src/view/contacts.ts +85 -0
- package/src/view/content-copy.ts +118 -0
- package/src/view/contrast.ts +286 -0
- package/src/view/copy.ts +101 -0
- package/src/view/count.ts +8 -0
- package/src/view/discovery-view.ts +74 -0
- package/src/view/editor-toolbar.ts +84 -0
- package/src/view/error-notice.ts +52 -0
- package/src/view/feed.ts +130 -0
- package/src/view/forum-cursor.ts +54 -0
- package/src/view/forum-display.ts +152 -0
- package/src/view/forum-jump.ts +60 -0
- package/src/view/forum-notice.ts +24 -0
- package/src/view/inline-moderation.ts +87 -0
- package/src/view/install-copy.ts +95 -0
- package/src/view/legal.ts +58 -0
- package/src/view/locale.ts +40 -0
- package/src/view/marketplace-panel.ts +51 -0
- package/src/view/member-identity.ts +23 -0
- package/src/view/member-profile.ts +65 -0
- package/src/view/messages.ts +222 -0
- package/src/view/metadata.ts +75 -0
- package/src/view/modcp-nav.ts +76 -0
- package/src/view/moderation-copy.ts +84 -0
- package/src/view/moderation-queue.ts +67 -0
- package/src/view/navigation-arrange.ts +188 -0
- package/src/view/navigation.ts +173 -0
- package/src/view/notification-menu.ts +202 -0
- package/src/view/notifications.ts +84 -0
- package/src/view/onboarding.ts +26 -0
- package/src/view/pager.ts +191 -0
- package/src/view/panel-nav.ts +203 -0
- package/src/view/plugin-panel.ts +42 -0
- package/src/view/post-form.ts +61 -0
- package/src/view/post-link.ts +29 -0
- package/src/view/presence.ts +99 -0
- package/src/view/promotion-rules.ts +52 -0
- package/src/view/redirect-notice.ts +21 -0
- package/src/view/reputation.ts +107 -0
- package/src/view/search-controls.ts +103 -0
- package/src/view/search-results.ts +291 -0
- package/src/view/security-activity.ts +73 -0
- package/src/view/setting-groups.ts +43 -0
- package/src/view/shell.ts +164 -0
- package/src/view/slug-id.ts +12 -0
- package/src/view/sso-hand-off.ts +44 -0
- package/src/view/sso-notices.ts +48 -0
- package/src/view/subscriptions.ts +76 -0
- package/src/view/theme-draft.ts +167 -0
- package/src/view/theme-preference.ts +30 -0
- package/src/view/theme-tokens.ts +333 -0
- package/src/view/thread-view.ts +280 -0
- package/src/view/time.ts +31 -0
- package/src/view/timezone.ts +35 -0
- package/src/view/two-factor.ts +6 -0
- package/src/view/usercp-nav.ts +103 -0
- package/src/view/usercp.ts +196 -0
- package/src/view/warnings.ts +128 -0
- package/src/view/word-filter.ts +5 -0
|
@@ -0,0 +1,969 @@
|
|
|
1
|
+
@import "tailwindcss";
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Theme and UI packages must be scanned for class names (F25).
|
|
5
|
+
*
|
|
6
|
+
* Tailwind v4 detects sources automatically, but only under the directory it is
|
|
7
|
+
* invoked from — here `apps/community`. `themes/` and `packages/ui/` are separate
|
|
8
|
+
* workspace packages outside that tree, so every class a theme slot uses was
|
|
9
|
+
* being dropped from the generated stylesheet. Nothing fails when that happens:
|
|
10
|
+
* the build is green, the classes are simply absent, and the page renders
|
|
11
|
+
* unstyled with no error anywhere to explain why.
|
|
12
|
+
*
|
|
13
|
+
* Paths are relative to this file, and deliberately not the `node_modules`
|
|
14
|
+
* symlinks: scanning through a symlinked workspace package is inconsistent
|
|
15
|
+
* between pnpm layouts.
|
|
16
|
+
*/
|
|
17
|
+
@source "../../../../themes";
|
|
18
|
+
@source "../../../../plugins";
|
|
19
|
+
@source "../../../../examples";
|
|
20
|
+
@source "../../../../packages/ui/src";
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* R7 design tokens.
|
|
24
|
+
*
|
|
25
|
+
* Every token in the R7 list is defined here as the theme *default*. At runtime
|
|
26
|
+
* `themes.token_overrides` is resolved on top of these and injected as a single
|
|
27
|
+
* <style> block in <head> (F26), so a board can be restyled without a deploy.
|
|
28
|
+
*
|
|
29
|
+
* Components must never hardcode a colour. A CI grep bans `#`, `rgb(` and
|
|
30
|
+
* `hsl(` literals in component files precisely so this file stays the only
|
|
31
|
+
* place colour is decided.
|
|
32
|
+
*
|
|
33
|
+
* ## The ground is neutral; the accent is one colour
|
|
34
|
+
*
|
|
35
|
+
* Every greyscale token here has **zero chroma**. Not "nearly grey" — zero. An
|
|
36
|
+
* earlier palette was the Meith identity applied to the whole page (hedgerow
|
|
37
|
+
* green ground, gorse accent), and it was a good palette for Meith and a bad
|
|
38
|
+
* default for everybody else: a board with a blue mark had a green wall behind
|
|
39
|
+
* it and no way to fix that short of overriding a dozen tokens by hand. The
|
|
40
|
+
* ground still holds no opinion about hue, and that part has not changed.
|
|
41
|
+
*
|
|
42
|
+
* What changed is `primary`. It was **ink** — near-black in light, near-white in
|
|
43
|
+
* dark — on the reasoning that a board's one loud control should be strongest by
|
|
44
|
+
* contrast rather than by hue. That is a real argument and it had a real cost: a
|
|
45
|
+
* board that never opened the theme editor had no accent at all, so "post reply"
|
|
46
|
+
* looked exactly like every other dark rectangle on the page, and the
|
|
47
|
+
* marketing site and a live board shared no visual language whatsoever.
|
|
48
|
+
*
|
|
49
|
+
* So `primary` is now the green the marketing site uses, and the rule it follows
|
|
50
|
+
* is the one that site states: *the ground is greyscale, the accent is a single
|
|
51
|
+
* colour, and it is spent deliberately.* It marks the one primary action, the
|
|
52
|
+
* current item in a list, a link's underline and a focus ring — and nothing
|
|
53
|
+
* else. A page where six things are green is a page where the button does not
|
|
54
|
+
* stand out.
|
|
55
|
+
*
|
|
56
|
+
* The two schemes carry different greens, and that is not a slip. The light
|
|
57
|
+
* scheme's pine (`oklch(0.508 …)`) reads at 5.2:1 against white; the emerald
|
|
58
|
+
* that works on near-black would read at about 3.5:1 there, under the floor for
|
|
59
|
+
* the small text it marks. Each scheme carries the step of the ramp that clears
|
|
60
|
+
* AA against its own ground.
|
|
61
|
+
*
|
|
62
|
+
* **None of this costs an operator their brand.** Branding is still the same
|
|
63
|
+
* one-group operation it was when the default was colourless: set `--primary`,
|
|
64
|
+
* `--primary-hover`, `--primary-foreground` and `--ring` in the control panel —
|
|
65
|
+
* or press one of the brand presets, which write all four — and nothing else in
|
|
66
|
+
* the palette argues with the result, because nothing else in the palette has a
|
|
67
|
+
* hue to argue with. The default now has an opinion; it is still one click to
|
|
68
|
+
* replace it.
|
|
69
|
+
*
|
|
70
|
+
* ## The semantic tokens still carry hue, because they carry meaning
|
|
71
|
+
*
|
|
72
|
+
* `thread-locked` is not decoration; it is the difference between a thread you
|
|
73
|
+
* can answer and one you cannot. Those keep conventional hues — amber for "needs
|
|
74
|
+
* an eye", rust for "stopped", green for "approved", blue and violet for the
|
|
75
|
+
* staff badges — held to chroma 0.11–0.17 so they read as information beside a
|
|
76
|
+
* brand rather than competing with it. Colour is never the only carrier: every
|
|
77
|
+
* state that a hue marks is also a word in the markup.
|
|
78
|
+
*
|
|
79
|
+
* ## Contrast is measured, not eyeballed
|
|
80
|
+
*
|
|
81
|
+
* Every foreground/surface pair below meets WCAG AA (4.5:1) for body text, and
|
|
82
|
+
* every semantic colour meets it against `card` — including the ambers, which is
|
|
83
|
+
* why they sit near L 0.55 in light rather than at the brighter value that looks
|
|
84
|
+
* nicer in isolation and fails on white. `input` is deliberately darker than
|
|
85
|
+
* `border`: a field's boundary is essential information (1.4.11, 3:1) and a
|
|
86
|
+
* rule between two rows is not.
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
@custom-variant dark (&:is(.dark *));
|
|
90
|
+
|
|
91
|
+
@theme inline {
|
|
92
|
+
--color-background: var(--background);
|
|
93
|
+
--color-foreground: var(--foreground);
|
|
94
|
+
/*
|
|
95
|
+
* The middle surface. `background` is the page, `card` is a panel raised off
|
|
96
|
+
* it, and `surface` is the band cut *into* it — a header, a table head, a
|
|
97
|
+
* panel's own toolbar. Those were `muted` before, which also means "a control
|
|
98
|
+
* that is disabled" and "the tint behind a hovered row"; one token doing three
|
|
99
|
+
* jobs is a token an operator cannot change without changing all three.
|
|
100
|
+
*/
|
|
101
|
+
--color-surface: var(--surface);
|
|
102
|
+
--color-card: var(--card);
|
|
103
|
+
--color-card-foreground: var(--card-foreground);
|
|
104
|
+
--color-primary: var(--primary);
|
|
105
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
106
|
+
/*
|
|
107
|
+
* The filled control under the cursor. This was `hover:opacity-90`, which
|
|
108
|
+
* fades the button *and its label* toward whatever is behind it — on a card
|
|
109
|
+
* that is white, so the one control the page is for got lighter and lower
|
|
110
|
+
* contrast at exactly the moment the reader aimed at it.
|
|
111
|
+
*/
|
|
112
|
+
--color-primary-hover: var(--primary-hover);
|
|
113
|
+
--color-secondary: var(--secondary);
|
|
114
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
115
|
+
--color-muted: var(--muted);
|
|
116
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
117
|
+
--color-accent: var(--accent);
|
|
118
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
119
|
+
--color-destructive: var(--destructive);
|
|
120
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
121
|
+
--color-border: var(--border);
|
|
122
|
+
--color-input: var(--input);
|
|
123
|
+
--color-ring: var(--ring);
|
|
124
|
+
|
|
125
|
+
/* Domain-semantic tokens. These carry meaning, not just appearance. */
|
|
126
|
+
--color-forum-unread: var(--forum-unread);
|
|
127
|
+
--color-forum-read: var(--forum-read);
|
|
128
|
+
--color-forum-locked: var(--forum-locked);
|
|
129
|
+
--color-thread-pinned: var(--thread-pinned);
|
|
130
|
+
--color-thread-locked: var(--thread-locked);
|
|
131
|
+
--color-thread-moved: var(--thread-moved);
|
|
132
|
+
--color-thread-unapproved: var(--thread-unapproved);
|
|
133
|
+
--color-thread-deleted: var(--thread-deleted);
|
|
134
|
+
--color-post-highlight: var(--post-highlight);
|
|
135
|
+
--color-post-own: var(--post-own);
|
|
136
|
+
--color-post-unapproved: var(--post-unapproved);
|
|
137
|
+
--color-moderation-pending: var(--moderation-pending);
|
|
138
|
+
--color-moderation-approved: var(--moderation-approved);
|
|
139
|
+
--color-moderation-rejected: var(--moderation-rejected);
|
|
140
|
+
--color-group-admin: var(--group-admin);
|
|
141
|
+
--color-group-supermod: var(--group-supermod);
|
|
142
|
+
--color-group-mod: var(--group-mod);
|
|
143
|
+
--color-group-banned: var(--group-banned);
|
|
144
|
+
|
|
145
|
+
/*
|
|
146
|
+
* A token like the mono stack is, rather than a literal, so a board can change
|
|
147
|
+
* the face it reads in from the control panel. That was already true of code
|
|
148
|
+
* and false of everything else, which is backwards — the face a board is *read*
|
|
149
|
+
* in is the one an operator is most likely to have an opinion about.
|
|
150
|
+
*/
|
|
151
|
+
--font-sans: var(--font-sans-stack);
|
|
152
|
+
--font-mono: var(--font-mono-stack);
|
|
153
|
+
/*
|
|
154
|
+
* The face headings are set in, and the reason `font-serif` no longer exists
|
|
155
|
+
* here.
|
|
156
|
+
*
|
|
157
|
+
* It used to be a literal — Newsreader, then a five-deep serif fallback — so
|
|
158
|
+
* "what face are this board's headings" was the one typographic question an
|
|
159
|
+
* operator could not answer from the control panel, while the *code* face next
|
|
160
|
+
* to it had been a token all along. That is backwards twice over: it is the
|
|
161
|
+
* more visible decision, and it is the one a board with its own identity is
|
|
162
|
+
* likeliest to have an opinion about.
|
|
163
|
+
*
|
|
164
|
+
* Dropping the Tailwind mapping rather than repointing it is deliberate.
|
|
165
|
+
* `font-serif` still existing would leave forty call sites compiling to a face
|
|
166
|
+
* the board no longer ships, and the next heading somebody wrote would reach
|
|
167
|
+
* for it out of habit. There is no `font-serif` utility now; there is
|
|
168
|
+
* `font-heading`, and it resolves to whatever the board says.
|
|
169
|
+
*/
|
|
170
|
+
--font-heading: var(--font-heading-stack);
|
|
171
|
+
|
|
172
|
+
/*
|
|
173
|
+
* Panel lift. The board used to separate a panel from its page with a border
|
|
174
|
+
* and nothing else, which works and is why it survived this long — but a
|
|
175
|
+
* 1px rule is the only depth cue on the page, so a long listing reads as one
|
|
176
|
+
* flat sheet with lines ruled across it.
|
|
177
|
+
*
|
|
178
|
+
* Both stops are tinted with `--shadow-tint` rather than a literal black, so
|
|
179
|
+
* the dark scheme can carry a deeper shadow (a 5%-black shadow is invisible on
|
|
180
|
+
* a near-black page) and an operator can turn the whole thing off by setting
|
|
181
|
+
* `--elevation: none`.
|
|
182
|
+
*/
|
|
183
|
+
--shadow-elevation: var(--elevation);
|
|
184
|
+
|
|
185
|
+
--radius-sm: calc(var(--radius) * 0.5);
|
|
186
|
+
--radius-md: calc(var(--radius) * 0.75);
|
|
187
|
+
--radius-lg: var(--radius);
|
|
188
|
+
--radius-xl: calc(var(--radius) * 1.5);
|
|
189
|
+
|
|
190
|
+
/*
|
|
191
|
+
* Density unit. Classic forums are information-dense; a compact theme sets
|
|
192
|
+
* this lower and every row inherits the change.
|
|
193
|
+
*/
|
|
194
|
+
--spacing-density: var(--density-unit);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
:root {
|
|
198
|
+
color-scheme: light;
|
|
199
|
+
|
|
200
|
+
/*
|
|
201
|
+
* Paper on a desk. The page is a light grey so that `card` — plain white — is
|
|
202
|
+
* a surface that sits *on* it: a board is a stack of panels, and a panel that
|
|
203
|
+
* is the same colour as its page needs a border to exist at all.
|
|
204
|
+
*/
|
|
205
|
+
--background: oklch(0.968 0 0);
|
|
206
|
+
--foreground: oklch(0.205 0 0);
|
|
207
|
+
/* The band between page and panel: header, table head, a panel's toolbar. */
|
|
208
|
+
--surface: oklch(0.941 0 0);
|
|
209
|
+
--card: oklch(1 0 0);
|
|
210
|
+
--card-foreground: oklch(0.205 0 0);
|
|
211
|
+
|
|
212
|
+
/*
|
|
213
|
+
* Pine, not emerald. See this file's header: the dark scheme's green reads at
|
|
214
|
+
* about 3.5:1 on white, and the small text this marks needs 4.5. This is the
|
|
215
|
+
* step of the same ramp that clears it — 5.2:1 on the page, 5.5:1 on a card.
|
|
216
|
+
*/
|
|
217
|
+
--primary: oklch(0.508 0.105 165.6);
|
|
218
|
+
--primary-foreground: oklch(0.985 0 0);
|
|
219
|
+
--primary-hover: oklch(0.434 0.089 165.6);
|
|
220
|
+
--secondary: oklch(0.94 0 0);
|
|
221
|
+
--secondary-foreground: oklch(0.269 0 0);
|
|
222
|
+
--muted: oklch(0.958 0 0);
|
|
223
|
+
--muted-foreground: oklch(0.494 0 0);
|
|
224
|
+
/*
|
|
225
|
+
* A hover surface, which is what `accent` means in this vocabulary — the
|
|
226
|
+
* previous palette used it as the one loud colour, and a token that is a
|
|
227
|
+
* highlight in one theme and a wash in another is a token nobody can style
|
|
228
|
+
* against. Anything that needs to shout uses a semantic token, which has a
|
|
229
|
+
* meaning to justify the volume.
|
|
230
|
+
*/
|
|
231
|
+
--accent: oklch(0.951 0 0);
|
|
232
|
+
--accent-foreground: oklch(0.205 0 0);
|
|
233
|
+
--destructive: oklch(0.514 0.183 28.5);
|
|
234
|
+
--destructive-foreground: oklch(0.985 0 0);
|
|
235
|
+
|
|
236
|
+
--border: oklch(0.905 0 0);
|
|
237
|
+
/* Darker than `border` on purpose: a field's edge is information. */
|
|
238
|
+
--input: oklch(0.64 0 0);
|
|
239
|
+
/*
|
|
240
|
+
* The ring follows the accent rather than staying grey. A focus outline is one
|
|
241
|
+
* of the four things the accent is spent on, and a neutral ring on a branded
|
|
242
|
+
* board looks like the board forgot to brand one thing.
|
|
243
|
+
*/
|
|
244
|
+
--ring: oklch(0.508 0.105 165.6);
|
|
245
|
+
|
|
246
|
+
/*
|
|
247
|
+
* The shadow's colour, apart from its geometry, because only this half changes
|
|
248
|
+
* between the schemes. Tinted with the foreground rather than pure black: a
|
|
249
|
+
* neutral-black shadow over a warm surface reads as dirt.
|
|
250
|
+
*/
|
|
251
|
+
--shadow-tint: oklch(0.205 0 0 / 8%);
|
|
252
|
+
|
|
253
|
+
/*
|
|
254
|
+
* 8px, up from 6. The rounding that matters is on the *outer* panels; rows
|
|
255
|
+
* inside them are ruled, not boxed, so density survives the softer corner.
|
|
256
|
+
* `radius-sm` derives 4px from this for the things that must stay tight —
|
|
257
|
+
* badges, a code span — so the increase does not propagate to every chip.
|
|
258
|
+
*/
|
|
259
|
+
--radius: 0.5rem;
|
|
260
|
+
--density-unit: 0.25rem;
|
|
261
|
+
--font-mono-stack: ui-monospace, "SFMono-Regular", "Menlo", monospace;
|
|
262
|
+
--font-sans-stack: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
|
|
263
|
+
/*
|
|
264
|
+
* Headings, and by default the same face as everything else.
|
|
265
|
+
*
|
|
266
|
+
* `var(--font-sans-stack)` rather than a repeat of its value, so a board that
|
|
267
|
+
* changes the face it is *read* in gets headings that follow — which is what
|
|
268
|
+
* an operator means nine times in ten by "change the font". Setting this token
|
|
269
|
+
* is the tenth: headings alone, to anything, including a serif
|
|
270
|
+
* (`Georgia, ui-serif, serif` needs no download) or a face the board already
|
|
271
|
+
* loads.
|
|
272
|
+
*/
|
|
273
|
+
--font-heading-stack: var(--font-sans-stack);
|
|
274
|
+
--elevation: 0 1px 2px var(--shadow-tint), 0 12px 32px -16px var(--shadow-tint);
|
|
275
|
+
|
|
276
|
+
/*
|
|
277
|
+
* Read state: unread is emphatic, read recedes. Both are neutral, so a board
|
|
278
|
+
* that brands `--primary` does not accidentally turn every unread marker into
|
|
279
|
+
* its logo colour — and an operator who *wants* that overrides one token.
|
|
280
|
+
*/
|
|
281
|
+
--forum-unread: oklch(0.205 0 0);
|
|
282
|
+
--forum-read: oklch(0.556 0 0);
|
|
283
|
+
--forum-locked: oklch(0.554 0.135 32);
|
|
284
|
+
|
|
285
|
+
--thread-pinned: oklch(0.55 0.12 68);
|
|
286
|
+
--thread-locked: oklch(0.554 0.135 32);
|
|
287
|
+
--thread-moved: oklch(0.556 0 0);
|
|
288
|
+
--thread-unapproved: oklch(0.545 0.11 88);
|
|
289
|
+
--thread-deleted: oklch(0.487 0.164 26);
|
|
290
|
+
|
|
291
|
+
/* Row washes. Held near the card so text on them keeps its full contrast. */
|
|
292
|
+
--post-highlight: oklch(0.964 0.036 92);
|
|
293
|
+
--post-own: oklch(0.972 0 0);
|
|
294
|
+
--post-unapproved: oklch(0.956 0.035 84);
|
|
295
|
+
|
|
296
|
+
--moderation-pending: oklch(0.55 0.12 68);
|
|
297
|
+
--moderation-approved: oklch(0.518 0.113 150);
|
|
298
|
+
--moderation-rejected: oklch(0.554 0.135 32);
|
|
299
|
+
|
|
300
|
+
--group-admin: oklch(0.505 0.169 27);
|
|
301
|
+
--group-supermod: oklch(0.496 0.153 305);
|
|
302
|
+
--group-mod: oklch(0.489 0.127 250);
|
|
303
|
+
--group-banned: oklch(0.556 0 0);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.dark {
|
|
307
|
+
color-scheme: dark;
|
|
308
|
+
|
|
309
|
+
/*
|
|
310
|
+
* The same neutral, inverted, and not to pure black: `background` at L 0.15
|
|
311
|
+
* rather than 0 leaves room for `card` to sit *above* it, which is the same
|
|
312
|
+
* page-and-panel relationship the light scheme has. Pure black would flatten
|
|
313
|
+
* the two and force every panel to be found by its border.
|
|
314
|
+
*
|
|
315
|
+
* `foreground` stops at 0.967 rather than 1 for the opposite reason —
|
|
316
|
+
* full-white body text on a near-black ground haloes, and a board is read for
|
|
317
|
+
* an hour at a time.
|
|
318
|
+
*/
|
|
319
|
+
--background: oklch(0.15 0 0);
|
|
320
|
+
--foreground: oklch(0.967 0 0);
|
|
321
|
+
--surface: oklch(0.17 0 0);
|
|
322
|
+
--card: oklch(0.196 0 0);
|
|
323
|
+
--card-foreground: oklch(0.967 0 0);
|
|
324
|
+
|
|
325
|
+
/*
|
|
326
|
+
* Emerald, and a near-black label on it. A mid-tone accent cannot carry white
|
|
327
|
+
* text on one scheme and dark text on the other from a single value, which is
|
|
328
|
+
* why `primary-foreground` is a token and not `white`.
|
|
329
|
+
*/
|
|
330
|
+
--primary: oklch(0.773 0.153 163.2);
|
|
331
|
+
--primary-foreground: oklch(0.181 0.029 166.6);
|
|
332
|
+
--primary-hover: oklch(0.84 0.139 166.8);
|
|
333
|
+
--secondary: oklch(0.256 0 0);
|
|
334
|
+
--secondary-foreground: oklch(0.94 0 0);
|
|
335
|
+
--muted: oklch(0.228 0 0);
|
|
336
|
+
--muted-foreground: oklch(0.702 0 0);
|
|
337
|
+
--accent: oklch(0.276 0 0);
|
|
338
|
+
--accent-foreground: oklch(0.967 0 0);
|
|
339
|
+
--destructive: oklch(0.674 0.174 26);
|
|
340
|
+
--destructive-foreground: oklch(0.18 0 0);
|
|
341
|
+
|
|
342
|
+
--border: oklch(0.31 0 0);
|
|
343
|
+
--input: oklch(0.52 0 0);
|
|
344
|
+
--ring: oklch(0.773 0.153 163.2);
|
|
345
|
+
|
|
346
|
+
/*
|
|
347
|
+
* Far heavier than the light scheme's 8%. A shadow is the absence of light,
|
|
348
|
+
* and on a near-black page there is almost none to take away — the light
|
|
349
|
+
* value is literally invisible here, so a panel would lose its lift entirely
|
|
350
|
+
* in dark mode while keeping it in light.
|
|
351
|
+
*/
|
|
352
|
+
--shadow-tint: oklch(0 0 0 / 45%);
|
|
353
|
+
|
|
354
|
+
--forum-unread: oklch(0.967 0 0);
|
|
355
|
+
--forum-read: oklch(0.6 0 0);
|
|
356
|
+
--forum-locked: oklch(0.708 0.13 34);
|
|
357
|
+
|
|
358
|
+
--thread-pinned: oklch(0.769 0.13 74);
|
|
359
|
+
--thread-locked: oklch(0.708 0.13 34);
|
|
360
|
+
--thread-moved: oklch(0.6 0 0);
|
|
361
|
+
--thread-unapproved: oklch(0.777 0.12 85);
|
|
362
|
+
--thread-deleted: oklch(0.664 0.157 27);
|
|
363
|
+
|
|
364
|
+
--post-highlight: oklch(0.276 0.043 92);
|
|
365
|
+
--post-own: oklch(0.221 0 0);
|
|
366
|
+
--post-unapproved: oklch(0.263 0.04 85);
|
|
367
|
+
|
|
368
|
+
--moderation-pending: oklch(0.769 0.13 74);
|
|
369
|
+
--moderation-approved: oklch(0.716 0.126 151);
|
|
370
|
+
--moderation-rejected: oklch(0.708 0.13 34);
|
|
371
|
+
|
|
372
|
+
--group-admin: oklch(0.687 0.166 27);
|
|
373
|
+
--group-supermod: oklch(0.703 0.144 305);
|
|
374
|
+
--group-mod: oklch(0.694 0.122 250);
|
|
375
|
+
--group-banned: oklch(0.6 0 0);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
@media (prefers-color-scheme: dark) {
|
|
379
|
+
:root:not(.light) {
|
|
380
|
+
color-scheme: dark;
|
|
381
|
+
|
|
382
|
+
--background: oklch(0.15 0 0);
|
|
383
|
+
--foreground: oklch(0.967 0 0);
|
|
384
|
+
--surface: oklch(0.17 0 0);
|
|
385
|
+
--card: oklch(0.196 0 0);
|
|
386
|
+
--card-foreground: oklch(0.967 0 0);
|
|
387
|
+
|
|
388
|
+
--primary: oklch(0.773 0.153 163.2);
|
|
389
|
+
--primary-foreground: oklch(0.181 0.029 166.6);
|
|
390
|
+
--primary-hover: oklch(0.84 0.139 166.8);
|
|
391
|
+
--secondary: oklch(0.256 0 0);
|
|
392
|
+
--secondary-foreground: oklch(0.94 0 0);
|
|
393
|
+
--muted: oklch(0.228 0 0);
|
|
394
|
+
--muted-foreground: oklch(0.702 0 0);
|
|
395
|
+
--accent: oklch(0.276 0 0);
|
|
396
|
+
--accent-foreground: oklch(0.967 0 0);
|
|
397
|
+
--destructive: oklch(0.674 0.174 26);
|
|
398
|
+
--destructive-foreground: oklch(0.18 0 0);
|
|
399
|
+
|
|
400
|
+
--border: oklch(0.31 0 0);
|
|
401
|
+
--input: oklch(0.52 0 0);
|
|
402
|
+
--ring: oklch(0.773 0.153 163.2);
|
|
403
|
+
|
|
404
|
+
--shadow-tint: oklch(0 0 0 / 45%);
|
|
405
|
+
|
|
406
|
+
--forum-unread: oklch(0.967 0 0);
|
|
407
|
+
--forum-read: oklch(0.6 0 0);
|
|
408
|
+
--forum-locked: oklch(0.708 0.13 34);
|
|
409
|
+
|
|
410
|
+
--thread-pinned: oklch(0.769 0.13 74);
|
|
411
|
+
--thread-locked: oklch(0.708 0.13 34);
|
|
412
|
+
--thread-moved: oklch(0.6 0 0);
|
|
413
|
+
--thread-unapproved: oklch(0.777 0.12 85);
|
|
414
|
+
--thread-deleted: oklch(0.664 0.157 27);
|
|
415
|
+
|
|
416
|
+
--post-highlight: oklch(0.276 0.043 92);
|
|
417
|
+
--post-own: oklch(0.221 0 0);
|
|
418
|
+
--post-unapproved: oklch(0.263 0.04 85);
|
|
419
|
+
|
|
420
|
+
--moderation-pending: oklch(0.769 0.13 74);
|
|
421
|
+
--moderation-approved: oklch(0.716 0.126 151);
|
|
422
|
+
--moderation-rejected: oklch(0.708 0.13 34);
|
|
423
|
+
|
|
424
|
+
--group-admin: oklch(0.687 0.166 27);
|
|
425
|
+
--group-supermod: oklch(0.703 0.144 305);
|
|
426
|
+
--group-mod: oklch(0.694 0.122 250);
|
|
427
|
+
--group-banned: oklch(0.6 0 0);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
@layer base {
|
|
432
|
+
* {
|
|
433
|
+
border-color: var(--border);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
body {
|
|
437
|
+
background-color: var(--background);
|
|
438
|
+
color: var(--foreground);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/*
|
|
442
|
+
* Balance only — deliberately **not** a font-family.
|
|
443
|
+
*
|
|
444
|
+
* An earlier version of this rule set every heading in the serif, as a
|
|
445
|
+
* backstop for markup that had not opted in. That was wrong, and rendering
|
|
446
|
+
* the midnight theme is what showed it: midnight is a terminal, its headings
|
|
447
|
+
* are IBM Plex Mono, and its slots only escaped the rule because every one of
|
|
448
|
+
* them happens to say `font-mono` explicitly. Any heading that did not — a
|
|
449
|
+
* plugin's, a future slot's — would have been silently overruled into the
|
|
450
|
+
* *default theme's* voice. Which face a heading wears is the theme's decision,
|
|
451
|
+
* and this file is the app.
|
|
452
|
+
*
|
|
453
|
+
* The default theme's slots and the app's own pages already carry
|
|
454
|
+
* `font-serif`, so nothing was gained by it either.
|
|
455
|
+
*
|
|
456
|
+
* Balance stays, because it is not a voice decision. Thread subjects are
|
|
457
|
+
* user-supplied and unbounded, and a two-line title with one orphaned word is
|
|
458
|
+
* the commonest way a dense listing looks broken — in any theme.
|
|
459
|
+
*/
|
|
460
|
+
h1,
|
|
461
|
+
h2,
|
|
462
|
+
h3,
|
|
463
|
+
h4 {
|
|
464
|
+
text-wrap: balance;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/*
|
|
468
|
+
* The paragraph counterpart. `balance` is quadratic and browsers cap it at a
|
|
469
|
+
* handful of lines, so it is wrong for a post body; `pretty` only fixes the
|
|
470
|
+
* last line, which is the orphan that makes a paragraph look broken.
|
|
471
|
+
*/
|
|
472
|
+
p {
|
|
473
|
+
text-wrap: pretty;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/* Keyboard focus must always be visible — R5 pages are used without a mouse. */
|
|
477
|
+
:focus-visible {
|
|
478
|
+
outline: 2px solid var(--ring);
|
|
479
|
+
outline-offset: 2px;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/*
|
|
483
|
+
* A permalink to `#post-12` otherwise lands the post flush against the top
|
|
484
|
+
* of the viewport, with its own header cropped and the previous post's footer
|
|
485
|
+
* nowhere — the reader cannot tell they arrived at the right one.
|
|
486
|
+
*/
|
|
487
|
+
:target {
|
|
488
|
+
scroll-margin-block-start: 1.5rem;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
::selection {
|
|
492
|
+
background-color: var(--secondary);
|
|
493
|
+
color: var(--secondary-foreground);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/*
|
|
497
|
+
* Transitions on this board are hover and focus feedback of 100–150ms, and
|
|
498
|
+
* every one of them is an affordance rather than an animation. Honour the
|
|
499
|
+
* preference anyway: the setting is often on for reasons that have nothing to
|
|
500
|
+
* do with how large the movement is.
|
|
501
|
+
*/
|
|
502
|
+
@media (prefers-reduced-motion: reduce) {
|
|
503
|
+
*,
|
|
504
|
+
*::before,
|
|
505
|
+
*::after {
|
|
506
|
+
animation-duration: 0.01ms !important;
|
|
507
|
+
animation-iteration-count: 1 !important;
|
|
508
|
+
transition-duration: 0.01ms !important;
|
|
509
|
+
scroll-behavior: auto !important;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/* Skip link: visually hidden until focused. */
|
|
515
|
+
.skip-link {
|
|
516
|
+
position: absolute;
|
|
517
|
+
left: -9999px;
|
|
518
|
+
top: 0;
|
|
519
|
+
z-index: 100;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.skip-link:focus {
|
|
523
|
+
left: 0.5rem;
|
|
524
|
+
top: 0.5rem;
|
|
525
|
+
padding: 0.5rem 0.75rem;
|
|
526
|
+
background-color: var(--card);
|
|
527
|
+
color: var(--card-foreground);
|
|
528
|
+
border: 1px solid var(--border);
|
|
529
|
+
border-radius: var(--radius);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/*
|
|
533
|
+
* `.prose-md` — the typography of a rendered post body.
|
|
534
|
+
*
|
|
535
|
+
* **This block is a bug fix as much as a design.** Both shipped themes have
|
|
536
|
+
* carried a prose class on the elements that receive `bodyHtml` since the slots
|
|
537
|
+
* were written, and it was defined nowhere in the workspace. Tailwind's
|
|
538
|
+
* preflight zeroes the margin on `p`, `ul` and `ol` and removes the underline
|
|
539
|
+
* and colour from `a`, so a four-paragraph post rendered as one unbroken block
|
|
540
|
+
* of text with invisible links in it. Nothing failed — there is no such thing
|
|
541
|
+
* as a stylesheet error — and the contract suite could not see it, because the
|
|
542
|
+
* markup was correct and only its appearance was not.
|
|
543
|
+
*
|
|
544
|
+
* It lives here rather than in a theme for the same reason the `.md-*` rules
|
|
545
|
+
* below do: the class names are emitted by `@meith/markdown`, which is the
|
|
546
|
+
* app's renderer, and a theme that had to restate all of this to show a
|
|
547
|
+
* paragraph break would be inheriting a bug rather than a baseline. Everything
|
|
548
|
+
* is in tokens and `em`, so a theme changes it by changing its tokens and its
|
|
549
|
+
* base size — and a board's operator reaches it through F26 like any other
|
|
550
|
+
* surface.
|
|
551
|
+
*
|
|
552
|
+
* Markdown widened what a post can contain — headings, tables, task lists, a
|
|
553
|
+
* horizontal rule — so this block is longer than the BBCode one it replaces.
|
|
554
|
+
* Every addition is a construct the parser can now produce; nothing here styles
|
|
555
|
+
* anything a post cannot emit.
|
|
556
|
+
*/
|
|
557
|
+
.prose-md {
|
|
558
|
+
line-height: 1.65;
|
|
559
|
+
overflow-wrap: break-word;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.prose-md > :first-child {
|
|
563
|
+
margin-top: 0;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.prose-md > :last-child {
|
|
567
|
+
margin-bottom: 0;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.prose-md p {
|
|
571
|
+
margin-block: 0.75em;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/*
|
|
575
|
+
* A link keeps the body's colour and is marked by its *underline*, which is the
|
|
576
|
+
* accent's third job (see this file's header).
|
|
577
|
+
*
|
|
578
|
+
* Colouring the text itself is the obvious alternative and it is the one that
|
|
579
|
+
* breaks under branding: a board whose operator has set a pale yellow accent has
|
|
580
|
+
* just made every link in every post unreadable, and the post body is the one
|
|
581
|
+
* region where that is not survivable. An underline carries the affordance at
|
|
582
|
+
* any accent lightness, because the text under it never stopped being body text.
|
|
583
|
+
*
|
|
584
|
+
* `color-mix` rather than a second token: the rule is "this accent, quieter",
|
|
585
|
+
* and an operator who changes the accent should not have to remember to change
|
|
586
|
+
* its underline to match.
|
|
587
|
+
*/
|
|
588
|
+
.prose-md a {
|
|
589
|
+
color: inherit;
|
|
590
|
+
text-decoration-line: underline;
|
|
591
|
+
text-decoration-color: color-mix(in srgb, var(--primary) 45%, transparent);
|
|
592
|
+
text-decoration-thickness: 1px;
|
|
593
|
+
text-underline-offset: 0.2em;
|
|
594
|
+
transition: text-decoration-color 120ms ease;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.prose-md a:hover {
|
|
598
|
+
text-decoration-color: var(--primary);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.prose-md strong,
|
|
602
|
+
.prose-md b {
|
|
603
|
+
font-weight: 600;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/*
|
|
607
|
+
* A URL a member pasted is one unbroken token, and a long one widens the post,
|
|
608
|
+
* then the thread, then the page. Breaking it is uglier than the alternative
|
|
609
|
+
* only until you meet the alternative.
|
|
610
|
+
*/
|
|
611
|
+
.prose-md a,
|
|
612
|
+
.prose-md code {
|
|
613
|
+
overflow-wrap: anywhere;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/*
|
|
617
|
+
* A post's headings start at `h2` — the renderer offsets them, because the page
|
|
618
|
+
* already has an `h1` — and they must not out-shout the thread's subject. Sized
|
|
619
|
+
* in `em` off the post's own text rather than the browser's defaults, which
|
|
620
|
+
* would make an `h2` in a post twice the size of the title above it.
|
|
621
|
+
*/
|
|
622
|
+
.prose-md h2,
|
|
623
|
+
.prose-md h3,
|
|
624
|
+
.prose-md h4,
|
|
625
|
+
.prose-md h5,
|
|
626
|
+
.prose-md h6 {
|
|
627
|
+
margin-block: 1.2em 0.5em;
|
|
628
|
+
font-weight: 600;
|
|
629
|
+
line-height: 1.3;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.prose-md h2 {
|
|
633
|
+
font-size: 1.35em;
|
|
634
|
+
}
|
|
635
|
+
.prose-md h3 {
|
|
636
|
+
font-size: 1.2em;
|
|
637
|
+
}
|
|
638
|
+
.prose-md h4 {
|
|
639
|
+
font-size: 1.05em;
|
|
640
|
+
}
|
|
641
|
+
.prose-md h5,
|
|
642
|
+
.prose-md h6 {
|
|
643
|
+
font-size: 1em;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/* Inline images and smilies sit on the text baseline, not below it. */
|
|
647
|
+
.md-smiley {
|
|
648
|
+
display: inline-block;
|
|
649
|
+
height: 1.25em;
|
|
650
|
+
width: auto;
|
|
651
|
+
vertical-align: text-bottom;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/*
|
|
655
|
+
* F36 — the Markdown renderer's output.
|
|
656
|
+
*
|
|
657
|
+
* `@meith/markdown` emits a fixed, closed set of class names and no inline
|
|
658
|
+
* styling at all. Everything below is therefore the *theme's* say in what a
|
|
659
|
+
* quote or a code block looks like, expressed in tokens so a runtime override
|
|
660
|
+
* (F26) reaches it like any other surface.
|
|
661
|
+
*/
|
|
662
|
+
.md-quote {
|
|
663
|
+
/* `em`, so a quote inside a heading scales with the text it is in. */
|
|
664
|
+
margin-block: 0.85em;
|
|
665
|
+
padding: 0.55em 0.85em;
|
|
666
|
+
border-inline-start: 3px solid var(--border);
|
|
667
|
+
background-color: var(--muted);
|
|
668
|
+
border-start-end-radius: var(--radius);
|
|
669
|
+
border-end-end-radius: var(--radius);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
/*
|
|
673
|
+
* A quote of a quote of a quote is how a forum argument is shaped, and three
|
|
674
|
+
* nested backgrounds of the same colour are indistinguishable. The inner ones
|
|
675
|
+
* drop the fill and keep the rule, so depth reads as a stack of margins.
|
|
676
|
+
*/
|
|
677
|
+
.md-quote .md-quote {
|
|
678
|
+
background-color: transparent;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/* Who was quoted on the left, the link back to their post in the corner. */
|
|
682
|
+
.md-quote-attribution {
|
|
683
|
+
display: flex;
|
|
684
|
+
flex-wrap: wrap;
|
|
685
|
+
align-items: baseline;
|
|
686
|
+
justify-content: space-between;
|
|
687
|
+
gap: 0.25em 1em;
|
|
688
|
+
margin-block: 0 0.5em;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
.md-quote-source {
|
|
692
|
+
margin-inline-start: auto;
|
|
693
|
+
font-size: 0.9em;
|
|
694
|
+
white-space: nowrap;
|
|
695
|
+
opacity: 0.85;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.md-code {
|
|
699
|
+
margin-block: 0.85em;
|
|
700
|
+
padding: 0.75em 0.85em;
|
|
701
|
+
overflow-x: auto;
|
|
702
|
+
background-color: var(--muted);
|
|
703
|
+
border: 1px solid var(--border);
|
|
704
|
+
border-radius: var(--radius);
|
|
705
|
+
font-size: 0.875em;
|
|
706
|
+
line-height: 1.6;
|
|
707
|
+
/* `pre` already preserves newlines; wrapping long lines would hide overflow. */
|
|
708
|
+
white-space: pre;
|
|
709
|
+
/*
|
|
710
|
+
* Tabs in pasted code default to eight columns, which throws away a third of
|
|
711
|
+
* the width of a post before the code has said anything.
|
|
712
|
+
*/
|
|
713
|
+
tab-size: 2;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/*
|
|
717
|
+
* A code *span* is a word inside a sentence, so it gets a tint and no border —
|
|
718
|
+
* a boxed word breaks the line's rhythm, and at this size a border is thicker
|
|
719
|
+
* than the letterforms it surrounds.
|
|
720
|
+
*/
|
|
721
|
+
.md-code-span {
|
|
722
|
+
padding: 0.15em 0.35em;
|
|
723
|
+
background-color: var(--muted);
|
|
724
|
+
border-radius: calc(var(--radius) - 2px);
|
|
725
|
+
font-size: 0.9em;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/*
|
|
729
|
+
* Shiki (code-highlighting.ts) tags every token with both a light and a dark
|
|
730
|
+
* colour as CSS custom properties (`defaultColor: false`) and leaves picking
|
|
731
|
+
* one to the page. This is the same three-state switch as the rest of the
|
|
732
|
+
* theme — system preference by default, `.dark`/`.light` to override it.
|
|
733
|
+
*/
|
|
734
|
+
.md-code code span {
|
|
735
|
+
color: var(--shiki-light);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
@media (prefers-color-scheme: dark) {
|
|
739
|
+
:root:not(.light) .md-code code span {
|
|
740
|
+
color: var(--shiki-dark);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.dark .md-code code span {
|
|
745
|
+
color: var(--shiki-dark);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.md-list {
|
|
749
|
+
margin: 0.5em 0 0.5em 1.5em;
|
|
750
|
+
list-style-position: outside;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
.md-list li {
|
|
754
|
+
margin-block: 0.2em;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
ul.md-list {
|
|
758
|
+
list-style-type: disc;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
ol.md-list {
|
|
762
|
+
list-style-type: decimal;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/*
|
|
766
|
+
* A task list is a list of statements, not of bullets: the checkbox is the
|
|
767
|
+
* marker, and leaving the disc there gives every line two.
|
|
768
|
+
*/
|
|
769
|
+
.md-list li.md-task {
|
|
770
|
+
list-style: none;
|
|
771
|
+
margin-inline-start: -1.2em;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.md-task input {
|
|
775
|
+
margin-inline-end: 0.35em;
|
|
776
|
+
vertical-align: baseline;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/* An oversized image must not widen the thread and force a horizontal scroll. */
|
|
780
|
+
.md-image {
|
|
781
|
+
max-width: 100%;
|
|
782
|
+
height: auto;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/*
|
|
786
|
+
* An [attachment=id] placed inline (attachment-embed.ts). An image sits with
|
|
787
|
+
* the text around it, the way a post's own  image does; a non-image
|
|
788
|
+
* file is a plain link — the download route is what actually enforces who
|
|
789
|
+
* may have the bytes, so this is styling, not a second permission surface.
|
|
790
|
+
*/
|
|
791
|
+
.md-attachment-image img {
|
|
792
|
+
max-width: 100%;
|
|
793
|
+
height: auto;
|
|
794
|
+
vertical-align: middle;
|
|
795
|
+
border-radius: var(--radius);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
.md-attachment-file {
|
|
799
|
+
display: inline-flex;
|
|
800
|
+
align-items: baseline;
|
|
801
|
+
gap: 0.35em;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.md-attachment-size {
|
|
805
|
+
color: var(--muted-foreground);
|
|
806
|
+
font-size: 0.85em;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/*
|
|
810
|
+
* A link unfurl card (embeds.ts) — a static figure, never an iframe, so it
|
|
811
|
+
* carries no third-party script and needs nothing from the CSP beyond the
|
|
812
|
+
* `img-src` widening its own thumbnail already required.
|
|
813
|
+
*/
|
|
814
|
+
.md-embed {
|
|
815
|
+
display: flex;
|
|
816
|
+
gap: 0.75em;
|
|
817
|
+
align-items: center;
|
|
818
|
+
margin-block: 0.5em 0.85em;
|
|
819
|
+
padding: 0.6em;
|
|
820
|
+
max-width: 28rem;
|
|
821
|
+
border: 1px solid var(--border);
|
|
822
|
+
border-radius: var(--radius);
|
|
823
|
+
background-color: var(--muted);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.md-embed-thumb {
|
|
827
|
+
flex: none;
|
|
828
|
+
display: block;
|
|
829
|
+
width: 6rem;
|
|
830
|
+
height: 6rem;
|
|
831
|
+
overflow: hidden;
|
|
832
|
+
border-radius: calc(var(--radius) - 2px);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.md-embed-thumb img {
|
|
836
|
+
width: 100%;
|
|
837
|
+
height: 100%;
|
|
838
|
+
object-fit: cover;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
.md-embed figcaption {
|
|
842
|
+
display: flex;
|
|
843
|
+
flex-direction: column;
|
|
844
|
+
gap: 0.15em;
|
|
845
|
+
min-width: 0;
|
|
846
|
+
font-size: 0.9em;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.md-embed-title {
|
|
850
|
+
font-weight: 600;
|
|
851
|
+
overflow: hidden;
|
|
852
|
+
text-overflow: ellipsis;
|
|
853
|
+
white-space: nowrap;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.md-embed-author,
|
|
857
|
+
.md-embed-provider {
|
|
858
|
+
color: var(--muted-foreground);
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
.md-rule {
|
|
862
|
+
margin-block: 1.2em;
|
|
863
|
+
border: 0;
|
|
864
|
+
border-top: 1px solid var(--border);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/*
|
|
868
|
+
* The scroller is the renderer's, not the theme's: a table wider than the post
|
|
869
|
+
* would otherwise make the *thread* scroll sideways, which on a phone is every
|
|
870
|
+
* table with four columns in it.
|
|
871
|
+
*/
|
|
872
|
+
.md-table-scroll {
|
|
873
|
+
margin-block: 0.85em;
|
|
874
|
+
overflow-x: auto;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
.md-table {
|
|
878
|
+
border-collapse: collapse;
|
|
879
|
+
font-size: 0.95em;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
.md-table th,
|
|
883
|
+
.md-table td {
|
|
884
|
+
padding: 0.35em 0.6em;
|
|
885
|
+
border: 1px solid var(--border);
|
|
886
|
+
text-align: start;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
.md-table th {
|
|
890
|
+
background-color: var(--muted);
|
|
891
|
+
font-weight: 600;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.md-align-left {
|
|
895
|
+
text-align: start;
|
|
896
|
+
}
|
|
897
|
+
.md-align-center {
|
|
898
|
+
text-align: center;
|
|
899
|
+
}
|
|
900
|
+
.md-align-right {
|
|
901
|
+
text-align: end;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/*
|
|
905
|
+
* A board's own directives (F71). The renderer gives each one a class and
|
|
906
|
+
* nothing else — no colour, no box — because what a directive looks like is a
|
|
907
|
+
* decision for the board that defined it, made in its theme's own stylesheet.
|
|
908
|
+
* The only thing stated here is that a block one is a block. `spoiler` is not
|
|
909
|
+
* one of these: it is built in, rendered as `<details>` below, and styled here.
|
|
910
|
+
*/
|
|
911
|
+
div.md-directive {
|
|
912
|
+
margin-block: 0.85em;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/*
|
|
916
|
+
* The spoiler reveal works from `<details>`/`<summary>` alone, so it is
|
|
917
|
+
* already correct with no JS and no click handler. The styling only has to
|
|
918
|
+
* make the closed state read as "tap to reveal" rather than as a stray box.
|
|
919
|
+
*/
|
|
920
|
+
.md-spoiler {
|
|
921
|
+
margin-block: 0.85em;
|
|
922
|
+
padding: 0.6em 0.85em;
|
|
923
|
+
background-color: var(--muted);
|
|
924
|
+
border: 1px solid var(--border);
|
|
925
|
+
border-radius: var(--radius);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.md-spoiler > summary {
|
|
929
|
+
cursor: pointer;
|
|
930
|
+
font-weight: 600;
|
|
931
|
+
list-style: none;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.md-spoiler > summary::-webkit-details-marker {
|
|
935
|
+
display: none;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
.md-spoiler > summary::before {
|
|
939
|
+
content: "▸ ";
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
.md-spoiler[open] > summary::before {
|
|
943
|
+
content: "▾ ";
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.md-spoiler[open] > summary {
|
|
947
|
+
margin-block-end: 0.5em;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
.md-spoiler > :last-child {
|
|
951
|
+
margin-block-end: 0;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
@media (pointer: coarse) {
|
|
955
|
+
input:not(
|
|
956
|
+
[type="checkbox"],
|
|
957
|
+
[type="radio"],
|
|
958
|
+
[type="range"],
|
|
959
|
+
[type="color"],
|
|
960
|
+
[type="file"],
|
|
961
|
+
[type="submit"],
|
|
962
|
+
[type="button"],
|
|
963
|
+
[type="reset"]
|
|
964
|
+
),
|
|
965
|
+
select,
|
|
966
|
+
textarea {
|
|
967
|
+
font-size: 1rem;
|
|
968
|
+
}
|
|
969
|
+
}
|