Adding: themes, predictions, match reporting, ui fixes, sse fixes, badge fixes, match flow, i18n, match edits, perf, auth fix #22
+5
-1
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"name": "tanstack-start-example-basic-react-query",
|
||||
"private": true,
|
||||
"sideEffects": false,
|
||||
"sideEffects": [
|
||||
"**/*.css",
|
||||
"**/themes/styles.ts",
|
||||
"**/themes/theme-styles.ts"
|
||||
],
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite dev --host 0.0.0.0",
|
||||
|
||||
@@ -203,7 +203,17 @@ function RootDocument({ children }: { children: React.ReactNode }) {
|
||||
media="(prefers-color-scheme: dark)"
|
||||
content={CHROME_COLORS.dark.base}
|
||||
/>
|
||||
<ColorSchemeScript />
|
||||
<ColorSchemeScript defaultColorScheme="auto" />
|
||||
{/* Pre-hydration theme restore from ThemeProvider's localStorage
|
||||
mirrors: data-theme (so exotic themes don't flash default),
|
||||
forced color scheme (dark-only themes must not paint light),
|
||||
and the theme's font stylesheets (avoid FOUT until hydration). */}
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
__html:
|
||||
'try{var d=document.documentElement,t=localStorage.getItem("flxn-theme");if(t&&t!=="default"){d.setAttribute("data-theme",t);}var s=localStorage.getItem("flxn-theme-scheme");if(s){d.setAttribute("data-mantine-color-scheme",s);}var f=JSON.parse(localStorage.getItem("flxn-theme-fonts")||"[]");for(var i=0;i<f.length;i++){var l=document.createElement("link");l.rel="stylesheet";l.href=f[i];l.setAttribute("data-flxn-theme-font",t||"default");document.head.appendChild(l);}}catch(e){}',
|
||||
}}
|
||||
/>
|
||||
<link rel="stylesheet" href="/styles.css" />
|
||||
</head>
|
||||
<body
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createFileRoute } from "@tanstack/react-router";
|
||||
import { Box, Title, Stack } from "@mantine/core";
|
||||
import { ColorSchemePicker } from "@/features/settings/components/color-scheme-picker";
|
||||
import AccentColorPicker from "@/features/settings/components/accent-color-picker";
|
||||
import ThemePicker from "@/features/settings/components/theme-picker";
|
||||
import LocalePicker from "@/features/settings/components/locale-picker";
|
||||
import { NotificationsSection } from "@/features/settings/components/notifications-section";
|
||||
import { SignOutIcon } from "@phosphor-icons/react";
|
||||
@@ -33,6 +34,7 @@ function RouteComponent() {
|
||||
>
|
||||
<Title order={3}><Trans>Appearance</Trans></Title>
|
||||
<Stack>
|
||||
<ThemePicker />
|
||||
<AccentColorPicker />
|
||||
<ColorSchemePicker />
|
||||
<LocalePicker />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
Avatar as MantineAvatar,
|
||||
AvatarProps as MantineAvatarProps,
|
||||
Paper,
|
||||
Box,
|
||||
Modal,
|
||||
Image,
|
||||
Group,
|
||||
@@ -22,10 +22,17 @@ interface AvatarProps
|
||||
contain?: boolean;
|
||||
}
|
||||
|
||||
// Mantine radius tokens ("sm", "xl") are valid as props but not as raw CSS
|
||||
// values — resolve them before using in style/borderRadius.
|
||||
const resolveRadius = (radius: string | number) =>
|
||||
typeof radius === "string" && /^[a-z]+$/.test(radius)
|
||||
? `var(--mantine-radius-${radius})`
|
||||
: radius;
|
||||
|
||||
const Avatar = ({
|
||||
name,
|
||||
size = 35,
|
||||
radius = "100%",
|
||||
radius = "var(--flxn-avatar-radius, 50%)",
|
||||
withBorder = true,
|
||||
disableFullscreen = false,
|
||||
contain = false,
|
||||
@@ -34,6 +41,7 @@ const Avatar = ({
|
||||
const { t } = useLingui();
|
||||
const [isFullscreenOpen, setIsFullscreenOpen] = useState(false);
|
||||
const hasImage = Boolean(props.src);
|
||||
const frameRadius = resolveRadius(radius);
|
||||
|
||||
const handleAvatarClick = () => {
|
||||
if (hasImage && !disableFullscreen) {
|
||||
@@ -43,11 +51,20 @@ const Avatar = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Paper
|
||||
p={size / 20}
|
||||
radius={radius}
|
||||
withBorder={withBorder}
|
||||
<Box
|
||||
className="flxn-avatar-frame"
|
||||
p={withBorder ? size / 20 : 0}
|
||||
style={{
|
||||
// Plain Box, not Paper: the frame must own the avatar's single
|
||||
// border (via --flxn-avatar-border) and stay immune to generic
|
||||
// theme Paper restyles; shape comes from --flxn-avatar-radius.
|
||||
borderRadius: frameRadius,
|
||||
border: withBorder
|
||||
? 'var(--flxn-avatar-border, 1px solid var(--mantine-color-default-border))'
|
||||
: undefined,
|
||||
backgroundColor: withBorder
|
||||
? 'var(--mantine-color-body)'
|
||||
: undefined,
|
||||
cursor: hasImage && !disableFullscreen ? 'pointer' : 'default',
|
||||
transition: 'transform 0.15s ease',
|
||||
}}
|
||||
@@ -69,14 +86,17 @@ const Avatar = ({
|
||||
size={size}
|
||||
radius={radius}
|
||||
w={size}
|
||||
{...props}
|
||||
styles={{
|
||||
root: {
|
||||
borderRadius: frameRadius,
|
||||
},
|
||||
image: {
|
||||
objectFit: contain ? 'contain' : 'cover',
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
<Modal
|
||||
opened={isFullscreenOpen}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { Box, Container, Title, useComputedColorScheme } from "@mantine/core";
|
||||
import { PropsWithChildren, useEffect, useRef } from "react";
|
||||
import { Drawer as VaulDrawer } from "vaul";
|
||||
import { CHROME_COLORS, setThemeColorMeta } from "@/lib/mantine/theme-colors";
|
||||
import {
|
||||
pushDimmedThemeColor,
|
||||
popDimmedThemeColor,
|
||||
} from "@/lib/mantine/theme-colors";
|
||||
import { getTheme } from "@/themes/registry";
|
||||
import { resolveChromeColors } from "@/themes/chrome";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
interface DrawerProps extends PropsWithChildren {
|
||||
@@ -20,22 +26,24 @@ const Drawer: React.FC<DrawerProps> = ({
|
||||
onExited,
|
||||
}) => {
|
||||
const colorScheme = useComputedColorScheme("light");
|
||||
const { metadata } = useAuth();
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const themeId = metadata.theme;
|
||||
|
||||
useEffect(() => {
|
||||
if (!opened) return;
|
||||
|
||||
const appElement = document.querySelector<HTMLElement>(".app");
|
||||
const colors = CHROME_COLORS[colorScheme];
|
||||
const colors = resolveChromeColors(getTheme(themeId))[colorScheme];
|
||||
|
||||
appElement?.classList.add("drawer-scaling");
|
||||
setThemeColorMeta(colors.dimmed);
|
||||
pushDimmedThemeColor(colors.dimmed);
|
||||
|
||||
return () => {
|
||||
appElement?.classList.remove("drawer-scaling");
|
||||
setThemeColorMeta(colors.base);
|
||||
popDimmedThemeColor(colors.base);
|
||||
};
|
||||
}, [opened, colorScheme]);
|
||||
}, [opened, colorScheme, themeId]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!opened || !contentRef.current) return;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.drawerOverlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
background-color: var(--flxn-overlay);
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@ function SwipeableTabs({
|
||||
}, [search?.tab, tabs, defaultTab]);
|
||||
|
||||
const [activeTab, setActiveTab] = useState(getActiveTabFromUrl);
|
||||
const [stuck, setStuck] = useState(false);
|
||||
const sentinelRef = useRef<HTMLDivElement>(null);
|
||||
const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null);
|
||||
const controlsRefs = useRef<Record<number, HTMLSpanElement | null>>({});
|
||||
const slideRefs = useRef<Record<number, HTMLDivElement | null>>({});
|
||||
@@ -132,6 +134,20 @@ function SwipeableTabs({
|
||||
};
|
||||
}, [activeTab, updateHeight]);
|
||||
|
||||
// A 1px sentinel above the sticky strip: once it scrolls out of view the
|
||||
// strip is pinned — flip data-stuck so themes can swap flat → docked chrome.
|
||||
useEffect(() => {
|
||||
const sentinel = sentinelRef.current;
|
||||
if (!sentinel) return;
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => setStuck(!entry.isIntersecting),
|
||||
{ threshold: 0 }
|
||||
);
|
||||
observer.observe(sentinel);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
const setControlRef = useCallback(
|
||||
(index: number) => (node: HTMLSpanElement | null) => {
|
||||
controlsRefs.current[index] = node;
|
||||
@@ -148,8 +164,11 @@ function SwipeableTabs({
|
||||
|
||||
return (
|
||||
<Box style={{ touchAction: "pan-y" }}>
|
||||
<div ref={sentinelRef} aria-hidden style={{ height: 1, marginTop: -1 }} />
|
||||
<Box
|
||||
ref={setRootRef}
|
||||
className="flxn-tabs"
|
||||
data-stuck={stuck || undefined}
|
||||
pos="sticky"
|
||||
top={0}
|
||||
style={{
|
||||
@@ -157,45 +176,28 @@ function SwipeableTabs({
|
||||
paddingInline: "var(--mantine-spacing-md)",
|
||||
marginBottom: mb !== undefined ? mb : "var(--mantine-spacing-md)",
|
||||
zIndex: 100,
|
||||
backgroundColor: "var(--mantine-color-body)",
|
||||
}}
|
||||
>
|
||||
<FloatingIndicator
|
||||
target={controlsRefs.current[activeTab]}
|
||||
parent={rootRef}
|
||||
styles={{
|
||||
root: {
|
||||
borderBottom: "2px solid var(--mantine-primary-color-filled)",
|
||||
paddingInline: "0.5rem",
|
||||
},
|
||||
}}
|
||||
className="flxn-tabs-indicator"
|
||||
/>
|
||||
{tabs.map((tab, index) => (
|
||||
<UnstyledButton
|
||||
key={`${tab.label}-${index}`}
|
||||
onClick={() => changeTab(index)}
|
||||
style={{
|
||||
flex: 1,
|
||||
padding: "var(--mantine-spacing-sm) var(--mantine-spacing-xs)",
|
||||
textAlign: "center",
|
||||
color:
|
||||
activeTab === index
|
||||
? "var(--mantine-primary-color-filled)"
|
||||
: "var(--mantine-color-text)",
|
||||
fontWeight: activeTab === index ? 600 : 400,
|
||||
transition: "color 200ms ease, font-weight 200ms ease",
|
||||
backgroundColor: "transparent",
|
||||
border: "none",
|
||||
borderRadius: 0,
|
||||
}}
|
||||
className="flxn-tab"
|
||||
data-active={activeTab === index || undefined}
|
||||
>
|
||||
<Text
|
||||
size="sm"
|
||||
component="span"
|
||||
style={{
|
||||
// the FloatingIndicator sizes to this span — keep padding symmetric
|
||||
display: "inline-block",
|
||||
paddingInline: "0.5rem",
|
||||
paddingBottom: "0.25rem",
|
||||
paddingInline: "0.875rem",
|
||||
paddingBlock: "0.375rem",
|
||||
}}
|
||||
ref={setControlRef(index)}
|
||||
>
|
||||
|
||||
@@ -62,7 +62,7 @@ const TeamAvatar = ({
|
||||
top: -crownSize * 1.1,
|
||||
left: "45%",
|
||||
transform: "translateX(-50%)",
|
||||
color: "gold",
|
||||
color: "var(--flxn-gold)",
|
||||
rotate: "-5deg",
|
||||
}}
|
||||
>
|
||||
@@ -83,7 +83,7 @@ const TeamAvatar = ({
|
||||
top: -crownSize * 0.95,
|
||||
left: "65%",
|
||||
transform: "translateX(-50%)",
|
||||
color: "gold",
|
||||
color: "var(--flxn-gold)",
|
||||
rotate: "10deg",
|
||||
}}
|
||||
>
|
||||
@@ -116,7 +116,7 @@ const TeamAvatar = ({
|
||||
top: -crownSize * 0.6,
|
||||
left: -crownSize * 0.25,
|
||||
transform: "rotate(-25deg)",
|
||||
color: "gold",
|
||||
color: "var(--flxn-gold)",
|
||||
}}
|
||||
>
|
||||
<CrownIcon size={crownSize} weight="fill" />
|
||||
|
||||
@@ -15,6 +15,7 @@ interface AuthData {
|
||||
metadata: {
|
||||
accentColor: MantineColor;
|
||||
colorScheme: MantineColorScheme;
|
||||
theme?: string;
|
||||
locale?: string;
|
||||
};
|
||||
roles: string[];
|
||||
|
||||
@@ -208,8 +208,8 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
|
||||
style={{
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
borderRadius: '12px',
|
||||
background: 'light-dark(var(--mantine-color-white), var(--mantine-color-dark-7))',
|
||||
borderRadius: 'var(--flxn-badge-radius)',
|
||||
background: 'var(--flxn-showcase-bg)',
|
||||
border: '2px solid var(--mantine-primary-color-5)',
|
||||
position: 'absolute',
|
||||
top: `${(i + 1) * 4}px`,
|
||||
@@ -226,8 +226,8 @@ const BadgeShowcase = ({ playerId }: BadgeShowcaseProps) => {
|
||||
style={{
|
||||
width: '100px',
|
||||
height: '100px',
|
||||
borderRadius: '12px',
|
||||
background: 'light-dark(var(--mantine-color-white), var(--mantine-color-dark-7))',
|
||||
borderRadius: 'var(--flxn-badge-radius)',
|
||||
background: 'var(--flxn-showcase-bg)',
|
||||
border: display.earned
|
||||
? '2px solid var(--mantine-primary-color-6)'
|
||||
: '2px dashed var(--mantine-primary-color-4)',
|
||||
|
||||
@@ -9,7 +9,7 @@ export function BracketPending() {
|
||||
p={0}
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
backgroundImage: `radial-gradient(circle, var(--mantine-color-default-border) 1px, transparent 1px)`,
|
||||
backgroundImage: `radial-gradient(circle, var(--flxn-dotgrid-color) 1px, transparent 1px)`,
|
||||
backgroundSize: "16px 16px",
|
||||
backgroundPosition: "0 0, 8px 8px",
|
||||
minHeight: "70dvh",
|
||||
|
||||
@@ -89,7 +89,7 @@ const BracketView: React.FC<BracketViewProps> = ({ bracket, showControls, groupC
|
||||
h={`calc(${height})`}
|
||||
className={styles["bracket-container"]}
|
||||
style={{
|
||||
backgroundImage: `radial-gradient(circle, var(--mantine-color-default-border) 1px, transparent 1px)`,
|
||||
backgroundImage: `radial-gradient(circle, var(--flxn-dotgrid-color) 1px, transparent 1px)`,
|
||||
backgroundSize: "16px 16px",
|
||||
backgroundPosition: "0 0, 8px 8px",
|
||||
}}
|
||||
|
||||
@@ -269,7 +269,11 @@ export const MatchCard: React.FC<MatchCardProps> = ({
|
||||
w={showToolbar || showEditButton ? 200 : 220}
|
||||
withBorder
|
||||
pos="relative"
|
||||
className={canTap ? styles["tappable-card"] : undefined}
|
||||
className={
|
||||
canTap
|
||||
? `flxn-bracket-card ${styles["tappable-card"]}`
|
||||
: "flxn-bracket-card"
|
||||
}
|
||||
onClick={canTap ? () => onTap!(match) : undefined}
|
||||
role={canTap ? "button" : undefined}
|
||||
tabIndex={canTap ? 0 : undefined}
|
||||
|
||||
@@ -83,10 +83,10 @@ export const MatchSlot: React.FC<MatchSlotProps> = ({
|
||||
size={14}
|
||||
weight="fill"
|
||||
style={{
|
||||
color: 'gold',
|
||||
color: 'var(--flxn-gold)',
|
||||
marginLeft: '2px',
|
||||
marginTop: '-1px',
|
||||
filter: 'drop-shadow(0 1px 1px rgba(0,0,0,0.3))',
|
||||
filter: 'drop-shadow(0 1px 1px var(--flxn-pop-shadow))',
|
||||
flexShrink: 0
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -52,6 +52,7 @@ const MatchCard = ({ match, hideH2H = false }: MatchCardProps) => {
|
||||
py="md"
|
||||
withBorder
|
||||
radius="md"
|
||||
className="flxn-match-card"
|
||||
style={{ position: "relative", zIndex: 2 }}
|
||||
>
|
||||
<Stack gap="sm">
|
||||
@@ -208,16 +209,12 @@ const MatchCard = ({ match, hideH2H = false }: MatchCardProps) => {
|
||||
<Paper
|
||||
px="md"
|
||||
pb={4}
|
||||
className="flxn-reaction-row"
|
||||
style={{
|
||||
position: "relative",
|
||||
zIndex: 1,
|
||||
marginTop: -6,
|
||||
paddingTop: 8,
|
||||
backgroundColor: "var(--mantine-color-gray-light)",
|
||||
borderTop: "none",
|
||||
borderRadius:
|
||||
"0 0 var(--mantine-radius-md) var(--mantine-radius-md)",
|
||||
border: "1px solid var(--mantine-color-default-border)",
|
||||
}}
|
||||
>
|
||||
<Suspense>
|
||||
|
||||
@@ -130,7 +130,7 @@ const TeamHeadToHeadContent = ({ team1, team2, isOpen = true }: TeamHeadToHeadSh
|
||||
|
||||
{leader && (
|
||||
<Group justify="center" gap="xs">
|
||||
<CrownIcon size={16} weight="fill" color="gold" />
|
||||
<CrownIcon size={16} weight="fill" color="var(--flxn-gold)" />
|
||||
<Text size="xs" c="dimmed">
|
||||
<Trans>{leader.name} leads the series</Trans>
|
||||
</Text>
|
||||
|
||||
@@ -158,7 +158,7 @@ const PlayerHeadToHeadContent = ({
|
||||
|
||||
{leader && (
|
||||
<Group justify="center" gap="xs">
|
||||
<CrownIcon size={16} weight="fill" color="gold" />
|
||||
<CrownIcon size={16} weight="fill" color="var(--flxn-gold)" />
|
||||
<Text size="xs" c="dimmed">
|
||||
<Trans>{leader} leads the series</Trans>
|
||||
</Text>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box, Stack, Text, Divider, Group, Button, Anchor } from "@mantine/core";
|
||||
import { Box, Stack, Text, Divider, Group, Button } from "@mantine/core";
|
||||
import { Suspense, useState, useDeferredValue } from "react";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
@@ -57,9 +57,14 @@ const Profile = ({ id }: ProfileProps) => {
|
||||
<Stack px="md">
|
||||
<Group justify="space-between" align="center">
|
||||
<Text size="md" fw={700}><Trans>Badges</Trans></Text>
|
||||
<Anchor component={Link} to="/badges" size="sm" fw={500}>
|
||||
<Button
|
||||
component={Link}
|
||||
to="/badges"
|
||||
variant="subtle"
|
||||
size="compact-sm"
|
||||
>
|
||||
<Trans>View all badges</Trans>
|
||||
</Anchor>
|
||||
</Button>
|
||||
</Group>
|
||||
<Suspense fallback={<BadgeShowcaseSkeleton />}>
|
||||
<BadgeShowcase playerId={id} />
|
||||
|
||||
@@ -244,7 +244,7 @@ export const PredictionLeaderboard: React.FC<PredictionLeaderboardProps> = ({
|
||||
weight="fill"
|
||||
color={
|
||||
entry.championCorrect && isComplete
|
||||
? "gold"
|
||||
? "var(--flxn-gold)"
|
||||
: "var(--mantine-color-dimmed)"
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -79,8 +79,8 @@ const TeamChip = ({
|
||||
size={14}
|
||||
weight="fill"
|
||||
style={{
|
||||
color: "gold",
|
||||
filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.3))",
|
||||
color: "var(--flxn-gold)",
|
||||
filter: "drop-shadow(0 1px 1px var(--flxn-pop-shadow))",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
import {
|
||||
Box,
|
||||
SimpleGrid,
|
||||
Stack,
|
||||
Text,
|
||||
UnstyledButton,
|
||||
useComputedColorScheme,
|
||||
} from "@mantine/core";
|
||||
import { CaretRightIcon } from "@phosphor-icons/react";
|
||||
import { Trans, useLingui } from "@lingui/react/macro";
|
||||
import Sheet from "@/components/sheet/sheet";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
import { updateUserTheme } from "@/features/settings/server";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { DEFAULT_THEME_ID, THEME_LIST, getTheme } from "@/themes/registry";
|
||||
import ThemePreview from "./theme-preview";
|
||||
|
||||
const ThemePicker = () => {
|
||||
const { metadata, user, set } = useAuth();
|
||||
const { t } = useLingui();
|
||||
const sheet = useSheet();
|
||||
const scheme = useComputedColorScheme("dark");
|
||||
const currentId = metadata.theme || DEFAULT_THEME_ID;
|
||||
const current = getTheme(currentId);
|
||||
|
||||
const handleSelect = async (id: string) => {
|
||||
if (!user || id === currentId) return;
|
||||
const previous = metadata;
|
||||
set({ metadata: { ...metadata, theme: id } });
|
||||
try {
|
||||
await updateUserTheme({ data: id });
|
||||
} catch {
|
||||
set({ metadata: previous });
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Text fw={500} size="sm" mb="xs">
|
||||
<Trans>Theme</Trans>
|
||||
</Text>
|
||||
<UnstyledButton
|
||||
onClick={sheet.open}
|
||||
w="100%"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "var(--mantine-spacing-sm)",
|
||||
padding: "var(--mantine-spacing-xs)",
|
||||
border: "1px solid var(--mantine-color-default-border)",
|
||||
borderRadius: "var(--mantine-radius-md)",
|
||||
}}
|
||||
>
|
||||
<Box w="3.25rem" style={{ flexShrink: 0 }}>
|
||||
<ThemePreview
|
||||
manifest={current}
|
||||
scheme={scheme}
|
||||
height="2.25rem"
|
||||
scale={0.5}
|
||||
/>
|
||||
</Box>
|
||||
<Text size="sm" fw={500} style={{ flex: 1, textAlign: "left" }}>
|
||||
{t(current.label)}
|
||||
</Text>
|
||||
<CaretRightIcon size={16} color="var(--mantine-color-dimmed)" />
|
||||
</UnstyledButton>
|
||||
|
||||
<Sheet title={t`Theme`} {...sheet.props}>
|
||||
<SimpleGrid cols={3} spacing="sm" py="sm">
|
||||
{[...THEME_LIST]
|
||||
.sort(
|
||||
(a, b) =>
|
||||
(a.order ?? 100) - (b.order ?? 100) ||
|
||||
t(a.label).localeCompare(t(b.label))
|
||||
)
|
||||
.map((manifest) => {
|
||||
const isSelected = manifest.id === currentId;
|
||||
return (
|
||||
<UnstyledButton
|
||||
key={manifest.id}
|
||||
onClick={() => handleSelect(manifest.id)}
|
||||
>
|
||||
<Stack gap={6} align="center">
|
||||
<Box
|
||||
w="100%"
|
||||
p="0.125rem"
|
||||
bd={
|
||||
isSelected
|
||||
? "0.125rem solid var(--mantine-color-bright)"
|
||||
: "0.125rem solid transparent"
|
||||
}
|
||||
style={{
|
||||
borderRadius: "calc(var(--mantine-radius-md) + 0.25rem)",
|
||||
}}
|
||||
>
|
||||
<ThemePreview manifest={manifest} scheme={scheme} />
|
||||
</Box>
|
||||
<Text size="xs" fw={isSelected ? 700 : 400} ta="center">
|
||||
{t(manifest.label)}
|
||||
</Text>
|
||||
</Stack>
|
||||
</UnstyledButton>
|
||||
);
|
||||
})}
|
||||
</SimpleGrid>
|
||||
</Sheet>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemePicker;
|
||||
@@ -0,0 +1,179 @@
|
||||
import {
|
||||
DEFAULT_THEME,
|
||||
convertCssVariables,
|
||||
defaultCssVariablesResolver,
|
||||
mergeMantineTheme,
|
||||
mergeThemeOverrides,
|
||||
} from "@mantine/core";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useLingui } from "@lingui/react/macro";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { baseTheme } from "@/lib/mantine/base-theme";
|
||||
import type { ThemeManifest } from "@/themes/types";
|
||||
|
||||
/* Each preview is a same-origin srcdoc iframe carrying the theme's own
|
||||
data-theme/-scheme, the app's stylesheets, the theme's font links, and its
|
||||
Mantine variables — 1:1 with the active theme, with nothing bleeding in. */
|
||||
|
||||
const buildMantineVarsCss = (manifest: ThemeManifest, accent: string) => {
|
||||
const merged = mergeMantineTheme(
|
||||
DEFAULT_THEME,
|
||||
mergeThemeOverrides(baseTheme, manifest.mantine ?? {}, {
|
||||
primaryColor: accent,
|
||||
})
|
||||
);
|
||||
return convertCssVariables(defaultCssVariablesResolver(merged), ":root");
|
||||
};
|
||||
|
||||
const collectAppCss = () =>
|
||||
Array.from(document.querySelectorAll('style, link[rel="stylesheet"]'))
|
||||
.filter(
|
||||
(el) =>
|
||||
!el.hasAttribute("data-mantine-styles") &&
|
||||
!el.hasAttribute("data-flxn-theme-font")
|
||||
)
|
||||
.map((el) =>
|
||||
el.tagName === "LINK"
|
||||
? el.outerHTML
|
||||
: `<style>${el.textContent ?? ""}</style>`
|
||||
)
|
||||
.join("\n");
|
||||
|
||||
const PREVIEW_LOCAL_CSS = `
|
||||
html, body { margin: 0; height: 100%; overflow: hidden; }
|
||||
body { display: flex; }
|
||||
.pv-card {
|
||||
flex: 1;
|
||||
margin: 0.375rem;
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
background-color: var(--mantine-color-body);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-default);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
.pv-heading {
|
||||
font-family: var(--mantine-font-family-headings);
|
||||
color: var(--mantine-color-text);
|
||||
font-size: 0.875rem;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
.pv-row { display: flex; align-items: center; gap: 4px; }
|
||||
.pv-chip {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
flex-shrink: 0;
|
||||
border-radius: var(--mantine-radius-default);
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
.pv-bars { display: flex; flex-direction: column; gap: 3px; flex: 1; }
|
||||
.pv-bar {
|
||||
display: block;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background-color: var(--mantine-color-dimmed);
|
||||
}
|
||||
`;
|
||||
|
||||
const buildSrcdoc = (
|
||||
manifest: ThemeManifest,
|
||||
scheme: "light" | "dark",
|
||||
accent: string,
|
||||
appCss: string
|
||||
) => {
|
||||
const fontLinks = (manifest.fontLinks ?? [])
|
||||
.map((href) => `<link rel="stylesheet" href="${href}">`)
|
||||
.join("");
|
||||
return `<!doctype html>
|
||||
<html data-theme="${manifest.id}" data-mantine-color-scheme="${scheme}">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style>html { color-scheme: ${scheme}; }</style>
|
||||
<style>${buildMantineVarsCss(manifest, accent)}</style>
|
||||
${appCss}
|
||||
${fontLinks}
|
||||
<style>${PREVIEW_LOCAL_CSS}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="pv-card">
|
||||
<span class="pv-heading">Ag</span>
|
||||
<div class="pv-row">
|
||||
<span class="pv-chip"></span>
|
||||
<span class="pv-bars">
|
||||
<span class="pv-bar" style="opacity: 0.7"></span>
|
||||
<span class="pv-bar" style="opacity: 0.4; width: 60%"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
};
|
||||
|
||||
interface ThemePreviewProps {
|
||||
manifest: ThemeManifest;
|
||||
scheme: "light" | "dark";
|
||||
height?: string;
|
||||
/** Renders the document at height/scale and scales it down visually. */
|
||||
scale?: number;
|
||||
}
|
||||
|
||||
const ThemePreview = ({
|
||||
manifest,
|
||||
scheme,
|
||||
height = "4.5rem",
|
||||
scale = 1,
|
||||
}: ThemePreviewProps) => {
|
||||
const { metadata } = useAuth();
|
||||
const { t } = useLingui();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
useEffect(() => setMounted(true), []);
|
||||
|
||||
const previewScheme =
|
||||
manifest.colorSchemes === "both" ? scheme : manifest.colorSchemes;
|
||||
const accent = metadata.accentColor || "blue";
|
||||
|
||||
const srcdoc = useMemo(
|
||||
() =>
|
||||
mounted
|
||||
? buildSrcdoc(manifest, previewScheme, accent, collectAppCss())
|
||||
: null,
|
||||
[mounted, manifest, previewScheme, accent]
|
||||
);
|
||||
|
||||
const frameStyle: React.CSSProperties = {
|
||||
width: "100%",
|
||||
height,
|
||||
border: "1px solid var(--mantine-color-default-border)",
|
||||
borderRadius: "var(--mantine-radius-md)",
|
||||
overflow: "hidden",
|
||||
};
|
||||
|
||||
if (!srcdoc) return <div style={frameStyle} />;
|
||||
return (
|
||||
<div style={frameStyle}>
|
||||
<iframe
|
||||
srcDoc={srcdoc}
|
||||
title={t(manifest.label)}
|
||||
sandbox=""
|
||||
scrolling="no"
|
||||
aria-hidden
|
||||
tabIndex={-1}
|
||||
style={{
|
||||
display: "block",
|
||||
border: 0,
|
||||
width: `${100 / scale}%`,
|
||||
height: `calc(${height} / ${scale})`,
|
||||
transform: `scale(${scale})`,
|
||||
transformOrigin: "top left",
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ThemePreview;
|
||||
@@ -2,12 +2,28 @@ import { createServerFn } from "@tanstack/react-start";
|
||||
import { superTokensFunctionMiddleware } from "@/utils/supertokens";
|
||||
import { serverFnLoggingMiddleware } from "@/utils/activities";
|
||||
|
||||
// Whitelists: these values flow into Mantine's primaryColor / the
|
||||
// data-mantine-color-scheme attribute — an unknown value crash-loops or
|
||||
// unstyles the account's UI on every load.
|
||||
const ACCENT_COLORS = [
|
||||
"blue",
|
||||
"red",
|
||||
"green",
|
||||
"yellow",
|
||||
"grape",
|
||||
"orange",
|
||||
"pink",
|
||||
"lime",
|
||||
];
|
||||
const COLOR_SCHEMES = ["light", "dark", "auto"];
|
||||
|
||||
export const updateUserColorScheme = createServerFn({ method: "POST" })
|
||||
.validator((data: string) => data)
|
||||
.middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware])
|
||||
.handler(async ({ context, data }) => {
|
||||
const { userAuthId, metadata } = context;
|
||||
if (!userAuthId) return;
|
||||
if (!COLOR_SCHEMES.includes(data)) return;
|
||||
|
||||
const { updateUserMetadataFields } = await import(
|
||||
"@/utils/supertokens-core.server"
|
||||
@@ -51,12 +67,41 @@ export const updateUserLocale = createServerFn({ method: "POST" })
|
||||
};
|
||||
});
|
||||
|
||||
export const updateUserTheme = createServerFn({ method: "POST" })
|
||||
.validator((data: string) => data)
|
||||
.middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware])
|
||||
.handler(async ({ context, data }) => {
|
||||
const { userAuthId, metadata } = context;
|
||||
if (!userAuthId) return;
|
||||
|
||||
const { THEME_IDS } = await import("@/themes/registry");
|
||||
if (!THEME_IDS.includes(data)) {
|
||||
throw new Error("Unknown theme");
|
||||
}
|
||||
|
||||
const { updateUserMetadataFields } = await import(
|
||||
"@/utils/supertokens-core.server"
|
||||
);
|
||||
|
||||
await updateUserMetadataFields(userAuthId, {
|
||||
theme: data,
|
||||
});
|
||||
|
||||
return {
|
||||
metadata: {
|
||||
...metadata,
|
||||
theme: data,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export const updateUserAccentColor = createServerFn({ method: "POST" })
|
||||
.validator((data: string) => data)
|
||||
.middleware([superTokensFunctionMiddleware, serverFnLoggingMiddleware])
|
||||
.handler(async ({ context, data }) => {
|
||||
const { userAuthId, metadata } = context;
|
||||
if (!userAuthId) return;
|
||||
if (!ACCENT_COLORS.includes(data)) return;
|
||||
|
||||
const { updateUserMetadataFields } = await import(
|
||||
"@/utils/supertokens-core.server"
|
||||
|
||||
@@ -14,26 +14,20 @@ type PodiumTier = "first" | "second" | "third";
|
||||
|
||||
const tierStyles: Record<PodiumTier, React.CSSProperties> = {
|
||||
first: {
|
||||
background:
|
||||
"light-dark(color-mix(in srgb, var(--mantine-color-yellow-4) 10%, var(--mantine-color-white)), color-mix(in srgb, var(--mantine-color-yellow-8) 16%, var(--mantine-color-dark-6)))",
|
||||
border:
|
||||
"1px solid light-dark(color-mix(in srgb, var(--mantine-color-yellow-6) 45%, var(--mantine-color-gray-3)), color-mix(in srgb, var(--mantine-color-yellow-6) 35%, var(--mantine-color-dark-4)))",
|
||||
background: "var(--flxn-podium-1-bg)",
|
||||
border: "1px solid var(--flxn-podium-1-border)",
|
||||
borderRadius: "var(--mantine-radius-md)",
|
||||
boxShadow: "var(--mantine-shadow-md)",
|
||||
},
|
||||
second: {
|
||||
background:
|
||||
"light-dark(color-mix(in srgb, var(--mantine-color-gray-5) 10%, var(--mantine-color-white)), color-mix(in srgb, var(--mantine-color-gray-5) 10%, var(--mantine-color-dark-6)))",
|
||||
border:
|
||||
"1px solid light-dark(var(--mantine-color-gray-4), var(--mantine-color-dark-4))",
|
||||
background: "var(--flxn-podium-2-bg)",
|
||||
border: "1px solid var(--flxn-podium-2-border)",
|
||||
borderRadius: "var(--mantine-radius-md)",
|
||||
boxShadow: "var(--mantine-shadow-xs)",
|
||||
},
|
||||
third: {
|
||||
background:
|
||||
"light-dark(color-mix(in srgb, var(--mantine-color-orange-5) 8%, var(--mantine-color-white)), color-mix(in srgb, var(--mantine-color-orange-9) 14%, var(--mantine-color-dark-6)))",
|
||||
border:
|
||||
"1px solid light-dark(color-mix(in srgb, var(--mantine-color-orange-6) 35%, var(--mantine-color-gray-3)), color-mix(in srgb, var(--mantine-color-orange-7) 30%, var(--mantine-color-dark-4)))",
|
||||
background: "var(--flxn-podium-3-bg)",
|
||||
border: "1px solid var(--flxn-podium-3-border)",
|
||||
borderRadius: "var(--mantine-radius-md)",
|
||||
boxShadow: "var(--mantine-shadow-xs)",
|
||||
},
|
||||
@@ -54,8 +48,7 @@ const tierConfig: Record<
|
||||
first: {
|
||||
color: "yellow",
|
||||
label: msg`Champions`,
|
||||
labelColor:
|
||||
"light-dark(var(--mantine-color-yellow-8), var(--mantine-color-yellow-4))",
|
||||
labelColor: "var(--flxn-podium-1-label)",
|
||||
icon: <CrownIcon size={24} />,
|
||||
iconSize: "xl",
|
||||
padding: "md",
|
||||
@@ -64,8 +57,7 @@ const tierConfig: Record<
|
||||
second: {
|
||||
color: "gray",
|
||||
label: msg`2nd place`,
|
||||
labelColor:
|
||||
"light-dark(var(--mantine-color-gray-6), var(--mantine-color-gray-4))",
|
||||
labelColor: "var(--flxn-podium-2-label)",
|
||||
icon: <MedalIcon size={20} />,
|
||||
iconSize: "lg",
|
||||
padding: "xs",
|
||||
@@ -74,8 +66,7 @@ const tierConfig: Record<
|
||||
third: {
|
||||
color: "orange",
|
||||
label: msg`3rd place`,
|
||||
labelColor:
|
||||
"light-dark(var(--mantine-color-orange-8), var(--mantine-color-orange-4))",
|
||||
labelColor: "var(--flxn-podium-3-label)",
|
||||
icon: <MedalIcon size={18} />,
|
||||
iconSize: "lg",
|
||||
padding: "xs",
|
||||
|
||||
@@ -320,7 +320,7 @@ const SetupGroupStage: React.FC<SetupGroupStageProps> = ({
|
||||
</Text>
|
||||
<Box
|
||||
style={{
|
||||
backgroundImage: `radial-gradient(circle, var(--mantine-color-default-border) 1px, transparent 1px)`,
|
||||
backgroundImage: `radial-gradient(circle, var(--flxn-dotgrid-color) 1px, transparent 1px)`,
|
||||
backgroundSize: "16px 16px",
|
||||
backgroundPosition: "0 0, 8px 8px",
|
||||
padding: "1rem",
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
height: 6px;
|
||||
border-radius: 3px;
|
||||
background-color: var(--mantine-color-default-border);
|
||||
/* Mantine ships box-shadow: var(--mantine-shadow-sm) on indicators;
|
||||
themes with hard offset shadow tokens render it as a doubled dot. */
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.indicator.indicator[data-active] {
|
||||
|
||||
@@ -39,8 +39,12 @@ interface NavTileProps {
|
||||
|
||||
/** A single square-ish nav tile with icon-over-label and press feedback. */
|
||||
export const NavTile = ({ label, Icon, onClick, disabled }: NavTileProps) => (
|
||||
<UnstyledButton className={classes.tile} onClick={onClick} disabled={disabled}>
|
||||
<span className={classes.icon}>
|
||||
<UnstyledButton
|
||||
className={`${classes.tile} flxn-tile`}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
>
|
||||
<span className={`${classes.icon} flxn-tile-icon`}>
|
||||
<Icon size={22} weight="bold" />
|
||||
</span>
|
||||
<Text size="xs" fw={600} lineClamp={2} lh={1.2}>
|
||||
|
||||
@@ -159,16 +159,29 @@ export function useServerEvents() {
|
||||
logger.error("SSE connection error", error);
|
||||
disconnect();
|
||||
|
||||
// The stream is auth-guarded, so an error is often the server rejecting
|
||||
// an expired session rather than a network blip. Try to refresh; if the
|
||||
// session is genuinely gone, stop retrying so we don't hammer the
|
||||
// endpoint forever — a real re-login (or a wake event) will reconnect.
|
||||
let sessionValid = true;
|
||||
try {
|
||||
const { attemptRefreshingSession } = await import('supertokens-web-js/recipe/session');
|
||||
sessionValid = await attemptRefreshingSession();
|
||||
} catch {
|
||||
// Refresh call itself failed (likely offline) — treat as transient.
|
||||
}
|
||||
|
||||
if (disposed) return;
|
||||
|
||||
if (!sessionValid) {
|
||||
logger.warn("SSE stopped: session is no longer valid");
|
||||
return;
|
||||
}
|
||||
|
||||
retryCount += 1;
|
||||
const delay = Math.min(1000 * Math.pow(1.5, retryCount - 1), 15000);
|
||||
logger.info(`SSE reconnection attempt ${retryCount} in ${Math.round(delay)}ms`);
|
||||
|
||||
try {
|
||||
const { attemptRefreshingSession } = await import('supertokens-web-js/recipe/session');
|
||||
await attemptRefreshingSession();
|
||||
} catch {
|
||||
}
|
||||
|
||||
reconnect(delay);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import { createTheme } from "@mantine/core";
|
||||
|
||||
const commonInputStyles = {
|
||||
label: {
|
||||
padding: 5,
|
||||
},
|
||||
root: {
|
||||
margin: "0",
|
||||
},
|
||||
};
|
||||
|
||||
// Shared by MantineProvider and the theme-picker preview iframes.
|
||||
export const baseTheme = createTheme({
|
||||
defaultRadius: "sm",
|
||||
respectReducedMotion: true,
|
||||
fontFamily: '"Inter", sans-serif',
|
||||
headings: { fontFamily: '"League Spartan", sans-serif' },
|
||||
activeClassName: "flxn-press",
|
||||
components: {
|
||||
TextInput: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
DateTimePicker: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
Input: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
Select: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
Autocomplete: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
Card: {
|
||||
defaultProps: {
|
||||
shadow: "xs",
|
||||
},
|
||||
},
|
||||
Title: {
|
||||
styles: {
|
||||
root: {
|
||||
letterSpacing: "-0.01em",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,18 +1,40 @@
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { useMantineColorScheme } from "@mantine/core";
|
||||
import { useEffect } from "react";
|
||||
import { CHROME_COLORS, setThemeColorMeta } from "./theme-colors";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { getTheme } from "@/themes/registry";
|
||||
import { resolveChromeColors } from "@/themes/chrome";
|
||||
import { setBaseThemeColor } from "./theme-colors";
|
||||
|
||||
const ColorSchemeProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const {
|
||||
metadata: { colorScheme },
|
||||
metadata: { colorScheme, theme },
|
||||
} = useAuth();
|
||||
const { setColorScheme } = useMantineColorScheme();
|
||||
const { colorScheme: currentScheme, setColorScheme } =
|
||||
useMantineColorScheme();
|
||||
|
||||
// Mantine recreates setColorScheme every render; calling it redundantly
|
||||
// triggers its global transition-suppression flash, so ref it and only
|
||||
// call on an actual value change.
|
||||
const setColorSchemeRef = useRef(setColorScheme);
|
||||
setColorSchemeRef.current = setColorScheme;
|
||||
|
||||
const manifest = getTheme(theme);
|
||||
const forcedScheme =
|
||||
manifest.colorSchemes === "both" ? undefined : manifest.colorSchemes;
|
||||
|
||||
useEffect(() => {
|
||||
const chrome = resolveChromeColors(manifest);
|
||||
|
||||
if (forcedScheme) {
|
||||
setBaseThemeColor(chrome[forcedScheme].base);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!colorScheme) return;
|
||||
|
||||
setColorScheme(colorScheme);
|
||||
if (colorScheme !== currentScheme) {
|
||||
setColorSchemeRef.current(colorScheme);
|
||||
}
|
||||
|
||||
const media = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
const applyThemeColor = () => {
|
||||
@@ -22,7 +44,7 @@ const ColorSchemeProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
? "dark"
|
||||
: "light"
|
||||
: colorScheme;
|
||||
setThemeColorMeta(CHROME_COLORS[resolved].base);
|
||||
setBaseThemeColor(chrome[resolved].base);
|
||||
};
|
||||
|
||||
applyThemeColor();
|
||||
@@ -31,7 +53,7 @@ const ColorSchemeProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
media.addEventListener("change", applyThemeColor);
|
||||
return () => media.removeEventListener("change", applyThemeColor);
|
||||
}
|
||||
}, [colorScheme, setColorScheme]);
|
||||
}, [colorScheme, currentScheme, manifest, forcedScheme]);
|
||||
|
||||
return children;
|
||||
};
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import {
|
||||
createTheme,
|
||||
mergeThemeOverrides,
|
||||
MantineProvider as MantineProviderCore,
|
||||
} from "@mantine/core";
|
||||
import { baseTheme } from "./base-theme";
|
||||
import { DatesProvider } from "@mantine/dates";
|
||||
import { useLingui } from "@lingui/react";
|
||||
import type { AppLocale } from "@/lib/i18n";
|
||||
import ColorSchemeProvider from "./color-scheme-provider";
|
||||
import ThemeProvider from "@/themes/theme-provider";
|
||||
import { DEFAULT_THEME_ID, getTheme } from "@/themes/registry";
|
||||
import "@/themes/styles";
|
||||
import { useState, useEffect, useMemo } from "react";
|
||||
import "dayjs/locale/es-mx";
|
||||
import "dayjs/locale/de";
|
||||
@@ -21,15 +25,6 @@ const DAYJS_LOCALE: Record<AppLocale, string> = {
|
||||
ja: "ja",
|
||||
};
|
||||
|
||||
const commonInputStyles = {
|
||||
label: {
|
||||
padding: 5,
|
||||
},
|
||||
root: {
|
||||
margin: "0",
|
||||
},
|
||||
};
|
||||
|
||||
const pressFeedbackCss = `
|
||||
.flxn-press {
|
||||
transition: transform 120ms cubic-bezier(0.32, 0.72, 0, 1);
|
||||
@@ -46,43 +41,6 @@ const pressFeedbackCss = `
|
||||
}
|
||||
`;
|
||||
|
||||
const theme = createTheme({
|
||||
defaultRadius: "sm",
|
||||
respectReducedMotion: true,
|
||||
fontFamily: '"Inter", sans-serif',
|
||||
headings: { fontFamily: '"League Spartan", sans-serif' },
|
||||
activeClassName: "flxn-press",
|
||||
components: {
|
||||
TextInput: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
DateTimePicker: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
Input: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
Select: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
Autocomplete: {
|
||||
styles: commonInputStyles,
|
||||
},
|
||||
Card: {
|
||||
defaultProps: {
|
||||
shadow: "xs",
|
||||
},
|
||||
},
|
||||
Title: {
|
||||
styles: {
|
||||
root: {
|
||||
letterSpacing: "-0.01em",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const MantineProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const { metadata } = useAuth();
|
||||
const { i18n } = useLingui();
|
||||
@@ -93,17 +51,23 @@ const MantineProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
}, []);
|
||||
|
||||
const colorScheme = isHydrated ? metadata.colorScheme || "auto" : "auto";
|
||||
const manifest = getTheme(isHydrated ? metadata.theme : DEFAULT_THEME_ID);
|
||||
const primaryColor = isHydrated ? metadata.accentColor || "blue" : "blue";
|
||||
|
||||
const themeWithPrimaryColor = useMemo(
|
||||
() => ({ ...theme, primaryColor }),
|
||||
[primaryColor]
|
||||
const theme = useMemo(
|
||||
() =>
|
||||
mergeThemeOverrides(baseTheme, manifest.mantine ?? {}, { primaryColor }),
|
||||
[manifest, primaryColor]
|
||||
);
|
||||
|
||||
const forceColorScheme =
|
||||
manifest.colorSchemes === "both" ? undefined : manifest.colorSchemes;
|
||||
|
||||
return (
|
||||
<MantineProviderCore
|
||||
defaultColorScheme={colorScheme}
|
||||
theme={themeWithPrimaryColor}
|
||||
forceColorScheme={forceColorScheme}
|
||||
theme={theme}
|
||||
>
|
||||
<style href="flxn-press-feedback" precedence="medium">
|
||||
{pressFeedbackCss}
|
||||
@@ -113,7 +77,9 @@ const MantineProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
locale: DAYJS_LOCALE[i18n.locale as AppLocale] ?? "en",
|
||||
}}
|
||||
>
|
||||
<ColorSchemeProvider>{children}</ColorSchemeProvider>
|
||||
<ThemeProvider manifest={manifest} ready={isHydrated}>
|
||||
<ColorSchemeProvider>{children}</ColorSchemeProvider>
|
||||
</ThemeProvider>
|
||||
</DatesProvider>
|
||||
</MantineProviderCore>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,24 @@ export const CHROME_COLORS: Record<
|
||||
dark: { base: "#242424", dimmed: "#161616" },
|
||||
};
|
||||
|
||||
// theme-color meta ownership: while a drawer holds a dimmed color, base
|
||||
// writes (from scheme/theme changes) must not overwrite it.
|
||||
let dimmedDepth = 0;
|
||||
|
||||
export function setBaseThemeColor(color: string): void {
|
||||
if (dimmedDepth === 0) setThemeColorMeta(color);
|
||||
}
|
||||
|
||||
export function pushDimmedThemeColor(color: string): void {
|
||||
dimmedDepth++;
|
||||
setThemeColorMeta(color);
|
||||
}
|
||||
|
||||
export function popDimmedThemeColor(base: string): void {
|
||||
dimmedDepth = Math.max(0, dimmedDepth - 1);
|
||||
if (dimmedDepth === 0) setThemeColorMeta(base);
|
||||
}
|
||||
|
||||
export function setThemeColorMeta(color: string): void {
|
||||
if (typeof document === "undefined") return;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ function success(toast: Omit<ToastProps, "id"> | string) {
|
||||
const config = typeof toast === "string" ? { description: toast } : toast;
|
||||
return makeToast({
|
||||
...config,
|
||||
icon: <ShieldCheckIcon color="lightgreen" size={48} weight="fill" />,
|
||||
icon: <ShieldCheckIcon color="var(--flxn-toast-success)" size={48} weight="fill" />,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ function error(toast: Omit<ToastProps, "id"> | string) {
|
||||
const config = typeof toast === "string" ? { description: toast } : toast;
|
||||
return makeToast({
|
||||
...config,
|
||||
icon: <WarningCircleIcon color="lightcoral" size={48} weight="fill" />,
|
||||
icon: <WarningCircleIcon color="var(--flxn-toast-error)" size={48} weight="fill" />,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+106
-33
@@ -13,7 +13,7 @@ msgstr ""
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#: src/features/matches/components/match-card.tsx:77
|
||||
#: src/features/matches/components/match-card.tsx:78
|
||||
msgid " (Losers)"
|
||||
msgstr " (Verlierer)"
|
||||
|
||||
@@ -140,7 +140,7 @@ msgstr "{0}ms"
|
||||
msgid "{count, plural, one {Players (#)} other {Players (#)}}"
|
||||
msgstr "{count, plural, one {Spieler (#)} other {Spieler (#)}}"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:130
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:134
|
||||
#: src/features/tournaments/components/upcoming-tournament/team-list-button.tsx:24
|
||||
msgid "{count, plural, one {Teams (#)} other {Teams (#)}}"
|
||||
msgstr "{count, plural, one {Teams (#)} other {Teams (#)}}"
|
||||
@@ -201,7 +201,7 @@ msgstr "{size}-Team-K.-o.-Runde"
|
||||
msgid "* Confidence penalty applied for players with <15 matches"
|
||||
msgstr "* Vertrauensabschlag für Spieler mit <15 Spielen"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:320
|
||||
#: src/features/bracket/components/match-card.tsx:324
|
||||
#: src/features/predictions/components/prediction-match-card.tsx:108
|
||||
msgid "* If necessary"
|
||||
msgstr "* Falls nötig"
|
||||
@@ -327,7 +327,7 @@ msgstr "1 s"
|
||||
msgid "2. Earlier submission"
|
||||
msgstr "2. Frühere Abgabe"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:66
|
||||
#: src/features/tournaments/components/podium.tsx:59
|
||||
msgid "2nd place"
|
||||
msgstr "2. Platz"
|
||||
|
||||
@@ -335,7 +335,7 @@ msgstr "2. Platz"
|
||||
msgid "30s"
|
||||
msgstr "30 s"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:76
|
||||
#: src/features/tournaments/components/podium.tsx:68
|
||||
msgid "3rd place"
|
||||
msgstr "3. Platz"
|
||||
|
||||
@@ -406,6 +406,10 @@ msgstr "Team hinzufügen"
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/themes/aero/manifest.ts:117
|
||||
msgid "Aero"
|
||||
msgstr "Aero"
|
||||
|
||||
#: src/app/routes/_authed/stats.tsx:59
|
||||
#: src/features/activities/components/activities-table.tsx:328
|
||||
#: src/features/players/components/profile/index.tsx:28
|
||||
@@ -436,11 +440,11 @@ msgstr "Beim Senden eines Einmal-Codes ist ein unerwarteter Fehler aufgetreten.
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "Ein unerwarteter Fehler ist aufgetreten. Bitte versuche es erneut."
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:336
|
||||
#: src/features/bracket/components/match-card.tsx:340
|
||||
msgid "Announce matchup"
|
||||
msgstr "Matchup ansagen"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:34
|
||||
#: src/app/routes/_authed/settings.tsx:35
|
||||
msgid "Appearance"
|
||||
msgstr "Erscheinungsbild"
|
||||
|
||||
@@ -452,6 +456,10 @@ msgstr "Bist du sicher, dass du dich von diesem Turnier abmelden möchtest? Du k
|
||||
msgid "Arguments"
|
||||
msgstr "Argumente"
|
||||
|
||||
#: src/themes/deco/manifest.ts:6
|
||||
msgid "Art Deco"
|
||||
msgstr "Art déco"
|
||||
|
||||
#: src/features/tournaments/components/manage-tournament.tsx:69
|
||||
msgid "Assign Partners"
|
||||
msgstr "Partner zuweisen"
|
||||
@@ -554,12 +562,20 @@ msgstr "Abzeichentyp"
|
||||
msgid "Badges"
|
||||
msgstr "Abzeichen"
|
||||
|
||||
#: src/themes/bauhaus/manifest.ts:6
|
||||
msgid "Bauhaus"
|
||||
msgstr "Bauhaus"
|
||||
|
||||
#: src/themes/circus/manifest.ts:141
|
||||
msgid "Big Top"
|
||||
msgstr "Zirkus"
|
||||
|
||||
#: src/features/bracket/components/match-form.tsx:43
|
||||
#: src/features/bracket/components/match-form.tsx:60
|
||||
msgid "Both teams cannot have 10 cups"
|
||||
msgstr "Beide Teams können nicht 10 Becher haben"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:102
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:106
|
||||
#: src/features/tournaments/components/upcoming-tournament/index.tsx:150
|
||||
msgid "Bracket"
|
||||
msgstr "Turnierbaum"
|
||||
@@ -573,6 +589,10 @@ msgstr "Turnierbaum-Vorschau"
|
||||
msgid "Bracket Reset"
|
||||
msgstr "Bracket-Reset"
|
||||
|
||||
#: src/themes/brutal/manifest.ts:6
|
||||
msgid "Brutal"
|
||||
msgstr "Brutal"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:139
|
||||
#: src/features/tournaments/components/tournament-stats.tsx:152
|
||||
msgid "CA"
|
||||
@@ -605,12 +625,16 @@ msgstr "Teams können nicht mit einer ungeraden Anzahl an Spielern erstellt werd
|
||||
msgid "Capture current state"
|
||||
msgstr "Aktuellen Status erfassen"
|
||||
|
||||
#: src/themes/cassette/manifest.ts:145
|
||||
msgid "Cassette Futurism"
|
||||
msgstr "Retro-Tech"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:138
|
||||
#: src/features/tournaments/components/tournament-stats.tsx:144
|
||||
msgid "CF"
|
||||
msgstr "CF"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:56
|
||||
#: src/features/tournaments/components/podium.tsx:50
|
||||
msgid "Champions"
|
||||
msgstr "Champions"
|
||||
|
||||
@@ -623,17 +647,21 @@ msgstr "Logo ändern"
|
||||
msgid "Choose a player"
|
||||
msgstr "Wähle einen Spieler"
|
||||
|
||||
#: src/themes/clay/manifest.ts:144
|
||||
msgid "Claymation"
|
||||
msgstr "Knete"
|
||||
|
||||
#: src/features/players/components/league-head-to-head.tsx:99
|
||||
msgid "Clear selected player"
|
||||
msgstr "Ausgewählten Spieler entfernen"
|
||||
|
||||
#: src/components/sheet/modal.tsx:35
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:165
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:169
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:36
|
||||
msgid "Close"
|
||||
msgstr "Schließen"
|
||||
|
||||
#: src/components/avatar.tsx:107
|
||||
#: src/components/avatar.tsx:127
|
||||
msgid "Close image preview"
|
||||
msgstr "Bildvorschau schließen"
|
||||
|
||||
@@ -785,10 +813,22 @@ msgstr "Benutzerdefinierter Hex-Code"
|
||||
msgid "Dark"
|
||||
msgstr "Dunkel"
|
||||
|
||||
#: src/themes/gothic/manifest.ts:6
|
||||
msgid "Dark Academia"
|
||||
msgstr "Dark Academia"
|
||||
|
||||
#: src/features/activities/components/activities-table.tsx:356
|
||||
msgid "Date"
|
||||
msgstr "Datum"
|
||||
|
||||
#: src/themes/ocean/manifest.ts:117
|
||||
msgid "Deep Sea"
|
||||
msgstr "Tiefsee"
|
||||
|
||||
#: src/themes/default/manifest.ts:6
|
||||
msgid "Default"
|
||||
msgstr "Standard"
|
||||
|
||||
#: src/features/tournaments/components/tournament-form.tsx:150
|
||||
msgid "Description"
|
||||
msgstr "Beschreibung"
|
||||
@@ -833,16 +873,16 @@ msgstr "Angemeldete Teams bearbeiten"
|
||||
msgid "Edit Enrollments"
|
||||
msgstr "Anmeldungen bearbeiten"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:388
|
||||
#: src/features/bracket/components/match-card.tsx:392
|
||||
msgid "Edit Match"
|
||||
msgstr "Match bearbeiten"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:376
|
||||
#: src/features/bracket/components/match-card.tsx:380
|
||||
#: src/features/tournaments/components/group-match-card.tsx:187
|
||||
msgid "Edit match score"
|
||||
msgstr "Spielstand bearbeiten"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:110
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:114
|
||||
msgid "Edit Prediction"
|
||||
msgstr "Tipp bearbeiten"
|
||||
|
||||
@@ -914,7 +954,7 @@ msgid "Enrolled Players"
|
||||
msgstr "Angemeldete Spieler"
|
||||
|
||||
#: src/features/tournaments/components/edit-enrolled-teams.tsx:151
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:141
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:145
|
||||
#: src/features/tournaments/components/upcoming-tournament/team-list-button.tsx:31
|
||||
msgid "Enrolled Teams"
|
||||
msgstr "Angemeldete Teams"
|
||||
@@ -1104,6 +1144,10 @@ msgstr "Zurück"
|
||||
msgid "Go Back"
|
||||
msgstr "Zurück"
|
||||
|
||||
#: src/themes/seventies/manifest.ts:6
|
||||
msgid "Groovy"
|
||||
msgstr "Groovy"
|
||||
|
||||
#. placeholder {0}: group.groupName
|
||||
#. placeholder {0}: group.name
|
||||
#: src/features/tournaments/components/group-preview.tsx:24
|
||||
@@ -1138,7 +1182,7 @@ msgstr "Gruppenphase erfolgreich erstellt!"
|
||||
msgid "Group Stage Setup"
|
||||
msgstr "Gruppenphase einrichten"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:94
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:98
|
||||
msgid "Groups"
|
||||
msgstr "Gruppen"
|
||||
|
||||
@@ -1154,8 +1198,8 @@ msgstr "Hast du schon mal mitgespielt?"
|
||||
#: src/app/routes/_authed/stats.tsx:47
|
||||
#: src/features/bracket/components/match-dock.tsx:173
|
||||
#: src/features/bracket/components/match-dock.tsx:215
|
||||
#: src/features/matches/components/match-card.tsx:83
|
||||
#: src/features/matches/components/match-card.tsx:231
|
||||
#: src/features/matches/components/match-card.tsx:84
|
||||
#: src/features/matches/components/match-card.tsx:228
|
||||
#: src/features/players/components/league-head-to-head.tsx:183
|
||||
#: src/features/players/components/profile/header.tsx:90
|
||||
msgid "Head to Head"
|
||||
@@ -1339,7 +1383,7 @@ msgstr "S"
|
||||
msgid "Mainline"
|
||||
msgstr "Mainline"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:110
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:114
|
||||
msgid "Make Prediction"
|
||||
msgstr "Tipp abgeben"
|
||||
|
||||
@@ -1347,7 +1391,7 @@ msgstr "Tipp abgeben"
|
||||
msgid "Make Your Prediction"
|
||||
msgstr "Gib deinen Tipp ab"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:85
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:89
|
||||
#: src/features/tournaments/components/upcoming-tournament/index.tsx:143
|
||||
msgid "Manage"
|
||||
msgstr "Verwalten"
|
||||
@@ -1392,7 +1436,7 @@ msgstr "Match {0} · Runde {1} (Verlierer)"
|
||||
#. placeholder {0}: match.order
|
||||
#. placeholder {1}: match.home!.name
|
||||
#. placeholder {2}: match.away!.name
|
||||
#: src/features/bracket/components/match-card.tsx:288
|
||||
#: src/features/bracket/components/match-card.tsx:292
|
||||
msgid "Match {0}: {1} vs {2}"
|
||||
msgstr "Match {0}: {1} vs {2}"
|
||||
|
||||
@@ -1415,7 +1459,7 @@ msgid "Match started!"
|
||||
msgstr "Match gestartet!"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:366
|
||||
#: src/features/players/components/profile/index.tsx:73
|
||||
#: src/features/players/components/profile/index.tsx:78
|
||||
#: src/features/players/components/profile/skeleton.tsx:70
|
||||
#: src/features/teams/components/team-profile/index.tsx:44
|
||||
#: src/features/teams/components/team-profile/skeleton.tsx:75
|
||||
@@ -1489,6 +1533,10 @@ msgstr "Nerd"
|
||||
msgid "Network error. Please check your connection and try again."
|
||||
msgstr "Netzwerkfehler. Bitte überprüfe deine Verbindung und versuche es erneut."
|
||||
|
||||
#: src/themes/neumorph/manifest.ts:6
|
||||
msgid "Neumorphic"
|
||||
msgstr "Neumorph"
|
||||
|
||||
#: src/features/players/components/players-activity-table.tsx:27
|
||||
msgid "Never"
|
||||
msgstr "Nie"
|
||||
@@ -1834,7 +1882,7 @@ msgstr "Punktevergabe für Tipps:"
|
||||
|
||||
#: src/app/routes/_authed/tournaments/$id.predictions.tsx:23
|
||||
#: src/features/predictions/components/prediction-leaderboard.tsx:147
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:119
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:123
|
||||
msgid "Predictions"
|
||||
msgstr "Tipps"
|
||||
|
||||
@@ -1867,6 +1915,10 @@ msgstr "PKT"
|
||||
msgid "Q"
|
||||
msgstr "Q"
|
||||
|
||||
#: src/themes/quest/manifest.ts:6
|
||||
msgid "Quest Log"
|
||||
msgstr "Questlog"
|
||||
|
||||
#: src/app/routes/_authed/admin/tournaments/$id/assign-partners.tsx:167
|
||||
msgid "Re-roll"
|
||||
msgstr "Neu würfeln"
|
||||
@@ -1923,11 +1975,11 @@ msgid "rofl"
|
||||
msgstr "rofl"
|
||||
|
||||
#. placeholder {0}: match.round + 1
|
||||
#: src/features/matches/components/match-card.tsx:76
|
||||
#: src/features/matches/components/match-card.tsx:77
|
||||
msgid "Round {0}"
|
||||
msgstr "Runde {0}"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:138
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:142
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:23
|
||||
msgid "Rules"
|
||||
msgstr "Regeln"
|
||||
@@ -2099,7 +2151,7 @@ msgstr "Serverfunktionen"
|
||||
msgid "serverFn name"
|
||||
msgstr "serverFn-Name"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:15
|
||||
#: src/app/routes/_authed/settings.tsx:16
|
||||
#: src/features/core/components/settings-button.tsx:19
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
@@ -2118,10 +2170,18 @@ msgstr "{0} von {1} Spielern angezeigt"
|
||||
msgid "Shuffle Groups"
|
||||
msgstr "Gruppen mischen"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:42
|
||||
#: src/app/routes/_authed/settings.tsx:44
|
||||
msgid "Sign Out"
|
||||
msgstr "Abmelden"
|
||||
|
||||
#: src/themes/sketch/manifest.ts:6
|
||||
msgid "Sketchbook"
|
||||
msgstr "Skizzenbuch"
|
||||
|
||||
#: src/themes/skeuo/manifest.ts:6
|
||||
msgid "Skeuomorphic"
|
||||
msgstr "Skeuomorph"
|
||||
|
||||
#: src/components/DefaultCatchBoundary.tsx:89
|
||||
msgid "Something went wrong"
|
||||
msgstr "Etwas ist schiefgelaufen"
|
||||
@@ -2188,7 +2248,7 @@ msgstr "Start"
|
||||
msgid "Start Date"
|
||||
msgstr "Startdatum"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:354
|
||||
#: src/features/bracket/components/match-card.tsx:358
|
||||
#: src/features/tournaments/components/group-match-card.tsx:168
|
||||
msgid "Start match"
|
||||
msgstr "Match starten"
|
||||
@@ -2316,11 +2376,11 @@ msgstr "Team aktualisiert, aber Logo-Upload fehlgeschlagen: {0}"
|
||||
msgid "Team updated successfully!"
|
||||
msgstr "Team erfolgreich aktualisiert!"
|
||||
|
||||
#: src/features/players/components/profile/index.tsx:78
|
||||
#: src/features/players/components/profile/index.tsx:83
|
||||
#: src/features/players/components/profile/skeleton.tsx:75
|
||||
#: src/features/tournaments/components/profile/index.tsx:32
|
||||
#: src/features/tournaments/components/profile/skeleton.tsx:89
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:133
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:137
|
||||
msgid "Teams"
|
||||
msgstr "Teams"
|
||||
|
||||
@@ -2328,6 +2388,10 @@ msgstr "Teams"
|
||||
msgid "Teams created successfully!"
|
||||
msgstr "Teams erfolgreich erstellt!"
|
||||
|
||||
#: src/themes/terminal/manifest.ts:6
|
||||
msgid "Terminal"
|
||||
msgstr "Terminal"
|
||||
|
||||
#: src/app/routes/api/push/test.ts:29
|
||||
msgid "Test notification — push is working on this device."
|
||||
msgstr "Test-Benachrichtigung — Push funktioniert auf diesem Gerät."
|
||||
@@ -2352,6 +2416,11 @@ msgstr "Das andere Team"
|
||||
msgid "The requested resource was not found"
|
||||
msgstr "Die angeforderte Ressource wurde nicht gefunden"
|
||||
|
||||
#: src/features/settings/components/theme-picker.tsx:40
|
||||
#: src/features/settings/components/theme-picker.tsx:68
|
||||
msgid "Theme"
|
||||
msgstr "Design"
|
||||
|
||||
#: src/features/players/components/player-head-to-head-sheet.tsx:107
|
||||
msgid "These players have not faced each other yet."
|
||||
msgstr "Diese Spieler sind noch nicht gegeneinander angetreten."
|
||||
@@ -2421,7 +2490,7 @@ msgstr "Turnier erfolgreich erstellt!"
|
||||
msgid "Tournament not found"
|
||||
msgstr "Turnier nicht gefunden"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:148
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:152
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:25
|
||||
msgid "Tournament Rules"
|
||||
msgstr "Turnierregeln"
|
||||
@@ -2512,7 +2581,7 @@ msgstr "User-Agent"
|
||||
msgid "versus"
|
||||
msgstr "gegen"
|
||||
|
||||
#: src/features/players/components/profile/index.tsx:61
|
||||
#: src/features/players/components/profile/index.tsx:66
|
||||
msgid "View all badges"
|
||||
msgstr "Alle Abzeichen ansehen"
|
||||
|
||||
@@ -2529,7 +2598,7 @@ msgid "View Groups"
|
||||
msgstr "Gruppen ansehen"
|
||||
|
||||
#: src/features/bracket/components/match-dock.tsx:178
|
||||
#: src/features/matches/components/match-card.tsx:88
|
||||
#: src/features/matches/components/match-card.tsx:89
|
||||
msgid "View head-to-head"
|
||||
msgstr "Direktvergleich ansehen"
|
||||
|
||||
@@ -2537,6 +2606,10 @@ msgstr "Direktvergleich ansehen"
|
||||
msgid "View Predictions"
|
||||
msgstr "Tipps ansehen"
|
||||
|
||||
#: src/themes/wireframe/manifest.ts:118
|
||||
msgid "Viewport"
|
||||
msgstr "Viewport"
|
||||
|
||||
#: src/app/routes/api/spotify/playback.ts:70
|
||||
msgid "volumePercent must be a number"
|
||||
msgstr "volumePercent muss eine Zahl sein"
|
||||
|
||||
+106
-33
@@ -13,7 +13,7 @@ msgstr ""
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#: src/features/matches/components/match-card.tsx:77
|
||||
#: src/features/matches/components/match-card.tsx:78
|
||||
msgid " (Losers)"
|
||||
msgstr " (Losers)"
|
||||
|
||||
@@ -140,7 +140,7 @@ msgstr "{0}ms"
|
||||
msgid "{count, plural, one {Players (#)} other {Players (#)}}"
|
||||
msgstr "{count, plural, one {Players (#)} other {Players (#)}}"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:130
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:134
|
||||
#: src/features/tournaments/components/upcoming-tournament/team-list-button.tsx:24
|
||||
msgid "{count, plural, one {Teams (#)} other {Teams (#)}}"
|
||||
msgstr "{count, plural, one {Teams (#)} other {Teams (#)}}"
|
||||
@@ -201,7 +201,7 @@ msgstr "{size}-team knockout"
|
||||
msgid "* Confidence penalty applied for players with <15 matches"
|
||||
msgstr "* Confidence penalty applied for players with <15 matches"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:320
|
||||
#: src/features/bracket/components/match-card.tsx:324
|
||||
#: src/features/predictions/components/prediction-match-card.tsx:108
|
||||
msgid "* If necessary"
|
||||
msgstr "* If necessary"
|
||||
@@ -327,7 +327,7 @@ msgstr "1s"
|
||||
msgid "2. Earlier submission"
|
||||
msgstr "2. Earlier submission"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:66
|
||||
#: src/features/tournaments/components/podium.tsx:59
|
||||
msgid "2nd place"
|
||||
msgstr "2nd place"
|
||||
|
||||
@@ -335,7 +335,7 @@ msgstr "2nd place"
|
||||
msgid "30s"
|
||||
msgstr "30s"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:76
|
||||
#: src/features/tournaments/components/podium.tsx:68
|
||||
msgid "3rd place"
|
||||
msgstr "3rd place"
|
||||
|
||||
@@ -406,6 +406,10 @@ msgstr "Add Team"
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/themes/aero/manifest.ts:117
|
||||
msgid "Aero"
|
||||
msgstr "Aero"
|
||||
|
||||
#: src/app/routes/_authed/stats.tsx:59
|
||||
#: src/features/activities/components/activities-table.tsx:328
|
||||
#: src/features/players/components/profile/index.tsx:28
|
||||
@@ -436,11 +440,11 @@ msgstr "An unexpected error occurred when trying to send a one-time passcode. Pl
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "An unexpected error occurred. Please try again."
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:336
|
||||
#: src/features/bracket/components/match-card.tsx:340
|
||||
msgid "Announce matchup"
|
||||
msgstr "Announce matchup"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:34
|
||||
#: src/app/routes/_authed/settings.tsx:35
|
||||
msgid "Appearance"
|
||||
msgstr "Appearance"
|
||||
|
||||
@@ -452,6 +456,10 @@ msgstr "Are you sure you want to unenroll from this tournament? You can enroll a
|
||||
msgid "Arguments"
|
||||
msgstr "Arguments"
|
||||
|
||||
#: src/themes/deco/manifest.ts:6
|
||||
msgid "Art Deco"
|
||||
msgstr "Art Deco"
|
||||
|
||||
#: src/features/tournaments/components/manage-tournament.tsx:69
|
||||
msgid "Assign Partners"
|
||||
msgstr "Assign Partners"
|
||||
@@ -554,12 +562,20 @@ msgstr "Badge Type"
|
||||
msgid "Badges"
|
||||
msgstr "Badges"
|
||||
|
||||
#: src/themes/bauhaus/manifest.ts:6
|
||||
msgid "Bauhaus"
|
||||
msgstr "Bauhaus"
|
||||
|
||||
#: src/themes/circus/manifest.ts:141
|
||||
msgid "Big Top"
|
||||
msgstr "Big Top"
|
||||
|
||||
#: src/features/bracket/components/match-form.tsx:43
|
||||
#: src/features/bracket/components/match-form.tsx:60
|
||||
msgid "Both teams cannot have 10 cups"
|
||||
msgstr "Both teams cannot have 10 cups"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:102
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:106
|
||||
#: src/features/tournaments/components/upcoming-tournament/index.tsx:150
|
||||
msgid "Bracket"
|
||||
msgstr "Bracket"
|
||||
@@ -573,6 +589,10 @@ msgstr "Bracket Preview"
|
||||
msgid "Bracket Reset"
|
||||
msgstr "Bracket Reset"
|
||||
|
||||
#: src/themes/brutal/manifest.ts:6
|
||||
msgid "Brutal"
|
||||
msgstr "Brutal"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:139
|
||||
#: src/features/tournaments/components/tournament-stats.tsx:152
|
||||
msgid "CA"
|
||||
@@ -605,12 +625,16 @@ msgstr "Cannot create teams with an odd number of players. Please have one playe
|
||||
msgid "Capture current state"
|
||||
msgstr "Capture current state"
|
||||
|
||||
#: src/themes/cassette/manifest.ts:145
|
||||
msgid "Cassette Futurism"
|
||||
msgstr "Cassette Futurism"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:138
|
||||
#: src/features/tournaments/components/tournament-stats.tsx:144
|
||||
msgid "CF"
|
||||
msgstr "CF"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:56
|
||||
#: src/features/tournaments/components/podium.tsx:50
|
||||
msgid "Champions"
|
||||
msgstr "Champions"
|
||||
|
||||
@@ -623,17 +647,21 @@ msgstr "Change Logo"
|
||||
msgid "Choose a player"
|
||||
msgstr "Choose a player"
|
||||
|
||||
#: src/themes/clay/manifest.ts:144
|
||||
msgid "Claymation"
|
||||
msgstr "Claymation"
|
||||
|
||||
#: src/features/players/components/league-head-to-head.tsx:99
|
||||
msgid "Clear selected player"
|
||||
msgstr "Clear selected player"
|
||||
|
||||
#: src/components/sheet/modal.tsx:35
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:165
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:169
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:36
|
||||
msgid "Close"
|
||||
msgstr "Close"
|
||||
|
||||
#: src/components/avatar.tsx:107
|
||||
#: src/components/avatar.tsx:127
|
||||
msgid "Close image preview"
|
||||
msgstr "Close image preview"
|
||||
|
||||
@@ -785,10 +813,22 @@ msgstr "Custom Hex Code"
|
||||
msgid "Dark"
|
||||
msgstr "Dark"
|
||||
|
||||
#: src/themes/gothic/manifest.ts:6
|
||||
msgid "Dark Academia"
|
||||
msgstr "Dark Academia"
|
||||
|
||||
#: src/features/activities/components/activities-table.tsx:356
|
||||
msgid "Date"
|
||||
msgstr "Date"
|
||||
|
||||
#: src/themes/ocean/manifest.ts:117
|
||||
msgid "Deep Sea"
|
||||
msgstr "Deep Sea"
|
||||
|
||||
#: src/themes/default/manifest.ts:6
|
||||
msgid "Default"
|
||||
msgstr "Default"
|
||||
|
||||
#: src/features/tournaments/components/tournament-form.tsx:150
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
@@ -833,16 +873,16 @@ msgstr "Edit Enrolled Teams"
|
||||
msgid "Edit Enrollments"
|
||||
msgstr "Edit Enrollments"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:388
|
||||
#: src/features/bracket/components/match-card.tsx:392
|
||||
msgid "Edit Match"
|
||||
msgstr "Edit Match"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:376
|
||||
#: src/features/bracket/components/match-card.tsx:380
|
||||
#: src/features/tournaments/components/group-match-card.tsx:187
|
||||
msgid "Edit match score"
|
||||
msgstr "Edit match score"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:110
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:114
|
||||
msgid "Edit Prediction"
|
||||
msgstr "Edit Prediction"
|
||||
|
||||
@@ -914,7 +954,7 @@ msgid "Enrolled Players"
|
||||
msgstr "Enrolled Players"
|
||||
|
||||
#: src/features/tournaments/components/edit-enrolled-teams.tsx:151
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:141
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:145
|
||||
#: src/features/tournaments/components/upcoming-tournament/team-list-button.tsx:31
|
||||
msgid "Enrolled Teams"
|
||||
msgstr "Enrolled Teams"
|
||||
@@ -1104,6 +1144,10 @@ msgstr "Go back"
|
||||
msgid "Go Back"
|
||||
msgstr "Go Back"
|
||||
|
||||
#: src/themes/seventies/manifest.ts:6
|
||||
msgid "Groovy"
|
||||
msgstr "Groovy"
|
||||
|
||||
#. placeholder {0}: group.groupName
|
||||
#. placeholder {0}: group.name
|
||||
#: src/features/tournaments/components/group-preview.tsx:24
|
||||
@@ -1138,7 +1182,7 @@ msgstr "Group stage generated successfully!"
|
||||
msgid "Group Stage Setup"
|
||||
msgstr "Group Stage Setup"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:94
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:98
|
||||
msgid "Groups"
|
||||
msgstr "Groups"
|
||||
|
||||
@@ -1154,8 +1198,8 @@ msgstr "Have you played before?"
|
||||
#: src/app/routes/_authed/stats.tsx:47
|
||||
#: src/features/bracket/components/match-dock.tsx:173
|
||||
#: src/features/bracket/components/match-dock.tsx:215
|
||||
#: src/features/matches/components/match-card.tsx:83
|
||||
#: src/features/matches/components/match-card.tsx:231
|
||||
#: src/features/matches/components/match-card.tsx:84
|
||||
#: src/features/matches/components/match-card.tsx:228
|
||||
#: src/features/players/components/league-head-to-head.tsx:183
|
||||
#: src/features/players/components/profile/header.tsx:90
|
||||
msgid "Head to Head"
|
||||
@@ -1339,7 +1383,7 @@ msgstr "M"
|
||||
msgid "Mainline"
|
||||
msgstr "Mainline"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:110
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:114
|
||||
msgid "Make Prediction"
|
||||
msgstr "Make Prediction"
|
||||
|
||||
@@ -1347,7 +1391,7 @@ msgstr "Make Prediction"
|
||||
msgid "Make Your Prediction"
|
||||
msgstr "Make Your Prediction"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:85
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:89
|
||||
#: src/features/tournaments/components/upcoming-tournament/index.tsx:143
|
||||
msgid "Manage"
|
||||
msgstr "Manage"
|
||||
@@ -1392,7 +1436,7 @@ msgstr "Match {0} · Round {1} (Losers)"
|
||||
#. placeholder {0}: match.order
|
||||
#. placeholder {1}: match.home!.name
|
||||
#. placeholder {2}: match.away!.name
|
||||
#: src/features/bracket/components/match-card.tsx:288
|
||||
#: src/features/bracket/components/match-card.tsx:292
|
||||
msgid "Match {0}: {1} vs {2}"
|
||||
msgstr "Match {0}: {1} vs {2}"
|
||||
|
||||
@@ -1415,7 +1459,7 @@ msgid "Match started!"
|
||||
msgstr "Match started!"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:366
|
||||
#: src/features/players/components/profile/index.tsx:73
|
||||
#: src/features/players/components/profile/index.tsx:78
|
||||
#: src/features/players/components/profile/skeleton.tsx:70
|
||||
#: src/features/teams/components/team-profile/index.tsx:44
|
||||
#: src/features/teams/components/team-profile/skeleton.tsx:75
|
||||
@@ -1489,6 +1533,10 @@ msgstr "nerd"
|
||||
msgid "Network error. Please check your connection and try again."
|
||||
msgstr "Network error. Please check your connection and try again."
|
||||
|
||||
#: src/themes/neumorph/manifest.ts:6
|
||||
msgid "Neumorphic"
|
||||
msgstr "Neumorphic"
|
||||
|
||||
#: src/features/players/components/players-activity-table.tsx:27
|
||||
msgid "Never"
|
||||
msgstr "Never"
|
||||
@@ -1834,7 +1882,7 @@ msgstr "Prediction Scoring:"
|
||||
|
||||
#: src/app/routes/_authed/tournaments/$id.predictions.tsx:23
|
||||
#: src/features/predictions/components/prediction-leaderboard.tsx:147
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:119
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:123
|
||||
msgid "Predictions"
|
||||
msgstr "Predictions"
|
||||
|
||||
@@ -1867,6 +1915,10 @@ msgstr "PTS"
|
||||
msgid "Q"
|
||||
msgstr "Q"
|
||||
|
||||
#: src/themes/quest/manifest.ts:6
|
||||
msgid "Quest Log"
|
||||
msgstr "Quest Log"
|
||||
|
||||
#: src/app/routes/_authed/admin/tournaments/$id/assign-partners.tsx:167
|
||||
msgid "Re-roll"
|
||||
msgstr "Re-roll"
|
||||
@@ -1923,11 +1975,11 @@ msgid "rofl"
|
||||
msgstr "rofl"
|
||||
|
||||
#. placeholder {0}: match.round + 1
|
||||
#: src/features/matches/components/match-card.tsx:76
|
||||
#: src/features/matches/components/match-card.tsx:77
|
||||
msgid "Round {0}"
|
||||
msgstr "Round {0}"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:138
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:142
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:23
|
||||
msgid "Rules"
|
||||
msgstr "Rules"
|
||||
@@ -2099,7 +2151,7 @@ msgstr "Server Functions"
|
||||
msgid "serverFn name"
|
||||
msgstr "serverFn name"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:15
|
||||
#: src/app/routes/_authed/settings.tsx:16
|
||||
#: src/features/core/components/settings-button.tsx:19
|
||||
msgid "Settings"
|
||||
msgstr "Settings"
|
||||
@@ -2118,10 +2170,18 @@ msgstr "Showing {0} of {1} players"
|
||||
msgid "Shuffle Groups"
|
||||
msgstr "Shuffle Groups"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:42
|
||||
#: src/app/routes/_authed/settings.tsx:44
|
||||
msgid "Sign Out"
|
||||
msgstr "Sign Out"
|
||||
|
||||
#: src/themes/sketch/manifest.ts:6
|
||||
msgid "Sketchbook"
|
||||
msgstr "Sketchbook"
|
||||
|
||||
#: src/themes/skeuo/manifest.ts:6
|
||||
msgid "Skeuomorphic"
|
||||
msgstr "Skeuomorphic"
|
||||
|
||||
#: src/components/DefaultCatchBoundary.tsx:89
|
||||
msgid "Something went wrong"
|
||||
msgstr "Something went wrong"
|
||||
@@ -2188,7 +2248,7 @@ msgstr "Start"
|
||||
msgid "Start Date"
|
||||
msgstr "Start Date"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:354
|
||||
#: src/features/bracket/components/match-card.tsx:358
|
||||
#: src/features/tournaments/components/group-match-card.tsx:168
|
||||
msgid "Start match"
|
||||
msgstr "Start match"
|
||||
@@ -2316,11 +2376,11 @@ msgstr "Team updated but logo upload failed: {0}"
|
||||
msgid "Team updated successfully!"
|
||||
msgstr "Team updated successfully!"
|
||||
|
||||
#: src/features/players/components/profile/index.tsx:78
|
||||
#: src/features/players/components/profile/index.tsx:83
|
||||
#: src/features/players/components/profile/skeleton.tsx:75
|
||||
#: src/features/tournaments/components/profile/index.tsx:32
|
||||
#: src/features/tournaments/components/profile/skeleton.tsx:89
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:133
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:137
|
||||
msgid "Teams"
|
||||
msgstr "Teams"
|
||||
|
||||
@@ -2328,6 +2388,10 @@ msgstr "Teams"
|
||||
msgid "Teams created successfully!"
|
||||
msgstr "Teams created successfully!"
|
||||
|
||||
#: src/themes/terminal/manifest.ts:6
|
||||
msgid "Terminal"
|
||||
msgstr "Terminal"
|
||||
|
||||
#: src/app/routes/api/push/test.ts:29
|
||||
msgid "Test notification — push is working on this device."
|
||||
msgstr "Test notification — push is working on this device."
|
||||
@@ -2352,6 +2416,11 @@ msgstr "The other team"
|
||||
msgid "The requested resource was not found"
|
||||
msgstr "The requested resource was not found"
|
||||
|
||||
#: src/features/settings/components/theme-picker.tsx:40
|
||||
#: src/features/settings/components/theme-picker.tsx:68
|
||||
msgid "Theme"
|
||||
msgstr "Theme"
|
||||
|
||||
#: src/features/players/components/player-head-to-head-sheet.tsx:107
|
||||
msgid "These players have not faced each other yet."
|
||||
msgstr "These players have not faced each other yet."
|
||||
@@ -2421,7 +2490,7 @@ msgstr "Tournament created successfully!"
|
||||
msgid "Tournament not found"
|
||||
msgstr "Tournament not found"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:148
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:152
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:25
|
||||
msgid "Tournament Rules"
|
||||
msgstr "Tournament Rules"
|
||||
@@ -2512,7 +2581,7 @@ msgstr "User Agent"
|
||||
msgid "versus"
|
||||
msgstr "versus"
|
||||
|
||||
#: src/features/players/components/profile/index.tsx:61
|
||||
#: src/features/players/components/profile/index.tsx:66
|
||||
msgid "View all badges"
|
||||
msgstr "View all badges"
|
||||
|
||||
@@ -2529,7 +2598,7 @@ msgid "View Groups"
|
||||
msgstr "View Groups"
|
||||
|
||||
#: src/features/bracket/components/match-dock.tsx:178
|
||||
#: src/features/matches/components/match-card.tsx:88
|
||||
#: src/features/matches/components/match-card.tsx:89
|
||||
msgid "View head-to-head"
|
||||
msgstr "View head-to-head"
|
||||
|
||||
@@ -2537,6 +2606,10 @@ msgstr "View head-to-head"
|
||||
msgid "View Predictions"
|
||||
msgstr "View Predictions"
|
||||
|
||||
#: src/themes/wireframe/manifest.ts:118
|
||||
msgid "Viewport"
|
||||
msgstr "Viewport"
|
||||
|
||||
#: src/app/routes/api/spotify/playback.ts:70
|
||||
msgid "volumePercent must be a number"
|
||||
msgstr "volumePercent must be a number"
|
||||
|
||||
+106
-33
@@ -13,7 +13,7 @@ msgstr ""
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#: src/features/matches/components/match-card.tsx:77
|
||||
#: src/features/matches/components/match-card.tsx:78
|
||||
msgid " (Losers)"
|
||||
msgstr " (Perdedores)"
|
||||
|
||||
@@ -140,7 +140,7 @@ msgstr "{0}ms"
|
||||
msgid "{count, plural, one {Players (#)} other {Players (#)}}"
|
||||
msgstr "{count, plural, one {Jugadores (#)} other {Jugadores (#)}}"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:130
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:134
|
||||
#: src/features/tournaments/components/upcoming-tournament/team-list-button.tsx:24
|
||||
msgid "{count, plural, one {Teams (#)} other {Teams (#)}}"
|
||||
msgstr "{count, plural, one {Equipos (#)} other {Equipos (#)}}"
|
||||
@@ -201,7 +201,7 @@ msgstr "Eliminación directa de {size} equipos"
|
||||
msgid "* Confidence penalty applied for players with <15 matches"
|
||||
msgstr "* Se aplica una penalización de confianza a jugadores con menos de 15 partidos"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:320
|
||||
#: src/features/bracket/components/match-card.tsx:324
|
||||
#: src/features/predictions/components/prediction-match-card.tsx:108
|
||||
msgid "* If necessary"
|
||||
msgstr "* Si es necesario"
|
||||
@@ -327,7 +327,7 @@ msgstr "1s"
|
||||
msgid "2. Earlier submission"
|
||||
msgstr "2. Envío más temprano"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:66
|
||||
#: src/features/tournaments/components/podium.tsx:59
|
||||
msgid "2nd place"
|
||||
msgstr "2do lugar"
|
||||
|
||||
@@ -335,7 +335,7 @@ msgstr "2do lugar"
|
||||
msgid "30s"
|
||||
msgstr "30s"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:76
|
||||
#: src/features/tournaments/components/podium.tsx:68
|
||||
msgid "3rd place"
|
||||
msgstr "3er lugar"
|
||||
|
||||
@@ -406,6 +406,10 @@ msgstr "Agregar Equipo"
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: src/themes/aero/manifest.ts:117
|
||||
msgid "Aero"
|
||||
msgstr "Aero"
|
||||
|
||||
#: src/app/routes/_authed/stats.tsx:59
|
||||
#: src/features/activities/components/activities-table.tsx:328
|
||||
#: src/features/players/components/profile/index.tsx:28
|
||||
@@ -436,11 +440,11 @@ msgstr "Ocurrió un error inesperado al intentar enviar el código de un solo us
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "Ocurrió un error inesperado. Intenta de nuevo."
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:336
|
||||
#: src/features/bracket/components/match-card.tsx:340
|
||||
msgid "Announce matchup"
|
||||
msgstr "Anunciar enfrentamiento"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:34
|
||||
#: src/app/routes/_authed/settings.tsx:35
|
||||
msgid "Appearance"
|
||||
msgstr "Apariencia"
|
||||
|
||||
@@ -452,6 +456,10 @@ msgstr "¿Seguro que quieres darte de baja de este torneo? Puedes volver a inscr
|
||||
msgid "Arguments"
|
||||
msgstr "Argumentos"
|
||||
|
||||
#: src/themes/deco/manifest.ts:6
|
||||
msgid "Art Deco"
|
||||
msgstr "Art Déco"
|
||||
|
||||
#: src/features/tournaments/components/manage-tournament.tsx:69
|
||||
msgid "Assign Partners"
|
||||
msgstr "Asignar Compañeros"
|
||||
@@ -554,12 +562,20 @@ msgstr "Tipo de insignia"
|
||||
msgid "Badges"
|
||||
msgstr "Insignias"
|
||||
|
||||
#: src/themes/bauhaus/manifest.ts:6
|
||||
msgid "Bauhaus"
|
||||
msgstr "Bauhaus"
|
||||
|
||||
#: src/themes/circus/manifest.ts:141
|
||||
msgid "Big Top"
|
||||
msgstr "Circo"
|
||||
|
||||
#: src/features/bracket/components/match-form.tsx:43
|
||||
#: src/features/bracket/components/match-form.tsx:60
|
||||
msgid "Both teams cannot have 10 cups"
|
||||
msgstr "Los dos equipos no pueden tener 10 vasos"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:102
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:106
|
||||
#: src/features/tournaments/components/upcoming-tournament/index.tsx:150
|
||||
msgid "Bracket"
|
||||
msgstr "Bracket"
|
||||
@@ -573,6 +589,10 @@ msgstr "Vista previa del bracket"
|
||||
msgid "Bracket Reset"
|
||||
msgstr "Reinicio del bracket"
|
||||
|
||||
#: src/themes/brutal/manifest.ts:6
|
||||
msgid "Brutal"
|
||||
msgstr "Brutal"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:139
|
||||
#: src/features/tournaments/components/tournament-stats.tsx:152
|
||||
msgid "CA"
|
||||
@@ -605,12 +625,16 @@ msgstr "No se pueden crear equipos con un número impar de jugadores. Pide que u
|
||||
msgid "Capture current state"
|
||||
msgstr "Capturar estado actual"
|
||||
|
||||
#: src/themes/cassette/manifest.ts:145
|
||||
msgid "Cassette Futurism"
|
||||
msgstr "Retro-Tec"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:138
|
||||
#: src/features/tournaments/components/tournament-stats.tsx:144
|
||||
msgid "CF"
|
||||
msgstr "VF"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:56
|
||||
#: src/features/tournaments/components/podium.tsx:50
|
||||
msgid "Champions"
|
||||
msgstr "Campeones"
|
||||
|
||||
@@ -623,17 +647,21 @@ msgstr "Cambiar logo"
|
||||
msgid "Choose a player"
|
||||
msgstr "Elige un jugador"
|
||||
|
||||
#: src/themes/clay/manifest.ts:144
|
||||
msgid "Claymation"
|
||||
msgstr "Plastilina"
|
||||
|
||||
#: src/features/players/components/league-head-to-head.tsx:99
|
||||
msgid "Clear selected player"
|
||||
msgstr "Quitar jugador seleccionado"
|
||||
|
||||
#: src/components/sheet/modal.tsx:35
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:165
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:169
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:36
|
||||
msgid "Close"
|
||||
msgstr "Cerrar"
|
||||
|
||||
#: src/components/avatar.tsx:107
|
||||
#: src/components/avatar.tsx:127
|
||||
msgid "Close image preview"
|
||||
msgstr "Cerrar vista previa de la imagen"
|
||||
|
||||
@@ -785,10 +813,22 @@ msgstr "Código hex personalizado"
|
||||
msgid "Dark"
|
||||
msgstr "Oscuro"
|
||||
|
||||
#: src/themes/gothic/manifest.ts:6
|
||||
msgid "Dark Academia"
|
||||
msgstr "Academia Oscura"
|
||||
|
||||
#: src/features/activities/components/activities-table.tsx:356
|
||||
msgid "Date"
|
||||
msgstr "Fecha"
|
||||
|
||||
#: src/themes/ocean/manifest.ts:117
|
||||
msgid "Deep Sea"
|
||||
msgstr "Mar Profundo"
|
||||
|
||||
#: src/themes/default/manifest.ts:6
|
||||
msgid "Default"
|
||||
msgstr "Predeterminado"
|
||||
|
||||
#: src/features/tournaments/components/tournament-form.tsx:150
|
||||
msgid "Description"
|
||||
msgstr "Descripción"
|
||||
@@ -833,16 +873,16 @@ msgstr "Editar equipos inscritos"
|
||||
msgid "Edit Enrollments"
|
||||
msgstr "Editar inscripciones"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:388
|
||||
#: src/features/bracket/components/match-card.tsx:392
|
||||
msgid "Edit Match"
|
||||
msgstr "Editar partido"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:376
|
||||
#: src/features/bracket/components/match-card.tsx:380
|
||||
#: src/features/tournaments/components/group-match-card.tsx:187
|
||||
msgid "Edit match score"
|
||||
msgstr "Editar marcador del partido"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:110
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:114
|
||||
msgid "Edit Prediction"
|
||||
msgstr "Editar predicción"
|
||||
|
||||
@@ -914,7 +954,7 @@ msgid "Enrolled Players"
|
||||
msgstr "Jugadores inscritos"
|
||||
|
||||
#: src/features/tournaments/components/edit-enrolled-teams.tsx:151
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:141
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:145
|
||||
#: src/features/tournaments/components/upcoming-tournament/team-list-button.tsx:31
|
||||
msgid "Enrolled Teams"
|
||||
msgstr "Equipos inscritos"
|
||||
@@ -1104,6 +1144,10 @@ msgstr "Regresar"
|
||||
msgid "Go Back"
|
||||
msgstr "Regresar"
|
||||
|
||||
#: src/themes/seventies/manifest.ts:6
|
||||
msgid "Groovy"
|
||||
msgstr "Setentero"
|
||||
|
||||
#. placeholder {0}: group.groupName
|
||||
#. placeholder {0}: group.name
|
||||
#: src/features/tournaments/components/group-preview.tsx:24
|
||||
@@ -1138,7 +1182,7 @@ msgstr "¡Fase de grupos generada con éxito!"
|
||||
msgid "Group Stage Setup"
|
||||
msgstr "Configuración de la fase de grupos"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:94
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:98
|
||||
msgid "Groups"
|
||||
msgstr "Grupos"
|
||||
|
||||
@@ -1154,8 +1198,8 @@ msgstr "¿Ya has jugado antes?"
|
||||
#: src/app/routes/_authed/stats.tsx:47
|
||||
#: src/features/bracket/components/match-dock.tsx:173
|
||||
#: src/features/bracket/components/match-dock.tsx:215
|
||||
#: src/features/matches/components/match-card.tsx:83
|
||||
#: src/features/matches/components/match-card.tsx:231
|
||||
#: src/features/matches/components/match-card.tsx:84
|
||||
#: src/features/matches/components/match-card.tsx:228
|
||||
#: src/features/players/components/league-head-to-head.tsx:183
|
||||
#: src/features/players/components/profile/header.tsx:90
|
||||
msgid "Head to Head"
|
||||
@@ -1339,7 +1383,7 @@ msgstr "J"
|
||||
msgid "Mainline"
|
||||
msgstr "Mainline"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:110
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:114
|
||||
msgid "Make Prediction"
|
||||
msgstr "Hacer predicción"
|
||||
|
||||
@@ -1347,7 +1391,7 @@ msgstr "Hacer predicción"
|
||||
msgid "Make Your Prediction"
|
||||
msgstr "Haz tu predicción"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:85
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:89
|
||||
#: src/features/tournaments/components/upcoming-tournament/index.tsx:143
|
||||
msgid "Manage"
|
||||
msgstr "Administrar"
|
||||
@@ -1392,7 +1436,7 @@ msgstr "Partido {0} · Ronda {1} (Perdedores)"
|
||||
#. placeholder {0}: match.order
|
||||
#. placeholder {1}: match.home!.name
|
||||
#. placeholder {2}: match.away!.name
|
||||
#: src/features/bracket/components/match-card.tsx:288
|
||||
#: src/features/bracket/components/match-card.tsx:292
|
||||
msgid "Match {0}: {1} vs {2}"
|
||||
msgstr "Partido {0}: {1} vs {2}"
|
||||
|
||||
@@ -1415,7 +1459,7 @@ msgid "Match started!"
|
||||
msgstr "¡Empezó el partido!"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:366
|
||||
#: src/features/players/components/profile/index.tsx:73
|
||||
#: src/features/players/components/profile/index.tsx:78
|
||||
#: src/features/players/components/profile/skeleton.tsx:70
|
||||
#: src/features/teams/components/team-profile/index.tsx:44
|
||||
#: src/features/teams/components/team-profile/skeleton.tsx:75
|
||||
@@ -1489,6 +1533,10 @@ msgstr "nerd"
|
||||
msgid "Network error. Please check your connection and try again."
|
||||
msgstr "Error de red. Revisa tu conexión e intenta de nuevo."
|
||||
|
||||
#: src/themes/neumorph/manifest.ts:6
|
||||
msgid "Neumorphic"
|
||||
msgstr "Neumórfico"
|
||||
|
||||
#: src/features/players/components/players-activity-table.tsx:27
|
||||
msgid "Never"
|
||||
msgstr "Nunca"
|
||||
@@ -1834,7 +1882,7 @@ msgstr "Puntuación de predicciones:"
|
||||
|
||||
#: src/app/routes/_authed/tournaments/$id.predictions.tsx:23
|
||||
#: src/features/predictions/components/prediction-leaderboard.tsx:147
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:119
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:123
|
||||
msgid "Predictions"
|
||||
msgstr "Predicciones"
|
||||
|
||||
@@ -1867,6 +1915,10 @@ msgstr "PTS"
|
||||
msgid "Q"
|
||||
msgstr "C"
|
||||
|
||||
#: src/themes/quest/manifest.ts:6
|
||||
msgid "Quest Log"
|
||||
msgstr "Misiones"
|
||||
|
||||
#: src/app/routes/_authed/admin/tournaments/$id/assign-partners.tsx:167
|
||||
msgid "Re-roll"
|
||||
msgstr "Volver a sortear"
|
||||
@@ -1923,11 +1975,11 @@ msgid "rofl"
|
||||
msgstr "carcajada"
|
||||
|
||||
#. placeholder {0}: match.round + 1
|
||||
#: src/features/matches/components/match-card.tsx:76
|
||||
#: src/features/matches/components/match-card.tsx:77
|
||||
msgid "Round {0}"
|
||||
msgstr "Ronda {0}"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:138
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:142
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:23
|
||||
msgid "Rules"
|
||||
msgstr "Reglas"
|
||||
@@ -2099,7 +2151,7 @@ msgstr "Funciones del servidor"
|
||||
msgid "serverFn name"
|
||||
msgstr "nombre de serverFn"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:15
|
||||
#: src/app/routes/_authed/settings.tsx:16
|
||||
#: src/features/core/components/settings-button.tsx:19
|
||||
msgid "Settings"
|
||||
msgstr "Configuración"
|
||||
@@ -2118,10 +2170,18 @@ msgstr "Mostrando {0} de {1} jugadores"
|
||||
msgid "Shuffle Groups"
|
||||
msgstr "Mezclar grupos"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:42
|
||||
#: src/app/routes/_authed/settings.tsx:44
|
||||
msgid "Sign Out"
|
||||
msgstr "Cerrar sesión"
|
||||
|
||||
#: src/themes/sketch/manifest.ts:6
|
||||
msgid "Sketchbook"
|
||||
msgstr "Cuaderno"
|
||||
|
||||
#: src/themes/skeuo/manifest.ts:6
|
||||
msgid "Skeuomorphic"
|
||||
msgstr "Esqueuomórfico"
|
||||
|
||||
#: src/components/DefaultCatchBoundary.tsx:89
|
||||
msgid "Something went wrong"
|
||||
msgstr "Algo salió mal"
|
||||
@@ -2188,7 +2248,7 @@ msgstr "Inicio"
|
||||
msgid "Start Date"
|
||||
msgstr "Fecha de inicio"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:354
|
||||
#: src/features/bracket/components/match-card.tsx:358
|
||||
#: src/features/tournaments/components/group-match-card.tsx:168
|
||||
msgid "Start match"
|
||||
msgstr "Iniciar partido"
|
||||
@@ -2316,11 +2376,11 @@ msgstr "Equipo actualizado, pero falló la carga del logo: {0}"
|
||||
msgid "Team updated successfully!"
|
||||
msgstr "¡Equipo actualizado exitosamente!"
|
||||
|
||||
#: src/features/players/components/profile/index.tsx:78
|
||||
#: src/features/players/components/profile/index.tsx:83
|
||||
#: src/features/players/components/profile/skeleton.tsx:75
|
||||
#: src/features/tournaments/components/profile/index.tsx:32
|
||||
#: src/features/tournaments/components/profile/skeleton.tsx:89
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:133
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:137
|
||||
msgid "Teams"
|
||||
msgstr "Equipos"
|
||||
|
||||
@@ -2328,6 +2388,10 @@ msgstr "Equipos"
|
||||
msgid "Teams created successfully!"
|
||||
msgstr "¡Equipos creados exitosamente!"
|
||||
|
||||
#: src/themes/terminal/manifest.ts:6
|
||||
msgid "Terminal"
|
||||
msgstr "Terminal"
|
||||
|
||||
#: src/app/routes/api/push/test.ts:29
|
||||
msgid "Test notification — push is working on this device."
|
||||
msgstr "Notificación de prueba: las notificaciones push funcionan en este dispositivo."
|
||||
@@ -2352,6 +2416,11 @@ msgstr "El otro equipo"
|
||||
msgid "The requested resource was not found"
|
||||
msgstr "No se encontró el recurso solicitado"
|
||||
|
||||
#: src/features/settings/components/theme-picker.tsx:40
|
||||
#: src/features/settings/components/theme-picker.tsx:68
|
||||
msgid "Theme"
|
||||
msgstr "Tema"
|
||||
|
||||
#: src/features/players/components/player-head-to-head-sheet.tsx:107
|
||||
msgid "These players have not faced each other yet."
|
||||
msgstr "Estos jugadores aún no se han enfrentado."
|
||||
@@ -2421,7 +2490,7 @@ msgstr "¡Torneo creado exitosamente!"
|
||||
msgid "Tournament not found"
|
||||
msgstr "Torneo no encontrado"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:148
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:152
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:25
|
||||
msgid "Tournament Rules"
|
||||
msgstr "Reglas del torneo"
|
||||
@@ -2512,7 +2581,7 @@ msgstr "User Agent"
|
||||
msgid "versus"
|
||||
msgstr "contra"
|
||||
|
||||
#: src/features/players/components/profile/index.tsx:61
|
||||
#: src/features/players/components/profile/index.tsx:66
|
||||
msgid "View all badges"
|
||||
msgstr "Ver todas las insignias"
|
||||
|
||||
@@ -2529,7 +2598,7 @@ msgid "View Groups"
|
||||
msgstr "Ver grupos"
|
||||
|
||||
#: src/features/bracket/components/match-dock.tsx:178
|
||||
#: src/features/matches/components/match-card.tsx:88
|
||||
#: src/features/matches/components/match-card.tsx:89
|
||||
msgid "View head-to-head"
|
||||
msgstr "Ver cara a cara"
|
||||
|
||||
@@ -2537,6 +2606,10 @@ msgstr "Ver cara a cara"
|
||||
msgid "View Predictions"
|
||||
msgstr "Ver predicciones"
|
||||
|
||||
#: src/themes/wireframe/manifest.ts:118
|
||||
msgid "Viewport"
|
||||
msgstr "Viewport"
|
||||
|
||||
#: src/app/routes/api/spotify/playback.ts:70
|
||||
msgid "volumePercent must be a number"
|
||||
msgstr "volumePercent debe ser un número"
|
||||
|
||||
+106
-33
@@ -13,7 +13,7 @@ msgstr ""
|
||||
"Language-Team: \n"
|
||||
"Plural-Forms: \n"
|
||||
|
||||
#: src/features/matches/components/match-card.tsx:77
|
||||
#: src/features/matches/components/match-card.tsx:78
|
||||
msgid " (Losers)"
|
||||
msgstr " (敗者側)"
|
||||
|
||||
@@ -140,7 +140,7 @@ msgstr "{0}ms"
|
||||
msgid "{count, plural, one {Players (#)} other {Players (#)}}"
|
||||
msgstr "{count, plural, one {プレイヤー(#)} other {プレイヤー(#)}}"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:130
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:134
|
||||
#: src/features/tournaments/components/upcoming-tournament/team-list-button.tsx:24
|
||||
msgid "{count, plural, one {Teams (#)} other {Teams (#)}}"
|
||||
msgstr "{count, plural, one {チーム(#)} other {チーム(#)}}"
|
||||
@@ -201,7 +201,7 @@ msgstr "{size}チームノックアウト"
|
||||
msgid "* Confidence penalty applied for players with <15 matches"
|
||||
msgstr "※試合数が15未満のプレイヤーには信頼度ペナルティが適用されます"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:320
|
||||
#: src/features/bracket/components/match-card.tsx:324
|
||||
#: src/features/predictions/components/prediction-match-card.tsx:108
|
||||
msgid "* If necessary"
|
||||
msgstr "※必要な場合"
|
||||
@@ -327,7 +327,7 @@ msgstr "1秒"
|
||||
msgid "2. Earlier submission"
|
||||
msgstr "2. 早い提出"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:66
|
||||
#: src/features/tournaments/components/podium.tsx:59
|
||||
msgid "2nd place"
|
||||
msgstr "2位"
|
||||
|
||||
@@ -335,7 +335,7 @@ msgstr "2位"
|
||||
msgid "30s"
|
||||
msgstr "30秒"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:76
|
||||
#: src/features/tournaments/components/podium.tsx:68
|
||||
msgid "3rd place"
|
||||
msgstr "3位"
|
||||
|
||||
@@ -406,6 +406,10 @@ msgstr "チームを追加"
|
||||
msgid "Admin"
|
||||
msgstr "管理者"
|
||||
|
||||
#: src/themes/aero/manifest.ts:117
|
||||
msgid "Aero"
|
||||
msgstr "エアロ"
|
||||
|
||||
#: src/app/routes/_authed/stats.tsx:59
|
||||
#: src/features/activities/components/activities-table.tsx:328
|
||||
#: src/features/players/components/profile/index.tsx:28
|
||||
@@ -436,11 +440,11 @@ msgstr "ワンタイムパスコードの送信中に予期しないエラーが
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "予期しないエラーが発生しました。もう一度お試しください。"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:336
|
||||
#: src/features/bracket/components/match-card.tsx:340
|
||||
msgid "Announce matchup"
|
||||
msgstr "対戦カードを発表"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:34
|
||||
#: src/app/routes/_authed/settings.tsx:35
|
||||
msgid "Appearance"
|
||||
msgstr "外観"
|
||||
|
||||
@@ -452,6 +456,10 @@ msgstr "このトーナメントから登録を解除してもよろしいです
|
||||
msgid "Arguments"
|
||||
msgstr "引数"
|
||||
|
||||
#: src/themes/deco/manifest.ts:6
|
||||
msgid "Art Deco"
|
||||
msgstr "アールデコ"
|
||||
|
||||
#: src/features/tournaments/components/manage-tournament.tsx:69
|
||||
msgid "Assign Partners"
|
||||
msgstr "パートナーを割り当て"
|
||||
@@ -554,12 +562,20 @@ msgstr "バッジの種類"
|
||||
msgid "Badges"
|
||||
msgstr "バッジ"
|
||||
|
||||
#: src/themes/bauhaus/manifest.ts:6
|
||||
msgid "Bauhaus"
|
||||
msgstr "バウハウス"
|
||||
|
||||
#: src/themes/circus/manifest.ts:141
|
||||
msgid "Big Top"
|
||||
msgstr "サーカス"
|
||||
|
||||
#: src/features/bracket/components/match-form.tsx:43
|
||||
#: src/features/bracket/components/match-form.tsx:60
|
||||
msgid "Both teams cannot have 10 cups"
|
||||
msgstr "両チーム同時に10カップにはなりません"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:102
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:106
|
||||
#: src/features/tournaments/components/upcoming-tournament/index.tsx:150
|
||||
msgid "Bracket"
|
||||
msgstr "ブラケット"
|
||||
@@ -573,6 +589,10 @@ msgstr "ブラケットプレビュー"
|
||||
msgid "Bracket Reset"
|
||||
msgstr "ブラケットリセット"
|
||||
|
||||
#: src/themes/brutal/manifest.ts:6
|
||||
msgid "Brutal"
|
||||
msgstr "ブルータル"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:139
|
||||
#: src/features/tournaments/components/tournament-stats.tsx:152
|
||||
msgid "CA"
|
||||
@@ -605,12 +625,16 @@ msgstr "参加者が奇数のためチームを作成できません。どなた
|
||||
msgid "Capture current state"
|
||||
msgstr "現在の状態をキャプチャ"
|
||||
|
||||
#: src/themes/cassette/manifest.ts:145
|
||||
msgid "Cassette Futurism"
|
||||
msgstr "レトロフューチャー"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:138
|
||||
#: src/features/tournaments/components/tournament-stats.tsx:144
|
||||
msgid "CF"
|
||||
msgstr "CF"
|
||||
|
||||
#: src/features/tournaments/components/podium.tsx:56
|
||||
#: src/features/tournaments/components/podium.tsx:50
|
||||
msgid "Champions"
|
||||
msgstr "チャンピオン"
|
||||
|
||||
@@ -623,17 +647,21 @@ msgstr "ロゴを変更"
|
||||
msgid "Choose a player"
|
||||
msgstr "プレイヤーを選択"
|
||||
|
||||
#: src/themes/clay/manifest.ts:144
|
||||
msgid "Claymation"
|
||||
msgstr "クレイ"
|
||||
|
||||
#: src/features/players/components/league-head-to-head.tsx:99
|
||||
msgid "Clear selected player"
|
||||
msgstr "選択したプレイヤーを解除"
|
||||
|
||||
#: src/components/sheet/modal.tsx:35
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:165
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:169
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:36
|
||||
msgid "Close"
|
||||
msgstr "閉じる"
|
||||
|
||||
#: src/components/avatar.tsx:107
|
||||
#: src/components/avatar.tsx:127
|
||||
msgid "Close image preview"
|
||||
msgstr "画像プレビューを閉じる"
|
||||
|
||||
@@ -785,10 +813,22 @@ msgstr "カスタムHEXコード"
|
||||
msgid "Dark"
|
||||
msgstr "ダーク"
|
||||
|
||||
#: src/themes/gothic/manifest.ts:6
|
||||
msgid "Dark Academia"
|
||||
msgstr "ダークアカデミア"
|
||||
|
||||
#: src/features/activities/components/activities-table.tsx:356
|
||||
msgid "Date"
|
||||
msgstr "日付"
|
||||
|
||||
#: src/themes/ocean/manifest.ts:117
|
||||
msgid "Deep Sea"
|
||||
msgstr "深海"
|
||||
|
||||
#: src/themes/default/manifest.ts:6
|
||||
msgid "Default"
|
||||
msgstr "デフォルト"
|
||||
|
||||
#: src/features/tournaments/components/tournament-form.tsx:150
|
||||
msgid "Description"
|
||||
msgstr "説明"
|
||||
@@ -833,16 +873,16 @@ msgstr "参加チームを編集"
|
||||
msgid "Edit Enrollments"
|
||||
msgstr "参加登録を編集"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:388
|
||||
#: src/features/bracket/components/match-card.tsx:392
|
||||
msgid "Edit Match"
|
||||
msgstr "試合を編集"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:376
|
||||
#: src/features/bracket/components/match-card.tsx:380
|
||||
#: src/features/tournaments/components/group-match-card.tsx:187
|
||||
msgid "Edit match score"
|
||||
msgstr "試合スコアを編集"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:110
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:114
|
||||
msgid "Edit Prediction"
|
||||
msgstr "予想を編集"
|
||||
|
||||
@@ -914,7 +954,7 @@ msgid "Enrolled Players"
|
||||
msgstr "登録済みプレイヤー"
|
||||
|
||||
#: src/features/tournaments/components/edit-enrolled-teams.tsx:151
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:141
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:145
|
||||
#: src/features/tournaments/components/upcoming-tournament/team-list-button.tsx:31
|
||||
msgid "Enrolled Teams"
|
||||
msgstr "登録済みチーム"
|
||||
@@ -1104,6 +1144,10 @@ msgstr "戻る"
|
||||
msgid "Go Back"
|
||||
msgstr "戻る"
|
||||
|
||||
#: src/themes/seventies/manifest.ts:6
|
||||
msgid "Groovy"
|
||||
msgstr "グルーヴィー"
|
||||
|
||||
#. placeholder {0}: group.groupName
|
||||
#. placeholder {0}: group.name
|
||||
#: src/features/tournaments/components/group-preview.tsx:24
|
||||
@@ -1138,7 +1182,7 @@ msgstr "グループステージを生成しました!"
|
||||
msgid "Group Stage Setup"
|
||||
msgstr "グループステージ設定"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:94
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:98
|
||||
msgid "Groups"
|
||||
msgstr "グループ"
|
||||
|
||||
@@ -1154,8 +1198,8 @@ msgstr "参加したことはありますか?"
|
||||
#: src/app/routes/_authed/stats.tsx:47
|
||||
#: src/features/bracket/components/match-dock.tsx:173
|
||||
#: src/features/bracket/components/match-dock.tsx:215
|
||||
#: src/features/matches/components/match-card.tsx:83
|
||||
#: src/features/matches/components/match-card.tsx:231
|
||||
#: src/features/matches/components/match-card.tsx:84
|
||||
#: src/features/matches/components/match-card.tsx:228
|
||||
#: src/features/players/components/league-head-to-head.tsx:183
|
||||
#: src/features/players/components/profile/header.tsx:90
|
||||
msgid "Head to Head"
|
||||
@@ -1339,7 +1383,7 @@ msgstr "M"
|
||||
msgid "Mainline"
|
||||
msgstr "メインライン"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:110
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:114
|
||||
msgid "Make Prediction"
|
||||
msgstr "予想する"
|
||||
|
||||
@@ -1347,7 +1391,7 @@ msgstr "予想する"
|
||||
msgid "Make Your Prediction"
|
||||
msgstr "予想を入力"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:85
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:89
|
||||
#: src/features/tournaments/components/upcoming-tournament/index.tsx:143
|
||||
msgid "Manage"
|
||||
msgstr "管理"
|
||||
@@ -1392,7 +1436,7 @@ msgstr "試合{0}・ラウンド{1}(敗者側)"
|
||||
#. placeholder {0}: match.order
|
||||
#. placeholder {1}: match.home!.name
|
||||
#. placeholder {2}: match.away!.name
|
||||
#: src/features/bracket/components/match-card.tsx:288
|
||||
#: src/features/bracket/components/match-card.tsx:292
|
||||
msgid "Match {0}: {1} vs {2}"
|
||||
msgstr "試合{0}: {1} vs {2}"
|
||||
|
||||
@@ -1415,7 +1459,7 @@ msgid "Match started!"
|
||||
msgstr "試合開始!"
|
||||
|
||||
#: src/features/players/components/player-stats-table.tsx:366
|
||||
#: src/features/players/components/profile/index.tsx:73
|
||||
#: src/features/players/components/profile/index.tsx:78
|
||||
#: src/features/players/components/profile/skeleton.tsx:70
|
||||
#: src/features/teams/components/team-profile/index.tsx:44
|
||||
#: src/features/teams/components/team-profile/skeleton.tsx:75
|
||||
@@ -1489,6 +1533,10 @@ msgstr "オタク"
|
||||
msgid "Network error. Please check your connection and try again."
|
||||
msgstr "ネットワークエラーです。接続を確認してもう一度お試しください。"
|
||||
|
||||
#: src/themes/neumorph/manifest.ts:6
|
||||
msgid "Neumorphic"
|
||||
msgstr "ネウモーフィズム"
|
||||
|
||||
#: src/features/players/components/players-activity-table.tsx:27
|
||||
msgid "Never"
|
||||
msgstr "なし"
|
||||
@@ -1834,7 +1882,7 @@ msgstr "予想の得点方式:"
|
||||
|
||||
#: src/app/routes/_authed/tournaments/$id.predictions.tsx:23
|
||||
#: src/features/predictions/components/prediction-leaderboard.tsx:147
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:119
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:123
|
||||
msgid "Predictions"
|
||||
msgstr "予想"
|
||||
|
||||
@@ -1867,6 +1915,10 @@ msgstr "PTS"
|
||||
msgid "Q"
|
||||
msgstr "Q"
|
||||
|
||||
#: src/themes/quest/manifest.ts:6
|
||||
msgid "Quest Log"
|
||||
msgstr "クエスト"
|
||||
|
||||
#: src/app/routes/_authed/admin/tournaments/$id/assign-partners.tsx:167
|
||||
msgid "Re-roll"
|
||||
msgstr "再抽選"
|
||||
@@ -1923,11 +1975,11 @@ msgid "rofl"
|
||||
msgstr "大笑い"
|
||||
|
||||
#. placeholder {0}: match.round + 1
|
||||
#: src/features/matches/components/match-card.tsx:76
|
||||
#: src/features/matches/components/match-card.tsx:77
|
||||
msgid "Round {0}"
|
||||
msgstr "ラウンド{0}"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:138
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:142
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:23
|
||||
msgid "Rules"
|
||||
msgstr "ルール"
|
||||
@@ -2099,7 +2151,7 @@ msgstr "サーバー関数"
|
||||
msgid "serverFn name"
|
||||
msgstr "serverFn名"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:15
|
||||
#: src/app/routes/_authed/settings.tsx:16
|
||||
#: src/features/core/components/settings-button.tsx:19
|
||||
msgid "Settings"
|
||||
msgstr "設定"
|
||||
@@ -2118,10 +2170,18 @@ msgstr "{1}人中{0}人のプレイヤーを表示"
|
||||
msgid "Shuffle Groups"
|
||||
msgstr "グループをシャッフル"
|
||||
|
||||
#: src/app/routes/_authed/settings.tsx:42
|
||||
#: src/app/routes/_authed/settings.tsx:44
|
||||
msgid "Sign Out"
|
||||
msgstr "サインアウト"
|
||||
|
||||
#: src/themes/sketch/manifest.ts:6
|
||||
msgid "Sketchbook"
|
||||
msgstr "スケッチ"
|
||||
|
||||
#: src/themes/skeuo/manifest.ts:6
|
||||
msgid "Skeuomorphic"
|
||||
msgstr "スキューモーフィズム"
|
||||
|
||||
#: src/components/DefaultCatchBoundary.tsx:89
|
||||
msgid "Something went wrong"
|
||||
msgstr "問題が発生しました"
|
||||
@@ -2188,7 +2248,7 @@ msgstr "開始"
|
||||
msgid "Start Date"
|
||||
msgstr "開始日"
|
||||
|
||||
#: src/features/bracket/components/match-card.tsx:354
|
||||
#: src/features/bracket/components/match-card.tsx:358
|
||||
#: src/features/tournaments/components/group-match-card.tsx:168
|
||||
msgid "Start match"
|
||||
msgstr "試合を開始"
|
||||
@@ -2316,11 +2376,11 @@ msgstr "チームを更新しましたが、ロゴのアップロードに失敗
|
||||
msgid "Team updated successfully!"
|
||||
msgstr "チームを更新しました!"
|
||||
|
||||
#: src/features/players/components/profile/index.tsx:78
|
||||
#: src/features/players/components/profile/index.tsx:83
|
||||
#: src/features/players/components/profile/skeleton.tsx:75
|
||||
#: src/features/tournaments/components/profile/index.tsx:32
|
||||
#: src/features/tournaments/components/profile/skeleton.tsx:89
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:133
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:137
|
||||
msgid "Teams"
|
||||
msgstr "チーム"
|
||||
|
||||
@@ -2328,6 +2388,10 @@ msgstr "チーム"
|
||||
msgid "Teams created successfully!"
|
||||
msgstr "チームを作成しました!"
|
||||
|
||||
#: src/themes/terminal/manifest.ts:6
|
||||
msgid "Terminal"
|
||||
msgstr "ターミナル"
|
||||
|
||||
#: src/app/routes/api/push/test.ts:29
|
||||
msgid "Test notification — push is working on this device."
|
||||
msgstr "テスト通知 — このデバイスでプッシュ通知が機能しています。"
|
||||
@@ -2352,6 +2416,11 @@ msgstr "相手チーム"
|
||||
msgid "The requested resource was not found"
|
||||
msgstr "リクエストされたリソースが見つかりませんでした"
|
||||
|
||||
#: src/features/settings/components/theme-picker.tsx:40
|
||||
#: src/features/settings/components/theme-picker.tsx:68
|
||||
msgid "Theme"
|
||||
msgstr "テーマ"
|
||||
|
||||
#: src/features/players/components/player-head-to-head-sheet.tsx:107
|
||||
msgid "These players have not faced each other yet."
|
||||
msgstr "このプレイヤー同士はまだ対戦していません。"
|
||||
@@ -2421,7 +2490,7 @@ msgstr "トーナメントを作成しました!"
|
||||
msgid "Tournament not found"
|
||||
msgstr "トーナメントが見つかりません"
|
||||
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:148
|
||||
#: src/features/tournaments/components/started-tournament/sections/nav-grid.tsx:152
|
||||
#: src/features/tournaments/components/upcoming-tournament/rules-list-button.tsx:25
|
||||
msgid "Tournament Rules"
|
||||
msgstr "トーナメントルール"
|
||||
@@ -2512,7 +2581,7 @@ msgstr "ユーザーエージェント"
|
||||
msgid "versus"
|
||||
msgstr "対"
|
||||
|
||||
#: src/features/players/components/profile/index.tsx:61
|
||||
#: src/features/players/components/profile/index.tsx:66
|
||||
msgid "View all badges"
|
||||
msgstr "すべてのバッジを見る"
|
||||
|
||||
@@ -2529,7 +2598,7 @@ msgid "View Groups"
|
||||
msgstr "グループを見る"
|
||||
|
||||
#: src/features/bracket/components/match-dock.tsx:178
|
||||
#: src/features/matches/components/match-card.tsx:88
|
||||
#: src/features/matches/components/match-card.tsx:89
|
||||
msgid "View head-to-head"
|
||||
msgstr "対戦成績を見る"
|
||||
|
||||
@@ -2537,6 +2606,10 @@ msgstr "対戦成績を見る"
|
||||
msgid "View Predictions"
|
||||
msgstr "予想を見る"
|
||||
|
||||
#: src/themes/wireframe/manifest.ts:118
|
||||
msgid "Viewport"
|
||||
msgstr "ビューポート"
|
||||
|
||||
#: src/app/routes/api/spotify/playback.ts:70
|
||||
msgid "volumePercent must be a number"
|
||||
msgstr "volumePercentは数値である必要があります"
|
||||
|
||||
@@ -0,0 +1,280 @@
|
||||
# FLXN theme system
|
||||
|
||||
A theme is a self-contained folder under `src/themes/<id>/` containing exactly
|
||||
two files. Themes are auto-discovered via `import.meta.glob` — adding a theme
|
||||
is adding a folder, removing one is deleting it. No shared file is ever edited.
|
||||
|
||||
```
|
||||
src/themes/
|
||||
<id>/
|
||||
manifest.ts # metadata + optional JS-side Mantine override
|
||||
theme.css # all visual work, scoped under [data-theme="<id>"]
|
||||
```
|
||||
|
||||
Activation: the provider sets `data-theme="<id>"` on `<html>` (mirrored to
|
||||
localStorage `flxn-theme` for the pre-hydration script in `__root.tsx`).
|
||||
The preference is stored per-user in SuperTokens metadata (`metadata.theme`).
|
||||
|
||||
## manifest.ts
|
||||
|
||||
```ts
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "comic", // MUST equal the folder name
|
||||
label: msg`Comic`, // i18n — always msg``
|
||||
colorSchemes: "both", // or "light" / "dark" to force a scheme
|
||||
fontLinks: [ // injected only while theme is active;
|
||||
"https://fonts.googleapis.com/css2?family=Bangers&display=swap",
|
||||
], // browsers fetch font files lazily
|
||||
chromeColors: { // browser-chrome theme-color meta
|
||||
light: { base: "#fde047", dimmed: "#ca8a04" },
|
||||
dark: { base: "#1c1917", dimmed: "#0c0a09" },
|
||||
},
|
||||
mantine: { // optional Mantine override, merged onto
|
||||
defaultRadius: "xs", // the base theme via mergeThemeOverrides.
|
||||
components: { /* defaultProps, vars, … */ },
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
```
|
||||
|
||||
Rules:
|
||||
- `label` must use `msg` from `@lingui/core/macro` (never raw strings, never
|
||||
global `t`). Translations are handled centrally afterwards.
|
||||
- Prefer doing visual work in `theme.css`; use `mantine` only for things CSS
|
||||
cannot express (defaultProps, per-component `vars` resolvers).
|
||||
|
||||
## Accent color (REQUIRED)
|
||||
|
||||
The user picks an accent (blue, red, green, yellow, grape, orange, pink,
|
||||
lime) and EVERY theme must honor it — there is no way to lock the accent.
|
||||
|
||||
- Primary/interactive styling must derive from the primary aliases
|
||||
(`--mantine-primary-color-filled`, `-light`, `-6`, …) or from the accent
|
||||
ramps generically — never from one hardcoded brand hue.
|
||||
- A theme MAY retune all eight accent ramps (`--mantine-color-blue-*`,
|
||||
`--mantine-color-red-*`, …) to fit its world — e.g. neon versions, pastel
|
||||
versions, phosphor-tinted versions — as long as the eight choices remain
|
||||
visually distinct. Retuning shades is encouraged; ignoring the choice is
|
||||
forbidden.
|
||||
- Theme-flavor decoration may still use fixed hues (a comic's halftone tint,
|
||||
a blueprint's grid ink), but anything that reads as "the accent" —
|
||||
filled buttons, active tabs/nav, focus rings, selection — follows the user.
|
||||
|
||||
## light-dark() trap
|
||||
|
||||
Never use `light-dark()` in a declaration whose selector matches `<html>`
|
||||
(any `[data-theme=…]` token block): postcss-preset-mantine rewrites it into
|
||||
a descendant selector that can never match the root element, so the dark
|
||||
branch silently dies. Use the explicit compound scheme selectors (shape 2)
|
||||
instead. Inside descendant rules (`[data-theme] .mantine-Button-root`)
|
||||
light-dark() is fine.
|
||||
|
||||
## theme.css — selector templates (specificity is load-bearing)
|
||||
|
||||
Mantine emits its variables from a runtime `<style>` tag that appears AFTER
|
||||
our bundled CSS, so theme overrides must WIN ON SPECIFICITY, not order. Use
|
||||
these exact selector shapes:
|
||||
|
||||
```css
|
||||
/* 1. Tokens for any scheme — (0,2,0), beats Mantine's :root block */
|
||||
[data-theme="comic"][data-theme] {
|
||||
--mantine-radius-default: 0;
|
||||
--mantine-font-family: "Comic Neue", cursive;
|
||||
}
|
||||
|
||||
/* 2. Per-scheme tokens — (0,3,0), beats Mantine's :root[scheme] blocks */
|
||||
[data-theme="comic"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #fef9c3;
|
||||
}
|
||||
[data-theme="comic"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #1c1917;
|
||||
}
|
||||
|
||||
/* 3. Component restyles — descendant selectors on static classes */
|
||||
[data-theme="comic"] .mantine-Button-root {
|
||||
border: 3px solid #000;
|
||||
box-shadow: 4px 4px 0 #000;
|
||||
}
|
||||
|
||||
/* 4. Full-page decorations (scanlines, halftone, grain) */
|
||||
[data-theme="comic"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998; /* above content, below --mantine-z-index-max */
|
||||
pointer-events: none;
|
||||
/* embed textures as data-URI SVG/gradients — no external requests */
|
||||
}
|
||||
```
|
||||
|
||||
The doubled `[data-theme]` attribute is intentional (specificity bump).
|
||||
Still never use `html[data-theme]` or `:root[data-theme]` — the doubled
|
||||
attribute form matches `<html>` at higher specificity and stays portable.
|
||||
|
||||
## Previews (no per-theme work required)
|
||||
|
||||
The settings picker renders each theme in its own sandboxed same-origin
|
||||
srcdoc iframe (`theme-preview.tsx`): the iframe's `<html>` carries the
|
||||
theme's `data-theme`/`data-mantine-color-scheme`, its head gets a snapshot
|
||||
of the app's real stylesheets, the theme's `fontLinks`, and the theme's
|
||||
Mantine JS-side variables computed with Mantine's own resolver from the
|
||||
same `baseTheme` + `manifest.mantine` + accent merge the live provider
|
||||
performs. Previews are therefore 1:1 with the active theme by construction
|
||||
— fonts, textures, html/body-level rules and all — and nothing bleeds
|
||||
between the active theme and a preview. There is no preview variable
|
||||
contract to maintain, and `--mantine-primary-color-*` must still never be
|
||||
pinned by a theme (the user's accent must show through everywhere,
|
||||
previews included).
|
||||
|
||||
## What you can override (cheat sheet)
|
||||
|
||||
Mantine components style themselves from CSS variables — overriding variables
|
||||
retints the whole app with zero React work.
|
||||
|
||||
- Palettes: `--mantine-color-<name>-<0..9>` and per-color variant vars
|
||||
(`-filled`, `-filled-hover`, `-light`, `-light-hover`, `-light-color`,
|
||||
`-outline`, `-outline-hover`, `-text`); primary aliases
|
||||
`--mantine-primary-color-{0..9,filled,filled-hover,light,light-hover,light-color,contrast}`.
|
||||
- Scheme-dependent semantics (define per scheme, selector 2):
|
||||
`--mantine-color-body`, `-text`, `-dimmed`, `-bright`, `-anchor`, `-error`,
|
||||
`-placeholder`, `-default`, `-default-hover`, `-default-color`,
|
||||
`-default-border`.
|
||||
- Shape: `--mantine-radius-{xs..xl}`, `--mantine-radius-default`.
|
||||
- Elevation: `--mantine-shadow-{xs..xl}` (composite strings — neobrutalism
|
||||
uses `4px 4px 0 #000`, glass uses soft large blurs).
|
||||
- Type: `--mantine-font-family{,-monospace,-headings}`,
|
||||
`--mantine-font-size-{xs..xl}`, `--mantine-h{1..6}-font-size/-line-height/-font-weight`,
|
||||
`--mantine-heading-font-weight`, `--mantine-line-height{,-xs..xl}`.
|
||||
- Spacing: `--mantine-spacing-{xs..xl}` (be conservative — layout shifts).
|
||||
- App tokens (see `base.css`): `--flxn-gold/-silver/-bronze`,
|
||||
`--flxn-toast-success/-error`, `--flxn-podium-{1,2,3}-{bg,border,label}`,
|
||||
`--flxn-showcase-bg`, `--flxn-overlay`, `--flxn-dotgrid-color`,
|
||||
`--flxn-pop-shadow`. Override these with selector 1/2 shapes (they beat
|
||||
base.css's `:root` on specificity).
|
||||
|
||||
Static classes for restyling (most-used components in this app): Button,
|
||||
ActionIcon, Paper, Card, TextInput/Input (`.mantine-Input-input`), Select,
|
||||
Badge, Tabs (`-list`, `-tab`), SegmentedControl (`-root`, `-indicator`,
|
||||
`-label`), Modal (`-content`, `-header`), Avatar, ThemeIcon, Skeleton,
|
||||
Loader, Alert, Tooltip, Popover (`-dropdown`), Switch, Checkbox, Progress,
|
||||
PinInput, NavLink, Notification, AppShell (`-header`, `-navbar`, `-main`),
|
||||
Divider, Indicator — as `.mantine-<Component>-<part>`. State comes as data
|
||||
attributes: `[data-variant]`, `[data-active]`, `[data-disabled]`, etc.
|
||||
|
||||
Custom app components (sheet drawers, nav tiles, list rows, carousels) are
|
||||
built on the same `--mantine-*`/`--flxn-*` variables and follow automatically.
|
||||
|
||||
## App component hooks
|
||||
|
||||
Stable classes/tokens for custom components (defaults live in
|
||||
`src/themes/hooks.css`; themes override under `[data-theme]` scopes — theme
|
||||
files load after hooks.css, so equal-specificity rules win by order):
|
||||
|
||||
- `.flxn-tabs` / `.flxn-tab` (+`[data-active]`) / `.flxn-tabs-indicator` —
|
||||
the swipeable tab strip used on profile/tournament pages. Restyle these so
|
||||
tabs belong to the theme (block active states, underlines, boxed tabs…).
|
||||
TWO STATES: resting (mid-page) must stay FLAT — transparent background,
|
||||
no strip chrome, blending into the page; the docked treatment (background,
|
||||
rules, shadows, textures) goes on `.flxn-tabs[data-stuck]` only, which the
|
||||
component sets while the strip is pinned to the top. hooks.css provides
|
||||
the transition between states. Tab/indicator styling must stay legible
|
||||
over the bare page background in the resting state.
|
||||
STACKING: the indicator is Mantine FloatingIndicator — absolutely
|
||||
positioned, so it would paint OVER the static tab labels; hooks.css
|
||||
lifts `.flxn-tab` (`position: relative; z-index: 1`) so labels always
|
||||
render on top. Never z-index the indicator above 1 or an opaque fill
|
||||
swallows the labels.
|
||||
PAIRING RULE: an accent-filled indicator pill/block (or accent-filled
|
||||
`.flxn-tab[data-active]`) MUST pair its label with `--flxn-on-accent`
|
||||
(black/white computed from the actual cascaded fill — safe under CSS
|
||||
ramp retunes, unlike `--mantine-primary-color-contrast`, which Mantine
|
||||
computes from the JS theme colors and can disagree with a CSS-retuned
|
||||
fill). Never accent text over an accent fill. If the indicator is an
|
||||
underline/rule, accent text is fine.
|
||||
NO glow/soft shadows on `.flxn-tabs-indicator` (owner preference): a
|
||||
clean underline or flat plate only. Rich active-tab chrome (wells,
|
||||
engraving, plates beyond the indicator) belongs under
|
||||
`.flxn-tabs[data-stuck]` like the strip chrome — resting tabs stay flat.
|
||||
- `.flxn-tile` / `.flxn-tile-icon` — home/tournament nav grid tiles. Treat
|
||||
like Card/Paper: give them the theme's surface language.
|
||||
- (retired) `.flxn-see-all` — "see all" actions are plain Mantine subtle
|
||||
Buttons now, accent-driven by design. Do NOT reintroduce per-theme chip
|
||||
styling for them; they inherit only your generic Button treatment.
|
||||
- `.flxn-bracket-card` — the small dense match cards inside the bracket
|
||||
view (they are Mantine Cards). Exclude them from heavy Card decorations
|
||||
(valances, ornaments) that suit full-width cards but overwhelm bracket
|
||||
density.
|
||||
- `.flxn-match-card` + `.flxn-reaction-row` — a match card with a reaction
|
||||
tray tucked underneath (tray = full border + full radius, hidden top edge).
|
||||
Keep the pair reading as one construction in your theme: matching borders
|
||||
and backgrounds, tray background contrasting subtly with the card.
|
||||
- `.flxn-badge-tile` — badge grid tile motion hook; tile shape follows
|
||||
`--flxn-badge-radius` (default 12px).
|
||||
- `.flxn-avatar-frame` + `--flxn-avatar-radius` (default `50%`) +
|
||||
`--flxn-avatar-border` (default `1px solid` default-border) — avatars.
|
||||
The frame owns the avatar's SINGLE border via the token; NEVER put a
|
||||
border/outline on `.mantine-Avatar-root` (hooks.css force-strips it —
|
||||
doing so doubles every ring). The frame is a plain Box, so generic
|
||||
Paper restyles don't reach it; square-language themes set the radius
|
||||
to 0–4px and restyle via the two tokens (plus `.flxn-avatar-frame` for
|
||||
anything richer, e.g. shadows/bezels).
|
||||
- `.flxn-tile-icon` — keep icons FLAT: tint the glyph (color), no
|
||||
background plates/borders/padding behind it. A plate is only justified
|
||||
when the theme's whole language demands it (rare); default to flat.
|
||||
|
||||
## Hard rules
|
||||
|
||||
- EVERYTHING scoped under `[data-theme="<id>"]`. Zero unscoped selectors —
|
||||
a theme must be inert when inactive.
|
||||
- Support both schemes unless the design genuinely demands one; then set
|
||||
`colorSchemes: "light" | "dark"` (the engine forces it).
|
||||
- Accessibility gates:
|
||||
- Wrap flicker/pulse/marquee animations in
|
||||
`@media (prefers-reduced-motion: no-preference) { … }`.
|
||||
- Give `backdrop-filter` surfaces a solid fallback via
|
||||
`@supports not (backdrop-filter: blur(1px))` and respect
|
||||
`@media (prefers-reduced-transparency: reduce)`.
|
||||
- Keep real borders on interactive elements (forced-colors mode strips
|
||||
shadows/gradients).
|
||||
- Body text must stay ≥ 4.5:1 contrast in every supported scheme.
|
||||
- Mantine hardcodes WHITE on `[data-combobox-selected]` (Select options)
|
||||
and `theme.autoContrast` does not reach it. hooks.css fixes this
|
||||
globally with `--flxn-on-accent`; if your theme overrides the
|
||||
selected-option styling, pair the fill with an explicit legible
|
||||
on-color yourself.
|
||||
- Any `background-clip: text` gradient text needs a
|
||||
`@media (forced-colors: active)` fallback (`background-image: none;
|
||||
color: CanvasText`) or headings vanish in forced-colors mode.
|
||||
- Re-flavored `.flxn-press` transforms MUST be wrapped in
|
||||
`@media (prefers-reduced-motion: no-preference)` — theme selectors
|
||||
outrank the global reduce kill in the provider.
|
||||
- Placeholder text ≥3:1 and dimmed text ≥4.5:1 against the body color.
|
||||
- Text must never share its hue with the fill directly behind it
|
||||
(accent-on-accent, gold-on-gold…). Accent fills pair with
|
||||
`--flxn-on-accent` (base.css token: black/white picked from the actual
|
||||
cascaded `--mantine-primary-color-filled`); accent washes pair with
|
||||
`--mantine-primary-color-light-color`; accent text needs a neutral
|
||||
backing. Applies to tab indicators, SegmentedControl, active NavLinks,
|
||||
badges, chips — anywhere a label sits on a colored plate.
|
||||
- Performance gates:
|
||||
- Never animate variables on `:root`/`html` — animate leaf elements.
|
||||
- At most 1–2 full-viewport overlay pseudo-elements, `pointer-events: none`.
|
||||
- Limit `backdrop-filter` to a handful of surfaces; never animate blur.
|
||||
- Textures/assets as data-URIs inside theme.css; no network requests.
|
||||
- Don't break layout: the app is a mobile-first PWA (AppShell header +
|
||||
navbar). Radius/borders/shadows/fonts are fair game; avoid changing
|
||||
spacing scales drastically or adding outer margins to shell parts.
|
||||
- The press feedback (`.flxn-press`, scale on :active) is global; themes may
|
||||
re-flavor it, e.g. `[data-theme="brutal"] .flxn-press:active { transform:
|
||||
translate(4px, 4px); }`.
|
||||
- i18n: manifest strings via `msg` only. Do NOT run lingui extract/compile —
|
||||
handled centrally.
|
||||
|
||||
## Verifying a theme
|
||||
|
||||
`bun x tsc --noEmit` must pass. Do not run the dev server; visual QA happens
|
||||
centrally after all themes land.
|
||||
@@ -0,0 +1,137 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
/* Candy-gloss Aero ramps for all eight accents. Declared in JS (not
|
||||
theme.css) so Mantine regenerates every derived variant var (-light rgba,
|
||||
-outline, autoContrast picks) from the retuned shades, whichever accent
|
||||
the user selects. */
|
||||
const aeroColors = {
|
||||
// aqua
|
||||
blue: [
|
||||
"#e7f6fd",
|
||||
"#d0edfb",
|
||||
"#a6ddf6",
|
||||
"#79ccf0",
|
||||
"#55bdec",
|
||||
"#3db1e8",
|
||||
"#2a9ed7",
|
||||
"#1f88bd",
|
||||
"#196f9b",
|
||||
"#135877",
|
||||
],
|
||||
// glossy grass
|
||||
green: [
|
||||
"#eefaea",
|
||||
"#d9f2d2",
|
||||
"#bce8b1",
|
||||
"#9cdc8d",
|
||||
"#7fd06d",
|
||||
"#66c353",
|
||||
"#4fb23c",
|
||||
"#3f9630",
|
||||
"#337b27",
|
||||
"#286120",
|
||||
],
|
||||
// chartreuse jelly
|
||||
lime: [
|
||||
"#f6fbe4",
|
||||
"#ebf6c6",
|
||||
"#dcefa0",
|
||||
"#cbe677",
|
||||
"#bbdc52",
|
||||
"#abd135",
|
||||
"#96bd20",
|
||||
"#7da019",
|
||||
"#648213",
|
||||
"#4e660f",
|
||||
],
|
||||
// candy apple
|
||||
red: [
|
||||
"#fdeef0",
|
||||
"#fbd9dd",
|
||||
"#f7b7bf",
|
||||
"#f2929e",
|
||||
"#ec7280",
|
||||
"#e65567",
|
||||
"#db3a50",
|
||||
"#bd2c41",
|
||||
"#9b2335",
|
||||
"#791b2a",
|
||||
],
|
||||
// glossy sunbeam
|
||||
yellow: [
|
||||
"#fff9e1",
|
||||
"#fff0bd",
|
||||
"#ffe492",
|
||||
"#fcd668",
|
||||
"#f7c845",
|
||||
"#f0b929",
|
||||
"#e3a614",
|
||||
"#c28a0e",
|
||||
"#9e6f0a",
|
||||
"#7c5607",
|
||||
],
|
||||
// jelly purple
|
||||
grape: [
|
||||
"#f7f0fd",
|
||||
"#ecdcfa",
|
||||
"#dbc0f5",
|
||||
"#c79fee",
|
||||
"#b581e6",
|
||||
"#a468dd",
|
||||
"#8f4dcd",
|
||||
"#7a3cb3",
|
||||
"#643093",
|
||||
"#4e2573",
|
||||
],
|
||||
// goldfish amber
|
||||
orange: [
|
||||
"#fff3e4",
|
||||
"#ffe4c4",
|
||||
"#ffcf9b",
|
||||
"#fdb56d",
|
||||
"#f89c45",
|
||||
"#f18827",
|
||||
"#e37113",
|
||||
"#c25c0d",
|
||||
"#9e4a0a",
|
||||
"#7b3a08",
|
||||
],
|
||||
// bubblegum
|
||||
pink: [
|
||||
"#fdeff5",
|
||||
"#fbdae9",
|
||||
"#f8b9d6",
|
||||
"#f394bf",
|
||||
"#ec72a9",
|
||||
"#e55596",
|
||||
"#d63c82",
|
||||
"#b82e6d",
|
||||
"#962558",
|
||||
"#751d45",
|
||||
],
|
||||
} as const;
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "aero",
|
||||
label: msg`Aero`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Nunito+Sans:opsz,wght@6..12,400;6..12,600;6..12,700;6..12,800&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#d3edfb", dimmed: "#8fcdee" },
|
||||
dark: { base: "#0a2536", dimmed: "#051925" },
|
||||
},
|
||||
mantine: {
|
||||
// Juicy mid-tone fills in both schemes; bright candy fills (yellow,
|
||||
// lime) and mid-luminance aqua get dark text instead of low-contrast
|
||||
// white (aqua blue-6 luminance ≈ 0.30 must land above the threshold).
|
||||
primaryShade: { light: 6, dark: 7 },
|
||||
autoContrast: true,
|
||||
luminanceThreshold: 0.28,
|
||||
colors: aeroColors,
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,607 @@
|
||||
/* Frutiger Aero: glossy skeuomorphic surfaces over a fixed sky-to-white
|
||||
gradient with static bubbles. The eight accent ramps are retuned in
|
||||
manifest.ts (candy-gloss versions) and everything interactive derives
|
||||
from --mantine-primary-color-* so the user's accent drives fills, active
|
||||
states and focus rings; the sky/grass scenery stays fixed decoration.
|
||||
Gloss is vertical half-highlight gradients (never animated) that layer
|
||||
over any base color; backdrop-filter is limited to the AppShell header,
|
||||
navbar and the docked ([data-stuck]) flxn tab strip. */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 1. Tokens for any scheme */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"][data-theme] {
|
||||
--mantine-font-family: "Nunito Sans", "Segoe UI", "Helvetica Neue", sans-serif;
|
||||
--mantine-font-family-headings: "Nunito Sans", "Segoe UI", "Helvetica Neue", sans-serif;
|
||||
--mantine-heading-font-weight: 800;
|
||||
|
||||
/* bubbly radii */
|
||||
--mantine-radius-xs: 0.5rem;
|
||||
--mantine-radius-sm: 0.75rem;
|
||||
--mantine-radius-md: 1rem;
|
||||
--mantine-radius-lg: 1.25rem;
|
||||
--mantine-radius-xl: 1.75rem;
|
||||
--mantine-radius-default: 1rem;
|
||||
|
||||
/* glossy bezelled circles for avatars, rounded candy badge tiles */
|
||||
--flxn-avatar-radius: 50%;
|
||||
--flxn-avatar-border: 1px solid var(--aero-panel-border);
|
||||
--flxn-badge-radius: 16px;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 2. Per-scheme tokens */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #e9f6fe;
|
||||
--mantine-color-text: #123c56;
|
||||
--mantine-color-bright: #082738;
|
||||
--mantine-color-dimmed: #4a758f;
|
||||
--mantine-color-placeholder: #5f7f95;
|
||||
--mantine-color-default: rgba(255, 255, 255, 0.75);
|
||||
--mantine-color-default-hover: rgba(255, 255, 255, 0.92);
|
||||
--mantine-color-default-color: #123c56;
|
||||
--mantine-color-default-border: rgba(125, 178, 212, 0.55);
|
||||
|
||||
/* soft blue-tinted elevation */
|
||||
--mantine-shadow-xs: 0 1px 3px rgba(23, 113, 159, 0.14);
|
||||
--mantine-shadow-sm: 0 2px 8px rgba(23, 113, 159, 0.16);
|
||||
--mantine-shadow-md: 0 6px 18px rgba(23, 113, 159, 0.18);
|
||||
--mantine-shadow-lg: 0 10px 28px rgba(23, 113, 159, 0.2);
|
||||
--mantine-shadow-xl: 0 16px 44px rgba(23, 113, 159, 0.24);
|
||||
|
||||
/* gloss ingredients */
|
||||
--aero-panel-bg: rgba(255, 255, 255, 0.66);
|
||||
--aero-panel-border: rgba(255, 255, 255, 0.75);
|
||||
--aero-panel-sheen: linear-gradient(
|
||||
rgba(255, 255, 255, 0.7),
|
||||
rgba(255, 255, 255, 0.15) 50%,
|
||||
rgba(255, 255, 255, 0) 50%
|
||||
);
|
||||
--aero-gloss: linear-gradient(
|
||||
rgba(255, 255, 255, 0.55),
|
||||
rgba(255, 255, 255, 0.14) 50%,
|
||||
rgba(255, 255, 255, 0) 50%
|
||||
);
|
||||
--aero-gloss-soft: linear-gradient(
|
||||
rgba(255, 255, 255, 0.35),
|
||||
rgba(255, 255, 255, 0.08) 50%,
|
||||
rgba(255, 255, 255, 0) 50%
|
||||
);
|
||||
--aero-solid: #f4fafe;
|
||||
--aero-chrome-bg: rgba(255, 255, 255, 0.62);
|
||||
--aero-input-bg: rgba(255, 255, 255, 0.85);
|
||||
--aero-input-inset: inset 0 2px 4px rgba(23, 113, 159, 0.16),
|
||||
inset 0 -1px 0 rgba(255, 255, 255, 0.8);
|
||||
--aero-track: rgba(178, 216, 238, 0.45);
|
||||
--aero-tube-inset: inset 0 2px 4px rgba(23, 113, 159, 0.22),
|
||||
inset 0 -1px 0 rgba(255, 255, 255, 0.6);
|
||||
--aero-indicator-bg: rgba(255, 255, 255, 0.95);
|
||||
--aero-thumb: linear-gradient(#ffffff, #e6f2fa);
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #f0ac12;
|
||||
--flxn-silver: #90a9ba;
|
||||
--flxn-bronze: #d0803f;
|
||||
--flxn-toast-success: #5cb455;
|
||||
--flxn-toast-error: #e56a62;
|
||||
--flxn-showcase-bg: rgba(255, 255, 255, 0.72);
|
||||
--flxn-overlay: rgba(16, 66, 102, 0.4);
|
||||
--flxn-dotgrid-color: rgba(61, 177, 232, 0.35);
|
||||
--flxn-pop-shadow: rgba(23, 113, 159, 0.3);
|
||||
|
||||
/* podium as glassy tiers */
|
||||
--flxn-podium-1-bg: rgba(255, 232, 155, 0.6);
|
||||
--flxn-podium-1-border: rgba(222, 178, 66, 0.65);
|
||||
--flxn-podium-1-label: #8a6410;
|
||||
--flxn-podium-2-bg: rgba(255, 255, 255, 0.6);
|
||||
--flxn-podium-2-border: rgba(151, 183, 203, 0.6);
|
||||
--flxn-podium-2-label: #4d6b7e;
|
||||
--flxn-podium-3-bg: rgba(255, 214, 178, 0.55);
|
||||
--flxn-podium-3-border: rgba(216, 138, 79, 0.6);
|
||||
--flxn-podium-3-label: #92511f;
|
||||
}
|
||||
|
||||
[data-theme="aero"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #071e2d;
|
||||
--mantine-color-text: #d8edf8;
|
||||
--mantine-color-bright: #f2fbff;
|
||||
--mantine-color-dimmed: #8db3c8;
|
||||
--mantine-color-placeholder: #618ba3;
|
||||
--mantine-color-default: rgba(19, 58, 82, 0.72);
|
||||
--mantine-color-default-hover: rgba(27, 74, 102, 0.85);
|
||||
--mantine-color-default-color: #d8edf8;
|
||||
--mantine-color-default-border: rgba(94, 193, 238, 0.28);
|
||||
|
||||
/* glow-edged elevation */
|
||||
--mantine-shadow-xs: 0 0 0 1px rgba(94, 193, 238, 0.1), 0 2px 6px rgba(0, 10, 18, 0.5);
|
||||
--mantine-shadow-sm: 0 0 0 1px rgba(94, 193, 238, 0.12), 0 4px 14px rgba(0, 10, 18, 0.55);
|
||||
--mantine-shadow-md: 0 0 0 1px rgba(94, 193, 238, 0.14), 0 8px 24px rgba(0, 10, 18, 0.6);
|
||||
--mantine-shadow-lg: 0 0 0 1px rgba(94, 193, 238, 0.16), 0 12px 34px rgba(0, 10, 18, 0.65);
|
||||
--mantine-shadow-xl: 0 0 0 1px rgba(94, 193, 238, 0.18), 0 18px 48px rgba(0, 10, 18, 0.7);
|
||||
|
||||
/* deep-aqua glass ingredients */
|
||||
--aero-panel-bg: rgba(12, 42, 62, 0.72);
|
||||
--aero-panel-border: rgba(94, 193, 238, 0.3);
|
||||
--aero-panel-sheen: linear-gradient(
|
||||
rgba(151, 214, 246, 0.16),
|
||||
rgba(151, 214, 246, 0.04) 50%,
|
||||
rgba(151, 214, 246, 0) 50%
|
||||
);
|
||||
--aero-gloss: linear-gradient(
|
||||
rgba(255, 255, 255, 0.28),
|
||||
rgba(255, 255, 255, 0.07) 50%,
|
||||
rgba(255, 255, 255, 0) 50%
|
||||
);
|
||||
--aero-gloss-soft: linear-gradient(
|
||||
rgba(255, 255, 255, 0.14),
|
||||
rgba(255, 255, 255, 0.04) 50%,
|
||||
rgba(255, 255, 255, 0) 50%
|
||||
);
|
||||
--aero-solid: #0d2a3e;
|
||||
--aero-chrome-bg: rgba(7, 28, 42, 0.68);
|
||||
--aero-input-bg: rgba(6, 26, 40, 0.8);
|
||||
--aero-input-inset: inset 0 2px 5px rgba(0, 10, 18, 0.6),
|
||||
inset 0 -1px 0 rgba(94, 193, 238, 0.12);
|
||||
--aero-track: rgba(9, 36, 54, 0.8);
|
||||
--aero-tube-inset: inset 0 2px 5px rgba(0, 10, 18, 0.55),
|
||||
inset 0 -1px 0 rgba(94, 193, 238, 0.1);
|
||||
--aero-indicator-bg: rgba(31, 100, 140, 0.8);
|
||||
--aero-thumb: linear-gradient(#e8f6fe, #a9d6ee);
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #ffd76a;
|
||||
--flxn-silver: #a5bccb;
|
||||
--flxn-bronze: #e29a63;
|
||||
--flxn-toast-success: #8fd98a;
|
||||
--flxn-toast-error: #f2938c;
|
||||
--flxn-showcase-bg: rgba(12, 42, 62, 0.75);
|
||||
--flxn-overlay: rgba(2, 12, 20, 0.6);
|
||||
--flxn-dotgrid-color: rgba(94, 193, 238, 0.22);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.55);
|
||||
|
||||
/* podium as glassy tiers */
|
||||
--flxn-podium-1-bg: rgba(255, 205, 92, 0.14);
|
||||
--flxn-podium-1-border: rgba(255, 205, 92, 0.4);
|
||||
--flxn-podium-1-label: #ffd76a;
|
||||
--flxn-podium-2-bg: rgba(190, 220, 238, 0.1);
|
||||
--flxn-podium-2-border: rgba(190, 220, 238, 0.3);
|
||||
--flxn-podium-2-label: #b8cfdd;
|
||||
--flxn-podium-3-bg: rgba(226, 154, 99, 0.13);
|
||||
--flxn-podium-3-border: rgba(226, 154, 99, 0.38);
|
||||
--flxn-podium-3-label: #eba76f;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 3. Fixed sky backdrop with static bubbles (below all content) */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-theme="aero"][data-mantine-color-scheme="light"] body::before {
|
||||
background-color: #e9f6fe;
|
||||
background-image:
|
||||
radial-gradient(circle 0.6rem at 13.5% 20%, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0) 70%),
|
||||
radial-gradient(circle 4.5rem at 15% 22%, rgba(255, 255, 255, 0) 60%, rgba(255, 255, 255, 0.5) 66%, rgba(255, 255, 255, 0.08) 72%, rgba(255, 255, 255, 0) 74%),
|
||||
radial-gradient(circle 2.5rem at 79% 12%, rgba(255, 255, 255, 0) 58%, rgba(255, 255, 255, 0.45) 66%, rgba(255, 255, 255, 0) 74%),
|
||||
radial-gradient(circle 6rem at 88% 64%, rgba(255, 255, 255, 0) 62%, rgba(255, 255, 255, 0.35) 68%, rgba(255, 255, 255, 0) 75%),
|
||||
radial-gradient(circle 3rem at 8% 72%, rgba(255, 255, 255, 0) 58%, rgba(255, 255, 255, 0.3) 66%, rgba(255, 255, 255, 0) 74%),
|
||||
radial-gradient(56rem 20rem at 50% 106%, rgba(124, 197, 118, 0.28), rgba(124, 197, 118, 0) 70%),
|
||||
linear-gradient(180deg, #a5daf6 0%, #c9e9fa 32%, #e9f6fe 60%, #ffffff 100%);
|
||||
}
|
||||
|
||||
[data-theme="aero"][data-mantine-color-scheme="dark"] body::before {
|
||||
background-color: #071e2d;
|
||||
background-image:
|
||||
radial-gradient(circle 4rem at 16% 24%, rgba(120, 205, 245, 0) 60%, rgba(120, 205, 245, 0.2) 67%, rgba(120, 205, 245, 0) 74%),
|
||||
radial-gradient(circle 2.5rem at 80% 16%, rgba(120, 205, 245, 0) 58%, rgba(120, 205, 245, 0.16) 66%, rgba(120, 205, 245, 0) 74%),
|
||||
radial-gradient(40rem 28rem at 82% -4%, rgba(31, 136, 189, 0.35), transparent 65%),
|
||||
radial-gradient(36rem 26rem at 10% 86%, rgba(23, 128, 118, 0.3), transparent 65%),
|
||||
linear-gradient(180deg, #0c3350 0%, #0a2a40 45%, #051520 100%);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 4. Panels: translucent white/deep-aqua with a top-half sheen */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"] .mantine-Paper-root,
|
||||
[data-theme="aero"] .mantine-Card-root,
|
||||
[data-theme="aero"] .mantine-Popover-dropdown {
|
||||
background-color: var(--aero-panel-bg);
|
||||
background-image: var(--aero-panel-sheen);
|
||||
border: 1px solid var(--aero-panel-border);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Modal-content {
|
||||
background-color: var(--aero-panel-bg);
|
||||
background-image: var(--aero-panel-sheen);
|
||||
border: 1px solid var(--aero-panel-border);
|
||||
box-shadow: var(--mantine-shadow-xl);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Modal-header {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Popover-dropdown {
|
||||
box-shadow: var(--mantine-shadow-lg);
|
||||
}
|
||||
|
||||
/* Notifications float over arbitrary content: keep near-opaque. */
|
||||
[data-theme="aero"] .mantine-Notification-root {
|
||||
background-color: var(--aero-solid);
|
||||
background-image: var(--aero-panel-sheen);
|
||||
border: 1px solid var(--aero-panel-border);
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
box-shadow: var(--mantine-shadow-lg);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 5. AppShell chrome — the ONLY backdrop-filter surfaces */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"] .mantine-AppShell-header,
|
||||
[data-theme="aero"] .mantine-AppShell-navbar {
|
||||
background-color: var(--aero-chrome-bg);
|
||||
background-image: var(--aero-gloss-soft);
|
||||
-webkit-backdrop-filter: blur(14px) saturate(150%);
|
||||
backdrop-filter: blur(14px) saturate(150%);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-AppShell-header {
|
||||
border-bottom: 1px solid var(--aero-panel-border);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-AppShell-navbar {
|
||||
border-inline-end: 1px solid var(--aero-panel-border);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 6. Glossy pill buttons with specular highlight */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"] .mantine-Button-root {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 999px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Button-root:is(
|
||||
[data-variant="filled"],
|
||||
[data-variant="default"],
|
||||
[data-variant="light"],
|
||||
[data-variant="gradient"]
|
||||
) {
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Button-root[data-variant="default"] {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Button-root:is(
|
||||
[data-variant="filled"],
|
||||
[data-variant="default"],
|
||||
[data-variant="light"],
|
||||
[data-variant="gradient"]
|
||||
)::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
background: var(--aero-gloss);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Button-inner {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-ActionIcon-root {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-ActionIcon-root:is(
|
||||
[data-variant="filled"],
|
||||
[data-variant="default"],
|
||||
[data-variant="light"],
|
||||
[data-variant="gradient"]
|
||||
) {
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-ActionIcon-root:is(
|
||||
[data-variant="filled"],
|
||||
[data-variant="default"],
|
||||
[data-variant="light"],
|
||||
[data-variant="gradient"]
|
||||
)::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: inherit;
|
||||
background: var(--aero-gloss);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-ThemeIcon-root {
|
||||
background-image: var(--aero-gloss);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
/* Press feedback: quick specular dim on top of the global scale. */
|
||||
[data-theme="aero"] .flxn-press:active {
|
||||
filter: brightness(0.95) saturate(1.05);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 7. Glossy inset inputs */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"] .mantine-Input-input {
|
||||
background-color: var(--aero-input-bg);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
box-shadow: var(--aero-input-inset);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Input-input:focus,
|
||||
[data-theme="aero"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: var(--aero-input-inset),
|
||||
0 0 0 3px color-mix(in srgb, var(--mantine-primary-color-filled) 25%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Checkbox-input {
|
||||
border-radius: 0.55rem;
|
||||
box-shadow: var(--aero-input-inset);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 8. Glass-tube progress, tracks, toggles */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"] .mantine-Progress-root {
|
||||
background-color: var(--aero-track);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: 999px;
|
||||
box-shadow: var(--aero-tube-inset);
|
||||
}
|
||||
|
||||
/* Shine only — background-color stays the per-instance section color. */
|
||||
[data-theme="aero"] .mantine-Progress-section {
|
||||
border-radius: 999px;
|
||||
background-image: linear-gradient(
|
||||
rgba(255, 255, 255, 0.5),
|
||||
rgba(255, 255, 255, 0.14) 48%,
|
||||
rgba(0, 0, 0, 0.05) 52%,
|
||||
rgba(255, 255, 255, 0.08)
|
||||
);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--aero-track);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: 999px;
|
||||
box-shadow: var(--aero-tube-inset);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--aero-indicator-bg);
|
||||
background-image: var(--aero-gloss);
|
||||
border: 1px solid var(--aero-panel-border);
|
||||
border-radius: 999px;
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-SegmentedControl-label {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Switch-track {
|
||||
background-image: var(--aero-gloss-soft);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 20, 35, 0.2);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Switch-thumb {
|
||||
background: var(--aero-thumb);
|
||||
border-color: transparent;
|
||||
box-shadow: 0 1px 2px rgba(0, 20, 35, 0.3), inset 0 -1px 0 rgba(140, 185, 215, 0.4);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 9. Smaller glossy details */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="aero"] .mantine-Badge-root {
|
||||
background-image: var(--aero-gloss-soft);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Badge-root[data-variant="default"] {
|
||||
background-color: var(--mantine-color-default);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Alert-root {
|
||||
background-image: var(--aero-gloss-soft);
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Tabs-list {
|
||||
--tabs-list-border-color: var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Tabs-tab {
|
||||
font-weight: 700;
|
||||
border-radius: var(--mantine-radius-md) var(--mantine-radius-md) 0 0;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Tabs-tab:hover,
|
||||
[data-theme="aero"] .mantine-NavLink-root:hover {
|
||||
background-color: var(--mantine-color-default-hover);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-NavLink-root {
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Tooltip-tooltip {
|
||||
background-color: rgba(10, 45, 66, 0.92);
|
||||
color: #eaf7ff;
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-Divider-root {
|
||||
--divider-color: var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="aero"] ::selection {
|
||||
background: color-mix(in srgb, var(--mantine-primary-color-filled) 25%, transparent);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 10. App component hooks in Aero language */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Swipeable tab strip: flat when resting; the white-glass bar (3rd and
|
||||
last blur surface, docked state only — resting pays no blur cost) */
|
||||
[data-theme="aero"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--aero-chrome-bg);
|
||||
background-image: var(--aero-gloss-soft);
|
||||
border-bottom-color: var(--aero-panel-border);
|
||||
-webkit-backdrop-filter: blur(14px) saturate(150%);
|
||||
backdrop-filter: blur(14px) saturate(150%);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .flxn-tab {
|
||||
color: var(--mantine-color-dimmed);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Text rides on the glossy accent pill indicator below */
|
||||
[data-theme="aero"] .flxn-tab[data-active] {
|
||||
color: var(--flxn-on-accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="aero"] .flxn-tabs-indicator {
|
||||
border-bottom: none;
|
||||
border-radius: 999px;
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
background-image: var(--aero-gloss);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45), var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
/* Nav grid tiles: glass panels with the cards' top-half sheen */
|
||||
[data-theme="aero"] .flxn-tile {
|
||||
background-color: var(--aero-panel-bg);
|
||||
background-image: var(--aero-panel-sheen);
|
||||
border: 1px solid var(--aero-panel-border);
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
/* Flat accent-tinted glyph */
|
||||
[data-theme="aero"] .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* "See all" link: glossy accent mini pill */
|
||||
[data-theme="aero"] .flxn-see-all {
|
||||
border-radius: 999px;
|
||||
background-image: var(--aero-gloss-soft);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35);
|
||||
}
|
||||
|
||||
/* Match card + reaction tray read as one glass construction: same
|
||||
translucent border; tray is a subtler aqua-tinted glass, no sheen. */
|
||||
[data-theme="aero"] .flxn-match-card {
|
||||
background-color: var(--aero-panel-bg);
|
||||
background-image: var(--aero-panel-sheen);
|
||||
border: 1px solid var(--aero-panel-border);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .flxn-reaction-row {
|
||||
background-color: var(--aero-track);
|
||||
background-image: none;
|
||||
border: 1px solid var(--aero-panel-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
/* Glossy bezel: soft drop under the frame; the single ring itself comes
|
||||
from --flxn-avatar-border */
|
||||
[data-theme="aero"] .flxn-avatar-frame {
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 11. Fallbacks and reduced transparency */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
@supports not (backdrop-filter: blur(1px)) {
|
||||
[data-theme="aero"] .mantine-AppShell-header,
|
||||
[data-theme="aero"] .mantine-AppShell-navbar,
|
||||
[data-theme="aero"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--aero-solid);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-transparency: reduce) {
|
||||
[data-theme="aero"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--aero-panel-bg: #ffffff;
|
||||
--aero-panel-border: rgba(125, 178, 212, 0.55);
|
||||
--aero-chrome-bg: #f4fafe;
|
||||
--aero-input-bg: #ffffff;
|
||||
--aero-track: #d5e8f4;
|
||||
--aero-indicator-bg: #ffffff;
|
||||
--mantine-color-default: #ffffff;
|
||||
--mantine-color-default-hover: #e6f2fa;
|
||||
--flxn-showcase-bg: #ffffff;
|
||||
--flxn-podium-1-bg: #fdf3d2;
|
||||
--flxn-podium-2-bg: #f2f7fb;
|
||||
--flxn-podium-3-bg: #fbe8d8;
|
||||
--flxn-overlay: rgba(10, 45, 70, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="aero"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--aero-panel-bg: #0d2a3e;
|
||||
--aero-chrome-bg: #0a2536;
|
||||
--aero-input-bg: #061a28;
|
||||
--aero-track: #0a2334;
|
||||
--aero-indicator-bg: #1f648c;
|
||||
--mantine-color-default: #133a52;
|
||||
--mantine-color-default-hover: #1b4a66;
|
||||
--flxn-showcase-bg: #0d2a3e;
|
||||
--flxn-podium-1-bg: #23303a;
|
||||
--flxn-podium-2-bg: #1a2c39;
|
||||
--flxn-podium-3-bg: #222c36;
|
||||
--flxn-overlay: rgba(0, 8, 14, 0.75);
|
||||
}
|
||||
|
||||
[data-theme="aero"] .mantine-AppShell-header,
|
||||
[data-theme="aero"] .mantine-AppShell-navbar,
|
||||
[data-theme="aero"] .flxn-tabs[data-stuck] {
|
||||
-webkit-backdrop-filter: none;
|
||||
backdrop-filter: none;
|
||||
background-color: var(--aero-solid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* App-level semantic tokens; themes restyle them under [data-theme] scopes.
|
||||
No light-dark() in html-level declarations — postcss-preset-mantine
|
||||
rewrites it into a descendant selector that never matches <html>. Use
|
||||
explicit [data-mantine-color-scheme] blocks. */
|
||||
|
||||
:root {
|
||||
/* accolades */
|
||||
--flxn-gold: gold;
|
||||
--flxn-silver: var(--mantine-color-gray-5);
|
||||
--flxn-bronze: var(--mantine-color-orange-6);
|
||||
|
||||
/* toast icons */
|
||||
--flxn-toast-success: lightgreen;
|
||||
--flxn-toast-error: lightcoral;
|
||||
|
||||
/* surfaces & decoration */
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.4);
|
||||
--flxn-dotgrid-color: var(--mantine-color-default-border);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.3);
|
||||
--flxn-avatar-radius: 50%;
|
||||
--flxn-avatar-border: 1px solid var(--mantine-color-default-border);
|
||||
--flxn-badge-radius: 12px;
|
||||
|
||||
/* text on accent fills: black/white from the cascaded fill (oklch block
|
||||
below overrides this fallback) */
|
||||
--flxn-on-accent: var(--mantine-primary-color-contrast);
|
||||
|
||||
/* light-scheme values */
|
||||
--flxn-podium-1-bg: color-mix(in srgb, var(--mantine-color-yellow-4) 10%, var(--mantine-color-white));
|
||||
--flxn-podium-1-border: color-mix(in srgb, var(--mantine-color-yellow-6) 45%, var(--mantine-color-gray-3));
|
||||
--flxn-podium-1-label: var(--mantine-color-yellow-8);
|
||||
--flxn-podium-2-bg: color-mix(in srgb, var(--mantine-color-gray-5) 10%, var(--mantine-color-white));
|
||||
--flxn-podium-2-border: var(--mantine-color-gray-4);
|
||||
--flxn-podium-2-label: var(--mantine-color-gray-6);
|
||||
--flxn-podium-3-bg: color-mix(in srgb, var(--mantine-color-orange-5) 8%, var(--mantine-color-white));
|
||||
--flxn-podium-3-border: color-mix(in srgb, var(--mantine-color-orange-6) 35%, var(--mantine-color-gray-3));
|
||||
--flxn-podium-3-label: var(--mantine-color-orange-8);
|
||||
--flxn-showcase-bg: var(--mantine-color-white);
|
||||
}
|
||||
|
||||
:root[data-mantine-color-scheme="dark"] {
|
||||
--flxn-podium-1-bg: color-mix(in srgb, var(--mantine-color-yellow-8) 16%, var(--mantine-color-dark-6));
|
||||
--flxn-podium-1-border: color-mix(in srgb, var(--mantine-color-yellow-6) 35%, var(--mantine-color-dark-4));
|
||||
--flxn-podium-1-label: var(--mantine-color-yellow-4);
|
||||
--flxn-podium-2-bg: color-mix(in srgb, var(--mantine-color-gray-5) 10%, var(--mantine-color-dark-6));
|
||||
--flxn-podium-2-border: var(--mantine-color-dark-4);
|
||||
--flxn-podium-2-label: var(--mantine-color-gray-4);
|
||||
--flxn-podium-3-bg: color-mix(in srgb, var(--mantine-color-orange-9) 14%, var(--mantine-color-dark-6));
|
||||
--flxn-podium-3-border: color-mix(in srgb, var(--mantine-color-orange-7) 30%, var(--mantine-color-dark-4));
|
||||
--flxn-podium-3-label: var(--mantine-color-orange-4);
|
||||
--flxn-showcase-bg: var(--mantine-color-dark-7);
|
||||
}
|
||||
|
||||
@supports (color: oklch(from red calc(1 - 1) 0 h)) {
|
||||
:root {
|
||||
--flxn-on-accent: oklch(
|
||||
from var(--mantine-primary-color-filled) calc((0.6 - l) * infinity) 0 h
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "bauhaus",
|
||||
label: msg`Bauhaus`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Jost:ital,wght@0,100..900;1,100..900&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#f4f1ea", dimmed: "#93918a" },
|
||||
dark: { base: "#0d0d0d", dimmed: "#000000" },
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,725 @@
|
||||
/* Bauhaus — 1925 Dessau. Flat planes, 2px black rules, zero radius.
|
||||
Fixed decoration keeps the canonical triad (red #d42220 / blue #0050b3 /
|
||||
yellow #f4cc00); everything interactive follows the user's accent via the
|
||||
primary aliases, with all eight ramps retuned to poster-flat print hues. */
|
||||
|
||||
/* ---------- 1. Scheme-independent tokens ---------- */
|
||||
|
||||
[data-theme="bauhaus"][data-theme] {
|
||||
--bh-red: #d42220;
|
||||
--bh-blue: #0050b3;
|
||||
--bh-yellow: #f4cc00;
|
||||
|
||||
--mantine-font-family: "Jost", "Inter", sans-serif;
|
||||
--mantine-font-family-headings: "Jost", "Inter", sans-serif;
|
||||
--mantine-heading-font-weight: 700;
|
||||
--mantine-h1-font-weight: 800;
|
||||
--mantine-h2-font-weight: 800;
|
||||
--mantine-h3-font-weight: 700;
|
||||
|
||||
--mantine-radius-default: 0;
|
||||
--mantine-radius-xs: 0;
|
||||
--mantine-radius-sm: 0;
|
||||
--mantine-radius-md: 0;
|
||||
--mantine-radius-lg: 0;
|
||||
--mantine-radius-xl: 0;
|
||||
|
||||
--mantine-shadow-xs: none;
|
||||
--mantine-shadow-sm: none;
|
||||
--mantine-shadow-md: none;
|
||||
--mantine-shadow-lg: none;
|
||||
--mantine-shadow-xl: none;
|
||||
|
||||
--flxn-avatar-radius: 0;
|
||||
--flxn-avatar-border: 2px solid var(--bh-line);
|
||||
--flxn-badge-radius: 0;
|
||||
|
||||
/* poster-flat accent ramps (all eight) */
|
||||
--mantine-color-red-0: #fbe9e8;
|
||||
--mantine-color-red-1: #f6d0cf;
|
||||
--mantine-color-red-2: #efaba9;
|
||||
--mantine-color-red-3: #e77f7c;
|
||||
--mantine-color-red-4: #dd534f;
|
||||
--mantine-color-red-5: #d42220;
|
||||
--mantine-color-red-6: #c01e1c;
|
||||
--mantine-color-red-7: #a51a18;
|
||||
--mantine-color-red-8: #871512;
|
||||
--mantine-color-red-9: #66100e;
|
||||
|
||||
--mantine-color-blue-0: #e7f0fa;
|
||||
--mantine-color-blue-1: #c9dcf4;
|
||||
--mantine-color-blue-2: #9dc0ea;
|
||||
--mantine-color-blue-3: #6b9edd;
|
||||
--mantine-color-blue-4: #3675c9;
|
||||
--mantine-color-blue-5: #0050b3;
|
||||
--mantine-color-blue-6: #00479f;
|
||||
--mantine-color-blue-7: #003d88;
|
||||
--mantine-color-blue-8: #00316d;
|
||||
--mantine-color-blue-9: #002550;
|
||||
|
||||
--mantine-color-yellow-0: #fdf9e2;
|
||||
--mantine-color-yellow-1: #fbf1bb;
|
||||
--mantine-color-yellow-2: #f8e587;
|
||||
--mantine-color-yellow-3: #f6d94d;
|
||||
--mantine-color-yellow-4: #f5d121;
|
||||
--mantine-color-yellow-5: #f4cc00;
|
||||
--mantine-color-yellow-6: #dcb800;
|
||||
--mantine-color-yellow-7: #c0a000;
|
||||
--mantine-color-yellow-8: #a08600;
|
||||
--mantine-color-yellow-9: #7d6900;
|
||||
|
||||
--mantine-color-green-0: #e6f3ea;
|
||||
--mantine-color-green-1: #c5e3cf;
|
||||
--mantine-color-green-2: #97cca9;
|
||||
--mantine-color-green-3: #64b17e;
|
||||
--mantine-color-green-4: #349756;
|
||||
--mantine-color-green-5: #0f7f36;
|
||||
--mantine-color-green-6: #0d7230;
|
||||
--mantine-color-green-7: #0b6229;
|
||||
--mantine-color-green-8: #095021;
|
||||
--mantine-color-green-9: #063d19;
|
||||
|
||||
--mantine-color-grape-0: #f2eaf7;
|
||||
--mantine-color-grape-1: #e0cfec;
|
||||
--mantine-color-grape-2: #c6a8da;
|
||||
--mantine-color-grape-3: #a87cc4;
|
||||
--mantine-color-grape-4: #8952aa;
|
||||
--mantine-color-grape-5: #6a2c91;
|
||||
--mantine-color-grape-6: #5f2782;
|
||||
--mantine-color-grape-7: #522170;
|
||||
--mantine-color-grape-8: #431b5c;
|
||||
--mantine-color-grape-9: #331546;
|
||||
|
||||
--mantine-color-orange-0: #fdefe2;
|
||||
--mantine-color-orange-1: #fadcbd;
|
||||
--mantine-color-orange-2: #f6c28d;
|
||||
--mantine-color-orange-3: #f1a355;
|
||||
--mantine-color-orange-4: #ec8524;
|
||||
--mantine-color-orange-5: #e86a00;
|
||||
--mantine-color-orange-6: #d05f00;
|
||||
--mantine-color-orange-7: #b25100;
|
||||
--mantine-color-orange-8: #924300;
|
||||
--mantine-color-orange-9: #703300;
|
||||
|
||||
--mantine-color-pink-0: #fbe9f1;
|
||||
--mantine-color-pink-1: #f6cede;
|
||||
--mantine-color-pink-2: #efa5c3;
|
||||
--mantine-color-pink-3: #e675a2;
|
||||
--mantine-color-pink-4: #dd4784;
|
||||
--mantine-color-pink-5: #d6246e;
|
||||
--mantine-color-pink-6: #c02063;
|
||||
--mantine-color-pink-7: #a51b55;
|
||||
--mantine-color-pink-8: #871646;
|
||||
--mantine-color-pink-9: #661134;
|
||||
|
||||
--mantine-color-lime-0: #f4f7e3;
|
||||
--mantine-color-lime-1: #e6edbe;
|
||||
--mantine-color-lime-2: #d2df8d;
|
||||
--mantine-color-lime-3: #bccd55;
|
||||
--mantine-color-lime-4: #a5bd24;
|
||||
--mantine-color-lime-5: #8fae00;
|
||||
--mantine-color-lime-6: #819c00;
|
||||
--mantine-color-lime-7: #6f8700;
|
||||
--mantine-color-lime-8: #5c7000;
|
||||
--mantine-color-lime-9: #475600;
|
||||
}
|
||||
|
||||
/* ---------- 2. Per-scheme tokens ---------- */
|
||||
|
||||
[data-theme="bauhaus"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--bh-line: #000000;
|
||||
--bh-plane: #f4f1ea;
|
||||
--bh-ink: #000000;
|
||||
--bh-ink-contrast: #f4f1ea;
|
||||
--bh-focus: var(--mantine-primary-color-filled);
|
||||
--bh-tray: #eae6db;
|
||||
|
||||
--mantine-color-body: #f4f1ea;
|
||||
--mantine-color-text: #000000;
|
||||
--mantine-color-bright: #000000;
|
||||
--mantine-color-dimmed: #52504a;
|
||||
--mantine-color-placeholder: #6f6c64;
|
||||
--mantine-color-anchor: #0050b3;
|
||||
--mantine-color-error: #c01e1c;
|
||||
--mantine-color-default: #f4f1ea;
|
||||
--mantine-color-default-hover: #eae6db;
|
||||
--mantine-color-default-color: #000000;
|
||||
--mantine-color-default-border: #000000;
|
||||
|
||||
--mantine-color-red-filled: #d42220;
|
||||
--mantine-color-red-filled-hover: #b81d1b;
|
||||
--mantine-color-red-contrast: #ffffff;
|
||||
--mantine-color-red-light: rgba(212, 34, 32, 0.1);
|
||||
--mantine-color-red-light-hover: rgba(212, 34, 32, 0.16);
|
||||
--mantine-color-red-light-color: #b81d1b;
|
||||
--mantine-color-red-outline: #c01e1c;
|
||||
--mantine-color-red-outline-hover: rgba(212, 34, 32, 0.1);
|
||||
--mantine-color-red-text: #c01e1c;
|
||||
|
||||
--mantine-color-blue-filled: #0050b3;
|
||||
--mantine-color-blue-filled-hover: #00479f;
|
||||
--mantine-color-blue-contrast: #ffffff;
|
||||
--mantine-color-blue-light: rgba(0, 80, 179, 0.1);
|
||||
--mantine-color-blue-light-hover: rgba(0, 80, 179, 0.16);
|
||||
--mantine-color-blue-light-color: #0050b3;
|
||||
--mantine-color-blue-outline: #0050b3;
|
||||
--mantine-color-blue-outline-hover: rgba(0, 80, 179, 0.1);
|
||||
--mantine-color-blue-text: #0050b3;
|
||||
|
||||
--mantine-color-yellow-filled: #f4cc00;
|
||||
--mantine-color-yellow-filled-hover: #dcb800;
|
||||
--mantine-color-yellow-contrast: #000000;
|
||||
--mantine-color-yellow-light: rgba(244, 204, 0, 0.16);
|
||||
--mantine-color-yellow-light-hover: rgba(244, 204, 0, 0.26);
|
||||
--mantine-color-yellow-light-color: #8a7300;
|
||||
--mantine-color-yellow-outline: #8a7300;
|
||||
--mantine-color-yellow-outline-hover: rgba(244, 204, 0, 0.16);
|
||||
--mantine-color-yellow-text: #8a7300;
|
||||
|
||||
--mantine-color-green-filled: #0f7f36;
|
||||
--mantine-color-green-filled-hover: #0d7230;
|
||||
--mantine-color-green-contrast: #ffffff;
|
||||
--mantine-color-green-light: rgba(15, 127, 54, 0.1);
|
||||
--mantine-color-green-light-hover: rgba(15, 127, 54, 0.16);
|
||||
--mantine-color-green-light-color: #0b6229;
|
||||
--mantine-color-green-outline: #0d7230;
|
||||
--mantine-color-green-outline-hover: rgba(15, 127, 54, 0.1);
|
||||
--mantine-color-green-text: #0d7230;
|
||||
|
||||
--mantine-color-grape-filled: #6a2c91;
|
||||
--mantine-color-grape-filled-hover: #5f2782;
|
||||
--mantine-color-grape-contrast: #ffffff;
|
||||
--mantine-color-grape-light: rgba(106, 44, 145, 0.1);
|
||||
--mantine-color-grape-light-hover: rgba(106, 44, 145, 0.16);
|
||||
--mantine-color-grape-light-color: #5f2782;
|
||||
--mantine-color-grape-outline: #5f2782;
|
||||
--mantine-color-grape-outline-hover: rgba(106, 44, 145, 0.1);
|
||||
--mantine-color-grape-text: #5f2782;
|
||||
|
||||
--mantine-color-orange-filled: #e86a00;
|
||||
--mantine-color-orange-filled-hover: #d05f00;
|
||||
--mantine-color-orange-contrast: #000000;
|
||||
--mantine-color-orange-light: rgba(232, 106, 0, 0.12);
|
||||
--mantine-color-orange-light-hover: rgba(232, 106, 0, 0.18);
|
||||
--mantine-color-orange-light-color: #b25100;
|
||||
--mantine-color-orange-outline: #b25100;
|
||||
--mantine-color-orange-outline-hover: rgba(232, 106, 0, 0.12);
|
||||
--mantine-color-orange-text: #b25100;
|
||||
|
||||
--mantine-color-pink-filled: #d6246e;
|
||||
--mantine-color-pink-filled-hover: #c02063;
|
||||
--mantine-color-pink-contrast: #ffffff;
|
||||
--mantine-color-pink-light: rgba(214, 36, 110, 0.1);
|
||||
--mantine-color-pink-light-hover: rgba(214, 36, 110, 0.16);
|
||||
--mantine-color-pink-light-color: #c02063;
|
||||
--mantine-color-pink-outline: #c02063;
|
||||
--mantine-color-pink-outline-hover: rgba(214, 36, 110, 0.1);
|
||||
--mantine-color-pink-text: #c02063;
|
||||
|
||||
--mantine-color-lime-filled: #8fae00;
|
||||
--mantine-color-lime-filled-hover: #819c00;
|
||||
--mantine-color-lime-contrast: #000000;
|
||||
--mantine-color-lime-light: rgba(143, 174, 0, 0.14);
|
||||
--mantine-color-lime-light-hover: rgba(143, 174, 0, 0.22);
|
||||
--mantine-color-lime-light-color: #5c7000;
|
||||
--mantine-color-lime-outline: #5c7000;
|
||||
--mantine-color-lime-outline-hover: rgba(143, 174, 0, 0.14);
|
||||
--mantine-color-lime-text: #5c7000;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #d9b500;
|
||||
--flxn-silver: #8d8a80;
|
||||
--flxn-bronze: #a05a2c;
|
||||
--flxn-toast-success: #2b8a3e;
|
||||
--flxn-toast-error: #c01e1c;
|
||||
--flxn-podium-1-bg: #f4cc00;
|
||||
--flxn-podium-1-border: #000000;
|
||||
--flxn-podium-1-label: #000000;
|
||||
--flxn-podium-2-bg: #c9dcf4;
|
||||
--flxn-podium-2-border: #000000;
|
||||
--flxn-podium-2-label: #003d88;
|
||||
--flxn-podium-3-bg: #f6d0cf;
|
||||
--flxn-podium-3-border: #000000;
|
||||
--flxn-podium-3-label: #a51a18;
|
||||
--flxn-showcase-bg: #faf8f2;
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.5);
|
||||
--flxn-dotgrid-color: rgba(0, 0, 0, 0.18);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--bh-line: #f4f1ea;
|
||||
--bh-plane: #0d0d0d;
|
||||
--bh-ink: #f4f1ea;
|
||||
--bh-ink-contrast: #000000;
|
||||
--bh-focus: var(--mantine-primary-color-4);
|
||||
--bh-tray: #1d1c19;
|
||||
|
||||
--mantine-color-body: #0d0d0d;
|
||||
--mantine-color-text: #f4f1ea;
|
||||
--mantine-color-bright: #ffffff;
|
||||
--mantine-color-dimmed: #a5a196;
|
||||
--mantine-color-placeholder: #8b877c;
|
||||
--mantine-color-anchor: #7fb0e8;
|
||||
--mantine-color-error: #ef6b64;
|
||||
--mantine-color-default: #0d0d0d;
|
||||
--mantine-color-default-hover: #1d1c19;
|
||||
--mantine-color-default-color: #f4f1ea;
|
||||
--mantine-color-default-border: #f4f1ea;
|
||||
|
||||
--mantine-color-red-filled: #d42220;
|
||||
--mantine-color-red-filled-hover: #b81d1b;
|
||||
--mantine-color-red-contrast: #ffffff;
|
||||
--mantine-color-red-light: rgba(229, 83, 79, 0.16);
|
||||
--mantine-color-red-light-hover: rgba(229, 83, 79, 0.24);
|
||||
--mantine-color-red-light-color: #f08984;
|
||||
--mantine-color-red-outline: #ef6b64;
|
||||
--mantine-color-red-outline-hover: rgba(229, 83, 79, 0.16);
|
||||
--mantine-color-red-text: #ef6b64;
|
||||
|
||||
--mantine-color-blue-filled: #0050b3;
|
||||
--mantine-color-blue-filled-hover: #00479f;
|
||||
--mantine-color-blue-contrast: #ffffff;
|
||||
--mantine-color-blue-light: rgba(107, 158, 221, 0.16);
|
||||
--mantine-color-blue-light-hover: rgba(107, 158, 221, 0.24);
|
||||
--mantine-color-blue-light-color: #9dc0ea;
|
||||
--mantine-color-blue-outline: #7fb0e8;
|
||||
--mantine-color-blue-outline-hover: rgba(107, 158, 221, 0.16);
|
||||
--mantine-color-blue-text: #7fb0e8;
|
||||
|
||||
--mantine-color-yellow-filled: #f4cc00;
|
||||
--mantine-color-yellow-filled-hover: #dcb800;
|
||||
--mantine-color-yellow-contrast: #000000;
|
||||
--mantine-color-yellow-light: rgba(244, 204, 0, 0.14);
|
||||
--mantine-color-yellow-light-hover: rgba(244, 204, 0, 0.22);
|
||||
--mantine-color-yellow-light-color: #f4cc00;
|
||||
--mantine-color-yellow-outline: #f4cc00;
|
||||
--mantine-color-yellow-outline-hover: rgba(244, 204, 0, 0.14);
|
||||
--mantine-color-yellow-text: #f4cc00;
|
||||
|
||||
--mantine-color-green-filled: #0f7f36;
|
||||
--mantine-color-green-filled-hover: #0d7230;
|
||||
--mantine-color-green-contrast: #ffffff;
|
||||
--mantine-color-green-light: rgba(100, 177, 126, 0.16);
|
||||
--mantine-color-green-light-hover: rgba(100, 177, 126, 0.24);
|
||||
--mantine-color-green-light-color: #97cca9;
|
||||
--mantine-color-green-outline: #64b17e;
|
||||
--mantine-color-green-outline-hover: rgba(100, 177, 126, 0.16);
|
||||
--mantine-color-green-text: #64b17e;
|
||||
|
||||
--mantine-color-grape-filled: #6a2c91;
|
||||
--mantine-color-grape-filled-hover: #5f2782;
|
||||
--mantine-color-grape-contrast: #ffffff;
|
||||
--mantine-color-grape-light: rgba(168, 124, 196, 0.16);
|
||||
--mantine-color-grape-light-hover: rgba(168, 124, 196, 0.24);
|
||||
--mantine-color-grape-light-color: #c6a8da;
|
||||
--mantine-color-grape-outline: #a87cc4;
|
||||
--mantine-color-grape-outline-hover: rgba(168, 124, 196, 0.16);
|
||||
--mantine-color-grape-text: #a87cc4;
|
||||
|
||||
--mantine-color-orange-filled: #e86a00;
|
||||
--mantine-color-orange-filled-hover: #d05f00;
|
||||
--mantine-color-orange-contrast: #000000;
|
||||
--mantine-color-orange-light: rgba(241, 163, 85, 0.16);
|
||||
--mantine-color-orange-light-hover: rgba(241, 163, 85, 0.24);
|
||||
--mantine-color-orange-light-color: #f6c28d;
|
||||
--mantine-color-orange-outline: #f1a355;
|
||||
--mantine-color-orange-outline-hover: rgba(241, 163, 85, 0.16);
|
||||
--mantine-color-orange-text: #f1a355;
|
||||
|
||||
--mantine-color-pink-filled: #d6246e;
|
||||
--mantine-color-pink-filled-hover: #c02063;
|
||||
--mantine-color-pink-contrast: #ffffff;
|
||||
--mantine-color-pink-light: rgba(230, 117, 162, 0.16);
|
||||
--mantine-color-pink-light-hover: rgba(230, 117, 162, 0.24);
|
||||
--mantine-color-pink-light-color: #efa5c3;
|
||||
--mantine-color-pink-outline: #e675a2;
|
||||
--mantine-color-pink-outline-hover: rgba(230, 117, 162, 0.16);
|
||||
--mantine-color-pink-text: #e675a2;
|
||||
|
||||
--mantine-color-lime-filled: #8fae00;
|
||||
--mantine-color-lime-filled-hover: #819c00;
|
||||
--mantine-color-lime-contrast: #000000;
|
||||
--mantine-color-lime-light: rgba(165, 189, 36, 0.16);
|
||||
--mantine-color-lime-light-hover: rgba(165, 189, 36, 0.24);
|
||||
--mantine-color-lime-light-color: #bccd55;
|
||||
--mantine-color-lime-outline: #a5bd24;
|
||||
--mantine-color-lime-outline-hover: rgba(165, 189, 36, 0.16);
|
||||
--mantine-color-lime-text: #a5bd24;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #f4cc00;
|
||||
--flxn-silver: #a5a196;
|
||||
--flxn-bronze: #d08048;
|
||||
--flxn-toast-success: #51cf66;
|
||||
--flxn-toast-error: #ef6b64;
|
||||
--flxn-podium-1-bg: #332b00;
|
||||
--flxn-podium-1-border: #f4cc00;
|
||||
--flxn-podium-1-label: #f4cc00;
|
||||
--flxn-podium-2-bg: #001a38;
|
||||
--flxn-podium-2-border: #6b9edd;
|
||||
--flxn-podium-2-label: #9dc0ea;
|
||||
--flxn-podium-3-bg: #380b0a;
|
||||
--flxn-podium-3-border: #e5534f;
|
||||
--flxn-podium-3-label: #f08984;
|
||||
--flxn-showcase-bg: #000000;
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.65);
|
||||
--flxn-dotgrid-color: rgba(244, 241, 234, 0.18);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Without JS autoContrast, Mantine pins --mantine-primary-color-contrast to
|
||||
white, which is unreadable on the light fills (yellow/orange/lime).
|
||||
Recompute it from the accent fill's own lightness: below 0.62 OKLCH-L
|
||||
gets white text, above gets black — matches the per-color -contrast
|
||||
values declared above for all eight accents. */
|
||||
@supports (color: oklch(from red calc((0.5 - l) * infinity) 0 h)) {
|
||||
[data-theme="bauhaus"][data-theme][data-mantine-color-scheme] {
|
||||
--mantine-primary-color-contrast: oklch(
|
||||
from var(--mantine-primary-color-filled) calc((0.62 - l) * infinity) 0 h
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 3. Structure: planes bounded by rules, never shadows ---------- */
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Paper-root {
|
||||
background-color: var(--bh-plane);
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"] .mantine-AppShell-root {
|
||||
--app-shell-border-color: var(--bh-line);
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-AppShell-header {
|
||||
background-color: var(--mantine-color-body);
|
||||
border-bottom: 2px solid var(--bh-line);
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-AppShell-navbar {
|
||||
background-color: var(--mantine-color-body);
|
||||
border-inline-end: 2px solid var(--bh-line);
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Divider-root {
|
||||
--divider-color: var(--bh-line);
|
||||
--divider-size: 3px;
|
||||
}
|
||||
|
||||
/* ---------- 4. Type: uppercase, widely-tracked functional labels ---------- */
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Button-root {
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
[data-theme="bauhaus"]
|
||||
.mantine-Button-root:where(
|
||||
[data-variant="filled"],
|
||||
[data-variant="default"],
|
||||
[data-variant="outline"],
|
||||
[data-variant="light"],
|
||||
[data-variant="white"]
|
||||
) {
|
||||
border: 2px solid var(--bh-line);
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"] .mantine-ActionIcon-root {
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="bauhaus"]
|
||||
.mantine-ActionIcon-root:where(
|
||||
[data-variant="filled"],
|
||||
[data-variant="default"],
|
||||
[data-variant="outline"],
|
||||
[data-variant="light"],
|
||||
[data-variant="white"]
|
||||
) {
|
||||
border: 2px solid var(--bh-line);
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"] .mantine-InputWrapper-label {
|
||||
font-size: var(--mantine-font-size-xs);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Badge-root {
|
||||
border-radius: 0;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
/* ---------- 5. Inputs ---------- */
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Input-input {
|
||||
background-color: var(--bh-plane);
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Input-input:focus,
|
||||
[data-theme="bauhaus"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--bh-focus);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Checkbox-input {
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Radio-radio {
|
||||
border: 2px solid var(--bh-line);
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Switch-track {
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Switch-thumb {
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ---------- 6. Tabs & SegmentedControl: black-line constructions ---------- */
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Tabs-list::before {
|
||||
border-color: var(--bh-line);
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Tabs-tab {
|
||||
border-radius: 0;
|
||||
border-width: 2px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Tabs-tab[data-active] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-color: var(--bh-line);
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"] .mantine-SegmentedControl-root {
|
||||
background-color: transparent;
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-SegmentedControl-label {
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-SegmentedControl-label[data-active],
|
||||
[data-theme="bauhaus"]
|
||||
.mantine-SegmentedControl-control[data-active]
|
||||
.mantine-SegmentedControl-label {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
/* Accent-fill on-colors: Mantine hardcodes white text on filled variants,
|
||||
selected combobox options and check glyphs; pair them with the accent's
|
||||
contrast color so yellow/orange/lime accents stay legible. */
|
||||
[data-theme="bauhaus"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="bauhaus"] .mantine-Button-root:not([data-variant]),
|
||||
[data-theme="bauhaus"] .mantine-ActionIcon-root[data-variant="filled"],
|
||||
[data-theme="bauhaus"] .mantine-ActionIcon-root:not([data-variant]),
|
||||
[data-theme="bauhaus"] .mantine-Badge-root[data-variant="filled"],
|
||||
[data-theme="bauhaus"] .mantine-Badge-root:not([data-variant]),
|
||||
[data-theme="bauhaus"] .mantine-ThemeIcon-root[data-variant="filled"],
|
||||
[data-theme="bauhaus"] .mantine-ThemeIcon-root:not([data-variant]) {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
[data-theme="bauhaus"] [data-combobox-selected] {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Checkbox-root {
|
||||
--checkbox-icon-color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Radio-root {
|
||||
--radio-icon-color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
/* ---------- 7. Overlays & feedback surfaces ---------- */
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Modal-content {
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Modal-header {
|
||||
border-bottom: 2px solid var(--bh-line);
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Popover-dropdown {
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Tooltip-tooltip {
|
||||
background-color: var(--bh-ink);
|
||||
border-radius: 0;
|
||||
color: var(--bh-ink-contrast);
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Notification-root {
|
||||
background-color: var(--bh-plane);
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Alert-root {
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
[data-theme="bauhaus"] .mantine-Progress-root {
|
||||
background-color: transparent;
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Progress-section {
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Indicator-indicator {
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-ThemeIcon-root {
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* strict square avatars: frame and content square together */
|
||||
[data-theme="bauhaus"] .mantine-Avatar-root {
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .mantine-Avatar-image,
|
||||
[data-theme="bauhaus"] .mantine-Avatar-placeholder {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ---------- 8. App component hooks ---------- */
|
||||
|
||||
/* Tab strip: flat while resting (2px transparent rule keeps height stable);
|
||||
docked gets the black under-rule. Active tab is a solid accent block. */
|
||||
[data-theme="bauhaus"] .flxn-tabs {
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
[data-theme="bauhaus"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--mantine-color-body);
|
||||
border-bottom-color: var(--bh-line);
|
||||
}
|
||||
[data-theme="bauhaus"] .flxn-tab {
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="bauhaus"] .flxn-tab[data-active] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: var(--flxn-on-accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
[data-theme="bauhaus"] .flxn-tabs-indicator {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Nav grid tiles: 2px-ruled flat planes */
|
||||
[data-theme="bauhaus"] .flxn-tile {
|
||||
background-color: var(--bh-plane);
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="bauhaus"] .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
/* "See all" chip: flat, bordered, uppercase tracked */
|
||||
[data-theme="bauhaus"] .flxn-see-all {
|
||||
background-color: var(--bh-plane);
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
color: var(--bh-ink);
|
||||
font-size: var(--mantine-font-size-xs);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
[data-theme="bauhaus"] .flxn-see-all:hover {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--bh-ink);
|
||||
}
|
||||
}
|
||||
|
||||
/* Match card + reaction tray: one construction, same 2px rules, flat fill */
|
||||
[data-theme="bauhaus"] .flxn-match-card {
|
||||
background-color: var(--bh-plane);
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="bauhaus"] .flxn-reaction-row {
|
||||
background-color: var(--bh-tray);
|
||||
border: 2px solid var(--bh-line);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ---------- 9. Geometric heading marks: circle / square / triangle ---------- */
|
||||
|
||||
[data-theme="bauhaus"] h1.mantine-Title-root::before,
|
||||
[data-theme="bauhaus"] h2.mantine-Title-root::before,
|
||||
[data-theme="bauhaus"] h3.mantine-Title-root::before,
|
||||
[data-theme="bauhaus"] h4.mantine-Title-root::before,
|
||||
[data-theme="bauhaus"] h5.mantine-Title-root::before,
|
||||
[data-theme="bauhaus"] h6.mantine-Title-root::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 0.5em;
|
||||
height: 0.5em;
|
||||
margin-inline-end: 0.45em;
|
||||
vertical-align: 0.06em;
|
||||
}
|
||||
[data-theme="bauhaus"] h1.mantine-Title-root::before {
|
||||
background-color: var(--bh-blue);
|
||||
border-radius: 50%;
|
||||
}
|
||||
[data-theme="bauhaus"] h2.mantine-Title-root::before {
|
||||
background-color: var(--bh-red);
|
||||
}
|
||||
[data-theme="bauhaus"] h3.mantine-Title-root::before {
|
||||
background-color: var(--bh-yellow);
|
||||
clip-path: polygon(50% 0, 100% 100%, 0 100%);
|
||||
}
|
||||
[data-theme="bauhaus"] h4.mantine-Title-root::before {
|
||||
background-color: var(--bh-red);
|
||||
border-radius: 50%;
|
||||
}
|
||||
[data-theme="bauhaus"] h5.mantine-Title-root::before {
|
||||
background-color: var(--bh-yellow);
|
||||
}
|
||||
[data-theme="bauhaus"] h6.mantine-Title-root::before {
|
||||
background-color: var(--bh-blue);
|
||||
clip-path: polygon(50% 0, 100% 100%, 0 100%);
|
||||
}
|
||||
|
||||
/* ---------- 10. Press feedback: mechanical, not springy ---------- */
|
||||
|
||||
[data-theme="bauhaus"]
|
||||
.flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transform: translateY(2px);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
[data-theme="bauhaus"]
|
||||
.flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "brutal",
|
||||
label: msg`Brutal`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Archivo+Black&family=Space+Grotesk:wght@400;500;600;700&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#f5f2ea", dimmed: "#e6e1d1" },
|
||||
dark: { base: "#111111", dimmed: "#000000" },
|
||||
},
|
||||
mantine: {
|
||||
// Light acid accents (yellow/lime) must flip filled text to dark ink.
|
||||
autoContrast: true,
|
||||
defaultRadius: 0,
|
||||
fontFamily: '"Space Grotesk", "Inter", sans-serif',
|
||||
headings: {
|
||||
fontFamily: '"Archivo Black", "League Spartan", sans-serif',
|
||||
fontWeight: "400",
|
||||
},
|
||||
components: {
|
||||
Loader: { defaultProps: { type: "bars" } },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,645 @@
|
||||
/* Neobrutalist theme: flat surfaces, zero radius, 3px ink borders, hard
|
||||
offset shadows. Ink is #000 in light and pale off-white in dark. Acid
|
||||
yellow is pure decoration (selection, hover flashes, podium gold); all
|
||||
accent/active/focus styling follows the user's chosen primary color via
|
||||
loud retuned ramps. */
|
||||
|
||||
/* ---------- 1. Scheme-independent tokens ---------- */
|
||||
|
||||
[data-theme="brutal"][data-theme] {
|
||||
--brutal-yellow: #ffde59;
|
||||
|
||||
--mantine-font-family: "Space Grotesk", "Inter", sans-serif;
|
||||
--mantine-font-family-headings: "Archivo Black", "League Spartan", sans-serif;
|
||||
--mantine-heading-font-weight: 400;
|
||||
--mantine-h1-font-weight: 400;
|
||||
--mantine-h2-font-weight: 400;
|
||||
--mantine-h3-font-weight: 400;
|
||||
--mantine-h4-font-weight: 400;
|
||||
--mantine-h5-font-weight: 400;
|
||||
--mantine-h6-font-weight: 400;
|
||||
|
||||
--mantine-radius-default: 0;
|
||||
--mantine-radius-xs: 0;
|
||||
--mantine-radius-sm: 0;
|
||||
--mantine-radius-md: 0;
|
||||
--mantine-radius-lg: 0;
|
||||
--mantine-radius-xl: 0;
|
||||
|
||||
--mantine-shadow-xs: 3px 3px 0 0 var(--brutal-ink, #000);
|
||||
--mantine-shadow-sm: 5px 5px 0 0 var(--brutal-ink, #000);
|
||||
--mantine-shadow-md: 6px 6px 0 0 var(--brutal-ink, #000);
|
||||
--mantine-shadow-lg: 8px 8px 0 0 var(--brutal-ink, #000);
|
||||
--mantine-shadow-xl: 10px 10px 0 0 var(--brutal-ink, #000);
|
||||
|
||||
--flxn-gold: var(--brutal-yellow);
|
||||
--flxn-pop-shadow: var(--brutal-ink, #000);
|
||||
--flxn-avatar-radius: 0;
|
||||
--flxn-avatar-border: 3px solid var(--brutal-ink, #000);
|
||||
--flxn-badge-radius: 0;
|
||||
|
||||
/* Accent ramps retuned flat and loud, borderline fluorescent. Shade 6
|
||||
(light filled) and shade 8 (dark filled) keep the same light/dark
|
||||
polarity as Mantine's defaults so autoContrast text stays legible. */
|
||||
--mantine-color-blue-0: #e6eeff;
|
||||
--mantine-color-blue-1: #c2d4ff;
|
||||
--mantine-color-blue-2: #99b8ff;
|
||||
--mantine-color-blue-3: #5c8aff;
|
||||
--mantine-color-blue-4: #2e66ff;
|
||||
--mantine-color-blue-5: #1a5eff;
|
||||
--mantine-color-blue-6: #0047ff;
|
||||
--mantine-color-blue-7: #003ae6;
|
||||
--mantine-color-blue-8: #0033cc;
|
||||
--mantine-color-blue-9: #002699;
|
||||
|
||||
--mantine-color-red-0: #ffe8e8;
|
||||
--mantine-color-red-1: #ffc9c9;
|
||||
--mantine-color-red-2: #ffa8a8;
|
||||
--mantine-color-red-3: #ff7a7a;
|
||||
--mantine-color-red-4: #ff5252;
|
||||
--mantine-color-red-5: #ff2b2b;
|
||||
--mantine-color-red-6: #f01e1e;
|
||||
--mantine-color-red-7: #d61414;
|
||||
--mantine-color-red-8: #c00d0d;
|
||||
--mantine-color-red-9: #8f0707;
|
||||
|
||||
--mantine-color-green-0: #e4ffe9;
|
||||
--mantine-color-green-1: #c0ffcf;
|
||||
--mantine-color-green-2: #8fffab;
|
||||
--mantine-color-green-3: #4dff85;
|
||||
--mantine-color-green-4: #1af06a;
|
||||
--mantine-color-green-5: #0ae862;
|
||||
--mantine-color-green-6: #00e05c;
|
||||
--mantine-color-green-7: #00b34a;
|
||||
--mantine-color-green-8: #0a8a3c;
|
||||
--mantine-color-green-9: #056629;
|
||||
|
||||
--mantine-color-yellow-0: #fff9db;
|
||||
--mantine-color-yellow-1: #fff0a8;
|
||||
--mantine-color-yellow-2: #ffe770;
|
||||
--mantine-color-yellow-3: #ffde59;
|
||||
--mantine-color-yellow-4: #ffd83d;
|
||||
--mantine-color-yellow-5: #ffd61f;
|
||||
--mantine-color-yellow-6: #ffd400;
|
||||
--mantine-color-yellow-7: #f5c400;
|
||||
--mantine-color-yellow-8: #f0b800;
|
||||
--mantine-color-yellow-9: #cc9900;
|
||||
|
||||
--mantine-color-grape-0: #fbe7ff;
|
||||
--mantine-color-grape-1: #f3c6ff;
|
||||
--mantine-color-grape-2: #ea9dff;
|
||||
--mantine-color-grape-3: #dd6bff;
|
||||
--mantine-color-grape-4: #cf47f2;
|
||||
--mantine-color-grape-5: #c437e9;
|
||||
--mantine-color-grape-6: #b829e0;
|
||||
--mantine-color-grape-7: #a21ec7;
|
||||
--mantine-color-grape-8: #8c14ad;
|
||||
--mantine-color-grape-9: #6b0c85;
|
||||
|
||||
--mantine-color-orange-0: #fff0e0;
|
||||
--mantine-color-orange-1: #ffddb8;
|
||||
--mantine-color-orange-2: #ffc78a;
|
||||
--mantine-color-orange-3: #ffab52;
|
||||
--mantine-color-orange-4: #ff9a2e;
|
||||
--mantine-color-orange-5: #ff9114;
|
||||
--mantine-color-orange-6: #ff8800;
|
||||
--mantine-color-orange-7: #f07300;
|
||||
--mantine-color-orange-8: #c95400;
|
||||
--mantine-color-orange-9: #9a4000;
|
||||
|
||||
--mantine-color-pink-0: #ffe6f1;
|
||||
--mantine-color-pink-1: #ffc2dd;
|
||||
--mantine-color-pink-2: #ff99c6;
|
||||
--mantine-color-pink-3: #ff66aa;
|
||||
--mantine-color-pink-4: #ff4796;
|
||||
--mantine-color-pink-5: #ff2e88;
|
||||
--mantine-color-pink-6: #f21578;
|
||||
--mantine-color-pink-7: #d80d67;
|
||||
--mantine-color-pink-8: #bd0857;
|
||||
--mantine-color-pink-9: #8f0642;
|
||||
|
||||
--mantine-color-lime-0: #f6ffdb;
|
||||
--mantine-color-lime-1: #eaffad;
|
||||
--mantine-color-lime-2: #dcff7a;
|
||||
--mantine-color-lime-3: #c8ff42;
|
||||
--mantine-color-lime-4: #b8fa1e;
|
||||
--mantine-color-lime-5: #aff50f;
|
||||
--mantine-color-lime-6: #a6f000;
|
||||
--mantine-color-lime-7: #99e000;
|
||||
--mantine-color-lime-8: #8ccc00;
|
||||
--mantine-color-lime-9: #6fa300;
|
||||
}
|
||||
|
||||
/* ---------- 2. Per-scheme tokens ---------- */
|
||||
|
||||
[data-theme="brutal"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--brutal-ink: #000000;
|
||||
--brutal-focus: var(--mantine-primary-color-filled);
|
||||
|
||||
--mantine-color-body: #f5f2ea;
|
||||
--mantine-color-text: #111111;
|
||||
--mantine-color-bright: #000000;
|
||||
--mantine-color-dimmed: #575145;
|
||||
--mantine-color-placeholder: #6b6557;
|
||||
/* shade 8, not 6: fluorescent accents (yellow/lime/green) are unreadable
|
||||
as link text on the light body at shade 6 */
|
||||
--mantine-color-anchor: var(--mantine-primary-color-8);
|
||||
--mantine-color-error: #d90429;
|
||||
--mantine-color-default: #f5f2ea;
|
||||
--mantine-color-default-hover: var(--brutal-yellow);
|
||||
--mantine-color-default-color: #111111;
|
||||
--mantine-color-default-border: #000000;
|
||||
|
||||
--flxn-silver: #767066;
|
||||
--flxn-bronze: #b45f06;
|
||||
--flxn-toast-success: #087f2c;
|
||||
--flxn-toast-error: #d90429;
|
||||
--flxn-podium-1-bg: var(--brutal-yellow);
|
||||
--flxn-podium-1-border: #000000;
|
||||
--flxn-podium-1-label: #111111;
|
||||
--flxn-podium-2-bg: #d9d4c6;
|
||||
--flxn-podium-2-border: #000000;
|
||||
--flxn-podium-2-label: #111111;
|
||||
--flxn-podium-3-bg: #ff9d5c;
|
||||
--flxn-podium-3-border: #000000;
|
||||
--flxn-podium-3-label: #111111;
|
||||
--flxn-showcase-bg: #fffdf5;
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.5);
|
||||
--flxn-dotgrid-color: rgba(0, 0, 0, 0.22);
|
||||
}
|
||||
|
||||
[data-theme="brutal"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--brutal-ink: #ece7da;
|
||||
--brutal-focus: var(--mantine-primary-color-4);
|
||||
|
||||
--mantine-color-body: #111111;
|
||||
--mantine-color-text: #f5f2ea;
|
||||
--mantine-color-bright: #ffffff;
|
||||
--mantine-color-dimmed: #a39d8c;
|
||||
--mantine-color-placeholder: #9a947f;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-4);
|
||||
--mantine-color-error: #ff4d6d;
|
||||
--mantine-color-default: #111111;
|
||||
--mantine-color-default-hover: #26241c;
|
||||
--mantine-color-default-color: #f5f2ea;
|
||||
--mantine-color-default-border: #ece7da;
|
||||
|
||||
--flxn-silver: #b8b2a4;
|
||||
--flxn-bronze: #e08e45;
|
||||
--flxn-toast-success: #3ddc73;
|
||||
--flxn-toast-error: #ff4d6d;
|
||||
--flxn-podium-1-bg: #292110;
|
||||
--flxn-podium-1-border: var(--brutal-yellow);
|
||||
--flxn-podium-1-label: var(--brutal-yellow);
|
||||
--flxn-podium-2-bg: #21201b;
|
||||
--flxn-podium-2-border: #b8b2a4;
|
||||
--flxn-podium-2-label: #cfc9bb;
|
||||
--flxn-podium-3-bg: #271a10;
|
||||
--flxn-podium-3-border: #e08e45;
|
||||
--flxn-podium-3-label: #ffb47a;
|
||||
--flxn-showcase-bg: #191813;
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.65);
|
||||
--flxn-dotgrid-color: rgba(236, 231, 218, 0.16);
|
||||
--flxn-pop-shadow: rgba(236, 231, 218, 0.55);
|
||||
}
|
||||
|
||||
/* ---------- 3. Type ---------- */
|
||||
|
||||
[data-theme="brutal"] :is(h1, h2, h3, h4, h5, h6) {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Title-root {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] *::selection {
|
||||
background: var(--brutal-yellow);
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] *:focus-visible:not(.mantine-Input-input) {
|
||||
outline: 3px solid var(--brutal-focus);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Anchor-root {
|
||||
font-weight: 600;
|
||||
text-decoration-thickness: 2px;
|
||||
text-underline-offset: 2px;
|
||||
}
|
||||
|
||||
/* ---------- 4. Press feedback: slide into the shadow ---------- */
|
||||
|
||||
[data-theme="brutal"] .flxn-press {
|
||||
transition:
|
||||
transform 100ms cubic-bezier(0.32, 0.72, 0, 1),
|
||||
box-shadow 100ms cubic-bezier(0.32, 0.72, 0, 1);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transform: translate(4px, 4px);
|
||||
box-shadow: 0 0 0 0 var(--brutal-ink);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
[data-theme="brutal"] .flxn-press,
|
||||
[data-theme="brutal"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transition: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 5. Buttons & ActionIcons ---------- */
|
||||
|
||||
[data-theme="brutal"] .mantine-Button-root {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
box-shadow: 4px 4px 0 0 var(--brutal-ink);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Button-root[data-variant="gradient"] {
|
||||
background: var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-ActionIcon-root {
|
||||
border: 2px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
box-shadow: 3px 3px 0 0 var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Button-root[data-variant="subtle"],
|
||||
[data-theme="brutal"] .mantine-Button-root[data-variant="transparent"],
|
||||
[data-theme="brutal"] .mantine-ActionIcon-root[data-variant="subtle"],
|
||||
[data-theme="brutal"] .mantine-ActionIcon-root[data-variant="transparent"] {
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Button-root:disabled,
|
||||
[data-theme="brutal"] .mantine-Button-root[data-disabled],
|
||||
[data-theme="brutal"] .mantine-ActionIcon-root:disabled,
|
||||
[data-theme="brutal"] .mantine-ActionIcon-root[data-disabled] {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-CloseButton-root {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ---------- 6. Surfaces: Paper, Card, Modal, Drawer, dropdowns ---------- */
|
||||
|
||||
[data-theme="brutal"] .mantine-Paper-root {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Card-root {
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
background: var(--flxn-showcase-bg);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Modal-content,
|
||||
[data-theme="brutal"] .mantine-Drawer-content {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
box-shadow: var(--mantine-shadow-lg);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Modal-header {
|
||||
background: var(--mantine-color-body);
|
||||
border-bottom: 3px solid var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Modal-title {
|
||||
font-family: var(--mantine-font-family-headings);
|
||||
text-transform: uppercase;
|
||||
font-size: var(--mantine-font-size-lg);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Popover-dropdown,
|
||||
[data-theme="brutal"] .mantine-Combobox-dropdown,
|
||||
[data-theme="brutal"] .mantine-Menu-dropdown {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Menu-item,
|
||||
[data-theme="brutal"] .mantine-Combobox-option {
|
||||
border-radius: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Hover flash stays decorative acid yellow; the SELECTED option is the
|
||||
accent and follows the user's primary color. */
|
||||
[data-theme="brutal"] .mantine-Menu-item:hover,
|
||||
[data-theme="brutal"] .mantine-Menu-item[data-hovered],
|
||||
[data-theme="brutal"] .mantine-Combobox-option:hover {
|
||||
background: var(--brutal-yellow);
|
||||
color: #111111;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Combobox-option[data-combobox-selected] {
|
||||
background: var(--mantine-primary-color-filled);
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Tooltip-tooltip {
|
||||
border-radius: 0;
|
||||
background: var(--brutal-ink);
|
||||
color: var(--mantine-color-body);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ---------- 7. Inputs ---------- */
|
||||
|
||||
[data-theme="brutal"] .mantine-Input-input {
|
||||
border-width: 3px;
|
||||
border-style: solid;
|
||||
border-color: var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
background: var(--mantine-color-body);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Input-input:focus,
|
||||
[data-theme="brutal"] .mantine-Input-input:focus-within {
|
||||
outline: none;
|
||||
border-color: var(--brutal-ink);
|
||||
box-shadow: 4px 4px 0 0 var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Input-input[data-error] {
|
||||
border-color: var(--mantine-color-error);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] :is(
|
||||
.mantine-TextInput-label,
|
||||
.mantine-Textarea-label,
|
||||
.mantine-NumberInput-label,
|
||||
.mantine-PasswordInput-label,
|
||||
.mantine-Select-label,
|
||||
.mantine-Autocomplete-label,
|
||||
.mantine-MultiSelect-label,
|
||||
.mantine-DateTimePicker-label,
|
||||
.mantine-DatePickerInput-label,
|
||||
.mantine-PinInput-label
|
||||
) {
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
/* ---------- 8. Badges, indicators, avatars, icons ---------- */
|
||||
|
||||
[data-theme="brutal"] .mantine-Badge-root {
|
||||
border: 2px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
box-shadow: 2px 2px 0 0 var(--brutal-ink);
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Indicator-indicator {
|
||||
border-radius: 0;
|
||||
border: 2px solid var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-ThemeIcon-root {
|
||||
border-radius: 0;
|
||||
border: 2px solid var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Skeleton-root {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ---------- 9. Tabs, NavLink, SegmentedControl: solid blocks ---------- */
|
||||
|
||||
[data-theme="brutal"] .mantine-Tabs-tab {
|
||||
border: 3px solid transparent;
|
||||
border-radius: 0;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Tabs-tab[data-active] {
|
||||
background: var(--mantine-primary-color-filled);
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
border-color: var(--brutal-ink);
|
||||
box-shadow: 3px 3px 0 0 var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Tabs-list::before {
|
||||
border-color: var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-NavLink-root {
|
||||
border: 3px solid transparent;
|
||||
border-radius: 0;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-NavLink-root[data-active] {
|
||||
background: var(--mantine-primary-color-filled);
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
border-color: var(--brutal-ink);
|
||||
box-shadow: 4px 4px 0 0 var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-NavLink-root[data-active] :is(
|
||||
.mantine-NavLink-label,
|
||||
.mantine-NavLink-description,
|
||||
.mantine-NavLink-section
|
||||
) {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-SegmentedControl-root {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
background: var(--mantine-color-body);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-SegmentedControl-control,
|
||||
[data-theme="brutal"] .mantine-SegmentedControl-label {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-SegmentedControl-label {
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-SegmentedControl-indicator {
|
||||
border-radius: 0;
|
||||
background: var(--mantine-primary-color-filled);
|
||||
border: 2px solid var(--brutal-ink);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-SegmentedControl-label[data-active],
|
||||
[data-theme="brutal"] .mantine-SegmentedControl-control[data-active] .mantine-SegmentedControl-label {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
/* ---------- 10. Controls: Switch, Checkbox, Radio, Progress ---------- */
|
||||
|
||||
[data-theme="brutal"] .mantine-Switch-track {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Switch-thumb {
|
||||
border: 2px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Checkbox-input {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Radio-radio {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Progress-root {
|
||||
border: 2px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
background: var(--mantine-color-body);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Progress-section {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ---------- 11. Feedback: Alert, Notification ---------- */
|
||||
|
||||
[data-theme="brutal"] .mantine-Alert-root {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Notification-root {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
background: var(--mantine-color-body);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Notification-title {
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* ---------- 12. Shell & structure ---------- */
|
||||
|
||||
[data-theme="brutal"] .mantine-AppShell-root {
|
||||
--app-shell-border-color: var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-AppShell-header {
|
||||
background: var(--mantine-color-body);
|
||||
border-bottom: 3px solid var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-AppShell-navbar,
|
||||
[data-theme="brutal"] .mantine-AppShell-aside {
|
||||
background: var(--mantine-color-body);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .mantine-Divider-root {
|
||||
--divider-color: var(--brutal-ink);
|
||||
--divider-size: 2px;
|
||||
}
|
||||
|
||||
/* ---------- 13. App component hooks ---------- */
|
||||
|
||||
/* Tab strip: flat while resting; docking rules the ink baseline (width is
|
||||
constant so pinning never shifts layout). Active tab is a solid accent
|
||||
block with ink border + hard shadow — the floating underline indicator
|
||||
is suppressed, the block IS the indicator. Constant transparent border
|
||||
keeps tab boxes the same size in both active states. */
|
||||
[data-theme="brutal"] .flxn-tabs {
|
||||
border-bottom-width: 3px;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--mantine-color-body);
|
||||
border-bottom-color: var(--brutal-ink);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .flxn-tab.flxn-tab {
|
||||
border: 3px solid transparent;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .flxn-tab.flxn-tab[data-active] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: var(--flxn-on-accent);
|
||||
border-color: var(--brutal-ink);
|
||||
box-shadow: 2px 2px 0 0 var(--brutal-ink);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Nav grid tiles: same construction as cards — ink border, hard offset
|
||||
shadow, flat accent glyph. Press sinks into the shadow. */
|
||||
[data-theme="brutal"] .flxn-tile.flxn-tile {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
background-color: var(--flxn-showcase-bg);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="brutal"] .flxn-tile.flxn-tile:active:not(:disabled) {
|
||||
transform: translate(3px, 3px);
|
||||
box-shadow: 0 0 0 0 var(--brutal-ink);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .flxn-tile-icon.flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
/* "See all" chip: bordered block with a mini offset shadow; accent tint
|
||||
comes through from hooks.css. */
|
||||
[data-theme="brutal"] .flxn-see-all.flxn-see-all {
|
||||
border: 2px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
box-shadow: 2px 2px 0 0 var(--brutal-ink);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
|
||||
/* Match card + reaction tray: one construction — identical 3px ink
|
||||
borders, card on the raised showcase surface, tray a body-toned step
|
||||
below carrying the construction's hard shadow at its bottom edge. */
|
||||
[data-theme="brutal"] .flxn-match-card.flxn-match-card {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
background-color: var(--flxn-showcase-bg);
|
||||
}
|
||||
|
||||
[data-theme="brutal"] .flxn-reaction-row.flxn-reaction-row {
|
||||
border: 3px solid var(--brutal-ink);
|
||||
border-radius: 0;
|
||||
background-color: var(--mantine-color-body);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
/* Instrument-panel indicator ramps — 1970s NASA/Braun control-deck lamps.
|
||||
Declared in JS so Mantine regenerates every derived variant var (-filled,
|
||||
-light rgba, autoContrast picks) from the retuned shades. Shade 6 is the
|
||||
fill on the light beige enclosure (deep enough for white/ink autoContrast
|
||||
to pick legibly); shade 5 is the fill on the powered-down dark deck
|
||||
(brighter, reads as a lit lamp). */
|
||||
const cassetteColors = {
|
||||
// scope blue — telemetry readout
|
||||
blue: [
|
||||
"#eef3f7",
|
||||
"#dae6ef",
|
||||
"#bfd4e3",
|
||||
"#9cbcd2",
|
||||
"#74a0bd",
|
||||
"#5586a8",
|
||||
"#416d8d",
|
||||
"#345a75",
|
||||
"#29485e",
|
||||
"#1f3748",
|
||||
],
|
||||
// alert red — warning lamp
|
||||
red: [
|
||||
"#fbecea",
|
||||
"#f5d3cd",
|
||||
"#edb3a8",
|
||||
"#e28d7c",
|
||||
"#d46c56",
|
||||
"#c0503a",
|
||||
"#a43f2d",
|
||||
"#863323",
|
||||
"#6a281b",
|
||||
"#4e1e14",
|
||||
],
|
||||
// avocado LED — armed/ready lamp
|
||||
green: [
|
||||
"#eef4e6",
|
||||
"#dbe8ca",
|
||||
"#c2d8a5",
|
||||
"#a4c47a",
|
||||
"#86ac56",
|
||||
"#6d9440",
|
||||
"#587a34",
|
||||
"#47632a",
|
||||
"#384d21",
|
||||
"#293818",
|
||||
],
|
||||
// amber — the classic panel indicator
|
||||
yellow: [
|
||||
"#fbf3dc",
|
||||
"#f6e6b0",
|
||||
"#f0d47c",
|
||||
"#e9c04c",
|
||||
"#e0ac2c",
|
||||
"#cd9420",
|
||||
"#ac7c19",
|
||||
"#8c6414",
|
||||
"#6d4d10",
|
||||
"#4f380b",
|
||||
],
|
||||
// UV violet — auxiliary system lamp
|
||||
grape: [
|
||||
"#f2edf6",
|
||||
"#e2d5ec",
|
||||
"#ccb4dc",
|
||||
"#b18fc9",
|
||||
"#9570b3",
|
||||
"#7c589c",
|
||||
"#654682",
|
||||
"#513869",
|
||||
"#3f2b52",
|
||||
"#2e1f3c",
|
||||
],
|
||||
// signal orange — caution lamp
|
||||
orange: [
|
||||
"#faede3",
|
||||
"#f4d3bd",
|
||||
"#ecb48c",
|
||||
"#e2925c",
|
||||
"#d47237",
|
||||
"#bd5c22",
|
||||
"#9e4b1b",
|
||||
"#813d17",
|
||||
"#653012",
|
||||
"#4a230d",
|
||||
],
|
||||
// magenta signal — comms lamp
|
||||
pink: [
|
||||
"#f9ecf1",
|
||||
"#f1d1dd",
|
||||
"#e6adc2",
|
||||
"#d885a2",
|
||||
"#c8617f",
|
||||
"#b44563",
|
||||
"#9a3852",
|
||||
"#7d2d42",
|
||||
"#622334",
|
||||
"#481a26",
|
||||
],
|
||||
// tracer chartreuse — tape-motion lamp
|
||||
lime: [
|
||||
"#f5f8de",
|
||||
"#e9efad",
|
||||
"#d9e378",
|
||||
"#c5d24c",
|
||||
"#adbb2f",
|
||||
"#96a11f",
|
||||
"#7c8618",
|
||||
"#656e13",
|
||||
"#4f560f",
|
||||
"#3a3f0a",
|
||||
],
|
||||
// warm putty — light-scheme neutrals, seams, borders
|
||||
gray: [
|
||||
"#faf7f0",
|
||||
"#f2ecdf",
|
||||
"#e6ddc9",
|
||||
"#d4c8ab",
|
||||
"#bcac8b",
|
||||
"#a08e6e",
|
||||
"#837259",
|
||||
"#665946",
|
||||
"#4a4132",
|
||||
"#302a20",
|
||||
],
|
||||
// powered-down deck — dark-scheme neutrals
|
||||
dark: [
|
||||
"#e9e3d8",
|
||||
"#cfc6b6",
|
||||
"#a89c88",
|
||||
"#7c705f",
|
||||
"#574c3f",
|
||||
"#3a3128",
|
||||
"#2a251f",
|
||||
"#211e19",
|
||||
"#191712",
|
||||
"#100f0b",
|
||||
],
|
||||
} as const;
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "cassette",
|
||||
label: msg`Cassette Futurism`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Jost:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#ece4d4", dimmed: "#d4c8ab" },
|
||||
dark: { base: "#211e19", dimmed: "#191712" },
|
||||
},
|
||||
mantine: {
|
||||
defaultRadius: "md",
|
||||
// Amber/lime/mustard fills are mid-luminance; without autoContrast they
|
||||
// render white-on-amber at ~2-3:1.
|
||||
autoContrast: true,
|
||||
black: "#241f19",
|
||||
primaryShade: { light: 6, dark: 5 },
|
||||
colors: cassetteColors,
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,550 @@
|
||||
/* Cassette Futurism — 1970s NASA/Braun control-deck instrument panel.
|
||||
Light: warm beige enclosure with recessed panel seams and rounded-rect
|
||||
modules in varied beige tones; buttons read as physical keys (top bevel,
|
||||
1px darker base edge, press sinks 1px). Dark: powered-down deck with
|
||||
glowing indicator lamps. Ramps/autoContrast live in manifest.ts; this
|
||||
file carries shape, seams, and the physical-key/readout language. */
|
||||
|
||||
/* ---------- 1. Tokens, any scheme — (0,2,0) ---------- */
|
||||
|
||||
[data-theme="cassette"][data-theme] {
|
||||
--mantine-font-family: "Jost", ui-sans-serif, system-ui, sans-serif;
|
||||
--mantine-font-family-headings: "Jost", ui-sans-serif, system-ui, sans-serif;
|
||||
--mantine-font-family-monospace: "Space Mono", ui-monospace, "SFMono-Regular",
|
||||
monospace;
|
||||
--mantine-heading-font-weight: 600;
|
||||
|
||||
--mantine-radius-xs: 6px;
|
||||
--mantine-radius-sm: 8px;
|
||||
--mantine-radius-md: 10px;
|
||||
--mantine-radius-lg: 14px;
|
||||
--mantine-radius-xl: 20px;
|
||||
--mantine-radius-default: 10px;
|
||||
|
||||
--flxn-avatar-radius: 14px;
|
||||
--flxn-avatar-border: 2px solid var(--mantine-color-default-border);
|
||||
--flxn-badge-radius: 8px;
|
||||
|
||||
/* uppercase micro-label treatment shared by controls (buttons, badges,
|
||||
tabs, toggles) — the "labeled toggle" panel aesthetic */
|
||||
--cassette-label-font: "Space Mono", ui-monospace, monospace;
|
||||
--cassette-label-tracking: 0.045em;
|
||||
|
||||
/* fine enclosure grain, tiled, baked-in low opacity */
|
||||
--cassette-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.035'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* ---------- 2. Per-scheme tokens — (0,3,0) ---------- */
|
||||
|
||||
[data-theme="cassette"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #ece4d4;
|
||||
--mantine-color-text: #2c2620;
|
||||
--mantine-color-bright: #1b1712;
|
||||
--mantine-color-dimmed: #6b6255;
|
||||
--mantine-color-placeholder: #857b6c;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-filled);
|
||||
--mantine-color-error: #a43f2d;
|
||||
--mantine-color-default: #f1ebdd;
|
||||
--mantine-color-default-hover: #e4dcc8;
|
||||
--mantine-color-default-color: #2c2620;
|
||||
--mantine-color-default-border: #b9ad95;
|
||||
|
||||
--cassette-module: #f1ebdd;
|
||||
--cassette-module-alt: #e7dfc9;
|
||||
--cassette-seam-hi: rgba(255, 255, 255, 0.6);
|
||||
--cassette-seam-lo: rgba(44, 38, 30, 0.28);
|
||||
--cassette-well: rgba(44, 38, 30, 0.14);
|
||||
|
||||
--mantine-shadow-xs: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 1px 2px rgba(44, 38, 30, 0.18);
|
||||
--mantine-shadow-sm: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 1px 2px rgba(44, 38, 30, 0.2), 0 2px 6px rgba(44, 38, 30, 0.12);
|
||||
--mantine-shadow-md: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 3px 8px rgba(44, 38, 30, 0.18);
|
||||
--mantine-shadow-lg: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 6px 16px rgba(44, 38, 30, 0.2);
|
||||
--mantine-shadow-xl: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 10px 28px rgba(44, 38, 30, 0.24);
|
||||
|
||||
--flxn-gold: #ac7c19;
|
||||
--flxn-silver: #837259;
|
||||
--flxn-bronze: #9e4b1b;
|
||||
--flxn-toast-success: #587a34;
|
||||
--flxn-toast-error: #a43f2d;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, var(--mantine-color-yellow-5) 16%, #f6f1e6);
|
||||
--flxn-podium-1-border: var(--mantine-color-yellow-7);
|
||||
--flxn-podium-1-label: var(--mantine-color-yellow-9);
|
||||
--flxn-podium-2-bg: color-mix(in srgb, var(--mantine-color-gray-5) 16%, #f6f1e6);
|
||||
--flxn-podium-2-border: var(--mantine-color-gray-6);
|
||||
--flxn-podium-2-label: var(--mantine-color-gray-8);
|
||||
--flxn-podium-3-bg: color-mix(in srgb, var(--mantine-color-orange-5) 14%, #f6f1e6);
|
||||
--flxn-podium-3-border: var(--mantine-color-orange-7);
|
||||
--flxn-podium-3-label: var(--mantine-color-orange-9);
|
||||
--flxn-showcase-bg: #f6f1e6;
|
||||
--flxn-overlay: rgba(33, 28, 22, 0.45);
|
||||
--flxn-dotgrid-color: #cabf9f;
|
||||
--flxn-pop-shadow: rgba(44, 38, 30, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="cassette"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #211e19;
|
||||
--mantine-color-text: #d8d0c0;
|
||||
--mantine-color-bright: #f2ece0;
|
||||
--mantine-color-dimmed: #8f8574;
|
||||
--mantine-color-placeholder: #6f6656;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-light-color);
|
||||
--mantine-color-error: #e2685a;
|
||||
--mantine-color-default: #2a251f;
|
||||
--mantine-color-default-hover: #332d25;
|
||||
--mantine-color-default-color: #d8d0c0;
|
||||
--mantine-color-default-border: #4a4335;
|
||||
|
||||
--cassette-module: #2a251f;
|
||||
--cassette-module-alt: #241f19;
|
||||
--cassette-seam-hi: rgba(255, 255, 255, 0.07);
|
||||
--cassette-seam-lo: rgba(0, 0, 0, 0.55);
|
||||
--cassette-well: rgba(0, 0, 0, 0.5);
|
||||
|
||||
--mantine-shadow-xs: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 1px 2px rgba(0, 0, 0, 0.5);
|
||||
--mantine-shadow-sm: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 2px 6px rgba(0, 0, 0, 0.55);
|
||||
--mantine-shadow-md: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 4px 12px rgba(0, 0, 0, 0.55);
|
||||
--mantine-shadow-lg: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 8px 20px rgba(0, 0, 0, 0.6);
|
||||
--mantine-shadow-xl: inset 0 1px 0 var(--cassette-seam-hi),
|
||||
0 14px 32px rgba(0, 0, 0, 0.65);
|
||||
|
||||
--flxn-gold: #e0ac2c;
|
||||
--flxn-silver: #a89c88;
|
||||
--flxn-bronze: #d47237;
|
||||
--flxn-toast-success: #86ac56;
|
||||
--flxn-toast-error: #e2685a;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, var(--mantine-color-yellow-7) 26%, #241f19);
|
||||
--flxn-podium-1-border: var(--mantine-color-yellow-5);
|
||||
--flxn-podium-1-label: var(--mantine-color-yellow-3);
|
||||
--flxn-podium-2-bg: color-mix(in srgb, var(--mantine-color-gray-6) 20%, #241f19);
|
||||
--flxn-podium-2-border: var(--mantine-color-gray-4);
|
||||
--flxn-podium-2-label: var(--mantine-color-gray-2);
|
||||
--flxn-podium-3-bg: color-mix(in srgb, var(--mantine-color-orange-7) 26%, #241f19);
|
||||
--flxn-podium-3-border: var(--mantine-color-orange-5);
|
||||
--flxn-podium-3-label: var(--mantine-color-orange-3);
|
||||
--flxn-showcase-bg: #241f19;
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.6);
|
||||
--flxn-dotgrid-color: #3a352c;
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
/* ---------- 3. Enclosure texture: seams + grain (1 fixed overlay) ---------- */
|
||||
|
||||
[data-theme="cassette"] body {
|
||||
background-color: var(--mantine-color-body);
|
||||
background-image: var(--cassette-grain);
|
||||
}
|
||||
|
||||
/* ---------- 4. AppShell: top bezel + seam rules ---------- */
|
||||
|
||||
[data-theme="cassette"] .mantine-AppShell-header {
|
||||
background-color: var(--cassette-module);
|
||||
border-bottom: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 -1px 0 var(--cassette-seam-hi),
|
||||
0 2px 6px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-AppShell-header .mantine-Title-root {
|
||||
font-family: var(--cassette-label-font);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--cassette-label-tracking);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-AppShell-navbar {
|
||||
background-color: var(--cassette-module);
|
||||
border-inline-end: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] nav[role="navigation"].mantine-Paper-root {
|
||||
background-color: var(--cassette-module);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 1px 0 var(--cassette-seam-hi), var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
/* ---------- 5. Buttons & ActionIcons: physical keys ---------- */
|
||||
|
||||
[data-theme="cassette"] .mantine-Button-root,
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root {
|
||||
border-radius: var(--mantine-radius-md);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
font-family: var(--cassette-label-font);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--cassette-label-tracking);
|
||||
transition: transform 100ms ease, box-shadow 100ms ease;
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="default"] {
|
||||
background-color: var(--cassette-module);
|
||||
border-bottom: 3px solid color-mix(in srgb, var(--mantine-color-default-border) 70%, var(--mantine-color-bright));
|
||||
box-shadow: inset 0 1px 0 var(--cassette-seam-hi);
|
||||
color: var(--mantine-color-text);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="filled"],
|
||||
[data-theme="cassette"] .mantine-Button-root:not([data-variant]),
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root:not([data-variant]) {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 55%, black);
|
||||
border-bottom: 3px solid color-mix(in srgb, var(--mantine-primary-color-filled) 45%, black);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-ActionIcon-root[data-variant="filled"],
|
||||
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-Button-root:not([data-variant]),
|
||||
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-ActionIcon-root:not([data-variant]) {
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),
|
||||
0 0 8px color-mix(in srgb, var(--mantine-primary-color-filled) 55%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Button-root[data-variant="light"],
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="light"] {
|
||||
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 40%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Button-root[data-variant="subtle"],
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="subtle"],
|
||||
[data-theme="cassette"] .mantine-Button-root[data-variant="transparent"],
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root[data-variant="transparent"] {
|
||||
border-color: transparent;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
/* pressed state — static sink cue, always on (no motion required) */
|
||||
[data-theme="cassette"] .mantine-Button-root:active:not(:disabled):not([data-disabled]):not([data-loading]),
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
border-bottom-width: 1px;
|
||||
box-shadow: inset 0 2px 4px var(--cassette-well);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Button-root:disabled,
|
||||
[data-theme="cassette"] .mantine-Button-root[data-disabled],
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root:disabled,
|
||||
[data-theme="cassette"] .mantine-ActionIcon-root[data-disabled] {
|
||||
box-shadow: none;
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
|
||||
/* the actual 1px sink — guarded, motion-only */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="cassette"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 6. Inputs: recessed readout wells ---------- */
|
||||
|
||||
[data-theme="cassette"] .mantine-Input-input {
|
||||
background-color: var(--cassette-module-alt);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
font-family: var(--cassette-label-font);
|
||||
box-shadow: inset 0 1px 3px var(--cassette-well);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Input-input:focus,
|
||||
[data-theme="cassette"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
outline: none;
|
||||
box-shadow: inset 0 1px 3px var(--cassette-well),
|
||||
0 0 0 3px color-mix(in srgb, var(--mantine-primary-color-filled) 28%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-PinInput-field {
|
||||
font-family: var(--cassette-label-font);
|
||||
}
|
||||
|
||||
/* ---------- 7. Panels: Paper, Card, Modal, Popover, Notification, Alert ---------- */
|
||||
|
||||
[data-theme="cassette"] .mantine-Paper-root,
|
||||
[data-theme="cassette"] .mantine-Card-root,
|
||||
[data-theme="cassette"] .mantine-Popover-dropdown,
|
||||
[data-theme="cassette"] .mantine-Modal-content,
|
||||
[data-theme="cassette"] .mantine-Notification-root,
|
||||
[data-theme="cassette"] .mantine-Alert-root {
|
||||
background-color: var(--cassette-module);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Paper-root,
|
||||
[data-theme="cassette"] .mantine-Card-root {
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Modal-content {
|
||||
box-shadow: var(--mantine-shadow-xl);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Modal-header {
|
||||
background-color: var(--cassette-module-alt);
|
||||
border-bottom: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 1px 0 var(--cassette-seam-hi);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Tooltip-tooltip {
|
||||
background-color: var(--mantine-color-bright);
|
||||
color: var(--mantine-color-body);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
font-family: var(--cassette-label-font);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
/* ---------- 8. Tabs & SegmentedControl: labeled toggles ---------- */
|
||||
|
||||
[data-theme="cassette"] .mantine-Tabs-tab {
|
||||
font-family: var(--cassette-label-font);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--cassette-label-tracking);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Tabs-tab[data-active] {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--cassette-module-alt);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: inset 0 1px 3px var(--cassette-well);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-SegmentedControl-label {
|
||||
font-family: var(--cassette-label-font);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--cassette-label-tracking);
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--cassette-module);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
box-shadow: inset 0 1px 0 var(--cassette-seam-hi), 0 1px 2px var(--cassette-well);
|
||||
}
|
||||
|
||||
/* ---------- 9. Badges, ThemeIcon, Checkbox/Radio, Switch ---------- */
|
||||
|
||||
[data-theme="cassette"] .mantine-Badge-root {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
font-family: var(--cassette-label-font);
|
||||
letter-spacing: var(--cassette-label-tracking);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-ThemeIcon-root {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Checkbox-input,
|
||||
[data-theme="cassette"] .mantine-Radio-radio {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 1px 2px var(--cassette-well);
|
||||
}
|
||||
|
||||
/* checked-glyph on-color is hardcoded white by Mantine regardless of
|
||||
autoContrast; recompute per accent so amber/lime checks stay legible */
|
||||
[data-theme="cassette"] .mantine-Checkbox-root {
|
||||
--checkbox-icon-color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
[data-theme="cassette"] .mantine-Radio-root {
|
||||
--radio-icon-color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Switch-track {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 1px 3px var(--cassette-well);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Switch-thumb {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 1px 0 var(--cassette-seam-hi), 0 1px 2px var(--cassette-well);
|
||||
}
|
||||
|
||||
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-Switch-input:checked + .mantine-Switch-track {
|
||||
box-shadow: inset 0 1px 3px var(--cassette-well),
|
||||
0 0 6px color-mix(in srgb, var(--mantine-primary-color-filled) 60%, transparent);
|
||||
}
|
||||
|
||||
/* ---------- 10. Progress: VU meter with tick marks ---------- */
|
||||
|
||||
[data-theme="cassette"] .mantine-Progress-root {
|
||||
position: relative;
|
||||
background-color: var(--cassette-module-alt);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 1px 3px var(--cassette-well);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Progress-root::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
background-image: repeating-linear-gradient(
|
||||
90deg,
|
||||
var(--mantine-color-default-border) 0 1px,
|
||||
transparent 1px 12.5%
|
||||
);
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Progress-section {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.32) 0%,
|
||||
rgba(255, 255, 255, 0.05) 45%,
|
||||
rgba(0, 0, 0, 0.1) 100%
|
||||
);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="cassette"][data-mantine-color-scheme="dark"] .mantine-Progress-section {
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16),
|
||||
0 0 6px color-mix(in srgb, var(--mantine-primary-color-filled) 65%, transparent);
|
||||
}
|
||||
|
||||
/* ---------- 11. Divider: tape-window (two reel circles + line) ---------- */
|
||||
|
||||
[data-theme="cassette"] .mantine-Divider-root {
|
||||
position: relative;
|
||||
--divider-color: var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Divider-root:not([data-orientation="vertical"])::before,
|
||||
[data-theme="cassette"] .mantine-Divider-root:not([data-orientation="vertical"])::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: var(--cassette-module);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 1px 1px var(--cassette-well), inset 0 -1px 0 var(--cassette-seam-hi);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Divider-root:not([data-orientation="vertical"])::before {
|
||||
left: 42%;
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .mantine-Divider-root:not([data-orientation="vertical"])::after {
|
||||
left: 58%;
|
||||
}
|
||||
|
||||
/* ---------- 12. App hooks: tab strip ---------- */
|
||||
|
||||
[data-theme="cassette"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--cassette-module);
|
||||
border-bottom-color: var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 -1px 0 var(--cassette-seam-hi);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .flxn-tab {
|
||||
font-family: var(--cassette-label-font);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--cassette-label-tracking);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
/* underline indicator (not a filled pill), so accent text stays legible */
|
||||
[data-theme="cassette"] .flxn-tab[data-active]::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
margin-inline-end: 6px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
[data-theme="cassette"][data-mantine-color-scheme="dark"] .flxn-tab[data-active]::before {
|
||||
box-shadow: 0 0 5px color-mix(in srgb, var(--mantine-primary-color-filled) 80%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .flxn-tabs-indicator {
|
||||
border-bottom: 3px solid var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
[data-theme="cassette"][data-mantine-color-scheme="dark"] .flxn-tabs-indicator {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* ---------- 13. App hooks: nav tiles ---------- */
|
||||
|
||||
[data-theme="cassette"] .flxn-tile {
|
||||
background-color: var(--cassette-module);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-bottom: 3px solid color-mix(in srgb, var(--mantine-color-default-border) 70%, var(--mantine-color-bright));
|
||||
box-shadow: inset 0 1px 0 var(--cassette-seam-hi);
|
||||
transition: transform 100ms ease, box-shadow 100ms ease;
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .flxn-tile:active {
|
||||
border-bottom-width: 1px;
|
||||
box-shadow: inset 0 2px 4px var(--cassette-well);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="cassette"] .flxn-tile.flxn-press:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
|
||||
/* flat tint — no plate behind the glyph */
|
||||
[data-theme="cassette"] .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* ---------- 14. App hooks: see-all as a labeled key chip ---------- */
|
||||
|
||||
[data-theme="cassette"] .flxn-see-all {
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
border: 1px solid color-mix(in srgb, var(--mantine-primary-color-filled) 45%, transparent);
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
font-family: var(--cassette-label-font);
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--cassette-label-tracking);
|
||||
font-size: 0.7rem;
|
||||
box-shadow: inset 0 1px 0 var(--cassette-seam-hi);
|
||||
}
|
||||
|
||||
/* ---------- 15. App hooks: match card + reaction tray ---------- */
|
||||
|
||||
[data-theme="cassette"] .flxn-match-card {
|
||||
background-color: var(--cassette-module);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="cassette"] .flxn-reaction-row {
|
||||
background-color: var(--cassette-module-alt);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 2px 4px var(--cassette-well);
|
||||
}
|
||||
|
||||
/* ---------- 16. App hooks: avatar frame (porthole bezel) ---------- */
|
||||
|
||||
[data-theme="cassette"] .flxn-avatar-frame {
|
||||
box-shadow: inset 0 1px 0 var(--cassette-seam-hi), inset 0 -1px 2px var(--cassette-well);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { CHROME_COLORS, ChromeColorScheme } from "@/lib/mantine/theme-colors";
|
||||
import type { ThemeManifest } from "./types";
|
||||
|
||||
export function resolveChromeColors(
|
||||
manifest: ThemeManifest
|
||||
): Record<ChromeColorScheme, { base: string; dimmed: string }> {
|
||||
return {
|
||||
light: manifest.chromeColors?.light ?? CHROME_COLORS.light,
|
||||
dark: manifest.chromeColors?.dark ?? CHROME_COLORS.dark,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
/* Carnival poster inks. Declared in JS so Mantine regenerates every derived
|
||||
variant var (-light rgba, -outline, filled hovers) from the retuned shades. */
|
||||
const circusColors = {
|
||||
// royal
|
||||
blue: [
|
||||
"#eef2fc",
|
||||
"#d8e1f8",
|
||||
"#b6c8f0",
|
||||
"#8fa9e6",
|
||||
"#6787d8",
|
||||
"#4267c8",
|
||||
"#2b4fb4",
|
||||
"#21409a",
|
||||
"#19317a",
|
||||
"#11235c",
|
||||
],
|
||||
// carnival red
|
||||
red: [
|
||||
"#fdefed",
|
||||
"#f9d8d4",
|
||||
"#f2b6af",
|
||||
"#e88d84",
|
||||
"#d9655c",
|
||||
"#c6443c",
|
||||
"#b12724",
|
||||
"#931c1d",
|
||||
"#731316",
|
||||
"#540c10",
|
||||
],
|
||||
// ticket-booth emerald
|
||||
green: [
|
||||
"#ecf8ef",
|
||||
"#d2eeda",
|
||||
"#a9dfba",
|
||||
"#7bcb95",
|
||||
"#4fb573",
|
||||
"#2f9c57",
|
||||
"#1d7f41",
|
||||
"#156634",
|
||||
"#0f4e27",
|
||||
"#09381c",
|
||||
],
|
||||
// mustard
|
||||
yellow: [
|
||||
"#fbf4e2",
|
||||
"#f5e5b8",
|
||||
"#edd288",
|
||||
"#e0ba55",
|
||||
"#cf9f2a",
|
||||
"#b58211",
|
||||
"#97660a",
|
||||
"#7b5207",
|
||||
"#5f3f05",
|
||||
"#452d03",
|
||||
],
|
||||
// sideshow plum
|
||||
grape: [
|
||||
"#f6effc",
|
||||
"#e8d8f6",
|
||||
"#d3b6ee",
|
||||
"#b98ee2",
|
||||
"#9d66d2",
|
||||
"#8547bd",
|
||||
"#6f2da0",
|
||||
"#5b2284",
|
||||
"#461868",
|
||||
"#33104d",
|
||||
],
|
||||
// pumpkin
|
||||
orange: [
|
||||
"#fdf1e8",
|
||||
"#f9dcc6",
|
||||
"#f3bd97",
|
||||
"#e99a63",
|
||||
"#dc7736",
|
||||
"#cd6016",
|
||||
"#b84d09",
|
||||
"#973d06",
|
||||
"#752f05",
|
||||
"#542103",
|
||||
],
|
||||
// raspberry
|
||||
pink: [
|
||||
"#fcedf4",
|
||||
"#f8d3e4",
|
||||
"#f1abcb",
|
||||
"#e67dac",
|
||||
"#d6528d",
|
||||
"#c43574",
|
||||
"#ab1f60",
|
||||
"#8d154e",
|
||||
"#6e0e3c",
|
||||
"#50082b",
|
||||
],
|
||||
// fairground olive
|
||||
lime: [
|
||||
"#f5f8e4",
|
||||
"#e7efbe",
|
||||
"#d3e18d",
|
||||
"#bccd5c",
|
||||
"#a2b532",
|
||||
"#849a15",
|
||||
"#667c07",
|
||||
"#536505",
|
||||
"#404e04",
|
||||
"#2e3902",
|
||||
],
|
||||
// warm parchment neutrals — light-scheme grays
|
||||
gray: [
|
||||
"#faf5ea",
|
||||
"#f1e8d6",
|
||||
"#e5d8bf",
|
||||
"#d3c1a2",
|
||||
"#b8a284",
|
||||
"#97826a",
|
||||
"#6f5d4b",
|
||||
"#554638",
|
||||
"#3d3128",
|
||||
"#28201a",
|
||||
],
|
||||
// night fair — dark-scheme surfaces/borders
|
||||
dark: [
|
||||
"#f2e6da",
|
||||
"#d8c7bb",
|
||||
"#b5a096",
|
||||
"#8a7268",
|
||||
"#5c4547",
|
||||
"#47343a",
|
||||
"#382930",
|
||||
"#2a1e24",
|
||||
"#20161b",
|
||||
"#150e12",
|
||||
],
|
||||
} as const;
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "circus",
|
||||
label: msg`Big Top`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Alfa+Slab+One&display=swap",
|
||||
"https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#f9f1e0", dimmed: "#e9dcbd" },
|
||||
dark: { base: "#1e151a", dimmed: "#140d11" },
|
||||
},
|
||||
mantine: {
|
||||
// deep poster inks in both schemes keep white filled-text legible
|
||||
primaryShade: { light: 6, dark: 6 },
|
||||
colors: circusColors,
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,608 @@
|
||||
/* Big Top — vintage carnival.
|
||||
Light: cream ticket paper, awning-stripe bands, scalloped card edges.
|
||||
Dark: night fair with warm glowing surfaces. */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 1. Tokens, any scheme — (0,2,0) */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"][data-theme] {
|
||||
--mantine-font-family: "Rubik", "Trebuchet MS", sans-serif;
|
||||
--mantine-font-family-headings: "Alfa Slab One", "Rockwell", "Georgia", serif;
|
||||
--mantine-heading-font-weight: 400;
|
||||
|
||||
--mantine-h1-font-size: 2rem;
|
||||
--mantine-h1-line-height: 1.15;
|
||||
--mantine-h2-font-size: 1.6rem;
|
||||
--mantine-h2-line-height: 1.2;
|
||||
--mantine-h3-font-size: 1.3rem;
|
||||
--mantine-h3-line-height: 1.25;
|
||||
|
||||
/* ticket-corner radii */
|
||||
--mantine-radius-xs: 0.25rem;
|
||||
--mantine-radius-sm: 0.375rem;
|
||||
--mantine-radius-md: 0.5rem;
|
||||
--mantine-radius-lg: 0.75rem;
|
||||
--mantine-radius-xl: 1rem;
|
||||
--mantine-radius-default: 0.5rem;
|
||||
|
||||
/* warm soft elevation (dark overrides below) */
|
||||
--mantine-shadow-xs: 0 1px 2px rgba(64, 41, 29, 0.12);
|
||||
--mantine-shadow-sm: 0 2px 6px rgba(64, 41, 29, 0.16);
|
||||
--mantine-shadow-md: 0 4px 12px rgba(64, 41, 29, 0.2);
|
||||
--mantine-shadow-lg: 0 8px 20px rgba(64, 41, 29, 0.22);
|
||||
--mantine-shadow-xl: 0 12px 32px rgba(64, 41, 29, 0.26);
|
||||
|
||||
--flxn-avatar-radius: 50%;
|
||||
--flxn-avatar-border: 2px solid var(--circus-ink);
|
||||
--flxn-badge-radius: 0.5rem;
|
||||
|
||||
/* awning valance band (stripe colors set per scheme) */
|
||||
--circus-awning: repeating-linear-gradient(
|
||||
90deg,
|
||||
var(--circus-red) 0 0.75rem,
|
||||
var(--circus-stripe) 0.75rem 1.5rem
|
||||
);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 2. Light — cream ticket paper — (0,3,0) */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--circus-ink: #40291d;
|
||||
--circus-paper: #fffaef;
|
||||
--circus-red: #b02e26;
|
||||
--circus-stripe: #f6ead0;
|
||||
--circus-scallop: #b02e26;
|
||||
--circus-gold: #a8790f;
|
||||
|
||||
--mantine-color-body: #f9f1e0;
|
||||
--mantine-color-text: #33221a;
|
||||
--mantine-color-bright: #1d100a;
|
||||
--mantine-color-dimmed: #7a6250;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-light-color);
|
||||
--mantine-color-error: #b12724;
|
||||
--mantine-color-placeholder: #8d7660;
|
||||
--mantine-color-default: #fffaef;
|
||||
--mantine-color-default-hover: #f3e7cb;
|
||||
--mantine-color-default-color: #33221a;
|
||||
--mantine-color-default-border: #40291d;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #c2900e;
|
||||
--flxn-silver: #857c6e;
|
||||
--flxn-bronze: #b05c2c;
|
||||
--flxn-toast-success: #1d7f41;
|
||||
--flxn-toast-error: #b12724;
|
||||
--flxn-podium-1-bg: #f7e8b8;
|
||||
--flxn-podium-1-border: #c2900e;
|
||||
--flxn-podium-1-label: #6b4e08;
|
||||
--flxn-podium-2-bg: #efe9dc;
|
||||
--flxn-podium-2-border: #9a8f7c;
|
||||
--flxn-podium-2-label: #5c5344;
|
||||
--flxn-podium-3-bg: #f6dfc8;
|
||||
--flxn-podium-3-border: #b05c2c;
|
||||
--flxn-podium-3-label: #7c3c14;
|
||||
--flxn-showcase-bg: #fffaef;
|
||||
--flxn-overlay: rgba(38, 24, 16, 0.5);
|
||||
--flxn-dotgrid-color: rgba(64, 41, 29, 0.3);
|
||||
--flxn-pop-shadow: rgba(64, 41, 29, 0.35);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 2. Dark — night fair — (0,3,0) */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--circus-ink: #6b4f43;
|
||||
--circus-paper: #2a1e24;
|
||||
--circus-red: #a03530;
|
||||
--circus-stripe: #d8b073;
|
||||
--circus-scallop: #a03530;
|
||||
--circus-gold: #e3b45c;
|
||||
|
||||
--mantine-color-body: #1e151a;
|
||||
--mantine-color-text: #f4e6d4;
|
||||
--mantine-color-bright: #fff6e8;
|
||||
--mantine-color-dimmed: #b39d8c;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-light-color);
|
||||
--mantine-color-error: #f2857e;
|
||||
--mantine-color-placeholder: #8a7466;
|
||||
--mantine-color-default: #2a1e24;
|
||||
--mantine-color-default-hover: #362730;
|
||||
--mantine-color-default-color: #f4e6d4;
|
||||
--mantine-color-default-border: #5c443c;
|
||||
|
||||
/* black depth plus a faint fairground-lamp glow */
|
||||
--mantine-shadow-xs: 0 1px 3px rgba(0, 0, 0, 0.4);
|
||||
--mantine-shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.45),
|
||||
0 0 14px rgba(232, 178, 102, 0.06);
|
||||
--mantine-shadow-md: 0 4px 14px rgba(0, 0, 0, 0.5),
|
||||
0 0 18px rgba(232, 178, 102, 0.08);
|
||||
--mantine-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.55),
|
||||
0 0 24px rgba(232, 178, 102, 0.09);
|
||||
--mantine-shadow-xl: 0 14px 36px rgba(0, 0, 0, 0.6),
|
||||
0 0 32px rgba(232, 178, 102, 0.1);
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #e8b84f;
|
||||
--flxn-silver: #c9bfae;
|
||||
--flxn-bronze: #e09060;
|
||||
--flxn-toast-success: #6fce8f;
|
||||
--flxn-toast-error: #f2857e;
|
||||
--flxn-podium-1-bg: #322818;
|
||||
--flxn-podium-1-border: #9c7c2c;
|
||||
--flxn-podium-1-label: #ecc86a;
|
||||
--flxn-podium-2-bg: #2c2522;
|
||||
--flxn-podium-2-border: #6e6357;
|
||||
--flxn-podium-2-label: #d6cabb;
|
||||
--flxn-podium-3-bg: #34211a;
|
||||
--flxn-podium-3-border: #9c5b34;
|
||||
--flxn-podium-3-label: #eda579;
|
||||
--flxn-showcase-bg: #2a1e24;
|
||||
--flxn-overlay: rgba(8, 4, 6, 0.65);
|
||||
--flxn-dotgrid-color: rgba(240, 221, 196, 0.22);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 3. Type — slab display headings, sparingly */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] :is(h1, h2, h3) {
|
||||
letter-spacing: 0.035em;
|
||||
}
|
||||
|
||||
/* small headings stay in the body face so the slab reads as a poster
|
||||
headline, not a wall of it */
|
||||
[data-theme="circus"] :is(h4, h5, h6) {
|
||||
font-family: var(--mantine-font-family);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 4. Surfaces — warm-ink borders, scalloped card valances */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] .mantine-Paper-root {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
/* scallop strip painted along the top edge only (repeat-x half-discs);
|
||||
bracket cards are dense and small — no valance there */
|
||||
[data-theme="circus"] .mantine-Card-root:not(.flxn-bracket-card),
|
||||
[data-theme="circus"] .flxn-match-card.flxn-match-card {
|
||||
background-image: radial-gradient(
|
||||
circle at 0.375rem 0,
|
||||
var(--circus-scallop) 0.3rem,
|
||||
transparent calc(0.3rem + 1px)
|
||||
);
|
||||
background-repeat: repeat-x;
|
||||
background-size: 0.75rem 0.45rem;
|
||||
background-position: top left;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 5. Buttons & action icons — poster lettering on inked plates */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] .mantine-Button-root {
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
box-shadow: 0 2px 0 color-mix(in srgb, var(--circus-ink) 45%, transparent);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Button-label {
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
[data-theme="circus"]
|
||||
.mantine-Button-root:is(
|
||||
[data-variant="subtle"],
|
||||
[data-variant="transparent"],
|
||||
[data-variant="white"]
|
||||
) {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="circus"]
|
||||
.mantine-ActionIcon-root:is(
|
||||
[data-variant="filled"],
|
||||
[data-variant="default"],
|
||||
[data-variant="outline"],
|
||||
[data-variant="light"]
|
||||
) {
|
||||
border: 2px solid var(--circus-ink);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="circus"] .mantine-Button-root {
|
||||
transition:
|
||||
transform 140ms cubic-bezier(0.32, 0.72, 0, 1),
|
||||
box-shadow 140ms cubic-bezier(0.32, 0.72, 0, 1);
|
||||
}
|
||||
|
||||
[data-theme="circus"]
|
||||
.mantine-Button-root:not(
|
||||
[data-variant="subtle"],
|
||||
[data-variant="transparent"],
|
||||
[data-variant="white"]
|
||||
):active:not([data-disabled]):not(:disabled) {
|
||||
transform: translateY(1px);
|
||||
box-shadow: 0 1px 0 color-mix(in srgb, var(--circus-ink) 45%, transparent);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 6. Inputs — ticket-window frames */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] .mantine-Input-input {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Input-input:focus,
|
||||
[data-theme="circus"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: 0 0 0 3px
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 25%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-InputWrapper-label {
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-PinInput-field {
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 7. Badges — prize ribbons (notched banner ends) */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] .mantine-Badge-root {
|
||||
border-radius: 0;
|
||||
clip-path: polygon(
|
||||
0 0,
|
||||
100% 0,
|
||||
calc(100% - 0.45em) 50%,
|
||||
100% 100%,
|
||||
0 100%,
|
||||
0.45em 50%
|
||||
);
|
||||
padding-inline: 0.95em;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 8. Tabs & SegmentedControl */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] .mantine-Tabs-list::before {
|
||||
border-color: color-mix(in srgb, var(--circus-ink) 40%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Tabs-tab {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Tabs-tab[data-active] {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-radius: var(--mantine-radius-xs);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-SegmentedControl-label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-SegmentedControl-label[data-active] {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 9. Overlays — marquee-framed modal, poster dropdowns */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] .mantine-Modal-content {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-xl);
|
||||
/* marquee-bulb ring just inside the frame */
|
||||
outline: 2px dotted var(--circus-gold);
|
||||
outline-offset: -0.45rem;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Modal-header {
|
||||
background-color: var(--circus-paper);
|
||||
border-bottom: 2px solid var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Modal-title {
|
||||
font-family: var(--mantine-font-family-headings);
|
||||
font-weight: 400;
|
||||
font-size: 1.25rem;
|
||||
letter-spacing: 0.035em;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Popover-dropdown,
|
||||
[data-theme="circus"] .mantine-Menu-dropdown {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
/* sign plate: inverts per scheme, always warm-on-warm neutral */
|
||||
[data-theme="circus"] .mantine-Tooltip-tooltip {
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="circus"][data-mantine-color-scheme="light"] .mantine-Tooltip-tooltip {
|
||||
background-color: #33221a;
|
||||
color: #f9f1e0;
|
||||
}
|
||||
|
||||
[data-theme="circus"][data-mantine-color-scheme="dark"] .mantine-Tooltip-tooltip {
|
||||
background-color: #f4e6d4;
|
||||
color: #33221a;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Notification-root {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-lg);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Notification-title {
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Alert-root {
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Alert-title {
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 10. App shell — awning band under the header */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] .mantine-AppShell-root {
|
||||
--app-shell-border-color: var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-AppShell-header {
|
||||
background-color: var(--circus-paper);
|
||||
background-image: var(--circus-awning);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 0.5rem;
|
||||
background-position: bottom left;
|
||||
border-bottom: 2px solid var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-AppShell-navbar {
|
||||
background-color: var(--circus-paper);
|
||||
border-inline-end: 2px solid var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-AppShell-aside {
|
||||
border-inline-start: 2px solid var(--circus-ink);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 11. Small controls & details */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] .mantine-Checkbox-input {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-xs);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Checkbox-input:checked {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-color: var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Switch-track {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Switch-input:checked + .mantine-Switch-track {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-color: var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Switch-thumb {
|
||||
background-color: #fffaef;
|
||||
border: 2px solid var(--circus-ink);
|
||||
}
|
||||
|
||||
/* striped midway banner bar */
|
||||
[data-theme="circus"] .mantine-Progress-root {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-xl);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Progress-section {
|
||||
border-radius: var(--mantine-radius-xl);
|
||||
background-image: repeating-linear-gradient(
|
||||
45deg,
|
||||
rgba(255, 250, 239, 0.28) 0 0.5rem,
|
||||
transparent 0.5rem 1rem
|
||||
);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-ThemeIcon-root {
|
||||
border: 2px solid var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Indicator-indicator {
|
||||
border: 2px solid var(--circus-paper);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-NavLink-root {
|
||||
font-weight: 600;
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Divider-root {
|
||||
--divider-color: color-mix(in srgb, var(--circus-ink) 45%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .mantine-Skeleton-root {
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 12. App component hooks */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Tab strip: flat resting; docking drops the awning valance. Rule width
|
||||
stays 2px in both states so pinning never shifts layout. */
|
||||
[data-theme="circus"] .flxn-tabs {
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--circus-paper);
|
||||
background-image: var(--circus-awning);
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100% 0.375rem;
|
||||
background-position: bottom left;
|
||||
border-bottom-color: var(--circus-ink);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .flxn-tab.flxn-tab {
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
[data-theme="circus"] .flxn-tab.flxn-tab[data-active] {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* marquee-dot indicator: a dotted rule, so accent tab text is fine */
|
||||
[data-theme="circus"] .flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: 0.25rem dotted var(--mantine-primary-color-filled);
|
||||
padding-inline: 0.4rem;
|
||||
}
|
||||
|
||||
/* Nav grid tiles: sideshow plates with flat accent-tinted icons */
|
||||
[data-theme="circus"] .flxn-tile {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="circus"] .flxn-tile:hover:not(:disabled) {
|
||||
background-color: color-mix(
|
||||
in srgb,
|
||||
var(--mantine-primary-color-filled) 8%,
|
||||
var(--circus-paper)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="circus"] .flxn-tile:active:not(:disabled) {
|
||||
background-color: color-mix(
|
||||
in srgb,
|
||||
var(--mantine-primary-color-filled) 8%,
|
||||
var(--circus-paper)
|
||||
);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* "See all" as a ticket stub: accent wash + dashed perforation edge */
|
||||
[data-theme="circus"] .flxn-see-all.flxn-see-all {
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
border: 1px dashed
|
||||
color-mix(in srgb, var(--mantine-primary-color-light-color) 70%, transparent);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="circus"] .flxn-see-all.flxn-see-all:hover {
|
||||
background-color: var(--mantine-primary-color-light-hover);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Match card + tray: same 2px warm-ink frame; tray one shade deeper */
|
||||
[data-theme="circus"] .flxn-match-card.flxn-match-card {
|
||||
background-color: var(--circus-paper);
|
||||
border: 2px solid var(--circus-ink);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="circus"] .flxn-reaction-row.flxn-reaction-row {
|
||||
background-color: color-mix(in srgb, var(--circus-ink) 8%, var(--circus-paper));
|
||||
border: 2px solid var(--circus-ink);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 13. Accent-driven selection & focus */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="circus"] ::selection {
|
||||
background-color: color-mix(
|
||||
in srgb,
|
||||
var(--mantine-primary-color-filled) 30%,
|
||||
transparent
|
||||
);
|
||||
}
|
||||
|
||||
[data-theme="circus"] :focus-visible {
|
||||
outline: 2px solid var(--mantine-primary-color-filled);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
/* Plasticine ramps — chalky, high-pigment clay mixes. Declared in JS so
|
||||
Mantine regenerates every derived variant var (-light rgba, -outline,
|
||||
autoContrast picks) from the retuned shades. Shade 4 (the fill) keeps
|
||||
>=4.5:1 with the clay ink #33291f; shade 8 keeps >=4.5:1 on the light
|
||||
backdrop; shades 3-4 keep >=4.5:1 on the dark backdrop. */
|
||||
const clayColors = {
|
||||
// denim clay
|
||||
blue: [
|
||||
"#eef3f7",
|
||||
"#dbe7f0",
|
||||
"#c2d7e8",
|
||||
"#9cc0dc",
|
||||
"#6fa5cd",
|
||||
"#5590bd",
|
||||
"#4478a3",
|
||||
"#396286",
|
||||
"#2d4d69",
|
||||
"#22394e",
|
||||
],
|
||||
// terracotta
|
||||
red: [
|
||||
"#f9eeea",
|
||||
"#f2dcd5",
|
||||
"#ecc5b9",
|
||||
"#e8a893",
|
||||
"#e08466",
|
||||
"#cd6a4c",
|
||||
"#b0543a",
|
||||
"#8f4430",
|
||||
"#713627",
|
||||
"#54291e",
|
||||
],
|
||||
// moss clay
|
||||
green: [
|
||||
"#edf4ea",
|
||||
"#dcead5",
|
||||
"#c4dcb9",
|
||||
"#a3c996",
|
||||
"#7fb371",
|
||||
"#689e5b",
|
||||
"#538148",
|
||||
"#44693c",
|
||||
"#365330",
|
||||
"#283d24",
|
||||
],
|
||||
// mustard clay
|
||||
yellow: [
|
||||
"#faf4e2",
|
||||
"#f5e8c2",
|
||||
"#efd99b",
|
||||
"#e9c96f",
|
||||
"#e0b545",
|
||||
"#c99b2e",
|
||||
"#a67d24",
|
||||
"#86641e",
|
||||
"#684d18",
|
||||
"#4b3812",
|
||||
],
|
||||
// plum clay
|
||||
grape: [
|
||||
"#f4eef6",
|
||||
"#e8dcec",
|
||||
"#d9c4e0",
|
||||
"#c5a4d2",
|
||||
"#b28ac3",
|
||||
"#9c70ae",
|
||||
"#7c548d",
|
||||
"#654573",
|
||||
"#4f365a",
|
||||
"#3a2842",
|
||||
],
|
||||
// apricot clay
|
||||
orange: [
|
||||
"#faf0e6",
|
||||
"#f4dfc9",
|
||||
"#eecaa6",
|
||||
"#e8b17e",
|
||||
"#de9355",
|
||||
"#c97a3d",
|
||||
"#a86230",
|
||||
"#885028",
|
||||
"#6a3f20",
|
||||
"#4d2e18",
|
||||
],
|
||||
// rose clay
|
||||
pink: [
|
||||
"#f9eef1",
|
||||
"#f2dbe2",
|
||||
"#ecc2cf",
|
||||
"#e6a1b6",
|
||||
"#dd7f9c",
|
||||
"#c96585",
|
||||
"#ab4f6d",
|
||||
"#8b4059",
|
||||
"#6d3346",
|
||||
"#502634",
|
||||
],
|
||||
// pea clay
|
||||
lime: [
|
||||
"#f3f6e4",
|
||||
"#e7edc6",
|
||||
"#d6e19f",
|
||||
"#c1d174",
|
||||
"#a8bd4c",
|
||||
"#90a636",
|
||||
"#75882b",
|
||||
"#5f6e24",
|
||||
"#4a561d",
|
||||
"#363f16",
|
||||
],
|
||||
// warm putty — light-scheme neutrals, borders, dimmed text
|
||||
gray: [
|
||||
"#f7f3ec",
|
||||
"#ede7dd",
|
||||
"#e0d8cb",
|
||||
"#cec3b2",
|
||||
"#b5a795",
|
||||
"#97887a",
|
||||
"#786a5d",
|
||||
"#5d5248",
|
||||
"#453d36",
|
||||
"#2e2925",
|
||||
],
|
||||
// night studio — dark-scheme body/surfaces/borders, warm-tinted
|
||||
dark: [
|
||||
"#e8e0da",
|
||||
"#cfc4bd",
|
||||
"#b1a49e",
|
||||
"#857a78",
|
||||
"#56494e",
|
||||
"#453a3f",
|
||||
"#332c30",
|
||||
"#262023",
|
||||
"#1e191c",
|
||||
"#141013",
|
||||
],
|
||||
} as const;
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "clay",
|
||||
label: msg`Claymation`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Baloo+2:wght@500;600;700;800&display=swap",
|
||||
"https://fonts.googleapis.com/css2?family=Nunito:wght@400;500;600;700;800&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#efe9e2", dimmed: "#d8cfc2" },
|
||||
dark: { base: "#262023", dimmed: "#141013" },
|
||||
},
|
||||
mantine: {
|
||||
defaultRadius: "md",
|
||||
// Chalky mid-tone fills pair with dark clay ink, not white
|
||||
autoContrast: true,
|
||||
luminanceThreshold: 0.28,
|
||||
black: "#33291f",
|
||||
primaryShade: { light: 4, dark: 4 },
|
||||
colors: clayColors,
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,620 @@
|
||||
/* Claymation — hand-pinched plasticine world.
|
||||
Light: soft studio backdrop; surfaces are matte clay blobs with irregular
|
||||
organic radii, "pinched" depth from an inner top highlight plus a soft
|
||||
bottom shadow. No hard edges anywhere.
|
||||
Dark: night studio with a warm key light — highlights warmer, shadows
|
||||
deeper. Filled controls carry dark clay ink, never white-on-mid-tone. */
|
||||
|
||||
/* ---------- 1. Tokens, any scheme ---------- */
|
||||
|
||||
[data-theme="clay"][data-theme] {
|
||||
--mantine-font-family: "Nunito", "Inter", system-ui, sans-serif;
|
||||
--mantine-font-family-headings: "Baloo 2", "Nunito", system-ui, sans-serif;
|
||||
--mantine-heading-font-weight: 700;
|
||||
|
||||
--mantine-radius-xs: 10px;
|
||||
--mantine-radius-sm: 14px;
|
||||
--mantine-radius-md: 18px;
|
||||
--mantine-radius-lg: 24px;
|
||||
--mantine-radius-xl: 30px;
|
||||
--mantine-radius-default: 18px;
|
||||
|
||||
/* hand-pinched blob radii, varied per component */
|
||||
--clay-blob-card: 26px 20px 28px 22px / 22px 28px 20px 26px;
|
||||
--clay-blob-card-alt: 20px 28px 22px 26px / 28px 20px 26px 22px;
|
||||
--clay-blob-md: 20px 16px 22px 18px / 18px 22px 16px 20px;
|
||||
--clay-blob-btn: 16px 20px 14px 22px / 20px 14px 22px 16px;
|
||||
--clay-blob-round: 42% 58% 55% 45% / 48% 45% 55% 52%;
|
||||
--clay-blob-pellet: 14px 18px 15px 19px / 18px 14px 19px 15px;
|
||||
|
||||
--clay-ink: #33291f;
|
||||
|
||||
--flxn-avatar-radius: 45%;
|
||||
--flxn-avatar-border: 3px solid var(--clay-ring);
|
||||
--flxn-badge-radius: 16px 20px 18px 22px;
|
||||
}
|
||||
|
||||
/* ---------- 2. Light — soft studio ---------- */
|
||||
|
||||
[data-theme="clay"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--clay-surface: #f6f0e7;
|
||||
--clay-surface-hover: #faf5ee;
|
||||
--clay-well: #e5dccd;
|
||||
--clay-border: #d3c8b8;
|
||||
--clay-ring: #fffdf7;
|
||||
--clay-inset: inset 0 3px 6px rgba(122, 104, 86, 0.28),
|
||||
inset 0 -1px 0 rgba(255, 255, 255, 0.5);
|
||||
--clay-inset-sm: inset 0 2px 4px rgba(122, 104, 86, 0.24),
|
||||
inset 0 -1px 0 rgba(255, 255, 255, 0.45);
|
||||
|
||||
--mantine-color-body: #efe9e2;
|
||||
--mantine-color-text: #3a3128;
|
||||
--mantine-color-bright: #241f19;
|
||||
--mantine-color-dimmed: #6d6156;
|
||||
--mantine-color-placeholder: #837568;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-light-color);
|
||||
--mantine-color-error: var(--mantine-color-red-7);
|
||||
--mantine-color-default: #f6f0e7;
|
||||
--mantine-color-default-hover: #faf5ee;
|
||||
--mantine-color-default-color: #3a3128;
|
||||
--mantine-color-default-border: #d3c8b8;
|
||||
|
||||
/* primaryShade 4 gives chalky plasticine fills, but Mantine then derives
|
||||
chalky light-variant/text/outline colors that fail contrast on the light
|
||||
backdrop. Re-point every ramp's aliases at deeper shades so
|
||||
--mantine-primary-color-* keeps following the user's accent. */
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-4) 18%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-4) 26%, transparent);
|
||||
--mantine-color-blue-light-color: var(--mantine-color-blue-8);
|
||||
--mantine-color-blue-text: var(--mantine-color-blue-8);
|
||||
--mantine-color-blue-outline: var(--mantine-color-blue-7);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-4) 18%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-4) 26%, transparent);
|
||||
--mantine-color-red-light-color: var(--mantine-color-red-8);
|
||||
--mantine-color-red-text: var(--mantine-color-red-8);
|
||||
--mantine-color-red-outline: var(--mantine-color-red-7);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-4) 18%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-4) 26%, transparent);
|
||||
--mantine-color-green-light-color: var(--mantine-color-green-8);
|
||||
--mantine-color-green-text: var(--mantine-color-green-8);
|
||||
--mantine-color-green-outline: var(--mantine-color-green-7);
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-4) 18%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-4) 26%, transparent);
|
||||
--mantine-color-yellow-light-color: var(--mantine-color-yellow-8);
|
||||
--mantine-color-yellow-text: var(--mantine-color-yellow-8);
|
||||
--mantine-color-yellow-outline: var(--mantine-color-yellow-7);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-4) 18%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-4) 26%, transparent);
|
||||
--mantine-color-grape-light-color: var(--mantine-color-grape-8);
|
||||
--mantine-color-grape-text: var(--mantine-color-grape-8);
|
||||
--mantine-color-grape-outline: var(--mantine-color-grape-7);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-4) 18%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-4) 26%, transparent);
|
||||
--mantine-color-orange-light-color: var(--mantine-color-orange-8);
|
||||
--mantine-color-orange-text: var(--mantine-color-orange-8);
|
||||
--mantine-color-orange-outline: var(--mantine-color-orange-7);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-4) 18%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-4) 26%, transparent);
|
||||
--mantine-color-pink-light-color: var(--mantine-color-pink-8);
|
||||
--mantine-color-pink-text: var(--mantine-color-pink-8);
|
||||
--mantine-color-pink-outline: var(--mantine-color-pink-7);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-4) 18%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-4) 26%, transparent);
|
||||
--mantine-color-lime-light-color: var(--mantine-color-lime-8);
|
||||
--mantine-color-lime-text: var(--mantine-color-lime-8);
|
||||
--mantine-color-lime-outline: var(--mantine-color-lime-7);
|
||||
|
||||
/* pinched elevation: inner top highlight + soft warm drop */
|
||||
--mantine-shadow-xs: inset 0 1px 0 rgba(255, 255, 255, 0.55),
|
||||
0 3px 8px rgba(122, 104, 86, 0.18);
|
||||
--mantine-shadow-sm: inset 0 2px 3px rgba(255, 255, 255, 0.6),
|
||||
0 6px 14px rgba(122, 104, 86, 0.22);
|
||||
--mantine-shadow-md: inset 0 2px 4px rgba(255, 255, 255, 0.6),
|
||||
0 10px 22px rgba(122, 104, 86, 0.26);
|
||||
--mantine-shadow-lg: inset 0 2px 4px rgba(255, 255, 255, 0.62),
|
||||
0 14px 30px rgba(122, 104, 86, 0.3);
|
||||
--mantine-shadow-xl: inset 0 3px 5px rgba(255, 255, 255, 0.65),
|
||||
0 20px 40px rgba(122, 104, 86, 0.34);
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #8a6716;
|
||||
--flxn-silver: #6f665c;
|
||||
--flxn-bronze: #8a5a34;
|
||||
--flxn-toast-success: #538148;
|
||||
--flxn-toast-error: #b0543a;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #e0b545 12%, #f6f0e7);
|
||||
--flxn-podium-1-border: color-mix(in srgb, #a67d24 40%, #d3c8b8);
|
||||
--flxn-podium-1-label: #7c5d1b;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #97887a 12%, #f6f0e7);
|
||||
--flxn-podium-2-border: color-mix(in srgb, #786a5d 35%, #d3c8b8);
|
||||
--flxn-podium-2-label: #5d5248;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #c97a3d 12%, #f6f0e7);
|
||||
--flxn-podium-3-border: color-mix(in srgb, #a86230 38%, #d3c8b8);
|
||||
--flxn-podium-3-label: #7d4a22;
|
||||
--flxn-showcase-bg: #f6f0e7;
|
||||
--flxn-overlay: rgba(58, 49, 40, 0.45);
|
||||
--flxn-dotgrid-color: #d9cfc1;
|
||||
--flxn-pop-shadow: rgba(122, 104, 86, 0.4);
|
||||
}
|
||||
|
||||
/* ---------- 2. Dark — night studio, warm key light ---------- */
|
||||
|
||||
[data-theme="clay"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--clay-surface: #332c30;
|
||||
--clay-surface-hover: #3b3336;
|
||||
--clay-well: #1f1a1d;
|
||||
--clay-border: #4a3f42;
|
||||
--clay-ring: #4a4046;
|
||||
--clay-inset: inset 0 3px 6px rgba(0, 0, 0, 0.5),
|
||||
inset 0 -1px 0 rgba(255, 225, 185, 0.08);
|
||||
--clay-inset-sm: inset 0 2px 4px rgba(0, 0, 0, 0.45),
|
||||
inset 0 -1px 0 rgba(255, 225, 185, 0.07);
|
||||
|
||||
--mantine-color-body: #262023;
|
||||
--mantine-color-text: #efe6dc;
|
||||
--mantine-color-bright: #fbf6ef;
|
||||
--mantine-color-dimmed: #b3a79d;
|
||||
--mantine-color-placeholder: #8c7f76;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-3);
|
||||
--mantine-color-error: var(--mantine-color-red-3);
|
||||
--mantine-color-default: #332c30;
|
||||
--mantine-color-default-hover: #3b3336;
|
||||
--mantine-color-default-color: #efe6dc;
|
||||
--mantine-color-default-border: #4a3f42;
|
||||
|
||||
/* warm inner highlight, deep studio shadows */
|
||||
--mantine-shadow-xs: inset 0 1px 0 rgba(255, 225, 185, 0.1),
|
||||
0 3px 8px rgba(0, 0, 0, 0.4);
|
||||
--mantine-shadow-sm: inset 0 2px 3px rgba(255, 225, 185, 0.12),
|
||||
0 8px 16px rgba(0, 0, 0, 0.45);
|
||||
--mantine-shadow-md: inset 0 2px 4px rgba(255, 225, 185, 0.13),
|
||||
0 12px 24px rgba(0, 0, 0, 0.5);
|
||||
--mantine-shadow-lg: inset 0 2px 4px rgba(255, 225, 185, 0.14),
|
||||
0 16px 32px rgba(0, 0, 0, 0.55);
|
||||
--mantine-shadow-xl: inset 0 3px 5px rgba(255, 225, 185, 0.15),
|
||||
0 22px 44px rgba(0, 0, 0, 0.6);
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #e0bd6a;
|
||||
--flxn-silver: #b8ada2;
|
||||
--flxn-bronze: #d69a6e;
|
||||
--flxn-toast-success: #9cc98e;
|
||||
--flxn-toast-error: #eda28c;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #e0bd6a 13%, #332c30);
|
||||
--flxn-podium-1-border: color-mix(in srgb, #e0bd6a 32%, #4a3f42);
|
||||
--flxn-podium-1-label: #e0bd6a;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #b8ada2 11%, #332c30);
|
||||
--flxn-podium-2-border: color-mix(in srgb, #b8ada2 28%, #4a3f42);
|
||||
--flxn-podium-2-label: #b8ada2;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #d69a6e 12%, #332c30);
|
||||
--flxn-podium-3-border: color-mix(in srgb, #d69a6e 28%, #4a3f42);
|
||||
--flxn-podium-3-label: #d69a6e;
|
||||
--flxn-showcase-bg: #332c30;
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.55);
|
||||
--flxn-dotgrid-color: rgba(255, 235, 215, 0.12);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* ---------- 3. Type flavor ---------- */
|
||||
|
||||
[data-theme="clay"] body {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ---------- 4. Backdrop — studio key light + clay grain ---------- */
|
||||
|
||||
[data-theme="clay"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -1; /* behind content — never tints text or surfaces */
|
||||
pointer-events: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
[data-theme="clay"][data-mantine-color-scheme="light"] body::before {
|
||||
background-image: radial-gradient(
|
||||
120% 70% at 50% 0%,
|
||||
rgba(255, 252, 244, 0.65),
|
||||
transparent 65%
|
||||
),
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
[data-theme="clay"][data-mantine-color-scheme="dark"] body::before {
|
||||
background-image: radial-gradient(
|
||||
110% 65% at 50% 0%,
|
||||
rgba(255, 208, 158, 0.09),
|
||||
transparent 62%
|
||||
),
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
|
||||
}
|
||||
|
||||
/* ---------- 5. Clay blob surfaces ---------- */
|
||||
|
||||
[data-theme="clay"] .mantine-Paper-root {
|
||||
background-color: var(--clay-surface);
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-md);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Card-root {
|
||||
border-radius: var(--clay-blob-card);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Popover-dropdown,
|
||||
[data-theme="clay"] .mantine-Menu-dropdown,
|
||||
[data-theme="clay"] .mantine-Modal-content,
|
||||
[data-theme="clay"] .mantine-Notification-root {
|
||||
background-color: var(--clay-surface);
|
||||
border: 1px solid var(--clay-border);
|
||||
box-shadow: var(--mantine-shadow-lg);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Modal-content {
|
||||
border-radius: var(--clay-blob-card);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Modal-header {
|
||||
background-color: var(--clay-surface);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Notification-root {
|
||||
border-radius: var(--clay-blob-md);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Alert-root {
|
||||
border-radius: var(--clay-blob-md);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Tooltip-tooltip {
|
||||
border-radius: var(--clay-blob-pellet);
|
||||
font-weight: 600;
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="clay"][data-mantine-color-scheme="light"] .mantine-Tooltip-tooltip {
|
||||
background-color: #3a3128;
|
||||
color: #f3ece2;
|
||||
}
|
||||
|
||||
[data-theme="clay"][data-mantine-color-scheme="dark"] .mantine-Tooltip-tooltip {
|
||||
background-color: #efe6dc;
|
||||
color: #33291f;
|
||||
}
|
||||
|
||||
/* App shell: rolled clay slabs, soft edges */
|
||||
[data-theme="clay"] .mantine-AppShell-header {
|
||||
background-color: var(--clay-surface);
|
||||
border-bottom: 1px solid var(--clay-border);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-AppShell-navbar {
|
||||
background-color: var(--clay-surface);
|
||||
border-top: 1px solid var(--clay-border);
|
||||
border-inline-end: 1px solid var(--clay-border);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
/* ---------- 6. Thumbed buttons ---------- */
|
||||
|
||||
[data-theme="clay"] .mantine-Button-root {
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-btn);
|
||||
font-family: "Baloo 2", "Nunito", system-ui, sans-serif;
|
||||
font-weight: 700;
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
transition: box-shadow 160ms ease, background-color 120ms ease-out;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-ActionIcon-root {
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-round);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Button-root:where([data-variant="filled"], :not([data-variant])),
|
||||
[data-theme="clay"] .mantine-ActionIcon-root:where([data-variant="filled"], :not([data-variant])) {
|
||||
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 78%, var(--clay-ink));
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Button-root:where([data-variant="default"], [data-variant="outline"]),
|
||||
[data-theme="clay"] .mantine-ActionIcon-root:where([data-variant="default"], [data-variant="outline"]) {
|
||||
background-color: var(--clay-surface);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Button-root:where([data-variant="default"], [data-variant="outline"]):hover,
|
||||
[data-theme="clay"] .mantine-ActionIcon-root:where([data-variant="default"], [data-variant="outline"]):hover {
|
||||
background-color: var(--clay-surface-hover);
|
||||
}
|
||||
|
||||
/* Ghost variants stay flat — no floating clay plates */
|
||||
[data-theme="clay"] .mantine-Button-root:where([data-variant="subtle"], [data-variant="transparent"], [data-variant="white"]),
|
||||
[data-theme="clay"] .mantine-ActionIcon-root:where([data-variant="subtle"], [data-variant="transparent"], [data-variant="white"]) {
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Button-root:active:not([data-disabled], :disabled, [data-loading]),
|
||||
[data-theme="clay"] .mantine-ActionIcon-root:active:not([data-disabled], :disabled, [data-loading]) {
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Button-root:where([data-disabled], :disabled),
|
||||
[data-theme="clay"] .mantine-ActionIcon-root:where([data-disabled], :disabled) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Every chalky fill pairs with the dark clay ink, never white */
|
||||
[data-theme="clay"] .mantine-Button-root:not([data-variant]):not(:disabled):not([data-disabled]),
|
||||
[data-theme="clay"] .mantine-Button-root[data-variant="filled"]:not(:disabled):not([data-disabled]),
|
||||
[data-theme="clay"] .mantine-ActionIcon-root:not([data-variant]):not(:disabled):not([data-disabled]),
|
||||
[data-theme="clay"] .mantine-ActionIcon-root[data-variant="filled"]:not(:disabled):not([data-disabled]),
|
||||
[data-theme="clay"] .mantine-Badge-root:not([data-variant]),
|
||||
[data-theme="clay"] .mantine-Badge-root[data-variant="filled"],
|
||||
[data-theme="clay"] .mantine-ThemeIcon-root:not([data-variant]),
|
||||
[data-theme="clay"] .mantine-ThemeIcon-root[data-variant="filled"] {
|
||||
color: var(--clay-ink);
|
||||
}
|
||||
|
||||
/* Extra squish: pressed clay squashes wide and short */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="clay"] .flxn-press {
|
||||
transition: transform 160ms cubic-bezier(0.34, 1.3, 0.5, 1);
|
||||
}
|
||||
[data-theme="clay"]
|
||||
.flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transform: scale(1.02, 0.92);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- 7. Inputs — thumb-pressed wells ---------- */
|
||||
|
||||
[data-theme="clay"] .mantine-Input-input {
|
||||
background-color: var(--clay-surface);
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-md);
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
transition: border-color 160ms ease, box-shadow 160ms ease;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Input-input:focus,
|
||||
[data-theme="clay"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: var(--clay-inset);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Input-input[data-error] {
|
||||
border-color: var(--mantine-color-error);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-PinInput-field {
|
||||
border-radius: var(--clay-blob-pellet);
|
||||
font-family: "Baloo 2", "Nunito", system-ui, sans-serif;
|
||||
}
|
||||
|
||||
/* ---------- 8. Clay pellet badges ---------- */
|
||||
|
||||
[data-theme="clay"] .mantine-Badge-root {
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-pellet);
|
||||
font-family: "Baloo 2", "Nunito", system-ui, sans-serif;
|
||||
font-weight: 700;
|
||||
text-transform: none;
|
||||
letter-spacing: 0.01em;
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Badge-root:where([data-variant="filled"], :not([data-variant])) {
|
||||
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 78%, var(--clay-ink));
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Badge-root[data-variant="default"] {
|
||||
background-color: var(--clay-surface);
|
||||
color: var(--mantine-color-text);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-ThemeIcon-root {
|
||||
border-radius: var(--clay-blob-round);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-ThemeIcon-root[data-variant="default"] {
|
||||
background-color: var(--clay-surface);
|
||||
border: 1px solid var(--clay-border);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
/* ---------- 9. Selection controls ---------- */
|
||||
|
||||
/* SegmentedControl: pressed trough, raised clay pellet indicator */
|
||||
[data-theme="clay"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--clay-well);
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-md);
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--clay-surface);
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-pellet);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-SegmentedControl-label {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-SegmentedControl-label[data-active] {
|
||||
color: var(--mantine-color-bright);
|
||||
}
|
||||
|
||||
/* Switch: trough + rolled clay ball thumb */
|
||||
[data-theme="clay"] .mantine-Switch-track {
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: 999px;
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Switch-thumb {
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-round);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Checkbox-input {
|
||||
border: 2px solid var(--clay-border);
|
||||
border-radius: 9px 11px 10px 12px / 11px 9px 12px 10px;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Checkbox-input:not(:checked) {
|
||||
background-color: var(--clay-surface);
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
}
|
||||
|
||||
/* Progress: finger-groove trough */
|
||||
[data-theme="clay"] .mantine-Progress-root {
|
||||
background-color: var(--clay-well);
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: 999px;
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Progress-section {
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
/* ---------- 10. Navigation & misc ---------- */
|
||||
|
||||
[data-theme="clay"] .mantine-Tabs-list {
|
||||
border-bottom-color: transparent;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Tabs-tab {
|
||||
border: 0;
|
||||
border-radius: var(--clay-blob-pellet);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Tabs-tab[data-active] {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-NavLink-root {
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--clay-blob-md);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-NavLink-root[data-active] {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
border-color: var(--clay-border);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Skeleton-root {
|
||||
border-radius: var(--clay-blob-md);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Divider-root {
|
||||
--divider-color: var(--clay-border);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .mantine-Loader-root {
|
||||
--loader-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
/* ---------- 11. App component hooks ---------- */
|
||||
|
||||
[data-theme="clay"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--mantine-color-body);
|
||||
border-bottom-color: var(--clay-border);
|
||||
box-shadow: 0 8px 16px -8px var(--flxn-pop-shadow);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .flxn-tab.flxn-tab {
|
||||
border-radius: var(--clay-blob-pellet);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .flxn-tab.flxn-tab[data-active] {
|
||||
color: var(--flxn-on-accent);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="clay"] .flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: none;
|
||||
border-radius: var(--clay-blob-pellet);
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
}
|
||||
|
||||
/* Nav grid tiles: pinched clay pats, radii varied like hand-rolled pieces */
|
||||
[data-theme="clay"] .flxn-tile.flxn-tile {
|
||||
background-color: var(--clay-surface);
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-card);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .flxn-tile.flxn-tile:nth-child(even) {
|
||||
border-radius: var(--clay-blob-card-alt);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="clay"] .flxn-tile.flxn-tile:hover:not(:disabled) {
|
||||
background-color: var(--clay-surface-hover);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="clay"] .flxn-tile.flxn-tile:active:not(:disabled) {
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
}
|
||||
|
||||
/* Flat glyph tint — no plates behind icons */
|
||||
[data-theme="clay"] .flxn-tile-icon.flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* "See all" as a small clay chip: accent wash + wash on-color */
|
||||
[data-theme="clay"] .flxn-see-all.flxn-see-all {
|
||||
font-family: "Baloo 2", "Nunito", system-ui, sans-serif;
|
||||
font-weight: 700;
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
border: 1px solid color-mix(in srgb, var(--mantine-primary-color-light-color) 30%, transparent);
|
||||
border-radius: var(--clay-blob-pellet);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="clay"] .flxn-see-all.flxn-see-all:hover {
|
||||
background-color: var(--mantine-primary-color-light-hover);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Match card + reaction tray: one pressed-together construction — the card
|
||||
is a raised pat, the tray a thumb-groove in the same slab */
|
||||
[data-theme="clay"] .flxn-match-card.flxn-match-card {
|
||||
background-color: var(--clay-surface);
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-card);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="clay"] .flxn-reaction-row.flxn-reaction-row {
|
||||
background-color: var(--clay-well);
|
||||
border: 1px solid var(--clay-border);
|
||||
border-radius: var(--clay-blob-md);
|
||||
box-shadow: var(--clay-inset-sm);
|
||||
}
|
||||
|
||||
/* Blobby avatar: the frame owns the single 3px clay ring */
|
||||
[data-theme="clay"] .flxn-avatar-frame {
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "deco",
|
||||
label: msg`Art Deco`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Cinzel:wght@400..700&family=Josefin+Sans:ital,wght@0,300..700;1,300..700&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#f6f1e5", dimmed: "#e7dfc9" },
|
||||
dark: { base: "#16151a", dimmed: "#0e0d11" },
|
||||
},
|
||||
mantine: {
|
||||
defaultRadius: 0,
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,619 @@
|
||||
/* Art Deco — 1928 Gatsby luxury. Champagne gold on midnight ink (dark) and
|
||||
ivory (light). Sharp geometry, double gold rules, gold-foil ornament.
|
||||
Gold is STRUCTURAL decoration only; the interactive accent follows the
|
||||
user's choice via the primary aliases over eight jewel-tone ramps. */
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 1. Tokens, any scheme */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"][data-theme] {
|
||||
--mantine-font-family: "Josefin Sans", "Avenir Next", "Century Gothic", sans-serif;
|
||||
--mantine-font-family-headings: "Cinzel", "Trajan Pro", "Times New Roman", serif;
|
||||
--mantine-heading-font-weight: 600;
|
||||
|
||||
--mantine-radius-default: 0;
|
||||
--mantine-radius-xs: 0;
|
||||
--mantine-radius-sm: 0;
|
||||
--mantine-radius-md: 0;
|
||||
--mantine-radius-lg: 0;
|
||||
--mantine-radius-xl: 0;
|
||||
|
||||
--flxn-avatar-radius: 0;
|
||||
--flxn-avatar-border: 1px solid var(--deco-rule);
|
||||
--flxn-badge-radius: 0;
|
||||
|
||||
--mantine-color-white: #fcf9f0;
|
||||
--mantine-color-black: #16151a;
|
||||
|
||||
/* Jewel-tone accent ramps. Shade 6 (light filled/text) holds >= 4.5:1
|
||||
against ivory; shades 3-4 (dark text/anchor) read on midnight ink. */
|
||||
|
||||
/* blue -> sapphire */
|
||||
--mantine-color-blue-0: #eaf1fb;
|
||||
--mantine-color-blue-1: #cfdff4;
|
||||
--mantine-color-blue-2: #a9c6e8;
|
||||
--mantine-color-blue-3: #7fa8d8;
|
||||
--mantine-color-blue-4: #5a8ac6;
|
||||
--mantine-color-blue-5: #3d6eb0;
|
||||
--mantine-color-blue-6: #2c5697;
|
||||
--mantine-color-blue-7: #224477;
|
||||
--mantine-color-blue-8: #19345c;
|
||||
--mantine-color-blue-9: #112544;
|
||||
|
||||
/* red -> ruby */
|
||||
--mantine-color-red-0: #fdecee;
|
||||
--mantine-color-red-1: #f7cdd2;
|
||||
--mantine-color-red-2: #eea6af;
|
||||
--mantine-color-red-3: #e17d8a;
|
||||
--mantine-color-red-4: #cf5766;
|
||||
--mantine-color-red-5: #b93a4c;
|
||||
--mantine-color-red-6: #9e2b3f;
|
||||
--mantine-color-red-7: #822235;
|
||||
--mantine-color-red-8: #651a2a;
|
||||
--mantine-color-red-9: #4a121f;
|
||||
|
||||
/* green -> emerald */
|
||||
--mantine-color-green-0: #e6f5ee;
|
||||
--mantine-color-green-1: #c6e8d8;
|
||||
--mantine-color-green-2: #9cd6bc;
|
||||
--mantine-color-green-3: #6fc19e;
|
||||
--mantine-color-green-4: #46aa82;
|
||||
--mantine-color-green-5: #21936a;
|
||||
--mantine-color-green-6: #147a57;
|
||||
--mantine-color-green-7: #0f6247;
|
||||
--mantine-color-green-8: #0b4c37;
|
||||
--mantine-color-green-9: #073828;
|
||||
|
||||
/* yellow -> champagne gold */
|
||||
--mantine-color-yellow-0: #fbf6e3;
|
||||
--mantine-color-yellow-1: #f7ecc4;
|
||||
--mantine-color-yellow-2: #f5e08c;
|
||||
--mantine-color-yellow-3: #eacf6d;
|
||||
--mantine-color-yellow-4: #dfbd52;
|
||||
--mantine-color-yellow-5: #d4af37;
|
||||
--mantine-color-yellow-6: #8a6508;
|
||||
--mantine-color-yellow-7: #6f5106;
|
||||
--mantine-color-yellow-8: #563e05;
|
||||
--mantine-color-yellow-9: #3d2c03;
|
||||
|
||||
/* grape -> amethyst */
|
||||
--mantine-color-grape-0: #f4edfa;
|
||||
--mantine-color-grape-1: #e2d3f2;
|
||||
--mantine-color-grape-2: #cdb1e8;
|
||||
--mantine-color-grape-3: #b58ade;
|
||||
--mantine-color-grape-4: #9c6ecb;
|
||||
--mantine-color-grape-5: #7f4cb3;
|
||||
--mantine-color-grape-6: #663693;
|
||||
--mantine-color-grape-7: #532b79;
|
||||
--mantine-color-grape-8: #40215e;
|
||||
--mantine-color-grape-9: #2e1844;
|
||||
|
||||
/* orange -> amber */
|
||||
--mantine-color-orange-0: #fdf1e3;
|
||||
--mantine-color-orange-1: #f9dcbb;
|
||||
--mantine-color-orange-2: #f2c184;
|
||||
--mantine-color-orange-3: #e8a355;
|
||||
--mantine-color-orange-4: #da8730;
|
||||
--mantine-color-orange-5: #c66f15;
|
||||
--mantine-color-orange-6: #a85a0c;
|
||||
--mantine-color-orange-7: #8a4a09;
|
||||
--mantine-color-orange-8: #6b3a07;
|
||||
--mantine-color-orange-9: #4d2a05;
|
||||
|
||||
/* pink -> rose */
|
||||
--mantine-color-pink-0: #fbedf3;
|
||||
--mantine-color-pink-1: #f5cfe0;
|
||||
--mantine-color-pink-2: #eba7c6;
|
||||
--mantine-color-pink-3: #dd7aa8;
|
||||
--mantine-color-pink-4: #c9538b;
|
||||
--mantine-color-pink-5: #b23a72;
|
||||
--mantine-color-pink-6: #a12a5e;
|
||||
--mantine-color-pink-7: #862150;
|
||||
--mantine-color-pink-8: #681940;
|
||||
--mantine-color-pink-9: #4b122e;
|
||||
|
||||
/* lime -> peridot */
|
||||
--mantine-color-lime-0: #f5f7e1;
|
||||
--mantine-color-lime-1: #e8edbd;
|
||||
--mantine-color-lime-2: #d5df90;
|
||||
--mantine-color-lime-3: #c0cd64;
|
||||
--mantine-color-lime-4: #a8b83f;
|
||||
--mantine-color-lime-5: #8c9c26;
|
||||
--mantine-color-lime-6: #5f6e12;
|
||||
--mantine-color-lime-7: #4c580e;
|
||||
--mantine-color-lime-8: #39430b;
|
||||
--mantine-color-lime-9: #283007;
|
||||
|
||||
/* minimal shadows with a whisper of gold edge-glow */
|
||||
--mantine-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.16);
|
||||
--mantine-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(212, 175, 55, 0.08);
|
||||
--mantine-shadow-md: 0 2px 6px rgba(0, 0, 0, 0.2), 0 0 10px rgba(212, 175, 55, 0.07);
|
||||
--mantine-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.24), 0 0 16px rgba(212, 175, 55, 0.09);
|
||||
--mantine-shadow-xl: 0 8px 24px rgba(0, 0, 0, 0.28), 0 0 22px rgba(212, 175, 55, 0.1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 2. Per-scheme tokens */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #16151a;
|
||||
--mantine-color-text: #eae3d1;
|
||||
--mantine-color-bright: #f6f1e5;
|
||||
--mantine-color-dimmed: #a79d85;
|
||||
--mantine-color-placeholder: #837a66;
|
||||
--mantine-color-error: #d06a6d;
|
||||
|
||||
--mantine-color-default: #201e25;
|
||||
--mantine-color-default-hover: #272430;
|
||||
--mantine-color-default-color: #eae3d1;
|
||||
--mantine-color-default-border: #4a4230;
|
||||
|
||||
/* ink-charcoal surface ramp */
|
||||
--mantine-color-dark-0: #d6d0c2;
|
||||
--mantine-color-dark-1: #aaa294;
|
||||
--mantine-color-dark-2: #8a8274;
|
||||
--mantine-color-dark-3: #5c564a;
|
||||
--mantine-color-dark-4: #444038;
|
||||
--mantine-color-dark-5: #302d31;
|
||||
--mantine-color-dark-6: #232127;
|
||||
--mantine-color-dark-7: #1b1a1f;
|
||||
--mantine-color-dark-8: #141317;
|
||||
--mantine-color-dark-9: #101014;
|
||||
|
||||
/* deep jewel fills in dark too (Mantine defaults to shade 8) */
|
||||
--mantine-color-blue-filled: var(--mantine-color-blue-6);
|
||||
--mantine-color-blue-filled-hover: var(--mantine-color-blue-5);
|
||||
--mantine-color-red-filled: var(--mantine-color-red-6);
|
||||
--mantine-color-red-filled-hover: var(--mantine-color-red-5);
|
||||
--mantine-color-green-filled: var(--mantine-color-green-6);
|
||||
--mantine-color-green-filled-hover: var(--mantine-color-green-5);
|
||||
--mantine-color-yellow-filled: var(--mantine-color-yellow-6);
|
||||
--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-7);
|
||||
--mantine-color-grape-filled: var(--mantine-color-grape-6);
|
||||
--mantine-color-grape-filled-hover: var(--mantine-color-grape-5);
|
||||
--mantine-color-orange-filled: var(--mantine-color-orange-6);
|
||||
--mantine-color-orange-filled-hover: var(--mantine-color-orange-5);
|
||||
--mantine-color-pink-filled: var(--mantine-color-pink-6);
|
||||
--mantine-color-pink-filled-hover: var(--mantine-color-pink-5);
|
||||
--mantine-color-lime-filled: var(--mantine-color-lime-6);
|
||||
--mantine-color-lime-filled-hover: var(--mantine-color-lime-7);
|
||||
|
||||
/* soft-variant tints from the jewel mid-shades */
|
||||
--mantine-color-blue-light: rgba(90, 138, 198, 0.14);
|
||||
--mantine-color-blue-light-hover: rgba(90, 138, 198, 0.2);
|
||||
--mantine-color-blue-outline-hover: rgba(90, 138, 198, 0.08);
|
||||
--mantine-color-red-light: rgba(207, 87, 102, 0.14);
|
||||
--mantine-color-red-light-hover: rgba(207, 87, 102, 0.2);
|
||||
--mantine-color-red-outline-hover: rgba(207, 87, 102, 0.08);
|
||||
--mantine-color-green-light: rgba(70, 170, 130, 0.14);
|
||||
--mantine-color-green-light-hover: rgba(70, 170, 130, 0.2);
|
||||
--mantine-color-green-outline-hover: rgba(70, 170, 130, 0.08);
|
||||
--mantine-color-yellow-light: rgba(212, 175, 55, 0.14);
|
||||
--mantine-color-yellow-light-hover: rgba(212, 175, 55, 0.2);
|
||||
--mantine-color-yellow-outline-hover: rgba(212, 175, 55, 0.08);
|
||||
--mantine-color-grape-light: rgba(156, 110, 203, 0.14);
|
||||
--mantine-color-grape-light-hover: rgba(156, 110, 203, 0.2);
|
||||
--mantine-color-grape-outline-hover: rgba(156, 110, 203, 0.08);
|
||||
--mantine-color-orange-light: rgba(218, 135, 48, 0.14);
|
||||
--mantine-color-orange-light-hover: rgba(218, 135, 48, 0.2);
|
||||
--mantine-color-orange-outline-hover: rgba(218, 135, 48, 0.08);
|
||||
--mantine-color-pink-light: rgba(201, 83, 139, 0.14);
|
||||
--mantine-color-pink-light-hover: rgba(201, 83, 139, 0.2);
|
||||
--mantine-color-pink-outline-hover: rgba(201, 83, 139, 0.08);
|
||||
--mantine-color-lime-light: rgba(168, 184, 63, 0.14);
|
||||
--mantine-color-lime-light-hover: rgba(168, 184, 63, 0.2);
|
||||
--mantine-color-lime-outline-hover: rgba(168, 184, 63, 0.08);
|
||||
|
||||
--mantine-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(212, 175, 55, 0.1);
|
||||
--mantine-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.45), 0 0 12px rgba(212, 175, 55, 0.08);
|
||||
|
||||
/* deco internals */
|
||||
--deco-rule: rgba(212, 175, 55, 0.55);
|
||||
--deco-rule-faint: rgba(212, 175, 55, 0.28);
|
||||
--deco-chrome: #1b1a20;
|
||||
--deco-gold-text: #eacf6d;
|
||||
--deco-ray: rgba(212, 175, 55, 0.045);
|
||||
--deco-tray: #121116;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #d4af37;
|
||||
--flxn-silver: #c9ccd6;
|
||||
--flxn-bronze: #c08447;
|
||||
--flxn-toast-success: #46aa82;
|
||||
--flxn-toast-error: #d06a6d;
|
||||
--flxn-podium-1-bg: linear-gradient(150deg, rgba(245, 224, 140, 0.16), rgba(184, 134, 11, 0.1) 55%, rgba(122, 86, 7, 0.16));
|
||||
--flxn-podium-1-border: #b8860b;
|
||||
--flxn-podium-1-label: #eacf6d;
|
||||
--flxn-podium-2-bg: linear-gradient(150deg, rgba(232, 234, 240, 0.13), rgba(148, 153, 166, 0.08) 55%, rgba(96, 101, 114, 0.12));
|
||||
--flxn-podium-2-border: #9aa0ad;
|
||||
--flxn-podium-2-label: #cfd4de;
|
||||
--flxn-podium-3-bg: linear-gradient(150deg, rgba(222, 152, 82, 0.14), rgba(160, 106, 53, 0.09) 55%, rgba(110, 70, 32, 0.14));
|
||||
--flxn-podium-3-border: #a06a35;
|
||||
--flxn-podium-3-label: #d9a066;
|
||||
--flxn-showcase-bg: #1b1a20;
|
||||
--flxn-overlay: rgba(8, 7, 10, 0.62);
|
||||
--flxn-dotgrid-color: rgba(212, 175, 55, 0.16);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
[data-theme="deco"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #f6f1e5;
|
||||
--mantine-color-text: #26200f;
|
||||
--mantine-color-bright: #131008;
|
||||
--mantine-color-dimmed: #6d6450;
|
||||
--mantine-color-placeholder: #948a72;
|
||||
--mantine-color-error: #9e2b3f;
|
||||
|
||||
--mantine-color-default: #fbf7ec;
|
||||
--mantine-color-default-hover: #f0e9d6;
|
||||
--mantine-color-default-color: #26200f;
|
||||
--mantine-color-default-border: #d3c69f;
|
||||
|
||||
/* warm champagne gray ramp */
|
||||
--mantine-color-gray-0: #f3edda;
|
||||
--mantine-color-gray-1: #eae2ca;
|
||||
--mantine-color-gray-2: #ddd2b4;
|
||||
--mantine-color-gray-3: #cfc29e;
|
||||
--mantine-color-gray-4: #b5a988;
|
||||
--mantine-color-gray-5: #988d70;
|
||||
--mantine-color-gray-6: #7a7059;
|
||||
--mantine-color-gray-7: #5c5443;
|
||||
--mantine-color-gray-8: #3f3a2e;
|
||||
--mantine-color-gray-9: #26221a;
|
||||
|
||||
/* soft-variant tints from the jewel shade-6 fills */
|
||||
--mantine-color-blue-light: rgba(44, 86, 151, 0.1);
|
||||
--mantine-color-blue-light-hover: rgba(44, 86, 151, 0.16);
|
||||
--mantine-color-blue-outline-hover: rgba(44, 86, 151, 0.06);
|
||||
--mantine-color-red-light: rgba(158, 43, 63, 0.1);
|
||||
--mantine-color-red-light-hover: rgba(158, 43, 63, 0.16);
|
||||
--mantine-color-red-outline-hover: rgba(158, 43, 63, 0.06);
|
||||
--mantine-color-green-light: rgba(20, 122, 87, 0.1);
|
||||
--mantine-color-green-light-hover: rgba(20, 122, 87, 0.16);
|
||||
--mantine-color-green-outline-hover: rgba(20, 122, 87, 0.06);
|
||||
--mantine-color-yellow-light: rgba(138, 101, 8, 0.1);
|
||||
--mantine-color-yellow-light-hover: rgba(138, 101, 8, 0.16);
|
||||
--mantine-color-yellow-outline-hover: rgba(138, 101, 8, 0.06);
|
||||
--mantine-color-grape-light: rgba(102, 54, 147, 0.1);
|
||||
--mantine-color-grape-light-hover: rgba(102, 54, 147, 0.16);
|
||||
--mantine-color-grape-outline-hover: rgba(102, 54, 147, 0.06);
|
||||
--mantine-color-orange-light: rgba(168, 90, 12, 0.1);
|
||||
--mantine-color-orange-light-hover: rgba(168, 90, 12, 0.16);
|
||||
--mantine-color-orange-outline-hover: rgba(168, 90, 12, 0.06);
|
||||
--mantine-color-pink-light: rgba(161, 42, 94, 0.1);
|
||||
--mantine-color-pink-light-hover: rgba(161, 42, 94, 0.16);
|
||||
--mantine-color-pink-outline-hover: rgba(161, 42, 94, 0.06);
|
||||
--mantine-color-lime-light: rgba(95, 110, 18, 0.1);
|
||||
--mantine-color-lime-light-hover: rgba(95, 110, 18, 0.16);
|
||||
--mantine-color-lime-outline-hover: rgba(95, 110, 18, 0.06);
|
||||
|
||||
--mantine-shadow-sm: 0 1px 2px rgba(60, 45, 10, 0.12), 0 0 0 1px rgba(150, 109, 9, 0.08);
|
||||
--mantine-shadow-md: 0 2px 6px rgba(60, 45, 10, 0.14), 0 0 10px rgba(150, 109, 9, 0.07);
|
||||
|
||||
/* deco internals — darker golds for on-ivory contrast */
|
||||
--deco-rule: rgba(150, 109, 9, 0.6);
|
||||
--deco-rule-faint: rgba(150, 109, 9, 0.32);
|
||||
--deco-chrome: #f2ecda;
|
||||
--deco-gold-text: #7c5a06;
|
||||
--deco-ray: rgba(150, 109, 9, 0.05);
|
||||
--deco-tray: #ede4cc;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #b8860b;
|
||||
--flxn-silver: #7b8494;
|
||||
--flxn-bronze: #9c5f28;
|
||||
--flxn-toast-success: #147a57;
|
||||
--flxn-toast-error: #9e2b3f;
|
||||
--flxn-podium-1-bg: linear-gradient(150deg, #fdf6dd, #f5e6b2 55%, #ecd68b);
|
||||
--flxn-podium-1-border: #c49a1e;
|
||||
--flxn-podium-1-label: #563e05;
|
||||
--flxn-podium-2-bg: linear-gradient(150deg, #f6f5f2, #e6e6e8 55%, #d7d8dc);
|
||||
--flxn-podium-2-border: #a9adb8;
|
||||
--flxn-podium-2-label: #565d6b;
|
||||
--flxn-podium-3-bg: linear-gradient(150deg, #f9ecdb, #f0d8b6 55%, #e5c294);
|
||||
--flxn-podium-3-border: #b07a3e;
|
||||
--flxn-podium-3-label: #6b3a07;
|
||||
--flxn-showcase-bg: #fdfaf1;
|
||||
--flxn-overlay: rgba(24, 20, 8, 0.42);
|
||||
--flxn-dotgrid-color: rgba(138, 101, 8, 0.28);
|
||||
--flxn-pop-shadow: rgba(60, 45, 10, 0.28);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 3. Typography */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] :is(h1, h2, h3, h4, h5, h6),
|
||||
[data-theme="deco"] .mantine-Title-root {
|
||||
letter-spacing: 0.06em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* gold-foil h1 (decoration): solid gold fallback, gradient foil where supported */
|
||||
[data-theme="deco"] h1 {
|
||||
color: var(--deco-gold-text);
|
||||
}
|
||||
|
||||
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
|
||||
[data-theme="deco"] h1 {
|
||||
background-image: linear-gradient(170deg, #f5e08c 0%, #d4af37 45%, #b8860b 100%);
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
[data-theme="deco"][data-mantine-color-scheme="light"] h1 {
|
||||
background-image: linear-gradient(170deg, #c49a1e 0%, #966d09 55%, #6e4f05 100%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
[data-theme="deco"] h1 {
|
||||
background-image: none;
|
||||
color: CanvasText;
|
||||
-webkit-text-fill-color: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Anchor-root {
|
||||
text-underline-offset: 3px;
|
||||
text-decoration-color: var(--deco-rule-faint);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 4. Sunburst fan — faint gold rays from top center */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998;
|
||||
pointer-events: none;
|
||||
background: repeating-conic-gradient(
|
||||
from 240deg at 50% -12%,
|
||||
var(--deco-ray) 0deg 3deg,
|
||||
transparent 3deg 8deg
|
||||
);
|
||||
-webkit-mask-image: linear-gradient(to bottom, #000, transparent 42%);
|
||||
mask-image: linear-gradient(to bottom, #000, transparent 42%);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 5. Surfaces — double gold rules */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] .mantine-Paper-root {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Card-root,
|
||||
[data-theme="deco"] .mantine-Modal-content,
|
||||
[data-theme="deco"] .mantine-Notification-root {
|
||||
border: 1px solid var(--deco-rule);
|
||||
outline: 1px solid var(--deco-rule-faint);
|
||||
outline-offset: -5px;
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Popover-dropdown,
|
||||
[data-theme="deco"] .mantine-Alert-root {
|
||||
border: 1px solid var(--deco-rule-faint);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Modal-header {
|
||||
border-bottom: 1px solid var(--deco-rule-faint);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Tooltip-tooltip {
|
||||
border: 1px solid var(--deco-rule-faint);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 6. App shell — gold double rules on header/navbar */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] .mantine-AppShell-header {
|
||||
background-color: var(--deco-chrome);
|
||||
border-bottom: 1px solid var(--deco-rule);
|
||||
box-shadow: 0 4px 0 -3px var(--deco-rule-faint);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-AppShell-navbar {
|
||||
background-color: var(--deco-chrome);
|
||||
border-top: 1px solid var(--deco-rule);
|
||||
box-shadow: 0 -4px 0 -3px var(--deco-rule-faint);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 7. Buttons — jewel accent fill inside a thin gold rim */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] .mantine-Button-root {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="deco"] .mantine-ActionIcon-root[data-variant="filled"] {
|
||||
border: 1px solid var(--deco-rule);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="deco"] .mantine-Button-root[data-variant="outline"] {
|
||||
border: 1px solid var(--deco-rule);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Button-root:disabled,
|
||||
[data-theme="deco"] .mantine-Button-root[data-disabled],
|
||||
[data-theme="deco"] .mantine-ActionIcon-root:disabled,
|
||||
[data-theme="deco"] .mantine-ActionIcon-root[data-disabled] {
|
||||
background: var(--mantine-color-default);
|
||||
color: var(--mantine-color-dimmed);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 8. Inputs */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] .mantine-Input-input,
|
||||
[data-theme="deco"] .mantine-PinInput-input {
|
||||
border: 1px solid var(--deco-rule-faint);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Input-input:focus,
|
||||
[data-theme="deco"] .mantine-Input-input:focus-within,
|
||||
[data-theme="deco"] .mantine-PinInput-input:focus {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: 0 0 0 1px var(--deco-rule-faint);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 9. Tabs / SegmentedControl / Badge / NavLink */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] .mantine-Tabs-tab {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-size: var(--mantine-font-size-xs);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Tabs-tab[data-active] {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
border-color: var(--flxn-gold);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-SegmentedControl-root {
|
||||
border: 1px solid var(--deco-rule-faint);
|
||||
background-color: var(--mantine-color-default);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border: 1px solid var(--deco-rule);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-SegmentedControl-label {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-SegmentedControl-label[data-active] {
|
||||
color: var(--mantine-color-white);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Badge-root {
|
||||
letter-spacing: 0.09em;
|
||||
border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-NavLink-root[data-active] {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
box-shadow: inset 2px 0 0 var(--flxn-gold);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 10. App hooks — tab strip, tiles, see-all, match card */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--deco-chrome);
|
||||
border-bottom-color: var(--deco-rule);
|
||||
box-shadow: 0 4px 0 -3px var(--deco-rule-faint);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .flxn-tab.flxn-tab {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-size: var(--mantine-font-size-xs);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .flxn-tab.flxn-tab[data-active] {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="deco"] .flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: 2px solid var(--flxn-gold);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .flxn-tile {
|
||||
background-color: var(--mantine-color-default);
|
||||
border: 1px solid var(--deco-rule);
|
||||
outline: 1px solid var(--deco-rule-faint);
|
||||
outline-offset: -4px;
|
||||
border-radius: 0;
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .flxn-see-all.flxn-see-all {
|
||||
border-radius: 0;
|
||||
border: 1px solid var(--deco-rule);
|
||||
background-color: transparent;
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-size: var(--mantine-font-size-xs);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="deco"] .flxn-see-all.flxn-see-all:hover {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="deco"] .flxn-match-card {
|
||||
border: 1px solid var(--deco-rule);
|
||||
border-radius: 0;
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .flxn-reaction-row.flxn-reaction-row {
|
||||
border: 1px solid var(--deco-rule);
|
||||
border-radius: 0;
|
||||
background-color: var(--deco-tray);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 11. Divider — centered diamond ornament */
|
||||
/* ------------------------------------------------------------------ */
|
||||
[data-theme="deco"] .mantine-Divider-root {
|
||||
--divider-color: var(--deco-rule-faint);
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Divider-root[data-orientation="horizontal"]:not(:has(.mantine-Divider-label)) {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Divider-root[data-orientation="horizontal"]:not(:has(.mantine-Divider-label))::after {
|
||||
content: "\25C6";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 0;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 0.5rem;
|
||||
line-height: 1;
|
||||
color: var(--flxn-gold);
|
||||
background-color: var(--mantine-color-body);
|
||||
padding: 0 0.5rem;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-theme="deco"] .mantine-Divider-label {
|
||||
color: var(--deco-gold-text);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.14em;
|
||||
font-size: 0.6875rem;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* 12. Press feedback re-flavor */
|
||||
/* ------------------------------------------------------------------ */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="deco"] .flxn-press:active {
|
||||
transform: scale(0.975);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "default",
|
||||
label: msg`Default`,
|
||||
colorSchemes: "both",
|
||||
order: 0,
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Preview-contract values for the default theme so its picker card renders
|
||||
correctly while another theme is active. Values mirror Mantine defaults +
|
||||
the base theme object; the live app gets these from Mantine itself. */
|
||||
|
||||
[data-theme="default"][data-theme] {
|
||||
--mantine-font-family: "Inter", sans-serif;
|
||||
--mantine-font-family-headings: "League Spartan", sans-serif;
|
||||
--mantine-radius-default: 0.25rem;
|
||||
--mantine-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.05) 0 10px 15px -5px, rgba(0, 0, 0, 0.04) 0 7px 7px -5px;
|
||||
}
|
||||
|
||||
[data-theme="default"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #ffffff;
|
||||
--mantine-color-text: #000000;
|
||||
--mantine-color-dimmed: #868e96;
|
||||
--mantine-color-default-border: #ced4da;
|
||||
}
|
||||
|
||||
[data-theme="default"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #242424;
|
||||
--mantine-color-text: #c9c9c9;
|
||||
--mantine-color-dimmed: #828282;
|
||||
--mantine-color-default-border: #424242;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "gothic",
|
||||
label: msg`Dark Academia`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,500;0,600;0,700;1,500;1,600&display=swap",
|
||||
"https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#efe6d5", dimmed: "#e2d4bc" },
|
||||
dark: { base: "#0e0b10", dimmed: "#070509" },
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,641 @@
|
||||
/* Dark Academia — candlelit library gothic.
|
||||
Antique brass #b08d57 is the structural decoration (double borders, rules,
|
||||
fleurons); the interactive accent follows the user via the primary aliases.
|
||||
All eight accent ramps are retuned as heraldic manuscript pigments. */
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 1. Scheme-independent tokens — (0,2,0)
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="gothic"][data-theme] {
|
||||
/* Type: Garamond has a small x-height — sizes are bumped to compensate. */
|
||||
--mantine-font-family: "EB Garamond", "Iowan Old Style", Georgia, serif;
|
||||
--mantine-font-family-headings: "Cormorant Garamond", "EB Garamond", Georgia, serif;
|
||||
--mantine-font-size-xs: 0.8125rem;
|
||||
--mantine-font-size-sm: 0.9375rem;
|
||||
--mantine-font-size-md: 1.0625rem;
|
||||
--mantine-font-size-lg: 1.1875rem;
|
||||
--mantine-font-size-xl: 1.375rem;
|
||||
--mantine-heading-font-weight: 600;
|
||||
--mantine-h1-font-size: 2.6rem;
|
||||
--mantine-h1-line-height: 1.15;
|
||||
--mantine-h2-font-size: 2.1rem;
|
||||
--mantine-h2-line-height: 1.2;
|
||||
--mantine-h3-font-size: 1.65rem;
|
||||
--mantine-h3-line-height: 1.25;
|
||||
--mantine-h4-font-size: 1.35rem;
|
||||
--mantine-h4-line-height: 1.3;
|
||||
--mantine-h5-font-size: 1.175rem;
|
||||
--mantine-h5-line-height: 1.35;
|
||||
--mantine-h6-font-size: 1.05rem;
|
||||
--mantine-h6-line-height: 1.4;
|
||||
|
||||
/* Shape: near-square, engraved rather than rounded. */
|
||||
--mantine-radius-xs: 0;
|
||||
--mantine-radius-sm: 0.0625rem;
|
||||
--mantine-radius-md: 0.125rem;
|
||||
--mantine-radius-lg: 0.125rem;
|
||||
--mantine-radius-xl: 0.125rem;
|
||||
--mantine-radius-default: 0.125rem;
|
||||
|
||||
/* Elevation: deep, soft, black — never bright. */
|
||||
--mantine-shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.45);
|
||||
--mantine-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5), 0 6px 16px rgba(0, 0, 0, 0.35);
|
||||
--mantine-shadow-md: 0 2px 4px rgba(0, 0, 0, 0.5), 0 12px 28px rgba(0, 0, 0, 0.4);
|
||||
--mantine-shadow-lg: 0 4px 8px rgba(0, 0, 0, 0.5), 0 20px 44px rgba(0, 0, 0, 0.45);
|
||||
--mantine-shadow-xl: 0 6px 12px rgba(0, 0, 0, 0.55), 0 28px 64px rgba(0, 0, 0, 0.5);
|
||||
|
||||
/* Accent ramps retuned as heraldic manuscript pigments — muted and
|
||||
ink-saturated; every shade 6 carries parchment contrast text. */
|
||||
|
||||
/* blue → lapis lazuli */
|
||||
--mantine-color-blue-0: #edeff7;
|
||||
--mantine-color-blue-1: #d7dcee;
|
||||
--mantine-color-blue-2: #b6bede;
|
||||
--mantine-color-blue-3: #8e9ac9;
|
||||
--mantine-color-blue-4: #6879b1;
|
||||
--mantine-color-blue-5: #4a5b97;
|
||||
--mantine-color-blue-6: #374a80;
|
||||
--mantine-color-blue-7: #2c3b69;
|
||||
--mantine-color-blue-8: #222d52;
|
||||
--mantine-color-blue-9: #18213c;
|
||||
|
||||
/* red → oxblood */
|
||||
--mantine-color-red-0: #f9ecea;
|
||||
--mantine-color-red-1: #f0d5d3;
|
||||
--mantine-color-red-2: #e2b0ad;
|
||||
--mantine-color-red-3: #d18a86;
|
||||
--mantine-color-red-4: #bd5f5c;
|
||||
--mantine-color-red-5: #a53a3f;
|
||||
--mantine-color-red-6: #8a1c2b;
|
||||
--mantine-color-red-7: #741522;
|
||||
--mantine-color-red-8: #5e101b;
|
||||
--mantine-color-red-9: #470b14;
|
||||
|
||||
/* green → forest */
|
||||
--mantine-color-green-0: #ecf1ea;
|
||||
--mantine-color-green-1: #d4e1d1;
|
||||
--mantine-color-green-2: #b2c9af;
|
||||
--mantine-color-green-3: #8aac88;
|
||||
--mantine-color-green-4: #628e62;
|
||||
--mantine-color-green-5: #427245;
|
||||
--mantine-color-green-6: #2f5b35;
|
||||
--mantine-color-green-7: #25492b;
|
||||
--mantine-color-green-8: #1c3821;
|
||||
--mantine-color-green-9: #132818;
|
||||
|
||||
/* yellow → gilded gold leaf */
|
||||
--mantine-color-yellow-0: #faf3df;
|
||||
--mantine-color-yellow-1: #f1e3ba;
|
||||
--mantine-color-yellow-2: #e5cd8c;
|
||||
--mantine-color-yellow-3: #d5b05c;
|
||||
--mantine-color-yellow-4: #c1963a;
|
||||
--mantine-color-yellow-5: #a87a1a;
|
||||
--mantine-color-yellow-6: #8a600f;
|
||||
--mantine-color-yellow-7: #6f4d0c;
|
||||
--mantine-color-yellow-8: #573c0a;
|
||||
--mantine-color-yellow-9: #402c07;
|
||||
|
||||
/* grape → royal purple */
|
||||
--mantine-color-grape-0: #f2edf5;
|
||||
--mantine-color-grape-1: #e1d6e9;
|
||||
--mantine-color-grape-2: #c8b4d6;
|
||||
--mantine-color-grape-3: #a98bbd;
|
||||
--mantine-color-grape-4: #8965a3;
|
||||
--mantine-color-grape-5: #6e4789;
|
||||
--mantine-color-grape-6: #593272;
|
||||
--mantine-color-grape-7: #48285d;
|
||||
--mantine-color-grape-8: #381e49;
|
||||
--mantine-color-grape-9: #291636;
|
||||
|
||||
/* orange → burnt amber */
|
||||
--mantine-color-orange-0: #f9efe3;
|
||||
--mantine-color-orange-1: #f1dcc0;
|
||||
--mantine-color-orange-2: #e6c192;
|
||||
--mantine-color-orange-3: #dc9d5c;
|
||||
--mantine-color-orange-4: #cd7c33;
|
||||
--mantine-color-orange-5: #b95f18;
|
||||
--mantine-color-orange-6: #9c4a10;
|
||||
--mantine-color-orange-7: #7e3c0d;
|
||||
--mantine-color-orange-8: #62300b;
|
||||
--mantine-color-orange-9: #482407;
|
||||
|
||||
/* pink → rose madder */
|
||||
--mantine-color-pink-0: #f8edf0;
|
||||
--mantine-color-pink-1: #efd6dc;
|
||||
--mantine-color-pink-2: #e2b3c0;
|
||||
--mantine-color-pink-3: #d18b9e;
|
||||
--mantine-color-pink-4: #bc637e;
|
||||
--mantine-color-pink-5: #a34463;
|
||||
--mantine-color-pink-6: #882f4e;
|
||||
--mantine-color-pink-7: #712540;
|
||||
--mantine-color-pink-8: #591c32;
|
||||
--mantine-color-pink-9: #421425;
|
||||
|
||||
/* lime → sage */
|
||||
--mantine-color-lime-0: #f0f2ea;
|
||||
--mantine-color-lime-1: #dfe3d0;
|
||||
--mantine-color-lime-2: #c8cdae;
|
||||
--mantine-color-lime-3: #aab187;
|
||||
--mantine-color-lime-4: #8c9465;
|
||||
--mantine-color-lime-5: #707a48;
|
||||
--mantine-color-lime-6: #5a6337;
|
||||
--mantine-color-lime-7: #48502c;
|
||||
--mantine-color-lime-8: #373d22;
|
||||
--mantine-color-lime-9: #292d19;
|
||||
|
||||
/* Gray ramp as parchment/ink so grey-derived UI stays in the world. */
|
||||
--mantine-color-gray-0: #f6efe0;
|
||||
--mantine-color-gray-1: #efe6d5;
|
||||
--mantine-color-gray-2: #e2d5bc;
|
||||
--mantine-color-gray-3: #cfc0a4;
|
||||
--mantine-color-gray-4: #b3a487;
|
||||
--mantine-color-gray-5: #8f8069;
|
||||
--mantine-color-gray-6: #6b5d4b;
|
||||
--mantine-color-gray-7: #4a3f33;
|
||||
--mantine-color-gray-8: #352c23;
|
||||
--mantine-color-gray-9: #2b2118;
|
||||
|
||||
/* Dark ramp as ink-black with a violet-umber cast. */
|
||||
--mantine-color-dark-0: #e8e0d0;
|
||||
--mantine-color-dark-1: #a89a8a;
|
||||
--mantine-color-dark-2: #6e5f68;
|
||||
--mantine-color-dark-3: #4a3e4a;
|
||||
--mantine-color-dark-4: #322833;
|
||||
--mantine-color-dark-5: #241c26;
|
||||
--mantine-color-dark-6: #1a141c;
|
||||
--mantine-color-dark-7: #141016;
|
||||
--mantine-color-dark-8: #0e0b10;
|
||||
--mantine-color-dark-9: #0a0709;
|
||||
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.55);
|
||||
--flxn-avatar-radius: 50%; /* portrait miniatures */
|
||||
--flxn-avatar-border: 1px solid var(--gothic-brass-faint);
|
||||
--flxn-badge-radius: 2px;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 2. Per-scheme tokens — (0,3,0)
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="gothic"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #0e0b10;
|
||||
--mantine-color-text: #e8e0d0;
|
||||
--mantine-color-bright: #f6efe0;
|
||||
--mantine-color-dimmed: #a89a82;
|
||||
--mantine-color-placeholder: #7d7264;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-2);
|
||||
--mantine-color-error: #d4736a;
|
||||
--mantine-color-default: #171219;
|
||||
--mantine-color-default-hover: #1f1822;
|
||||
--mantine-color-default-color: #e8e0d0;
|
||||
--mantine-color-default-border: #453729;
|
||||
|
||||
/* Accent variant vars re-derived from the retuned ramps (Mantine's
|
||||
defaults are literal rgba of its stock hues). Filled stays mid-ramp:
|
||||
shade 8 pigment vanishes on ink black. */
|
||||
--mantine-color-blue-filled: var(--mantine-color-blue-6);
|
||||
--mantine-color-blue-filled-hover: var(--mantine-color-blue-5);
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-4) 15%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-4) 22%, transparent);
|
||||
--mantine-color-blue-light-color: var(--mantine-color-blue-2);
|
||||
--mantine-color-blue-outline: var(--mantine-color-blue-3);
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-3) 12%, transparent);
|
||||
--mantine-color-blue-text: var(--mantine-color-blue-3);
|
||||
--mantine-color-blue-contrast: #f3ead8;
|
||||
--mantine-color-red-filled: var(--mantine-color-red-6);
|
||||
--mantine-color-red-filled-hover: var(--mantine-color-red-5);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-4) 15%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-4) 22%, transparent);
|
||||
--mantine-color-red-light-color: var(--mantine-color-red-2);
|
||||
--mantine-color-red-outline: var(--mantine-color-red-3);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-3) 12%, transparent);
|
||||
--mantine-color-red-text: var(--mantine-color-red-3);
|
||||
--mantine-color-red-contrast: #f3ead8;
|
||||
--mantine-color-green-filled: var(--mantine-color-green-6);
|
||||
--mantine-color-green-filled-hover: var(--mantine-color-green-5);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-4) 15%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-4) 22%, transparent);
|
||||
--mantine-color-green-light-color: var(--mantine-color-green-2);
|
||||
--mantine-color-green-outline: var(--mantine-color-green-3);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-3) 12%, transparent);
|
||||
--mantine-color-green-text: var(--mantine-color-green-3);
|
||||
--mantine-color-green-contrast: #f3ead8;
|
||||
--mantine-color-yellow-filled: var(--mantine-color-yellow-6);
|
||||
--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-5);
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-4) 15%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-4) 22%, transparent);
|
||||
--mantine-color-yellow-light-color: var(--mantine-color-yellow-2);
|
||||
--mantine-color-yellow-outline: var(--mantine-color-yellow-3);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-3) 12%, transparent);
|
||||
--mantine-color-yellow-text: var(--mantine-color-yellow-3);
|
||||
--mantine-color-yellow-contrast: #f3ead8;
|
||||
--mantine-color-grape-filled: var(--mantine-color-grape-6);
|
||||
--mantine-color-grape-filled-hover: var(--mantine-color-grape-5);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-4) 15%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-4) 22%, transparent);
|
||||
--mantine-color-grape-light-color: var(--mantine-color-grape-2);
|
||||
--mantine-color-grape-outline: var(--mantine-color-grape-3);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-3) 12%, transparent);
|
||||
--mantine-color-grape-text: var(--mantine-color-grape-3);
|
||||
--mantine-color-grape-contrast: #f3ead8;
|
||||
--mantine-color-orange-filled: var(--mantine-color-orange-6);
|
||||
--mantine-color-orange-filled-hover: var(--mantine-color-orange-5);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-4) 15%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-4) 22%, transparent);
|
||||
--mantine-color-orange-light-color: var(--mantine-color-orange-2);
|
||||
--mantine-color-orange-outline: var(--mantine-color-orange-3);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-3) 12%, transparent);
|
||||
--mantine-color-orange-text: var(--mantine-color-orange-3);
|
||||
--mantine-color-orange-contrast: #f3ead8;
|
||||
--mantine-color-pink-filled: var(--mantine-color-pink-6);
|
||||
--mantine-color-pink-filled-hover: var(--mantine-color-pink-5);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-4) 15%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-4) 22%, transparent);
|
||||
--mantine-color-pink-light-color: var(--mantine-color-pink-2);
|
||||
--mantine-color-pink-outline: var(--mantine-color-pink-3);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-3) 12%, transparent);
|
||||
--mantine-color-pink-text: var(--mantine-color-pink-3);
|
||||
--mantine-color-pink-contrast: #f3ead8;
|
||||
--mantine-color-lime-filled: var(--mantine-color-lime-6);
|
||||
--mantine-color-lime-filled-hover: var(--mantine-color-lime-5);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-4) 15%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-4) 22%, transparent);
|
||||
--mantine-color-lime-light-color: var(--mantine-color-lime-2);
|
||||
--mantine-color-lime-outline: var(--mantine-color-lime-3);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-3) 12%, transparent);
|
||||
--mantine-color-lime-text: var(--mantine-color-lime-3);
|
||||
--mantine-color-lime-contrast: #f3ead8;
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-4) 12%, transparent);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-4) 18%, transparent);
|
||||
--mantine-color-gray-light-color: var(--mantine-color-gray-2);
|
||||
|
||||
/* Theme-local palette used by component rules below. */
|
||||
--gothic-brass: #b08d57;
|
||||
--gothic-brass-bright: #c9a86b;
|
||||
--gothic-brass-faint: rgba(176, 141, 87, 0.38);
|
||||
--gothic-brass-ghost: rgba(176, 141, 87, 0.14);
|
||||
--gothic-surface: #17121a;
|
||||
--gothic-recessed: #0a0709;
|
||||
--gothic-shell: #120e14;
|
||||
--gothic-line: #060409;
|
||||
--gothic-line-highlight: rgba(232, 224, 208, 0.08);
|
||||
|
||||
/* App tokens: gold -> antique brass; manuscript podium tiers. */
|
||||
--flxn-gold: #c9a86b;
|
||||
--flxn-silver: #a8a196;
|
||||
--flxn-bronze: #b57945;
|
||||
--flxn-toast-success: #a3b98a;
|
||||
--flxn-toast-error: #dc9a90;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #b08d57 14%, #141016);
|
||||
--flxn-podium-1-border: color-mix(in srgb, #b08d57 55%, #322833);
|
||||
--flxn-podium-1-label: #d6b878;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #a8a196 8%, #141016);
|
||||
--flxn-podium-2-border: color-mix(in srgb, #a8a196 32%, #322833);
|
||||
--flxn-podium-2-label: #b5aea1;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #b57945 12%, #141016);
|
||||
--flxn-podium-3-border: color-mix(in srgb, #b57945 45%, #322833);
|
||||
--flxn-podium-3-label: #c08757;
|
||||
--flxn-showcase-bg: #141016;
|
||||
--flxn-overlay: rgba(6, 3, 8, 0.62);
|
||||
--flxn-dotgrid-color: rgba(176, 141, 87, 0.18);
|
||||
}
|
||||
|
||||
[data-theme="gothic"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #efe6d5;
|
||||
--mantine-color-text: #2b2118;
|
||||
--mantine-color-bright: #1a140e;
|
||||
--mantine-color-dimmed: #6b5d4b;
|
||||
--mantine-color-placeholder: #857661;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-7);
|
||||
--mantine-color-error: #9e2b20;
|
||||
--mantine-color-default: #f4ecdc;
|
||||
--mantine-color-default-hover: #ece1cb;
|
||||
--mantine-color-default-color: #2b2118;
|
||||
--mantine-color-default-border: #b9a67f;
|
||||
|
||||
/* Accent variant vars re-derived from the retuned ramps; ink-saturated
|
||||
text shades on aged parchment. */
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-6) 10%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-6) 16%, transparent);
|
||||
--mantine-color-blue-light-color: var(--mantine-color-blue-7);
|
||||
--mantine-color-blue-outline: var(--mantine-color-blue-6);
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-6) 8%, transparent);
|
||||
--mantine-color-blue-text: var(--mantine-color-blue-7);
|
||||
--mantine-color-blue-contrast: #f3ead8;
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-6) 10%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-6) 16%, transparent);
|
||||
--mantine-color-red-light-color: var(--mantine-color-red-7);
|
||||
--mantine-color-red-outline: var(--mantine-color-red-6);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-6) 8%, transparent);
|
||||
--mantine-color-red-text: var(--mantine-color-red-7);
|
||||
--mantine-color-red-contrast: #f3ead8;
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-6) 10%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-6) 16%, transparent);
|
||||
--mantine-color-green-light-color: var(--mantine-color-green-7);
|
||||
--mantine-color-green-outline: var(--mantine-color-green-6);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-6) 8%, transparent);
|
||||
--mantine-color-green-text: var(--mantine-color-green-7);
|
||||
--mantine-color-green-contrast: #f3ead8;
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-6) 10%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 16%, transparent);
|
||||
--mantine-color-yellow-light-color: var(--mantine-color-yellow-7);
|
||||
--mantine-color-yellow-outline: var(--mantine-color-yellow-6);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 8%, transparent);
|
||||
--mantine-color-yellow-text: var(--mantine-color-yellow-7);
|
||||
--mantine-color-yellow-contrast: #f3ead8;
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-6) 10%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-6) 16%, transparent);
|
||||
--mantine-color-grape-light-color: var(--mantine-color-grape-7);
|
||||
--mantine-color-grape-outline: var(--mantine-color-grape-6);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-6) 8%, transparent);
|
||||
--mantine-color-grape-text: var(--mantine-color-grape-7);
|
||||
--mantine-color-grape-contrast: #f3ead8;
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-6) 10%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-6) 16%, transparent);
|
||||
--mantine-color-orange-light-color: var(--mantine-color-orange-7);
|
||||
--mantine-color-orange-outline: var(--mantine-color-orange-6);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-6) 8%, transparent);
|
||||
--mantine-color-orange-text: var(--mantine-color-orange-7);
|
||||
--mantine-color-orange-contrast: #f3ead8;
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-6) 10%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-6) 16%, transparent);
|
||||
--mantine-color-pink-light-color: var(--mantine-color-pink-7);
|
||||
--mantine-color-pink-outline: var(--mantine-color-pink-6);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-6) 8%, transparent);
|
||||
--mantine-color-pink-text: var(--mantine-color-pink-7);
|
||||
--mantine-color-pink-contrast: #f3ead8;
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-6) 10%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-6) 16%, transparent);
|
||||
--mantine-color-lime-light-color: var(--mantine-color-lime-7);
|
||||
--mantine-color-lime-outline: var(--mantine-color-lime-6);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-6) 8%, transparent);
|
||||
--mantine-color-lime-text: var(--mantine-color-lime-7);
|
||||
--mantine-color-lime-contrast: #f3ead8;
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-6) 10%, transparent);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-6) 15%, transparent);
|
||||
--mantine-color-gray-light-color: var(--mantine-color-gray-7);
|
||||
|
||||
--gothic-brass: #8a6a34;
|
||||
--gothic-brass-bright: #7a5a28;
|
||||
--gothic-brass-faint: rgba(138, 106, 52, 0.45);
|
||||
--gothic-brass-ghost: rgba(138, 106, 52, 0.12);
|
||||
--gothic-surface: #f6efe0;
|
||||
--gothic-recessed: #e4d6bd;
|
||||
--gothic-shell: #e9dec9;
|
||||
--gothic-line: rgba(74, 58, 38, 0.45);
|
||||
--gothic-line-highlight: rgba(255, 252, 240, 0.85);
|
||||
|
||||
--flxn-gold: #7a5a16;
|
||||
--flxn-silver: #7b7264;
|
||||
--flxn-bronze: #8c4f22;
|
||||
--flxn-toast-success: #4d6b34;
|
||||
--flxn-toast-error: #9e2b20;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #b08d57 16%, #f6efe0);
|
||||
--flxn-podium-1-border: color-mix(in srgb, #8a6a34 55%, #cfc0a4);
|
||||
--flxn-podium-1-label: #6f5116;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #8f8069 10%, #f6efe0);
|
||||
--flxn-podium-2-border: #b3a487;
|
||||
--flxn-podium-2-label: #6b5d4b;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #8c4f22 12%, #f6efe0);
|
||||
--flxn-podium-3-border: color-mix(in srgb, #8c4f22 45%, #cfc0a4);
|
||||
--flxn-podium-3-label: #74431c;
|
||||
--flxn-showcase-bg: #f6efe0;
|
||||
--flxn-overlay: rgba(26, 18, 10, 0.45);
|
||||
--flxn-dotgrid-color: rgba(138, 104, 58, 0.22);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 3. Full-page decoration: candlelit vignette (dark scheme only)
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="gothic"][data-mantine-color-scheme="dark"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998;
|
||||
pointer-events: none;
|
||||
background:
|
||||
radial-gradient(80% 50% at 50% 0%, rgba(176, 141, 87, 0.04), transparent 70%),
|
||||
radial-gradient(120% 90% at 50% 42%, transparent 55%, rgba(4, 2, 6, 0.45) 100%);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 4. Component restyles
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
/* Headings: Cormorant, slight italic from h3 down for the manuscript voice. */
|
||||
[data-theme="gothic"] .mantine-Title-root {
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
[data-theme="gothic"] h3.mantine-Title-root,
|
||||
[data-theme="gothic"] h4.mantine-Title-root {
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Cards & panels: thin double border in brass (1px border + inset outline). */
|
||||
[data-theme="gothic"] .mantine-Paper-root[data-with-border] {
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
outline: 1px solid var(--gothic-brass-ghost);
|
||||
outline-offset: -4px;
|
||||
background-color: var(--gothic-surface);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Card-root {
|
||||
background-color: var(--gothic-surface);
|
||||
}
|
||||
|
||||
/* Buttons: wax-seal solids in the user's accent, or brass-ruled outlines. */
|
||||
[data-theme="gothic"] .mantine-Button-root {
|
||||
letter-spacing: 0.03em;
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="gothic"] .mantine-ActionIcon-root[data-variant="filled"] {
|
||||
border: 1px solid var(--mantine-primary-color-9);
|
||||
box-shadow: inset 0 1px 0 rgba(246, 239, 224, 0.12), 0 2px 8px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="gothic"] .mantine-Button-root[data-variant="outline"],
|
||||
[data-theme="gothic"] .mantine-ActionIcon-root[data-variant="default"],
|
||||
[data-theme="gothic"] .mantine-ActionIcon-root[data-variant="outline"] {
|
||||
border-color: var(--gothic-brass-faint);
|
||||
}
|
||||
|
||||
/* Inputs: recessed ledger lines with brass rules; focus follows the accent. */
|
||||
[data-theme="gothic"] .mantine-Input-input {
|
||||
background-color: var(--gothic-recessed);
|
||||
border-color: var(--gothic-brass-faint);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-PinInput-input {
|
||||
background-color: var(--gothic-recessed);
|
||||
}
|
||||
|
||||
/* Tabs: rubricated active label in the accent under a brass rule. */
|
||||
[data-theme="gothic"] .mantine-Tabs-list {
|
||||
--tabs-list-border-size: 1px;
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Tabs-tab {
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Tabs-tab[data-active] {
|
||||
border-color: var(--gothic-brass);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Tabs-tab[data-active]:hover {
|
||||
border-color: var(--gothic-brass-bright);
|
||||
}
|
||||
|
||||
/* Nav: active entries follow the accent — tinted wash plus a marginal rule. */
|
||||
[data-theme="gothic"] .mantine-NavLink-root[data-active] {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
box-shadow: inset 2px 0 0 var(--mantine-primary-color-filled);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-NavLink-root[data-active]:hover {
|
||||
background-color: var(--mantine-primary-color-light-hover);
|
||||
}
|
||||
|
||||
/* Shell: bound pages — header and navbar as darker leather edges. */
|
||||
[data-theme="gothic"] .mantine-AppShell-header {
|
||||
background-color: var(--gothic-shell);
|
||||
border-bottom: 1px solid var(--gothic-brass-faint);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-AppShell-navbar {
|
||||
background-color: var(--gothic-shell);
|
||||
border-color: var(--gothic-brass-faint);
|
||||
}
|
||||
|
||||
/* Segmented control: engraved channel with a brass-edged slider. */
|
||||
[data-theme="gothic"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--gothic-recessed);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--gothic-surface);
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-SegmentedControl-label {
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
/* Dividers: engraved rule with a centered fleuron ornament. */
|
||||
[data-theme="gothic"] .mantine-Divider-root {
|
||||
--divider-color: var(--gothic-line);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Divider-root[data-orientation="horizontal"] {
|
||||
box-shadow: 0 1px 0 var(--gothic-line-highlight);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Divider-root[data-orientation="horizontal"]:not([data-with-label]) {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Divider-root[data-orientation="horizontal"]:not([data-with-label])::before {
|
||||
content: "\2766"; /* ❦ fleuron */
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 0 0.5em;
|
||||
background-color: var(--mantine-color-body);
|
||||
color: var(--gothic-brass);
|
||||
font-size: 0.8rem;
|
||||
line-height: 1;
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Divider-label {
|
||||
color: var(--gothic-brass);
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
font-size: var(--mantine-font-size-xs);
|
||||
}
|
||||
|
||||
/* Overlays: sealed-note dropdowns and modals with double brass borders. */
|
||||
[data-theme="gothic"] .mantine-Modal-content,
|
||||
[data-theme="gothic"] .mantine-Popover-dropdown {
|
||||
background-color: var(--gothic-surface);
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
outline: 1px solid var(--gothic-brass-ghost);
|
||||
outline-offset: -4px;
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Modal-header {
|
||||
background-color: var(--gothic-surface);
|
||||
}
|
||||
[data-theme="gothic"] .mantine-Tooltip-tooltip {
|
||||
background-color: #060409;
|
||||
color: #e8e0d0;
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
}
|
||||
|
||||
/* Notifications: sealed notes with a brass frame. */
|
||||
[data-theme="gothic"] .mantine-Notification-root {
|
||||
background-color: var(--gothic-surface);
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
/* Badges: engraved plaques. */
|
||||
[data-theme="gothic"] .mantine-Badge-root {
|
||||
letter-spacing: 0.06em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Alerts keep a real border for forced-colors resilience. */
|
||||
[data-theme="gothic"] .mantine-Alert-root {
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 5. App component hooks
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
/* Tab strip: docks as a shell strip with a brass rule; active label
|
||||
rubricated in the accent over a thin double brass rule (gilded underline). */
|
||||
[data-theme="gothic"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--gothic-shell);
|
||||
box-shadow: inset 0 -1px 0 var(--gothic-brass-faint);
|
||||
}
|
||||
[data-theme="gothic"] .flxn-tab {
|
||||
color: var(--mantine-color-dimmed);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
[data-theme="gothic"] .flxn-tab[data-active] {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
[data-theme="gothic"] .flxn-tabs-indicator {
|
||||
border-bottom: 3px double var(--gothic-brass);
|
||||
padding-inline: 0.5rem;
|
||||
}
|
||||
|
||||
/* Nav grid tiles: brass double-ruled panels, flat gilded glyph. */
|
||||
[data-theme="gothic"] .flxn-tile {
|
||||
background-color: var(--gothic-surface);
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
outline: 1px solid var(--gothic-brass-ghost);
|
||||
outline-offset: -4px;
|
||||
}
|
||||
[data-theme="gothic"] .flxn-tile-icon {
|
||||
color: var(--gothic-brass-bright);
|
||||
}
|
||||
|
||||
/* "See all" link: brass-rimmed chip, accent-inked label. */
|
||||
[data-theme="gothic"] .flxn-see-all {
|
||||
background-color: var(--gothic-brass-ghost);
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
@media (hover: hover) {
|
||||
[data-theme="gothic"] .flxn-see-all:hover {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
}
|
||||
}
|
||||
|
||||
/* Match card + reaction tray: one construction — matching brass rules,
|
||||
tray recessed as a deeper ink panel. */
|
||||
[data-theme="gothic"] .flxn-match-card {
|
||||
background-color: var(--gothic-surface);
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
}
|
||||
[data-theme="gothic"] .flxn-reaction-row {
|
||||
background-color: var(--gothic-recessed);
|
||||
border: 1px solid var(--gothic-brass-faint);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Default look for custom app-component hooks; themes override under
|
||||
[data-theme] scopes (see README "App component hooks"). Loads before all
|
||||
theme.css files. */
|
||||
|
||||
/* Mantine hardcodes white on selected combobox options; autoContrast never
|
||||
reaches this rule. */
|
||||
[data-combobox-selected] {
|
||||
color: var(--flxn-on-accent);
|
||||
}
|
||||
|
||||
/* Swipeable tab strip: flat while resting, docked chrome on [data-stuck]. */
|
||||
.flxn-tabs {
|
||||
background-color: transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: background-color 200ms ease, border-color 200ms ease,
|
||||
box-shadow 200ms ease;
|
||||
}
|
||||
.flxn-tabs[data-stuck] {
|
||||
background-color: var(--mantine-color-body);
|
||||
border-bottom-color: var(--mantine-color-default-border);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.flxn-tabs {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
.flxn-tab.flxn-tab {
|
||||
/* lifted above the absolutely-positioned FloatingIndicator, or an opaque
|
||||
indicator fill covers the labels */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
flex: 1;
|
||||
padding: var(--mantine-spacing-sm) var(--mantine-spacing-xs);
|
||||
text-align: center;
|
||||
color: var(--mantine-color-text);
|
||||
font-weight: 400;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
transition: color 200ms ease;
|
||||
}
|
||||
.flxn-tab.flxn-tab[data-active] {
|
||||
color: var(--mantine-primary-color-filled);
|
||||
font-weight: 600;
|
||||
}
|
||||
.flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: 2px solid var(--mantine-primary-color-filled);
|
||||
padding-inline: 0.5rem;
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.flxn-tab.flxn-tab {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* The frame owns the avatar's single border (--flxn-avatar-border); an inner
|
||||
Avatar border would double every ring. */
|
||||
.flxn-avatar-frame .mantine-Avatar-root.mantine-Avatar-root {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Reaction tray tucked under a match card; full border + radius so rounded
|
||||
card corners never expose square tray corners. */
|
||||
.flxn-reaction-row.flxn-reaction-row {
|
||||
background-color: var(--mantine-color-gray-light);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "neumorph",
|
||||
label: msg`Neumorphic`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#e0e5ec", dimmed: "#c8d0dc" },
|
||||
dark: { base: "#2a2d34", dimmed: "#1e2127" },
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,632 @@
|
||||
/* Neumorphic — soft-UI extruded plastic. One surface color for body AND
|
||||
cards; elevation comes only from paired light/dark shadows. Raised =
|
||||
drop pair, pressed = inset pair. Faint real 1px borders stay on every
|
||||
interactive element so forced-colors / high-contrast modes survive. */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 1. Scheme-independent tokens */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="neumorph"][data-theme] {
|
||||
--mantine-font-family: "Nunito", "Inter", system-ui, sans-serif;
|
||||
--mantine-font-family-headings: "Nunito", "Inter", system-ui, sans-serif;
|
||||
--mantine-heading-font-weight: 800;
|
||||
|
||||
--mantine-radius-xs: 8px;
|
||||
--mantine-radius-sm: 12px;
|
||||
--mantine-radius-md: 16px;
|
||||
--mantine-radius-lg: 20px;
|
||||
--mantine-radius-xl: 28px;
|
||||
--mantine-radius-default: 16px;
|
||||
|
||||
--flxn-avatar-radius: 30%;
|
||||
--flxn-avatar-border: 1px solid var(--neu-border);
|
||||
--flxn-badge-radius: 16px;
|
||||
|
||||
/* muted, low-saturation slate grays (light-scheme neutrals) */
|
||||
--mantine-color-gray-0: #f2f5fa;
|
||||
--mantine-color-gray-1: #e9edf4;
|
||||
--mantine-color-gray-2: #dfe4ed;
|
||||
--mantine-color-gray-3: #d0d7e2;
|
||||
--mantine-color-gray-4: #bac4d3;
|
||||
--mantine-color-gray-5: #9daabd;
|
||||
--mantine-color-gray-6: #7d8ba0;
|
||||
--mantine-color-gray-7: #606d81;
|
||||
--mantine-color-gray-8: #495466;
|
||||
--mantine-color-gray-9: #333c4b;
|
||||
|
||||
/* dark-scheme neutrals tuned to the #2a2d34 shell */
|
||||
--mantine-color-dark-0: #d5dae3;
|
||||
--mantine-color-dark-1: #b8bfcb;
|
||||
--mantine-color-dark-2: #99a1b0;
|
||||
--mantine-color-dark-3: #6f7787;
|
||||
--mantine-color-dark-4: #4a505c;
|
||||
--mantine-color-dark-5: #383d47;
|
||||
--mantine-color-dark-6: #2a2d34;
|
||||
--mantine-color-dark-7: #2a2d34;
|
||||
--mantine-color-dark-8: #222429;
|
||||
--mantine-color-dark-9: #191b1f;
|
||||
|
||||
/* accent ramps retuned to muted pastel-plastic; shade 6 keeps >=4.5:1 on
|
||||
the light surface, shades 3-4 keep >=4.5:1 on the dark surface */
|
||||
--mantine-color-blue-0: #e9eff6;
|
||||
--mantine-color-blue-1: #d3dfee;
|
||||
--mantine-color-blue-2: #b9cce4;
|
||||
--mantine-color-blue-3: #98b4d7;
|
||||
--mantine-color-blue-4: #779cca;
|
||||
--mantine-color-blue-5: #5181bb;
|
||||
--mantine-color-blue-6: #3c669a;
|
||||
--mantine-color-blue-7: #31537d;
|
||||
--mantine-color-blue-8: #274263;
|
||||
--mantine-color-blue-9: #1d3149;
|
||||
--mantine-color-red-0: #f6ebe9;
|
||||
--mantine-color-red-1: #edd6d4;
|
||||
--mantine-color-red-2: #e3beba;
|
||||
--mantine-color-red-3: #d6a09a;
|
||||
--mantine-color-red-4: #c88179;
|
||||
--mantine-color-red-5: #b95d53;
|
||||
--mantine-color-red-6: #98473e;
|
||||
--mantine-color-red-7: #7b3a32;
|
||||
--mantine-color-red-8: #622e28;
|
||||
--mantine-color-red-9: #48221e;
|
||||
--mantine-color-green-0: #eaf5f0;
|
||||
--mantine-color-green-1: #d5ebe0;
|
||||
--mantine-color-green-2: #bde0cf;
|
||||
--mantine-color-green-3: #9ed1b8;
|
||||
--mantine-color-green-4: #7fc3a1;
|
||||
--mantine-color-green-5: #4ea67a;
|
||||
--mantine-color-green-6: #357153;
|
||||
--mantine-color-green-7: #2b5c44;
|
||||
--mantine-color-green-8: #214734;
|
||||
--mantine-color-green-9: #183225;
|
||||
--mantine-color-yellow-0: #f9f4e7;
|
||||
--mantine-color-yellow-1: #f2e9cf;
|
||||
--mantine-color-yellow-2: #ebdcb2;
|
||||
--mantine-color-yellow-3: #e1cb8e;
|
||||
--mantine-color-yellow-4: #d7ba6a;
|
||||
--mantine-color-yellow-5: #bc9732;
|
||||
--mantine-color-yellow-6: #7b6321;
|
||||
--mantine-color-yellow-7: #634f1a;
|
||||
--mantine-color-yellow-8: #4b3c14;
|
||||
--mantine-color-yellow-9: #32290d;
|
||||
--mantine-color-grape-0: #f3eaf5;
|
||||
--mantine-color-grape-1: #e7d5eb;
|
||||
--mantine-color-grape-2: #d9bde0;
|
||||
--mantine-color-grape-3: #c79ed1;
|
||||
--mantine-color-grape-4: #b680c3;
|
||||
--mantine-color-grape-5: #a15bb2;
|
||||
--mantine-color-grape-6: #824592;
|
||||
--mantine-color-grape-7: #693776;
|
||||
--mantine-color-grape-8: #542c5e;
|
||||
--mantine-color-grape-9: #3e2145;
|
||||
--mantine-color-orange-0: #f9efe7;
|
||||
--mantine-color-orange-1: #f2decf;
|
||||
--mantine-color-orange-2: #ebcbb2;
|
||||
--mantine-color-orange-3: #e1b28e;
|
||||
--mantine-color-orange-4: #d7996a;
|
||||
--mantine-color-orange-5: #c97636;
|
||||
--mantine-color-orange-6: #955728;
|
||||
--mantine-color-orange-7: #7d4921;
|
||||
--mantine-color-orange-8: #653b1b;
|
||||
--mantine-color-orange-9: #4d2d14;
|
||||
--mantine-color-pink-0: #f6e9ee;
|
||||
--mantine-color-pink-1: #edd4dc;
|
||||
--mantine-color-pink-2: #e3bac8;
|
||||
--mantine-color-pink-3: #d69aae;
|
||||
--mantine-color-pink-4: #ca7d96;
|
||||
--mantine-color-pink-5: #b95576;
|
||||
--mantine-color-pink-6: #983e5c;
|
||||
--mantine-color-pink-7: #7b324b;
|
||||
--mantine-color-pink-8: #62283b;
|
||||
--mantine-color-pink-9: #481e2c;
|
||||
--mantine-color-lime-0: #eff6e9;
|
||||
--mantine-color-lime-1: #e0eed3;
|
||||
--mantine-color-lime-2: #cde4b9;
|
||||
--mantine-color-lime-3: #b6d798;
|
||||
--mantine-color-lime-4: #9eca77;
|
||||
--mantine-color-lime-5: #74ac43;
|
||||
--mantine-color-lime-6: #4b702c;
|
||||
--mantine-color-lime-7: #3d5a23;
|
||||
--mantine-color-lime-8: #2e441a;
|
||||
--mantine-color-lime-9: #1f2e12;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 2. Per-scheme tokens */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="neumorph"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--neu-surface: #e0e5ec;
|
||||
--neu-surface-high: #e8ecf2; /* hover */
|
||||
--neu-well: #d3dae4; /* pressed-in wells */
|
||||
--neu-border: rgba(148, 163, 184, 0.4);
|
||||
--neu-shadow-dark: rgba(163, 177, 198, 0.6);
|
||||
--neu-shadow-light: rgba(255, 255, 255, 0.9);
|
||||
--neu-inset: inset 6px 6px 12px rgba(163, 177, 198, 0.6),
|
||||
inset -6px -6px 12px rgba(255, 255, 255, 0.9);
|
||||
--neu-inset-sm: inset 3px 3px 6px rgba(163, 177, 198, 0.55),
|
||||
inset -3px -3px 6px rgba(255, 255, 255, 0.85);
|
||||
--neu-edge: 0 8px 16px rgba(163, 177, 198, 0.35);
|
||||
|
||||
--mantine-color-body: #e0e5ec;
|
||||
--mantine-color-text: #2f3542;
|
||||
--mantine-color-bright: #171b23;
|
||||
--mantine-color-dimmed: #5b6472;
|
||||
--mantine-color-placeholder: #5f6a80;
|
||||
--mantine-color-error: var(--mantine-color-red-6);
|
||||
--mantine-color-default: #e0e5ec;
|
||||
--mantine-color-default-hover: #e8ecf2;
|
||||
--mantine-color-default-color: #2f3542;
|
||||
--mantine-color-default-border: rgba(148, 163, 184, 0.4);
|
||||
|
||||
/* Mantine's -light variants are alpha literals of its stock hues;
|
||||
re-derive them from the retuned ramps */
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-6) 10%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-6) 14%, transparent);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-6) 10%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-6) 14%, transparent);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-6) 10%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-6) 14%, transparent);
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-6) 10%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 14%, transparent);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-6) 10%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-6) 14%, transparent);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-6) 10%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-6) 14%, transparent);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-6) 10%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-6) 14%, transparent);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-6) 10%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-6) 14%, transparent);
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-6) 10%, transparent);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-6) 14%, transparent);
|
||||
|
||||
/* Compact spreads: app containers clip overflow, and big soft shadows
|
||||
truncate visibly at those edges. Keep the extrusion read tight. */
|
||||
--mantine-shadow-xs: 2px 2px 5px rgba(163, 177, 198, 0.45),
|
||||
-2px -2px 5px rgba(255, 255, 255, 0.8);
|
||||
--mantine-shadow-sm: 3px 3px 7px rgba(163, 177, 198, 0.5),
|
||||
-3px -3px 7px rgba(255, 255, 255, 0.85);
|
||||
--mantine-shadow-md: 4px 4px 9px rgba(163, 177, 198, 0.55),
|
||||
-4px -4px 9px rgba(255, 255, 255, 0.85);
|
||||
--mantine-shadow-lg: 5px 5px 12px rgba(163, 177, 198, 0.55),
|
||||
-5px -5px 12px rgba(255, 255, 255, 0.85);
|
||||
--mantine-shadow-xl: 7px 7px 16px rgba(163, 177, 198, 0.6),
|
||||
-7px -7px 16px rgba(255, 255, 255, 0.9);
|
||||
|
||||
/* app tokens — soft embossed metals, muted toasts, extruded podium */
|
||||
--flxn-gold: #8f6f1e;
|
||||
--flxn-silver: #66727f;
|
||||
--flxn-bronze: #96603a;
|
||||
--flxn-toast-success: #2f8f5b;
|
||||
--flxn-toast-error: #b04a44;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #d9b25a 10%, #e0e5ec);
|
||||
--flxn-podium-1-border: color-mix(in srgb, #b08d2c 35%, rgba(148, 163, 184, 0.5));
|
||||
--flxn-podium-1-label: #7d651f;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #9daabd 10%, #e0e5ec);
|
||||
--flxn-podium-2-border: color-mix(in srgb, #7d8ba0 35%, rgba(148, 163, 184, 0.5));
|
||||
--flxn-podium-2-label: #5b6472;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #c08552 10%, #e0e5ec);
|
||||
--flxn-podium-3-border: color-mix(in srgb, #a56a3a 35%, rgba(148, 163, 184, 0.5));
|
||||
--flxn-podium-3-label: #7d5230;
|
||||
--flxn-showcase-bg: #e0e5ec;
|
||||
--flxn-overlay: rgba(99, 112, 133, 0.45);
|
||||
--flxn-dotgrid-color: rgba(148, 163, 184, 0.5);
|
||||
--flxn-pop-shadow: rgba(163, 177, 198, 0.65);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--neu-surface: #2a2d34;
|
||||
--neu-surface-high: #31353d;
|
||||
--neu-well: #23262c;
|
||||
--neu-border: rgba(255, 255, 255, 0.08);
|
||||
--neu-shadow-dark: rgba(13, 15, 19, 0.65);
|
||||
--neu-shadow-light: rgba(68, 74, 86, 0.5);
|
||||
--neu-inset: inset 6px 6px 12px rgba(13, 15, 19, 0.65),
|
||||
inset -6px -6px 12px rgba(68, 74, 86, 0.5);
|
||||
--neu-inset-sm: inset 3px 3px 6px rgba(13, 15, 19, 0.6),
|
||||
inset -3px -3px 6px rgba(68, 74, 86, 0.45);
|
||||
--neu-edge: 0 8px 16px rgba(0, 0, 0, 0.4);
|
||||
|
||||
--mantine-color-body: #2a2d34;
|
||||
--mantine-color-text: #dbdfe7;
|
||||
--mantine-color-bright: #f4f6fa;
|
||||
--mantine-color-dimmed: #9ba3b2;
|
||||
--mantine-color-placeholder: #8a92a3;
|
||||
--mantine-color-error: var(--mantine-color-red-3);
|
||||
--mantine-color-default: #2a2d34;
|
||||
--mantine-color-default-hover: #31353d;
|
||||
--mantine-color-default-color: #dbdfe7;
|
||||
--mantine-color-default-border: rgba(255, 255, 255, 0.08);
|
||||
|
||||
/* re-derive alpha-literal -light variants from the retuned ramps */
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-6) 15%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-6) 20%, transparent);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-6) 15%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-6) 20%, transparent);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-6) 15%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-6) 20%, transparent);
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-6) 15%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 20%, transparent);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-6) 15%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-6) 20%, transparent);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-6) 15%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-6) 20%, transparent);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-6) 15%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-6) 20%, transparent);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-6) 15%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-6) 20%, transparent);
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-5) 15%, transparent);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-5) 20%, transparent);
|
||||
|
||||
--mantine-shadow-xs: 2px 2px 5px rgba(13, 15, 19, 0.5),
|
||||
-2px -2px 5px rgba(68, 74, 86, 0.4);
|
||||
--mantine-shadow-sm: 3px 3px 7px rgba(13, 15, 19, 0.55),
|
||||
-3px -3px 7px rgba(68, 74, 86, 0.45);
|
||||
--mantine-shadow-md: 4px 4px 9px rgba(13, 15, 19, 0.6),
|
||||
-4px -4px 9px rgba(68, 74, 86, 0.45);
|
||||
--mantine-shadow-lg: 5px 5px 12px rgba(13, 15, 19, 0.6),
|
||||
-5px -5px 12px rgba(68, 74, 86, 0.45);
|
||||
--mantine-shadow-xl: 7px 7px 16px rgba(13, 15, 19, 0.65),
|
||||
-7px -7px 16px rgba(68, 74, 86, 0.5);
|
||||
|
||||
--flxn-gold: #dcbb6a;
|
||||
--flxn-silver: #b3bcc9;
|
||||
--flxn-bronze: #cf9a72;
|
||||
--flxn-toast-success: #86d3a8;
|
||||
--flxn-toast-error: #ef9d9d;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #dcbb6a 12%, #2a2d34);
|
||||
--flxn-podium-1-border: color-mix(in srgb, #dcbb6a 30%, rgba(255, 255, 255, 0.12));
|
||||
--flxn-podium-1-label: #dcbb6a;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #b3bcc9 10%, #2a2d34);
|
||||
--flxn-podium-2-border: color-mix(in srgb, #b3bcc9 28%, rgba(255, 255, 255, 0.12));
|
||||
--flxn-podium-2-label: #b3bcc9;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #cf9a72 11%, #2a2d34);
|
||||
--flxn-podium-3-border: color-mix(in srgb, #cf9a72 28%, rgba(255, 255, 255, 0.12));
|
||||
--flxn-podium-3-label: #cf9a72;
|
||||
--flxn-showcase-bg: #2a2d34;
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.55);
|
||||
--flxn-dotgrid-color: rgba(255, 255, 255, 0.09);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 3. Surfaces — same color as body, elevation via shadow only */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="neumorph"] .mantine-Paper-root {
|
||||
background-color: var(--neu-surface);
|
||||
border: 1px solid var(--neu-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Card-root {
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
}
|
||||
|
||||
/* Floating surfaces sit higher */
|
||||
[data-theme="neumorph"] .mantine-Modal-content,
|
||||
[data-theme="neumorph"] .mantine-Popover-dropdown,
|
||||
[data-theme="neumorph"] .mantine-Notification-root {
|
||||
background-color: var(--neu-surface);
|
||||
border: 1px solid var(--neu-border);
|
||||
box-shadow: var(--mantine-shadow-lg);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Modal-content {
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Modal-header {
|
||||
background-color: var(--neu-surface);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Notification-root {
|
||||
border-radius: var(--mantine-radius-md);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Tooltip-tooltip {
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Alert-root {
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
/* App shell: soft edges instead of hard hairlines */
|
||||
[data-theme="neumorph"] .mantine-AppShell-header {
|
||||
background-color: var(--neu-surface);
|
||||
border-bottom: 1px solid var(--neu-border);
|
||||
box-shadow: var(--neu-edge);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-AppShell-navbar {
|
||||
background-color: var(--neu-surface);
|
||||
border-top: 1px solid var(--neu-border);
|
||||
border-inline-end: 1px solid var(--neu-border);
|
||||
box-shadow: var(--neu-edge);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 4. Raised controls — extruded plastic; press swaps to inset */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="neumorph"] .mantine-Button-root,
|
||||
[data-theme="neumorph"] .mantine-ActionIcon-root {
|
||||
border: 1px solid var(--neu-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
transition:
|
||||
box-shadow 160ms ease,
|
||||
transform 120ms cubic-bezier(0.32, 0.72, 0, 1);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Button-root:where([data-variant="default"], [data-variant="outline"]),
|
||||
[data-theme="neumorph"] .mantine-ActionIcon-root:where([data-variant="default"], [data-variant="outline"]) {
|
||||
background-color: var(--neu-surface);
|
||||
color: var(--mantine-color-default-color);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Button-root:where([data-variant="default"], [data-variant="outline"]):hover,
|
||||
[data-theme="neumorph"] .mantine-ActionIcon-root:where([data-variant="default"], [data-variant="outline"]):hover {
|
||||
background-color: var(--neu-surface-high);
|
||||
}
|
||||
|
||||
/* Ghost variants stay flat — no floating shadow plates */
|
||||
[data-theme="neumorph"] .mantine-Button-root:where([data-variant="subtle"], [data-variant="transparent"], [data-variant="white"]),
|
||||
[data-theme="neumorph"] .mantine-ActionIcon-root:where([data-variant="subtle"], [data-variant="transparent"], [data-variant="white"]) {
|
||||
border-color: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Button-root:active:not([data-disabled], :disabled, [data-loading]),
|
||||
[data-theme="neumorph"] .mantine-ActionIcon-root:active:not([data-disabled], :disabled, [data-loading]) {
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Button-root:where([data-disabled], :disabled),
|
||||
[data-theme="neumorph"] .mantine-ActionIcon-root:where([data-disabled], :disabled) {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Re-flavor global press feedback: pressed-in, not just scaled */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="neumorph"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
transform: scale(0.985);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 5. Inputs — pressed-in wells */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="neumorph"] .mantine-Input-input {
|
||||
background-color: var(--neu-surface);
|
||||
border: 1px solid var(--neu-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
transition: border-color 160ms ease, box-shadow 160ms ease;
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Input-input:focus,
|
||||
[data-theme="neumorph"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: var(--neu-inset);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Input-input[data-error] {
|
||||
border-color: var(--mantine-color-error);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 6. Selection controls */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* SegmentedControl: raised track, indicator is a pressed-in well */
|
||||
[data-theme="neumorph"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--neu-surface);
|
||||
border: 1px solid var(--neu-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--neu-well);
|
||||
border: 1px solid var(--neu-border);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-SegmentedControl-label[data-active] {
|
||||
color: var(--mantine-color-bright);
|
||||
}
|
||||
|
||||
/* Switch: inset track, raised thumb */
|
||||
[data-theme="neumorph"] .mantine-Switch-track {
|
||||
border: 1px solid var(--neu-border);
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Switch-thumb {
|
||||
border: 1px solid var(--neu-border);
|
||||
box-shadow: 2px 2px 5px var(--neu-shadow-dark), -2px -2px 5px var(--neu-shadow-light);
|
||||
}
|
||||
|
||||
/* Checkbox / Radio: unchecked = soft well, checked keeps accent */
|
||||
[data-theme="neumorph"] .mantine-Checkbox-input,
|
||||
[data-theme="neumorph"] .mantine-Radio-radio {
|
||||
border: 1px solid var(--neu-border);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Checkbox-input:not(:checked),
|
||||
[data-theme="neumorph"] .mantine-Radio-radio:not(:checked) {
|
||||
background-color: var(--neu-surface);
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Checkbox-input {
|
||||
border-radius: 0.375rem;
|
||||
}
|
||||
|
||||
/* Progress: inset trough, soft bar */
|
||||
[data-theme="neumorph"] .mantine-Progress-root {
|
||||
background-color: var(--neu-well);
|
||||
border: 1px solid var(--neu-border);
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Progress-section {
|
||||
border-radius: var(--mantine-radius-xl);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 7. Navigation & misc */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="neumorph"] .mantine-Tabs-tab {
|
||||
border-radius: var(--mantine-radius-sm) var(--mantine-radius-sm) 0 0;
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Tabs-tab:hover {
|
||||
background-color: var(--neu-surface-high);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-NavLink-root {
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--mantine-radius-md);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-NavLink-root[data-active] {
|
||||
background-color: var(--neu-well);
|
||||
border-color: var(--neu-border);
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
color: var(--mantine-color-text);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Badge-root {
|
||||
border: 1px solid var(--neu-border);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Badge-root[data-variant="default"] {
|
||||
background-color: var(--neu-surface);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
color: var(--mantine-color-text);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .flxn-avatar-frame {
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-ThemeIcon-root[data-variant="default"] {
|
||||
background-color: var(--neu-surface);
|
||||
border: 1px solid var(--neu-border);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Skeleton-root {
|
||||
border-radius: var(--mantine-radius-md);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .mantine-Divider-root {
|
||||
--divider-color: var(--neu-border);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 8. App hooks — tab strip, nav tiles, chips, match tray */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Tab strip: flat while resting; docking lands it back on the shared
|
||||
surface. The active state is a soft pressed-in pill instead of a hard
|
||||
underline, legible on the bare page (body IS --neu-surface). */
|
||||
[data-theme="neumorph"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--neu-surface);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .flxn-tab.flxn-tab {
|
||||
border-radius: var(--mantine-radius-xl);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .flxn-tab.flxn-tab[data-active] {
|
||||
color: color-mix(
|
||||
in srgb,
|
||||
var(--mantine-primary-color-filled) 45%,
|
||||
var(--mantine-color-text)
|
||||
);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: none;
|
||||
border-radius: var(--mantine-radius-xl);
|
||||
background-color: color-mix(in srgb, var(--mantine-primary-color-filled) 8%, var(--neu-well));
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
|
||||
/* Nav tiles: extruded plastic, pressed-in on tap; icon sits on a
|
||||
debossed coin */
|
||||
[data-theme="neumorph"] .flxn-tile.flxn-tile {
|
||||
background-color: var(--neu-surface);
|
||||
border: 1px solid var(--neu-border);
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="neumorph"] .flxn-tile.flxn-tile:hover:not(:disabled) {
|
||||
background-color: var(--neu-surface-high);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .flxn-tile.flxn-tile:active:not(:disabled) {
|
||||
background-color: var(--neu-surface);
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="neumorph"] .flxn-tile.flxn-tile {
|
||||
transition:
|
||||
background-color 120ms ease-out,
|
||||
box-shadow 160ms ease,
|
||||
transform 120ms cubic-bezier(0.32, 0.72, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .flxn-tile-icon.flxn-tile-icon {
|
||||
color: light-dark(var(--mantine-primary-color-6), var(--mantine-primary-color-3));
|
||||
}
|
||||
|
||||
/* "See all" as a soft extruded chip */
|
||||
[data-theme="neumorph"] .flxn-see-all.flxn-see-all {
|
||||
background-color: var(--neu-surface);
|
||||
border: 1px solid var(--neu-border);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="neumorph"] .flxn-see-all.flxn-see-all:hover {
|
||||
background-color: var(--neu-surface-high);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .flxn-see-all.flxn-see-all:active {
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
|
||||
/* Match card stays extruded; the reaction tray tucked beneath it is a
|
||||
pressed-in well */
|
||||
[data-theme="neumorph"] .flxn-match-card.flxn-match-card {
|
||||
background-color: var(--neu-surface);
|
||||
border: 1px solid var(--neu-border);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="neumorph"] .flxn-reaction-row.flxn-reaction-row {
|
||||
background-color: var(--neu-well);
|
||||
border: 1px solid var(--neu-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--neu-inset-sm);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
/* Bioluminescent sea ramps for all eight accents. Declared in JS (not
|
||||
theme.css) so Mantine regenerates every derived variant var (-light rgba,
|
||||
-outline, autoContrast picks) from the retuned shades, whichever accent
|
||||
the user selects. */
|
||||
const oceanColors = {
|
||||
// plankton blue
|
||||
blue: [
|
||||
"#e3f7fd",
|
||||
"#c6eefb",
|
||||
"#9ce2f8",
|
||||
"#6dd2f2",
|
||||
"#45c3ec",
|
||||
"#27b3e2",
|
||||
"#1897c7",
|
||||
"#147ba6",
|
||||
"#106284",
|
||||
"#0c4c67",
|
||||
],
|
||||
// kelp green
|
||||
green: [
|
||||
"#e8f8ee",
|
||||
"#cdefdb",
|
||||
"#a8e3bf",
|
||||
"#80d5a1",
|
||||
"#5cc686",
|
||||
"#3eb56e",
|
||||
"#2f9c5c",
|
||||
"#27814d",
|
||||
"#1f683e",
|
||||
"#185231",
|
||||
],
|
||||
// sea-sparkle phosphor
|
||||
lime: [
|
||||
"#f2fbe3",
|
||||
"#e2f6c4",
|
||||
"#ccee9d",
|
||||
"#b3e474",
|
||||
"#9cda50",
|
||||
"#86ce32",
|
||||
"#6fb51f",
|
||||
"#5c9718",
|
||||
"#4a7a12",
|
||||
"#3a600e",
|
||||
],
|
||||
// siphonophore crimson
|
||||
red: [
|
||||
"#fdeef0",
|
||||
"#fad8dc",
|
||||
"#f6b6be",
|
||||
"#f18f9c",
|
||||
"#ec6c7e",
|
||||
"#e54d64",
|
||||
"#d1344e",
|
||||
"#b02840",
|
||||
"#8f2034",
|
||||
"#701929",
|
||||
],
|
||||
// anglerfish gold
|
||||
yellow: [
|
||||
"#fdf8e2",
|
||||
"#fbefbe",
|
||||
"#f8e392",
|
||||
"#f4d363",
|
||||
"#efc43c",
|
||||
"#e8b31d",
|
||||
"#ce9a10",
|
||||
"#ad800c",
|
||||
"#8c6709",
|
||||
"#6d5007",
|
||||
],
|
||||
// amber lure
|
||||
orange: [
|
||||
"#fef2e5",
|
||||
"#fce2c6",
|
||||
"#f9cb9c",
|
||||
"#f5b06e",
|
||||
"#f09746",
|
||||
"#ea8127",
|
||||
"#d16a15",
|
||||
"#af5810",
|
||||
"#8d460c",
|
||||
"#6e3709",
|
||||
],
|
||||
// medusa violet
|
||||
grape: [
|
||||
"#f5f0fd",
|
||||
"#e8dcfa",
|
||||
"#d4c0f5",
|
||||
"#bd9fee",
|
||||
"#a781e6",
|
||||
"#9268dc",
|
||||
"#7e4fca",
|
||||
"#6a3fae",
|
||||
"#56328e",
|
||||
"#43276f",
|
||||
],
|
||||
// jelly pink
|
||||
pink: [
|
||||
"#fdeef6",
|
||||
"#fbd8ea",
|
||||
"#f7b5d8",
|
||||
"#f28dc2",
|
||||
"#ec69ae",
|
||||
"#e54c9c",
|
||||
"#d13487",
|
||||
"#b02871",
|
||||
"#8f215c",
|
||||
"#701a48",
|
||||
],
|
||||
} as const;
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "ocean",
|
||||
label: msg`Deep Sea`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Comfortaa:wght@500;600;700&family=Figtree:wght@400;500;600;700&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#eaf6f6", dimmed: "#c3e2df" },
|
||||
dark: { base: "#052430", dimmed: "#03141d" },
|
||||
},
|
||||
mantine: {
|
||||
// Bright bioluminescent fills in the dark (shade 5), deeper sea tones in
|
||||
// the shallows (shade 6); bright fills (gold, phosphor, plankton) take
|
||||
// dark text via autoContrast.
|
||||
primaryShade: { light: 6, dark: 5 },
|
||||
autoContrast: true,
|
||||
luminanceThreshold: 0.3,
|
||||
colors: oceanColors,
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,423 @@
|
||||
/* Deep Sea: a submarine descent. Dark is the primary mood — a fixed
|
||||
abyssal deep-teal→ink-navy backdrop with sparse static rising bubbles;
|
||||
surfaces are opaque pressure-hull panels with 1px bioluminescent rims,
|
||||
focus states are sonar rings (double accent box-shadow), avatars are
|
||||
portholes. Light is the sunlit shallows: sand-and-seafoam with a very
|
||||
subtle refracted-caustic hint. The fixed teal rim/scenery is decoration;
|
||||
everything interactive derives from --mantine-primary-color-* (the eight
|
||||
ramps are retuned in manifest.ts as bioluminescent sea colors). No
|
||||
backdrop-filter anywhere — hulls are solid. */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 1. Tokens for any scheme */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="ocean"][data-theme] {
|
||||
--mantine-font-family: "Figtree", "Avenir Next", "Helvetica Neue", sans-serif;
|
||||
--mantine-font-family-headings: "Comfortaa", "Figtree", sans-serif;
|
||||
--mantine-heading-font-weight: 700;
|
||||
|
||||
/* rounded, water-worn radii */
|
||||
--mantine-radius-xs: 0.375rem;
|
||||
--mantine-radius-sm: 0.5625rem;
|
||||
--mantine-radius-md: 0.75rem;
|
||||
--mantine-radius-lg: 1rem;
|
||||
--mantine-radius-xl: 1.5rem;
|
||||
--mantine-radius-default: 0.75rem;
|
||||
|
||||
/* porthole avatars: circle + bold hull ring (the frame owns the border) */
|
||||
--flxn-avatar-radius: 50%;
|
||||
--flxn-avatar-border: 3px solid var(--ocean-porthole);
|
||||
--flxn-badge-radius: 14px;
|
||||
|
||||
/* sonar focus ring: two accent rings, inner solid + outer echo */
|
||||
--ocean-sonar: 0 0 0 2px
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 90%, transparent),
|
||||
0 0 0 6px
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 28%, transparent);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 2. Per-scheme tokens */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="ocean"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #062632;
|
||||
--mantine-color-text: #d9f2f0;
|
||||
--mantine-color-bright: #f2fffd;
|
||||
--mantine-color-dimmed: #93bcc0;
|
||||
--mantine-color-placeholder: #628e96;
|
||||
--mantine-color-default: #0c3745;
|
||||
--mantine-color-default-hover: #11424f;
|
||||
--mantine-color-default-color: #d9f2f0;
|
||||
--mantine-color-default-border: rgba(103, 232, 214, 0.24);
|
||||
|
||||
/* deep-water elevation with a faint bioluminescent edge */
|
||||
--mantine-shadow-xs: 0 0 0 1px rgba(103, 232, 214, 0.06), 0 2px 6px rgba(1, 10, 16, 0.5);
|
||||
--mantine-shadow-sm: 0 0 0 1px rgba(103, 232, 214, 0.08), 0 4px 12px rgba(1, 10, 16, 0.55);
|
||||
--mantine-shadow-md: 0 0 0 1px rgba(103, 232, 214, 0.1), 0 8px 24px rgba(1, 10, 16, 0.6);
|
||||
--mantine-shadow-lg: 0 0 0 1px rgba(103, 232, 214, 0.12), 0 12px 34px rgba(1, 10, 16, 0.65);
|
||||
--mantine-shadow-xl: 0 0 0 1px rgba(103, 232, 214, 0.14), 0 18px 48px rgba(1, 10, 16, 0.7);
|
||||
|
||||
/* pressure-hull ingredients */
|
||||
--ocean-hull: #0a3240;
|
||||
--ocean-hull-raised: #0e3d4d;
|
||||
--ocean-deep: #041d27;
|
||||
--ocean-rim: rgba(103, 232, 214, 0.22);
|
||||
--ocean-rim-strong: rgba(103, 232, 214, 0.38);
|
||||
--ocean-chrome: #052430;
|
||||
--ocean-porthole: #2c7482;
|
||||
--ocean-porthole-glow: 0 0 0 1px rgba(103, 232, 214, 0.25),
|
||||
0 0 12px rgba(103, 232, 214, 0.2);
|
||||
--ocean-tooltip-bg: #0d3947;
|
||||
--ocean-tooltip-color: #dcf5f2;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #f2c14b;
|
||||
--flxn-silver: #a9c3cb;
|
||||
--flxn-bronze: #dd9364;
|
||||
--flxn-toast-success: #6fe3a5;
|
||||
--flxn-toast-error: #ff8f9f;
|
||||
--flxn-showcase-bg: #0a3240;
|
||||
--flxn-overlay: rgba(2, 10, 16, 0.62);
|
||||
--flxn-dotgrid-color: rgba(103, 232, 214, 0.16);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.55);
|
||||
|
||||
/* podium as glowing depth tiers */
|
||||
--flxn-podium-1-bg: rgba(242, 193, 75, 0.1);
|
||||
--flxn-podium-1-border: rgba(242, 193, 75, 0.38);
|
||||
--flxn-podium-1-label: #f2c14b;
|
||||
--flxn-podium-2-bg: rgba(169, 195, 203, 0.08);
|
||||
--flxn-podium-2-border: rgba(169, 195, 203, 0.3);
|
||||
--flxn-podium-2-label: #b8ccd2;
|
||||
--flxn-podium-3-bg: rgba(221, 147, 100, 0.1);
|
||||
--flxn-podium-3-border: rgba(221, 147, 100, 0.36);
|
||||
--flxn-podium-3-label: #e5a273;
|
||||
}
|
||||
|
||||
[data-theme="ocean"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #eaf6f6;
|
||||
--mantine-color-text: #11373f;
|
||||
--mantine-color-bright: #072229;
|
||||
--mantine-color-dimmed: #4a6e72;
|
||||
--mantine-color-placeholder: #5f858a;
|
||||
--mantine-color-default: #ffffff;
|
||||
--mantine-color-default-hover: #f0f7f4;
|
||||
--mantine-color-default-color: #11373f;
|
||||
--mantine-color-default-border: rgba(23, 115, 110, 0.3);
|
||||
|
||||
/* soft sea-tinted elevation */
|
||||
--mantine-shadow-xs: 0 1px 3px rgba(15, 80, 90, 0.1);
|
||||
--mantine-shadow-sm: 0 2px 8px rgba(15, 80, 90, 0.12);
|
||||
--mantine-shadow-md: 0 6px 18px rgba(15, 80, 90, 0.14);
|
||||
--mantine-shadow-lg: 0 10px 28px rgba(15, 80, 90, 0.16);
|
||||
--mantine-shadow-xl: 0 16px 44px rgba(15, 80, 90, 0.2);
|
||||
|
||||
/* sand-and-seafoam ingredients */
|
||||
--ocean-hull: #fbfaf3;
|
||||
--ocean-hull-raised: #ffffff;
|
||||
--ocean-deep: #ddeeea;
|
||||
--ocean-rim: rgba(23, 115, 110, 0.25);
|
||||
--ocean-rim-strong: rgba(23, 115, 110, 0.42);
|
||||
--ocean-chrome: #f3f9f6;
|
||||
--ocean-porthole: #7fb5ae;
|
||||
--ocean-porthole-glow: 0 0 0 1px rgba(23, 115, 110, 0.18),
|
||||
0 2px 8px rgba(15, 80, 90, 0.16);
|
||||
--ocean-tooltip-bg: #14424d;
|
||||
--ocean-tooltip-color: #e4f6f3;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #d8a419;
|
||||
--flxn-silver: #8ba7ad;
|
||||
--flxn-bronze: #c76e34;
|
||||
--flxn-toast-success: #2e9e6b;
|
||||
--flxn-toast-error: #d64d64;
|
||||
--flxn-showcase-bg: #ffffff;
|
||||
--flxn-overlay: rgba(10, 50, 60, 0.4);
|
||||
--flxn-dotgrid-color: rgba(23, 115, 110, 0.2);
|
||||
--flxn-pop-shadow: rgba(15, 80, 90, 0.28);
|
||||
|
||||
/* podium as sunlit sand tiers */
|
||||
--flxn-podium-1-bg: rgba(216, 164, 25, 0.14);
|
||||
--flxn-podium-1-border: rgba(179, 131, 16, 0.45);
|
||||
--flxn-podium-1-label: #7c5a0b;
|
||||
--flxn-podium-2-bg: rgba(90, 120, 125, 0.1);
|
||||
--flxn-podium-2-border: rgba(90, 120, 125, 0.35);
|
||||
--flxn-podium-2-label: #47666a;
|
||||
--flxn-podium-3-bg: rgba(199, 110, 52, 0.12);
|
||||
--flxn-podium-3-border: rgba(199, 110, 52, 0.42);
|
||||
--flxn-podium-3-label: #8a4c1d;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 3. Fixed backdrop (below all content) */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="ocean"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Abyssal descent: deep teal fading to ink navy, sparse static bubbles
|
||||
rising (bigger and brighter near the sea floor, fading toward the top). */
|
||||
[data-theme="ocean"][data-mantine-color-scheme="dark"] body::before {
|
||||
background-color: #062632;
|
||||
background-image:
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='260' height='640' viewBox='0 0 260 640'%3E%3Cg fill='none' stroke='%239beee2'%3E%3Ccircle cx='36' cy='584' r='5' stroke-opacity='.13'/%3E%3Ccircle cx='44' cy='512' r='3' stroke-opacity='.1'/%3E%3Ccircle cx='210' cy='612' r='4' stroke-opacity='.12'/%3E%3Ccircle cx='202' cy='540' r='2.5' stroke-opacity='.09'/%3E%3Ccircle cx='128' cy='430' r='3.5' stroke-opacity='.1'/%3E%3Ccircle cx='120' cy='360' r='2' stroke-opacity='.08'/%3E%3Ccircle cx='232' cy='300' r='3' stroke-opacity='.09'/%3E%3Ccircle cx='60' cy='250' r='2.5' stroke-opacity='.08'/%3E%3Ccircle cx='150' cy='160' r='2' stroke-opacity='.07'/%3E%3Ccircle cx='90' cy='80' r='1.5' stroke-opacity='.06'/%3E%3C/g%3E%3Cg fill='%239beee2'%3E%3Ccircle cx='70' cy='470' r='1.2' fill-opacity='.1'/%3E%3Ccircle cx='180' cy='390' r='1' fill-opacity='.09'/%3E%3Ccircle cx='40' cy='330' r='1' fill-opacity='.08'/%3E%3Ccircle cx='222' cy='190' r='1' fill-opacity='.07'/%3E%3Ccircle cx='140' cy='40' r='1' fill-opacity='.05'/%3E%3C/g%3E%3C/svg%3E"),
|
||||
radial-gradient(50rem 30rem at 50% -10%, rgba(45, 160, 175, 0.18), transparent 65%),
|
||||
linear-gradient(180deg, #0b3b46 0%, #072b38 45%, #03121e 100%);
|
||||
background-repeat: repeat, no-repeat, no-repeat;
|
||||
background-size: 260px 640px, auto, auto;
|
||||
}
|
||||
|
||||
/* Sunlit shallows: seafoam fading to a sandy floor, with a faint white
|
||||
caustic ripple tile — refracted light, kept very subtle. */
|
||||
[data-theme="ocean"][data-mantine-color-scheme="light"] body::before {
|
||||
background-color: #eaf6f6;
|
||||
background-image:
|
||||
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='220' viewBox='0 0 320 220'%3E%3Cg fill='none' stroke='%23ffffff' stroke-width='1.4'%3E%3Cpath d='M0 40 Q 40 10 80 42 T 160 44 T 240 38 T 320 42' stroke-opacity='.4'/%3E%3Cpath d='M0 110 Q 45 82 90 112 T 180 110 T 268 114 T 320 108' stroke-opacity='.3'/%3E%3Cpath d='M0 180 Q 50 152 100 182 T 200 178 T 300 184 T 320 180' stroke-opacity='.35'/%3E%3C/g%3E%3C/svg%3E"),
|
||||
radial-gradient(46rem 26rem at 30% -8%, rgba(255, 255, 255, 0.75), transparent 60%),
|
||||
radial-gradient(60rem 22rem at 50% 108%, rgba(226, 214, 178, 0.5), transparent 70%),
|
||||
linear-gradient(180deg, #d8efee 0%, #eaf6f6 55%, #f2f3e9 100%);
|
||||
background-repeat: repeat, no-repeat, no-repeat, no-repeat;
|
||||
background-size: 320px 220px, auto, auto, auto;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 4. Pressure-hull surfaces: solid panels, bioluminescent rims */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="ocean"] .mantine-Paper-root,
|
||||
[data-theme="ocean"] .mantine-Card-root {
|
||||
background-color: var(--ocean-hull);
|
||||
border: 1px solid var(--ocean-rim);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Modal-content {
|
||||
background-color: var(--ocean-hull);
|
||||
border: 1px solid var(--ocean-rim-strong);
|
||||
box-shadow: var(--mantine-shadow-xl);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Modal-header {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Popover-dropdown {
|
||||
background-color: var(--ocean-hull);
|
||||
border: 1px solid var(--ocean-rim-strong);
|
||||
box-shadow: var(--mantine-shadow-lg);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Notification-root {
|
||||
background-color: var(--ocean-hull);
|
||||
border: 1px solid var(--ocean-rim-strong);
|
||||
box-shadow: var(--mantine-shadow-lg);
|
||||
}
|
||||
|
||||
/* AppShell chrome: the conning tower and lower deck — solid hull strips
|
||||
sealed with a stronger rim seam. */
|
||||
[data-theme="ocean"] .mantine-AppShell-header {
|
||||
background-color: var(--ocean-chrome);
|
||||
border-bottom: 1px solid var(--ocean-rim-strong);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-AppShell-navbar {
|
||||
background-color: var(--ocean-chrome);
|
||||
border-inline-end: 1px solid var(--ocean-rim-strong);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 5. Sonar focus rings */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* The transparent outline stays invisible here but becomes a real ring in
|
||||
forced-colors mode, where the box-shadow sonar is stripped. */
|
||||
[data-theme="ocean"] :focus-visible {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
box-shadow: var(--ocean-sonar);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Input-input:focus,
|
||||
[data-theme="ocean"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: var(--ocean-sonar);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 6. Controls */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Filled controls give off a faint accent glow; the transparent border
|
||||
keeps a real edge for forced-colors mode. */
|
||||
[data-theme="ocean"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="ocean"] .mantine-ActionIcon-root[data-variant="filled"] {
|
||||
border: 1px solid transparent;
|
||||
box-shadow:
|
||||
0 0 14px -4px color-mix(in srgb, var(--mantine-primary-color-filled) 55%, transparent),
|
||||
var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Button-root {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Input-input {
|
||||
background-color: var(--ocean-deep);
|
||||
border: 1px solid var(--ocean-rim);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Checkbox-input {
|
||||
background-color: var(--ocean-deep);
|
||||
border-color: var(--ocean-rim-strong);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--ocean-deep);
|
||||
border: 1px solid var(--ocean-rim);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--ocean-hull-raised);
|
||||
border: 1px solid var(--ocean-rim-strong);
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Progress-root {
|
||||
background-color: var(--ocean-deep);
|
||||
border: 1px solid var(--ocean-rim);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Badge-root[data-variant="default"] {
|
||||
background-color: var(--mantine-color-default);
|
||||
border: 1px solid var(--ocean-rim);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Tabs-list {
|
||||
--tabs-list-border-color: var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Tabs-tab:hover,
|
||||
[data-theme="ocean"] .mantine-NavLink-root:hover {
|
||||
background-color: var(--mantine-color-default-hover);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Tooltip-tooltip {
|
||||
background-color: var(--ocean-tooltip-bg);
|
||||
color: var(--ocean-tooltip-color);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] ::selection {
|
||||
background: color-mix(in srgb, var(--mantine-primary-color-filled) 30%, transparent);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 7. Wave divider: repeating radial scallop line */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="ocean"] .mantine-Divider-root {
|
||||
--divider-color: var(--ocean-rim-strong);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .mantine-Divider-root[data-orientation="horizontal"]:not([data-with-label]) {
|
||||
border-top: none;
|
||||
height: 5px;
|
||||
background-image: radial-gradient(
|
||||
circle at 6px -2px,
|
||||
transparent 4px,
|
||||
var(--ocean-rim-strong) 4px,
|
||||
var(--ocean-rim-strong) 5.4px,
|
||||
transparent 5.4px
|
||||
);
|
||||
background-size: 12px 5px;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
@media (forced-colors: active) {
|
||||
[data-theme="ocean"] .mantine-Divider-root[data-orientation="horizontal"]:not([data-with-label]) {
|
||||
border-top: 1px solid CanvasText;
|
||||
height: auto;
|
||||
background-image: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 8. App component hooks */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Tab strip: flat while resting; docked it becomes a hull deck strip. */
|
||||
[data-theme="ocean"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--ocean-chrome);
|
||||
border-bottom-color: var(--ocean-rim-strong);
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .flxn-tab {
|
||||
color: var(--mantine-color-dimmed);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Underline indicator, so accent text on the active tab is allowed. */
|
||||
[data-theme="ocean"] .flxn-tab[data-active] {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .flxn-tabs-indicator {
|
||||
border-bottom: 2px solid var(--mantine-primary-color-filled);
|
||||
padding-inline: 0.5rem;
|
||||
}
|
||||
|
||||
/* Nav grid tiles: instrument panels — hull plate with a lit top seam. */
|
||||
[data-theme="ocean"] .flxn-tile {
|
||||
background-color: var(--ocean-hull);
|
||||
border: 1px solid var(--ocean-rim);
|
||||
border-radius: var(--mantine-radius-lg);
|
||||
box-shadow: var(--mantine-shadow-xs), inset 0 1px 0 var(--ocean-rim);
|
||||
}
|
||||
|
||||
/* Flat accent-tinted glyph — no plate. */
|
||||
[data-theme="ocean"] .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* "See all" as a depth-tag chip: accent wash + its dedicated on-color. */
|
||||
[data-theme="ocean"] .flxn-see-all {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
border: 1px solid
|
||||
color-mix(in srgb, var(--mantine-primary-color-light-color) 35%, transparent);
|
||||
}
|
||||
|
||||
/* Match card + reaction tray as one hull construction: same rim, tray one
|
||||
deck lower (deeper water). */
|
||||
[data-theme="ocean"] .flxn-match-card {
|
||||
background-color: var(--ocean-hull);
|
||||
border: 1px solid var(--ocean-rim);
|
||||
}
|
||||
|
||||
[data-theme="ocean"] .flxn-reaction-row {
|
||||
background-color: var(--ocean-deep);
|
||||
border: 1px solid var(--ocean-rim);
|
||||
}
|
||||
|
||||
/* Porthole: the bold ring comes from --flxn-avatar-border; the frame adds
|
||||
the bioluminescent halo around it. */
|
||||
[data-theme="ocean"] .flxn-avatar-frame {
|
||||
border-radius: 50%;
|
||||
box-shadow: var(--ocean-porthole-glow);
|
||||
}
|
||||
|
||||
/* Press feedback: a brief bioluminescent flare (filter only — the global
|
||||
scale transform stays untouched). */
|
||||
[data-theme="ocean"] .flxn-press:active {
|
||||
filter: brightness(1.06) saturate(1.08);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "quest",
|
||||
label: msg`Quest Log`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Grenze:wght@500;600;700&display=swap",
|
||||
"https://fonts.googleapis.com/css2?family=Alegreya:ital,wght@0,400;0,500;0,600;0,700;1,400;1,600&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#f0e6cf", dimmed: "#ddcca6" },
|
||||
dark: { base: "#211a12", dimmed: "#150f08" },
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,762 @@
|
||||
/* Quest Log — fantasy-RPG journal.
|
||||
Aged bronze is the structural decoration (2px entry frames, corner
|
||||
brackets, ribbon banners); the interactive accent follows the user via
|
||||
the primary aliases. All eight accent ramps are retuned as heraldic
|
||||
banner dyes. Light = aged parchment journal, dark = torchlit hall. */
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 1. Scheme-independent tokens — (0,2,0)
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="quest"][data-theme] {
|
||||
/* Type: Grenze for medieval-but-readable headings, Alegreya body. */
|
||||
--mantine-font-family: "Alegreya", "Iowan Old Style", Georgia, serif;
|
||||
--mantine-font-family-headings: "Grenze", "Alegreya", Georgia, serif;
|
||||
--mantine-font-size-xs: 0.8125rem;
|
||||
--mantine-font-size-sm: 0.9375rem;
|
||||
--mantine-font-size-md: 1.0625rem;
|
||||
--mantine-font-size-lg: 1.1875rem;
|
||||
--mantine-font-size-xl: 1.375rem;
|
||||
--mantine-heading-font-weight: 600;
|
||||
--mantine-h1-font-size: 2.4rem;
|
||||
--mantine-h1-line-height: 1.15;
|
||||
--mantine-h2-font-size: 1.95rem;
|
||||
--mantine-h2-line-height: 1.2;
|
||||
--mantine-h3-font-size: 1.55rem;
|
||||
--mantine-h3-line-height: 1.25;
|
||||
--mantine-h4-font-size: 1.3rem;
|
||||
--mantine-h4-line-height: 1.3;
|
||||
--mantine-h5-font-size: 1.15rem;
|
||||
--mantine-h5-line-height: 1.35;
|
||||
--mantine-h6-font-size: 1.05rem;
|
||||
--mantine-h6-line-height: 1.4;
|
||||
|
||||
/* Shape: gently squared journal entries. */
|
||||
--mantine-radius-xs: 0.125rem;
|
||||
--mantine-radius-sm: 0.25rem;
|
||||
--mantine-radius-md: 0.375rem;
|
||||
--mantine-radius-lg: 0.5rem;
|
||||
--mantine-radius-xl: 0.75rem;
|
||||
--mantine-radius-default: 0.375rem;
|
||||
|
||||
/* Elevation: soft warm sepia, never harsh. */
|
||||
--mantine-shadow-xs: 0 1px 2px rgba(38, 26, 10, 0.2);
|
||||
--mantine-shadow-sm: 0 1px 2px rgba(38, 26, 10, 0.22), 0 5px 14px rgba(38, 26, 10, 0.16);
|
||||
--mantine-shadow-md: 0 2px 4px rgba(38, 26, 10, 0.24), 0 10px 24px rgba(38, 26, 10, 0.2);
|
||||
--mantine-shadow-lg: 0 3px 7px rgba(38, 26, 10, 0.26), 0 18px 40px rgba(38, 26, 10, 0.24);
|
||||
--mantine-shadow-xl: 0 5px 10px rgba(38, 26, 10, 0.28), 0 26px 56px rgba(38, 26, 10, 0.28);
|
||||
|
||||
/* Accent ramps retuned as heraldic banner dyes — saturated but cloth-worn;
|
||||
every shade 6 carries ≥4.5:1 parchment contrast text. */
|
||||
|
||||
/* blue → azure banner */
|
||||
--mantine-color-blue-0: #eef1fa;
|
||||
--mantine-color-blue-1: #d8dff2;
|
||||
--mantine-color-blue-2: #b4c2e6;
|
||||
--mantine-color-blue-3: #8aa0d6;
|
||||
--mantine-color-blue-4: #6280c4;
|
||||
--mantine-color-blue-5: #4263ae;
|
||||
--mantine-color-blue-6: #2f4d96;
|
||||
--mantine-color-blue-7: #263e7b;
|
||||
--mantine-color-blue-8: #1d2f60;
|
||||
--mantine-color-blue-9: #152246;
|
||||
|
||||
/* red → gules crimson */
|
||||
--mantine-color-red-0: #faeceb;
|
||||
--mantine-color-red-1: #f2d3d1;
|
||||
--mantine-color-red-2: #e6aba7;
|
||||
--mantine-color-red-3: #d87d78;
|
||||
--mantine-color-red-4: #c65450;
|
||||
--mantine-color-red-5: #ad322f;
|
||||
--mantine-color-red-6: #92201f;
|
||||
--mantine-color-red-7: #7a1719;
|
||||
--mantine-color-red-8: #601114;
|
||||
--mantine-color-red-9: #470c0f;
|
||||
|
||||
/* green → vert */
|
||||
--mantine-color-green-0: #ebf3ec;
|
||||
--mantine-color-green-1: #d2e5d4;
|
||||
--mantine-color-green-2: #aacfae;
|
||||
--mantine-color-green-3: #7db383;
|
||||
--mantine-color-green-4: #55975d;
|
||||
--mantine-color-green-5: #35793f;
|
||||
--mantine-color-green-6: #24632e;
|
||||
--mantine-color-green-7: #1c5026;
|
||||
--mantine-color-green-8: #153e1e;
|
||||
--mantine-color-green-9: #0e2c16;
|
||||
|
||||
/* yellow → or (gold leaf) */
|
||||
--mantine-color-yellow-0: #fbf3dc;
|
||||
--mantine-color-yellow-1: #f4e3b0;
|
||||
--mantine-color-yellow-2: #e9cd7c;
|
||||
--mantine-color-yellow-3: #dbb14b;
|
||||
--mantine-color-yellow-4: #c99527;
|
||||
--mantine-color-yellow-5: #ab7812;
|
||||
--mantine-color-yellow-6: #8c5f0b;
|
||||
--mantine-color-yellow-7: #714c09;
|
||||
--mantine-color-yellow-8: #583b07;
|
||||
--mantine-color-yellow-9: #402b05;
|
||||
|
||||
/* grape → purpure */
|
||||
--mantine-color-grape-0: #f4edf7;
|
||||
--mantine-color-grape-1: #e5d5ec;
|
||||
--mantine-color-grape-2: #cfb2dc;
|
||||
--mantine-color-grape-3: #b389c8;
|
||||
--mantine-color-grape-4: #9663b2;
|
||||
--mantine-color-grape-5: #7a4399;
|
||||
--mantine-color-grape-6: #642e82;
|
||||
--mantine-color-grape-7: #52246b;
|
||||
--mantine-color-grape-8: #401b54;
|
||||
--mantine-color-grape-9: #2f133e;
|
||||
|
||||
/* orange → tenné */
|
||||
--mantine-color-orange-0: #faeee2;
|
||||
--mantine-color-orange-1: #f3d9bd;
|
||||
--mantine-color-orange-2: #e9bc8d;
|
||||
--mantine-color-orange-3: #dd9a58;
|
||||
--mantine-color-orange-4: #cf7a2c;
|
||||
--mantine-color-orange-5: #b45e14;
|
||||
--mantine-color-orange-6: #96490d;
|
||||
--mantine-color-orange-7: #7a3a0b;
|
||||
--mantine-color-orange-8: #602d08;
|
||||
--mantine-color-orange-9: #472106;
|
||||
|
||||
/* pink → rose madder */
|
||||
--mantine-color-pink-0: #f9ecf1;
|
||||
--mantine-color-pink-1: #f0d3de;
|
||||
--mantine-color-pink-2: #e3aac1;
|
||||
--mantine-color-pink-3: #d27da0;
|
||||
--mantine-color-pink-4: #bf5280;
|
||||
--mantine-color-pink-5: #a53064;
|
||||
--mantine-color-pink-6: #8a1f51;
|
||||
--mantine-color-pink-7: #711842;
|
||||
--mantine-color-pink-8: #581233;
|
||||
--mantine-color-pink-9: #400c25;
|
||||
|
||||
/* lime → spring leaf */
|
||||
--mantine-color-lime-0: #f2f5e6;
|
||||
--mantine-color-lime-1: #e2e9c6;
|
||||
--mantine-color-lime-2: #cdd89e;
|
||||
--mantine-color-lime-3: #b2c26f;
|
||||
--mantine-color-lime-4: #96a944;
|
||||
--mantine-color-lime-5: #7a8d26;
|
||||
--mantine-color-lime-6: #59690f;
|
||||
--mantine-color-lime-7: #485510;
|
||||
--mantine-color-lime-8: #38420d;
|
||||
--mantine-color-lime-9: #293009;
|
||||
|
||||
/* Gray ramp as parchment/sepia so gray-derived UI stays in the world. */
|
||||
--mantine-color-gray-0: #f7efdd;
|
||||
--mantine-color-gray-1: #f0e6cf;
|
||||
--mantine-color-gray-2: #e3d4b4;
|
||||
--mantine-color-gray-3: #d0bd95;
|
||||
--mantine-color-gray-4: #b5a17a;
|
||||
--mantine-color-gray-5: #92805e;
|
||||
--mantine-color-gray-6: #6a5a41;
|
||||
--mantine-color-gray-7: #4a3d2b;
|
||||
--mantine-color-gray-8: #362c1e;
|
||||
--mantine-color-gray-9: #291f14;
|
||||
|
||||
/* Dark ramp as torch-lit umber. */
|
||||
--mantine-color-dark-0: #ecdfc6;
|
||||
--mantine-color-dark-1: #b3a488;
|
||||
--mantine-color-dark-2: #7a6a52;
|
||||
--mantine-color-dark-3: #55462f;
|
||||
--mantine-color-dark-4: #3b2f1f;
|
||||
--mantine-color-dark-5: #2b2318;
|
||||
--mantine-color-dark-6: #241d13;
|
||||
--mantine-color-dark-7: #1c160e;
|
||||
--mantine-color-dark-8: #15100a;
|
||||
--mantine-color-dark-9: #0e0a06;
|
||||
|
||||
--flxn-avatar-radius: 50%; /* party-member portraits */
|
||||
--flxn-avatar-border: 2px solid var(--quest-frame);
|
||||
--flxn-badge-radius: 8px;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 2. Per-scheme tokens — (0,3,0)
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="quest"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #f0e6cf;
|
||||
--mantine-color-text: #2f2414;
|
||||
--mantine-color-bright: #1d1509;
|
||||
--mantine-color-dimmed: #6a5a41;
|
||||
--mantine-color-placeholder: #83704f;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-7);
|
||||
--mantine-color-error: #9e2b20;
|
||||
--mantine-color-default: #f7efdd;
|
||||
--mantine-color-default-hover: #efe3c8;
|
||||
--mantine-color-default-color: #2f2414;
|
||||
--mantine-color-default-border: #b39a6b;
|
||||
|
||||
/* Accent variant vars re-derived from the retuned ramps (Mantine's
|
||||
defaults are literal rgba of its stock hues). */
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-6) 10%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-6) 16%, transparent);
|
||||
--mantine-color-blue-light-color: var(--mantine-color-blue-7);
|
||||
--mantine-color-blue-outline: var(--mantine-color-blue-6);
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-6) 8%, transparent);
|
||||
--mantine-color-blue-text: var(--mantine-color-blue-7);
|
||||
--mantine-color-blue-contrast: #f6ecd8;
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-6) 10%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-6) 16%, transparent);
|
||||
--mantine-color-red-light-color: var(--mantine-color-red-7);
|
||||
--mantine-color-red-outline: var(--mantine-color-red-6);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-6) 8%, transparent);
|
||||
--mantine-color-red-text: var(--mantine-color-red-7);
|
||||
--mantine-color-red-contrast: #f6ecd8;
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-6) 10%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-6) 16%, transparent);
|
||||
--mantine-color-green-light-color: var(--mantine-color-green-7);
|
||||
--mantine-color-green-outline: var(--mantine-color-green-6);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-6) 8%, transparent);
|
||||
--mantine-color-green-text: var(--mantine-color-green-7);
|
||||
--mantine-color-green-contrast: #f6ecd8;
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-6) 10%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 16%, transparent);
|
||||
--mantine-color-yellow-light-color: var(--mantine-color-yellow-7);
|
||||
--mantine-color-yellow-outline: var(--mantine-color-yellow-6);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 8%, transparent);
|
||||
--mantine-color-yellow-text: var(--mantine-color-yellow-7);
|
||||
--mantine-color-yellow-contrast: #f6ecd8;
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-6) 10%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-6) 16%, transparent);
|
||||
--mantine-color-grape-light-color: var(--mantine-color-grape-7);
|
||||
--mantine-color-grape-outline: var(--mantine-color-grape-6);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-6) 8%, transparent);
|
||||
--mantine-color-grape-text: var(--mantine-color-grape-7);
|
||||
--mantine-color-grape-contrast: #f6ecd8;
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-6) 10%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-6) 16%, transparent);
|
||||
--mantine-color-orange-light-color: var(--mantine-color-orange-7);
|
||||
--mantine-color-orange-outline: var(--mantine-color-orange-6);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-6) 8%, transparent);
|
||||
--mantine-color-orange-text: var(--mantine-color-orange-7);
|
||||
--mantine-color-orange-contrast: #f6ecd8;
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-6) 10%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-6) 16%, transparent);
|
||||
--mantine-color-pink-light-color: var(--mantine-color-pink-7);
|
||||
--mantine-color-pink-outline: var(--mantine-color-pink-6);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-6) 8%, transparent);
|
||||
--mantine-color-pink-text: var(--mantine-color-pink-7);
|
||||
--mantine-color-pink-contrast: #f6ecd8;
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-6) 10%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-6) 16%, transparent);
|
||||
--mantine-color-lime-light-color: var(--mantine-color-lime-7);
|
||||
--mantine-color-lime-outline: var(--mantine-color-lime-6);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-6) 8%, transparent);
|
||||
--mantine-color-lime-text: var(--mantine-color-lime-7);
|
||||
--mantine-color-lime-contrast: #f6ecd8;
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-6) 10%, transparent);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-6) 15%, transparent);
|
||||
--mantine-color-gray-light-color: var(--mantine-color-gray-7);
|
||||
|
||||
/* Theme-local palette. */
|
||||
--quest-frame: #a3854f;
|
||||
--quest-corner: #8a6a3a;
|
||||
--quest-bronze: #7c5f2c;
|
||||
--quest-surface: #f7efdd;
|
||||
--quest-recessed: #e7d8b6;
|
||||
--quest-shell: #ece0c3;
|
||||
--quest-tick: rgba(90, 66, 30, 0.22);
|
||||
--quest-ribbon-hi: #8d6c38;
|
||||
--quest-ribbon: #7a5c2e;
|
||||
--quest-ribbon-lo: #5f4620;
|
||||
--quest-ribbon-ink: #f7eedb;
|
||||
|
||||
/* App tokens: guild-board accolades on parchment. */
|
||||
--flxn-gold: #7d5c12;
|
||||
--flxn-silver: #776e5c;
|
||||
--flxn-bronze: #8a4f22;
|
||||
--flxn-toast-success: #45702c;
|
||||
--flxn-toast-error: #9e2b20;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #c99527 15%, #f7efdd);
|
||||
--flxn-podium-1-border: color-mix(in srgb, #7d5c12 55%, #d0bd95);
|
||||
--flxn-podium-1-label: #6f5116;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #92805e 10%, #f7efdd);
|
||||
--flxn-podium-2-border: #b5a17a;
|
||||
--flxn-podium-2-label: #6a5a41;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #8a4f22 12%, #f7efdd);
|
||||
--flxn-podium-3-border: color-mix(in srgb, #8a4f22 45%, #d0bd95);
|
||||
--flxn-podium-3-label: #74431c;
|
||||
--flxn-showcase-bg: #f7efdd;
|
||||
--flxn-overlay: rgba(35, 24, 10, 0.45);
|
||||
--flxn-dotgrid-color: rgba(138, 106, 58, 0.25);
|
||||
--flxn-pop-shadow: rgba(46, 32, 12, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="quest"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #211a12;
|
||||
--mantine-color-text: #ecdfc6;
|
||||
--mantine-color-bright: #f7efdd;
|
||||
--mantine-color-dimmed: #a5937a;
|
||||
--mantine-color-placeholder: #837259;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-2);
|
||||
--mantine-color-error: #d4736a;
|
||||
--mantine-color-default: #2b2216;
|
||||
--mantine-color-default-hover: #342a1b;
|
||||
--mantine-color-default-color: #ecdfc6;
|
||||
--mantine-color-default-border: #5c4a2c;
|
||||
|
||||
/* Filled stays mid-ramp: shade-8 dye vanishes in the torchlit hall. */
|
||||
--mantine-color-blue-filled: var(--mantine-color-blue-6);
|
||||
--mantine-color-blue-filled-hover: var(--mantine-color-blue-5);
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-4) 15%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-4) 22%, transparent);
|
||||
--mantine-color-blue-light-color: var(--mantine-color-blue-2);
|
||||
--mantine-color-blue-outline: var(--mantine-color-blue-3);
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-3) 12%, transparent);
|
||||
--mantine-color-blue-text: var(--mantine-color-blue-3);
|
||||
--mantine-color-blue-contrast: #f6ecd8;
|
||||
--mantine-color-red-filled: var(--mantine-color-red-6);
|
||||
--mantine-color-red-filled-hover: var(--mantine-color-red-5);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-4) 15%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-4) 22%, transparent);
|
||||
--mantine-color-red-light-color: var(--mantine-color-red-2);
|
||||
--mantine-color-red-outline: var(--mantine-color-red-3);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-3) 12%, transparent);
|
||||
--mantine-color-red-text: var(--mantine-color-red-3);
|
||||
--mantine-color-red-contrast: #f6ecd8;
|
||||
--mantine-color-green-filled: var(--mantine-color-green-6);
|
||||
--mantine-color-green-filled-hover: var(--mantine-color-green-5);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-4) 15%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-4) 22%, transparent);
|
||||
--mantine-color-green-light-color: var(--mantine-color-green-2);
|
||||
--mantine-color-green-outline: var(--mantine-color-green-3);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-3) 12%, transparent);
|
||||
--mantine-color-green-text: var(--mantine-color-green-3);
|
||||
--mantine-color-green-contrast: #f6ecd8;
|
||||
--mantine-color-yellow-filled: var(--mantine-color-yellow-6);
|
||||
--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-5);
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-4) 15%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-4) 22%, transparent);
|
||||
--mantine-color-yellow-light-color: var(--mantine-color-yellow-2);
|
||||
--mantine-color-yellow-outline: var(--mantine-color-yellow-3);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-3) 12%, transparent);
|
||||
--mantine-color-yellow-text: var(--mantine-color-yellow-3);
|
||||
--mantine-color-yellow-contrast: #f6ecd8;
|
||||
--mantine-color-grape-filled: var(--mantine-color-grape-6);
|
||||
--mantine-color-grape-filled-hover: var(--mantine-color-grape-5);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-4) 15%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-4) 22%, transparent);
|
||||
--mantine-color-grape-light-color: var(--mantine-color-grape-2);
|
||||
--mantine-color-grape-outline: var(--mantine-color-grape-3);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-3) 12%, transparent);
|
||||
--mantine-color-grape-text: var(--mantine-color-grape-3);
|
||||
--mantine-color-grape-contrast: #f6ecd8;
|
||||
--mantine-color-orange-filled: var(--mantine-color-orange-6);
|
||||
--mantine-color-orange-filled-hover: var(--mantine-color-orange-5);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-4) 15%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-4) 22%, transparent);
|
||||
--mantine-color-orange-light-color: var(--mantine-color-orange-2);
|
||||
--mantine-color-orange-outline: var(--mantine-color-orange-3);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-3) 12%, transparent);
|
||||
--mantine-color-orange-text: var(--mantine-color-orange-3);
|
||||
--mantine-color-orange-contrast: #f6ecd8;
|
||||
--mantine-color-pink-filled: var(--mantine-color-pink-6);
|
||||
--mantine-color-pink-filled-hover: var(--mantine-color-pink-5);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-4) 15%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-4) 22%, transparent);
|
||||
--mantine-color-pink-light-color: var(--mantine-color-pink-2);
|
||||
--mantine-color-pink-outline: var(--mantine-color-pink-3);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-3) 12%, transparent);
|
||||
--mantine-color-pink-text: var(--mantine-color-pink-3);
|
||||
--mantine-color-pink-contrast: #f6ecd8;
|
||||
--mantine-color-lime-filled: var(--mantine-color-lime-6);
|
||||
--mantine-color-lime-filled-hover: var(--mantine-color-lime-5);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-4) 15%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-4) 22%, transparent);
|
||||
--mantine-color-lime-light-color: var(--mantine-color-lime-2);
|
||||
--mantine-color-lime-outline: var(--mantine-color-lime-3);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-3) 12%, transparent);
|
||||
--mantine-color-lime-text: var(--mantine-color-lime-3);
|
||||
--mantine-color-lime-contrast: #f6ecd8;
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-5) 12%, transparent);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-5) 18%, transparent);
|
||||
--mantine-color-gray-light-color: var(--mantine-color-gray-2);
|
||||
|
||||
/* Theme-local palette: ember-warm parchment panels in a torchlit hall. */
|
||||
--quest-frame: #7a6136;
|
||||
--quest-corner: #c49a5e;
|
||||
--quest-bronze: #cfa768;
|
||||
--quest-surface: #2b2216;
|
||||
--quest-recessed: #171208;
|
||||
--quest-shell: #1a140c;
|
||||
--quest-tick: rgba(0, 0, 0, 0.4);
|
||||
--quest-ribbon-hi: #d8b077;
|
||||
--quest-ribbon: #c49a5e;
|
||||
--quest-ribbon-lo: #a97f45;
|
||||
--quest-ribbon-ink: #241a0c;
|
||||
|
||||
--flxn-gold: #d9b36b;
|
||||
--flxn-silver: #a89f90;
|
||||
--flxn-bronze: #c08050;
|
||||
--flxn-toast-success: #a8bd85;
|
||||
--flxn-toast-error: #dc9a90;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #c99527 14%, #2b2216);
|
||||
--flxn-podium-1-border: color-mix(in srgb, #d9b36b 45%, #3b2f1f);
|
||||
--flxn-podium-1-label: #d9b36b;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #a89f90 9%, #2b2216);
|
||||
--flxn-podium-2-border: color-mix(in srgb, #a89f90 32%, #3b2f1f);
|
||||
--flxn-podium-2-label: #b5aea1;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #c08050 12%, #2b2216);
|
||||
--flxn-podium-3-border: color-mix(in srgb, #c08050 42%, #3b2f1f);
|
||||
--flxn-podium-3-label: #cd8f61;
|
||||
--flxn-showcase-bg: #2b2216;
|
||||
--flxn-overlay: rgba(8, 5, 2, 0.6);
|
||||
--flxn-dotgrid-color: rgba(196, 154, 94, 0.18);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 3. Full-page decoration: worn parchment edges / torchlight
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="quest"][data-mantine-color-scheme="light"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998;
|
||||
pointer-events: none;
|
||||
background:
|
||||
radial-gradient(140% 100% at 50% 32%, transparent 58%, rgba(122, 91, 42, 0.1) 88%, rgba(96, 69, 28, 0.2) 100%),
|
||||
radial-gradient(55% 38% at 6% 2%, rgba(122, 91, 42, 0.07), transparent 70%),
|
||||
radial-gradient(55% 38% at 95% 98%, rgba(122, 91, 42, 0.07), transparent 70%);
|
||||
}
|
||||
|
||||
[data-theme="quest"][data-mantine-color-scheme="dark"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998;
|
||||
pointer-events: none;
|
||||
background:
|
||||
radial-gradient(90% 55% at 50% 0%, rgba(214, 158, 84, 0.07), transparent 70%),
|
||||
radial-gradient(130% 95% at 50% 45%, transparent 55%, rgba(5, 3, 1, 0.5) 100%);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 4. Quest entries: 2px bronze frames + ornate corner brackets
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="quest"] .mantine-Paper-root[data-with-border],
|
||||
[data-theme="quest"] .mantine-Card-root,
|
||||
[data-theme="quest"] .mantine-Modal-content,
|
||||
[data-theme="quest"] .flxn-tile,
|
||||
[data-theme="quest"] .flxn-match-card {
|
||||
position: relative;
|
||||
background-color: var(--quest-surface);
|
||||
border: 2px solid var(--quest-frame);
|
||||
}
|
||||
|
||||
/* One pseudo paints all four L-shaped brackets (2 strips per corner). */
|
||||
[data-theme="quest"] .mantine-Paper-root[data-with-border]::before,
|
||||
[data-theme="quest"] .mantine-Card-root::before,
|
||||
[data-theme="quest"] .mantine-Modal-content::before,
|
||||
[data-theme="quest"] .flxn-tile::before,
|
||||
[data-theme="quest"] .flxn-match-card::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 3px;
|
||||
pointer-events: none;
|
||||
background-image:
|
||||
linear-gradient(var(--quest-corner), var(--quest-corner)),
|
||||
linear-gradient(var(--quest-corner), var(--quest-corner)),
|
||||
linear-gradient(var(--quest-corner), var(--quest-corner)),
|
||||
linear-gradient(var(--quest-corner), var(--quest-corner)),
|
||||
linear-gradient(var(--quest-corner), var(--quest-corner)),
|
||||
linear-gradient(var(--quest-corner), var(--quest-corner)),
|
||||
linear-gradient(var(--quest-corner), var(--quest-corner)),
|
||||
linear-gradient(var(--quest-corner), var(--quest-corner));
|
||||
background-repeat: no-repeat;
|
||||
background-size:
|
||||
12px 2px, 2px 12px,
|
||||
12px 2px, 2px 12px,
|
||||
12px 2px, 2px 12px,
|
||||
12px 2px, 2px 12px;
|
||||
background-position:
|
||||
left top, left top,
|
||||
right top, right top,
|
||||
left bottom, left bottom,
|
||||
right bottom, right bottom;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 5. Component restyles
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
/* Headings: Grenze; section headers (h3/h4) ride ribbon banners. */
|
||||
[data-theme="quest"] .mantine-Title-root {
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
[data-theme="quest"] h3.mantine-Title-root,
|
||||
[data-theme="quest"] h4.mantine-Title-root {
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
padding: 0.12em 1.1em 0.18em;
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
var(--quest-ribbon-hi) 0%,
|
||||
var(--quest-ribbon) 55%,
|
||||
var(--quest-ribbon-lo) 100%
|
||||
);
|
||||
color: var(--quest-ribbon-ink);
|
||||
clip-path: polygon(
|
||||
0 0,
|
||||
100% 0,
|
||||
calc(100% - 0.55em) 50%,
|
||||
100% 100%,
|
||||
0 100%,
|
||||
0.55em 50%
|
||||
);
|
||||
}
|
||||
|
||||
/* Buttons: banner-dye solids in the user's accent; bronze-ruled defaults. */
|
||||
[data-theme="quest"] .mantine-Button-root {
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
[data-theme="quest"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="quest"] .mantine-ActionIcon-root[data-variant="filled"] {
|
||||
border: 1px solid color-mix(in srgb, var(--mantine-primary-color-filled) 55%, black);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 250, 235, 0.2), 0 1px 3px var(--flxn-pop-shadow);
|
||||
}
|
||||
[data-theme="quest"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="quest"] .mantine-ActionIcon-root[data-variant="default"] {
|
||||
border-color: var(--quest-frame);
|
||||
background-color: var(--quest-surface);
|
||||
}
|
||||
|
||||
/* Inputs: recessed ledger lines; focus follows the accent. */
|
||||
[data-theme="quest"] .mantine-Input-input {
|
||||
background-color: var(--quest-recessed);
|
||||
border-color: var(--quest-frame);
|
||||
}
|
||||
[data-theme="quest"] .mantine-PinInput-input {
|
||||
background-color: var(--quest-recessed);
|
||||
}
|
||||
|
||||
/* Mantine Tabs: illuminated active label under a bronze rule. */
|
||||
[data-theme="quest"] .mantine-Tabs-tab {
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
[data-theme="quest"] .mantine-Tabs-tab[data-active] {
|
||||
border-color: var(--quest-corner);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* Nav: active entries follow the accent — wash plus a marginal rule. */
|
||||
[data-theme="quest"] .mantine-NavLink-root[data-active] {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
box-shadow: inset 3px 0 0 var(--mantine-primary-color-filled);
|
||||
}
|
||||
[data-theme="quest"] .mantine-NavLink-root[data-active]:hover {
|
||||
background-color: var(--mantine-primary-color-light-hover);
|
||||
}
|
||||
|
||||
/* Shell: the journal's leather binding. */
|
||||
[data-theme="quest"] .mantine-AppShell-header {
|
||||
background-color: var(--quest-shell);
|
||||
border-bottom: 1px solid var(--quest-frame);
|
||||
}
|
||||
[data-theme="quest"] .mantine-AppShell-navbar {
|
||||
background-color: var(--quest-shell);
|
||||
border-color: var(--quest-frame);
|
||||
}
|
||||
|
||||
/* Segmented control: carved channel with a parchment slider. */
|
||||
[data-theme="quest"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--quest-recessed);
|
||||
border: 1px solid var(--quest-frame);
|
||||
}
|
||||
[data-theme="quest"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--quest-surface);
|
||||
border: 1px solid var(--quest-frame);
|
||||
box-shadow: 0 1px 3px var(--flxn-pop-shadow);
|
||||
}
|
||||
|
||||
/* Progress: XP bars — framed groove, segment ticks, glossed accent fill. */
|
||||
[data-theme="quest"] .mantine-Progress-root {
|
||||
position: relative;
|
||||
background-color: var(--quest-recessed);
|
||||
border: 1px solid var(--quest-frame);
|
||||
box-shadow: inset 0 1px 2px rgba(20, 12, 4, 0.3);
|
||||
}
|
||||
[data-theme="quest"] .mantine-Progress-root::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
background-image: repeating-linear-gradient(
|
||||
90deg,
|
||||
transparent 0,
|
||||
transparent 11px,
|
||||
var(--quest-tick) 11px,
|
||||
var(--quest-tick) 12px
|
||||
);
|
||||
}
|
||||
[data-theme="quest"] .mantine-Progress-section {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 246, 224, 0.32) 0%,
|
||||
rgba(255, 246, 224, 0.06) 45%,
|
||||
rgba(24, 14, 4, 0.14) 100%
|
||||
);
|
||||
}
|
||||
|
||||
/* Badges: embossed wax/metal seals; filled keeps a legible on-color. */
|
||||
[data-theme="quest"] .mantine-Badge-root {
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
border: 1px solid rgba(24, 14, 4, 0.25);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 250, 235, 0.28),
|
||||
inset 0 -1px 0 rgba(24, 14, 4, 0.18), 0 1px 2px var(--flxn-pop-shadow);
|
||||
}
|
||||
[data-theme="quest"] .mantine-Badge-root[data-variant="filled"],
|
||||
[data-theme="quest"] .mantine-Badge-root:not([data-variant]),
|
||||
[data-theme="quest"] .mantine-ThemeIcon-root[data-variant="filled"],
|
||||
[data-theme="quest"] .mantine-ThemeIcon-root:not([data-variant]) {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
[data-theme="quest"] .mantine-Checkbox-root {
|
||||
--checkbox-icon-color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
/* Dividers: bronze rule with a compass-star waypoint. */
|
||||
[data-theme="quest"] .mantine-Divider-root {
|
||||
--divider-color: color-mix(in srgb, var(--quest-frame) 60%, transparent);
|
||||
}
|
||||
[data-theme="quest"] .mantine-Divider-root[data-orientation="horizontal"]:not([data-with-label]) {
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
}
|
||||
[data-theme="quest"] .mantine-Divider-root[data-orientation="horizontal"]:not([data-with-label])::before {
|
||||
content: "\2726"; /* ✦ */
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
padding: 0 0.5em;
|
||||
background-color: var(--mantine-color-body);
|
||||
color: var(--quest-bronze);
|
||||
font-size: 0.7rem;
|
||||
line-height: 1;
|
||||
}
|
||||
[data-theme="quest"] .mantine-Divider-label {
|
||||
color: var(--quest-bronze);
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
font-size: var(--mantine-font-size-xs);
|
||||
}
|
||||
|
||||
/* Overlays: sealed notes. Popovers get a single bronze rule (the corner
|
||||
brackets are reserved for full entries; Modal-content has them above). */
|
||||
[data-theme="quest"] .mantine-Popover-dropdown {
|
||||
background-color: var(--quest-surface);
|
||||
border: 1px solid var(--quest-frame);
|
||||
}
|
||||
[data-theme="quest"] .mantine-Modal-header {
|
||||
background-color: var(--quest-surface);
|
||||
}
|
||||
[data-theme="quest"] .mantine-Tooltip-tooltip {
|
||||
background-color: #1c160e;
|
||||
color: #ecdfc6;
|
||||
border: 1px solid var(--quest-frame);
|
||||
}
|
||||
|
||||
/* Notifications: dispatched scrolls. */
|
||||
[data-theme="quest"] .mantine-Notification-root {
|
||||
background-color: var(--quest-surface);
|
||||
border: 1px solid var(--quest-frame);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
/* Alerts keep a real border for forced-colors resilience. */
|
||||
[data-theme="quest"] .mantine-Alert-root {
|
||||
border: 1px solid var(--quest-frame);
|
||||
}
|
||||
|
||||
[data-theme="quest"][data-mantine-color-scheme="light"] .mantine-Skeleton-root::after {
|
||||
background-color: #e3d3ae;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- *
|
||||
* 6. App component hooks
|
||||
* ---------------------------------------------------------------- */
|
||||
|
||||
/* Tab strip: flat chapter tabs resting; docked = binding strip with a
|
||||
bronze rule. Underline indicator, so accent text on the tab is fine. */
|
||||
[data-theme="quest"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--quest-shell);
|
||||
border-bottom-color: var(--quest-frame);
|
||||
}
|
||||
[data-theme="quest"] .flxn-tab {
|
||||
color: var(--mantine-color-dimmed);
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
[data-theme="quest"] .flxn-tab[data-active] {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
font-weight: 700;
|
||||
}
|
||||
[data-theme="quest"] .flxn-tabs-indicator {
|
||||
border-bottom: 3px solid var(--mantine-primary-color-filled);
|
||||
padding-inline: 0.5rem;
|
||||
}
|
||||
|
||||
/* Nav grid tiles: quest entries (frame + brackets set in section 4);
|
||||
glyphs stay FLAT — bronze-inked tint only. */
|
||||
[data-theme="quest"] .flxn-tile-icon {
|
||||
color: var(--quest-bronze);
|
||||
}
|
||||
|
||||
/* "See all": wax-seal-tabbed chip — parchment chip, accent seal dot,
|
||||
accent ink on a neutral backing. */
|
||||
[data-theme="quest"] .flxn-see-all {
|
||||
background-color: var(--quest-surface);
|
||||
border: 1px solid var(--quest-frame);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
[data-theme="quest"] .flxn-see-all::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 0.6em;
|
||||
height: 0.6em;
|
||||
margin-right: 0.45em;
|
||||
border-radius: 50%;
|
||||
vertical-align: baseline;
|
||||
background-image: radial-gradient(
|
||||
circle at 35% 30%,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 55%, white) 0%,
|
||||
var(--mantine-primary-color-filled) 45%,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 55%, black) 100%
|
||||
);
|
||||
box-shadow: 0 1px 1px var(--flxn-pop-shadow);
|
||||
}
|
||||
@media (hover: hover) {
|
||||
[data-theme="quest"] .flxn-see-all:hover {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Match card + reaction tray: the entry and its reward line share one
|
||||
frame — same 2px bronze border, tray on deeper parchment. */
|
||||
[data-theme="quest"] .flxn-reaction-row {
|
||||
background-color: var(--quest-recessed);
|
||||
border: 2px solid var(--quest-frame);
|
||||
}
|
||||
|
||||
/* Badge tiles: seal-stamped keepsakes. */
|
||||
[data-theme="quest"] .flxn-badge-tile {
|
||||
box-shadow: var(--mantine-shadow-xs);
|
||||
}
|
||||
|
||||
/* Avatars: party-member portrait medallions (ring via --flxn-avatar-*). */
|
||||
[data-theme="quest"] .flxn-avatar-frame {
|
||||
box-shadow: 0 1px 2px var(--flxn-pop-shadow);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { ThemeManifest } from "./types";
|
||||
|
||||
// Themes are auto-discovered: each src/themes/<id>/manifest.ts default-export
|
||||
// is registered here. Keep this module CSS-free so server fns can import it;
|
||||
// theme stylesheets are aggregated separately in ./styles.ts.
|
||||
const modules = import.meta.glob<{ default: ThemeManifest }>("./*/manifest.ts", {
|
||||
eager: true,
|
||||
});
|
||||
|
||||
export const THEMES: Record<string, ThemeManifest> = {};
|
||||
|
||||
for (const [path, mod] of Object.entries(modules)) {
|
||||
const folder = path.split("/")[1];
|
||||
const manifest = mod.default;
|
||||
if (!manifest || manifest.id !== folder) {
|
||||
console.warn(`[themes] skipping ${path}: manifest id must equal folder name`);
|
||||
continue;
|
||||
}
|
||||
THEMES[manifest.id] = manifest;
|
||||
}
|
||||
|
||||
export const DEFAULT_THEME_ID = "default";
|
||||
|
||||
if (!THEMES[DEFAULT_THEME_ID]) {
|
||||
throw new Error("[themes] default theme manifest is missing or invalid");
|
||||
}
|
||||
|
||||
export const THEME_IDS = Object.keys(THEMES);
|
||||
|
||||
// Base order: default first, rest by id. Pickers re-sort by LOCALIZED title
|
||||
// at render time (labels are i18n descriptors, unresolvable here).
|
||||
export const THEME_LIST: ThemeManifest[] = Object.values(THEMES).sort(
|
||||
(a, b) => (a.order ?? 100) - (b.order ?? 100) || a.id.localeCompare(b.id)
|
||||
);
|
||||
|
||||
export const getTheme = (id?: string | null): ThemeManifest =>
|
||||
(id ? THEMES[id] : undefined) ?? THEMES[DEFAULT_THEME_ID];
|
||||
@@ -0,0 +1,24 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "seventies",
|
||||
label: msg`Groovy`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Righteous&display=swap",
|
||||
"https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#f6ecd9", dimmed: "#e4d5b8" },
|
||||
dark: { base: "#241a12", dimmed: "#171009" },
|
||||
},
|
||||
mantine: {
|
||||
// Mustard/avocado fills are mid-luminance; without autoContrast the
|
||||
// yellow/lime accents render white-on-mustard at ~2-3.5:1.
|
||||
autoContrast: true,
|
||||
black: "#3f2d20",
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,728 @@
|
||||
/* ============================================================
|
||||
seventies — "Groovy": 1974 warm earth-tone lounge.
|
||||
Cream + chocolate, the classic quad (mustard / burnt orange /
|
||||
avocado / harvest brown), chunky radii, 2px chocolate borders,
|
||||
sunburst stripe bands, contour-line arcs on cards.
|
||||
============================================================ */
|
||||
|
||||
/* ---------- 1. Scheme-independent tokens — (0,2,0) ---------- */
|
||||
|
||||
[data-theme="seventies"][data-theme] {
|
||||
/* type */
|
||||
--mantine-font-family: "Poppins", "Trebuchet MS", "Verdana", ui-sans-serif,
|
||||
sans-serif;
|
||||
--mantine-font-family-headings: "Righteous", "Poppins", "Trebuchet MS",
|
||||
ui-sans-serif, sans-serif;
|
||||
--mantine-heading-font-weight: 400;
|
||||
|
||||
/* chunky rounded shape */
|
||||
--mantine-radius-xs: 0.375rem;
|
||||
--mantine-radius-sm: 0.5rem;
|
||||
--mantine-radius-md: 0.75rem;
|
||||
--mantine-radius-lg: 1rem;
|
||||
--mantine-radius-xl: 1.5rem;
|
||||
--mantine-radius-default: var(--mantine-radius-lg);
|
||||
|
||||
/* flat / soft warm shadows */
|
||||
--mantine-shadow-xs: 0 1px 0 rgba(63, 45, 32, 0.08),
|
||||
0 2px 6px rgba(63, 45, 32, 0.06);
|
||||
--mantine-shadow-sm: 0 2px 0 rgba(63, 45, 32, 0.1),
|
||||
0 4px 12px -2px rgba(63, 45, 32, 0.1);
|
||||
--mantine-shadow-md: 0 3px 0 rgba(63, 45, 32, 0.1),
|
||||
0 8px 20px -6px rgba(63, 45, 32, 0.16);
|
||||
--mantine-shadow-lg: 0 4px 0 rgba(63, 45, 32, 0.1),
|
||||
0 14px 32px -10px rgba(63, 45, 32, 0.2);
|
||||
--mantine-shadow-xl: 0 5px 0 rgba(63, 45, 32, 0.12),
|
||||
0 22px 44px -12px rgba(63, 45, 32, 0.24);
|
||||
|
||||
/* sunburst stripe band: mustard / burnt orange / harvest brown / avocado */
|
||||
--seventies-band: linear-gradient(
|
||||
to bottom,
|
||||
#e3a92e 0 25%,
|
||||
#c9552e 25% 50%,
|
||||
#7a4a21 50% 75%,
|
||||
#7a8450 75% 100%
|
||||
);
|
||||
|
||||
/* app hook shape tokens */
|
||||
--flxn-avatar-radius: 30%;
|
||||
--flxn-avatar-border: 2px solid var(--mantine-color-default-border);
|
||||
--flxn-badge-radius: 14px;
|
||||
|
||||
/* --- retuned ramps (warm-shifted 1974 palette) --- */
|
||||
|
||||
/* yellow → mustard (#e3a92e) */
|
||||
--mantine-color-yellow-0: #fbf3dc;
|
||||
--mantine-color-yellow-1: #f5e7bf;
|
||||
--mantine-color-yellow-2: #efd899;
|
||||
--mantine-color-yellow-3: #e9c46b;
|
||||
--mantine-color-yellow-4: #e6b544;
|
||||
--mantine-color-yellow-5: #e3a92e;
|
||||
--mantine-color-yellow-6: #cd9322;
|
||||
--mantine-color-yellow-7: #ad7a1c;
|
||||
--mantine-color-yellow-8: #8c6216;
|
||||
--mantine-color-yellow-9: #6b4a11;
|
||||
|
||||
/* orange → burnt orange (#c9552e) */
|
||||
--mantine-color-orange-0: #fbeee6;
|
||||
--mantine-color-orange-1: #f6dcca;
|
||||
--mantine-color-orange-2: #efc2a4;
|
||||
--mantine-color-orange-3: #e5a179;
|
||||
--mantine-color-orange-4: #d87b50;
|
||||
--mantine-color-orange-5: #c9552e;
|
||||
--mantine-color-orange-6: #b64826;
|
||||
--mantine-color-orange-7: #973b20;
|
||||
--mantine-color-orange-8: #782f1a;
|
||||
--mantine-color-orange-9: #5c2414;
|
||||
|
||||
/* red → cherry brick (crimson, kept off burnt orange's hue) */
|
||||
--mantine-color-red-0: #fae9e9;
|
||||
--mantine-color-red-1: #f2cfcf;
|
||||
--mantine-color-red-2: #e8abab;
|
||||
--mantine-color-red-3: #db8282;
|
||||
--mantine-color-red-4: #ca5b5b;
|
||||
--mantine-color-red-5: #b83a3a;
|
||||
--mantine-color-red-6: #a32f2f;
|
||||
--mantine-color-red-7: #872626;
|
||||
--mantine-color-red-8: #6b1e1e;
|
||||
--mantine-color-red-9: #511717;
|
||||
|
||||
/* green → avocado (#7a8450) */
|
||||
--mantine-color-green-0: #f3f4e7;
|
||||
--mantine-color-green-1: #e5e7cb;
|
||||
--mantine-color-green-2: #d1d5a9;
|
||||
--mantine-color-green-3: #b9bf85;
|
||||
--mantine-color-green-4: #9aa268;
|
||||
--mantine-color-green-5: #7a8450;
|
||||
--mantine-color-green-6: #6a7343;
|
||||
--mantine-color-green-7: #575e36;
|
||||
--mantine-color-green-8: #444a2a;
|
||||
--mantine-color-green-9: #32361f;
|
||||
|
||||
/* lime → olive chartreuse */
|
||||
--mantine-color-lime-0: #f6f6e2;
|
||||
--mantine-color-lime-1: #ecedc2;
|
||||
--mantine-color-lime-2: #dee09b;
|
||||
--mantine-color-lime-3: #cbcf72;
|
||||
--mantine-color-lime-4: #b5bb50;
|
||||
--mantine-color-lime-5: #9da437;
|
||||
--mantine-color-lime-6: #888f2c;
|
||||
--mantine-color-lime-7: #6f7423;
|
||||
--mantine-color-lime-8: #575b1b;
|
||||
--mantine-color-lime-9: #404313;
|
||||
|
||||
/* teal → lounge teal */
|
||||
--mantine-color-teal-0: #e9f2ef;
|
||||
--mantine-color-teal-1: #cfe3dd;
|
||||
--mantine-color-teal-2: #adcec5;
|
||||
--mantine-color-teal-3: #86b3a7;
|
||||
--mantine-color-teal-4: #619789;
|
||||
--mantine-color-teal-5: #467d6f;
|
||||
--mantine-color-teal-6: #3a6b5f;
|
||||
--mantine-color-teal-7: #2f574d;
|
||||
--mantine-color-teal-8: #24443c;
|
||||
--mantine-color-teal-9: #1a322c;
|
||||
|
||||
/* cyan → dusty aqua */
|
||||
--mantine-color-cyan-0: #e9f2f2;
|
||||
--mantine-color-cyan-1: #cfe3e2;
|
||||
--mantine-color-cyan-2: #accccb;
|
||||
--mantine-color-cyan-3: #85b0af;
|
||||
--mantine-color-cyan-4: #629392;
|
||||
--mantine-color-cyan-5: #4a7c7a;
|
||||
--mantine-color-cyan-6: #3e6a69;
|
||||
--mantine-color-cyan-7: #325655;
|
||||
--mantine-color-cyan-8: #274343;
|
||||
--mantine-color-cyan-9: #1c3131;
|
||||
|
||||
/* blue → petrol denim */
|
||||
--mantine-color-blue-0: #eaf0f3;
|
||||
--mantine-color-blue-1: #d1dee4;
|
||||
--mantine-color-blue-2: #b0c5cf;
|
||||
--mantine-color-blue-3: #89a7b5;
|
||||
--mantine-color-blue-4: #648b9c;
|
||||
--mantine-color-blue-5: #4b7386;
|
||||
--mantine-color-blue-6: #3f6274;
|
||||
--mantine-color-blue-7: #33505f;
|
||||
--mantine-color-blue-8: #283e4a;
|
||||
--mantine-color-blue-9: #1d2d36;
|
||||
|
||||
/* indigo → deep denim */
|
||||
--mantine-color-indigo-0: #eaeef4;
|
||||
--mantine-color-indigo-1: #d3dbe6;
|
||||
--mantine-color-indigo-2: #b4c1d3;
|
||||
--mantine-color-indigo-3: #8fa2bb;
|
||||
--mantine-color-indigo-4: #6d85a3;
|
||||
--mantine-color-indigo-5: #546d8c;
|
||||
--mantine-color-indigo-6: #475d79;
|
||||
--mantine-color-indigo-7: #3a4c63;
|
||||
--mantine-color-indigo-8: #2d3b4d;
|
||||
--mantine-color-indigo-9: #212b38;
|
||||
|
||||
/* violet → plum */
|
||||
--mantine-color-violet-0: #f1edf2;
|
||||
--mantine-color-violet-1: #e0d7e2;
|
||||
--mantine-color-violet-2: #c9bacc;
|
||||
--mantine-color-violet-3: #ad97b1;
|
||||
--mantine-color-violet-4: #917797;
|
||||
--mantine-color-violet-5: #7a5f80;
|
||||
--mantine-color-violet-6: #695070;
|
||||
--mantine-color-violet-7: #56415c;
|
||||
--mantine-color-violet-8: #443348;
|
||||
--mantine-color-violet-9: #322535;
|
||||
|
||||
/* grape → aubergine */
|
||||
--mantine-color-grape-0: #f4ecf1;
|
||||
--mantine-color-grape-1: #e6d4df;
|
||||
--mantine-color-grape-2: #d2b3c6;
|
||||
--mantine-color-grape-3: #b98da7;
|
||||
--mantine-color-grape-4: #a06a8b;
|
||||
--mantine-color-grape-5: #8b5175;
|
||||
--mantine-color-grape-6: #794464;
|
||||
--mantine-color-grape-7: #633751;
|
||||
--mantine-color-grape-8: #4e2b40;
|
||||
--mantine-color-grape-9: #3a202f;
|
||||
|
||||
/* pink → dusty rose (rosier than red so the pair stays distinct) */
|
||||
--mantine-color-pink-0: #f9edf0;
|
||||
--mantine-color-pink-1: #f1d5dc;
|
||||
--mantine-color-pink-2: #e6b3c0;
|
||||
--mantine-color-pink-3: #d78da0;
|
||||
--mantine-color-pink-4: #c66781;
|
||||
--mantine-color-pink-5: #b24a66;
|
||||
--mantine-color-pink-6: #9e3e59;
|
||||
--mantine-color-pink-7: #83334a;
|
||||
--mantine-color-pink-8: #682839;
|
||||
--mantine-color-pink-9: #4e1e2b;
|
||||
|
||||
/* gray → warm taupe */
|
||||
--mantine-color-gray-0: #faf4e6;
|
||||
--mantine-color-gray-1: #f1e6cf;
|
||||
--mantine-color-gray-2: #e4d5b8;
|
||||
--mantine-color-gray-3: #d0bd9c;
|
||||
--mantine-color-gray-4: #b5a083;
|
||||
--mantine-color-gray-5: #97826a;
|
||||
--mantine-color-gray-6: #7a6753;
|
||||
--mantine-color-gray-7: #5f4e3e;
|
||||
--mantine-color-gray-8: #47392c;
|
||||
--mantine-color-gray-9: #30251b;
|
||||
|
||||
/* dark → espresso */
|
||||
--mantine-color-dark-0: #efe3d3;
|
||||
--mantine-color-dark-1: #d9c6ad;
|
||||
--mantine-color-dark-2: #b39a7d;
|
||||
--mantine-color-dark-3: #8a7258;
|
||||
--mantine-color-dark-4: #5c4732;
|
||||
--mantine-color-dark-5: #4a3826;
|
||||
--mantine-color-dark-6: #33261a;
|
||||
--mantine-color-dark-7: #241a12;
|
||||
--mantine-color-dark-8: #1b130d;
|
||||
--mantine-color-dark-9: #120c08;
|
||||
}
|
||||
|
||||
/* ---------- 2. Per-scheme tokens — (0,3,0) ---------- */
|
||||
|
||||
[data-theme="seventies"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #f6ecd9;
|
||||
--mantine-color-text: #3f2d20;
|
||||
--mantine-color-bright: #241a12;
|
||||
--mantine-color-dimmed: #7a6753;
|
||||
--mantine-color-placeholder: #97826a;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-filled);
|
||||
--mantine-color-error: var(--mantine-color-red-6);
|
||||
--mantine-color-default: #fdf7ea;
|
||||
--mantine-color-default-hover: #f3e6c9;
|
||||
--mantine-color-default-color: #3f2d20;
|
||||
--mantine-color-default-border: #3f2d20;
|
||||
|
||||
--seventies-ink: #3f2d20;
|
||||
--seventies-surface: #fdf7ea;
|
||||
--seventies-tray: #f0e2c3;
|
||||
--seventies-contour: rgba(63, 45, 32, 0.07);
|
||||
|
||||
/* alpha tints re-derived from the retuned ramps */
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-6) 12%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 16%, transparent);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-6) 10%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-6) 14%, transparent);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-6) 10%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-6) 14%, transparent);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-6) 11%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-6) 15%, transparent);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-6) 11%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-6) 15%, transparent);
|
||||
--mantine-color-teal-light: color-mix(in srgb, var(--mantine-color-teal-6) 10%, transparent);
|
||||
--mantine-color-teal-light-hover: color-mix(in srgb, var(--mantine-color-teal-6) 14%, transparent);
|
||||
--mantine-color-cyan-light: color-mix(in srgb, var(--mantine-color-cyan-6) 10%, transparent);
|
||||
--mantine-color-cyan-light-hover: color-mix(in srgb, var(--mantine-color-cyan-6) 14%, transparent);
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-6) 10%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-6) 14%, transparent);
|
||||
--mantine-color-indigo-light: color-mix(in srgb, var(--mantine-color-indigo-6) 10%, transparent);
|
||||
--mantine-color-indigo-light-hover: color-mix(in srgb, var(--mantine-color-indigo-6) 14%, transparent);
|
||||
--mantine-color-violet-light: color-mix(in srgb, var(--mantine-color-violet-6) 10%, transparent);
|
||||
--mantine-color-violet-light-hover: color-mix(in srgb, var(--mantine-color-violet-6) 14%, transparent);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-6) 10%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-6) 14%, transparent);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-6) 10%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-6) 14%, transparent);
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-6) 10%, transparent);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-6) 14%, transparent);
|
||||
|
||||
/* outline-hover tints for the pickable accents (Mantine's are stock-hue rgba) */
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-6) 6%, transparent);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-6) 6%, transparent);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-6) 6%, transparent);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 6%, transparent);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-6) 6%, transparent);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-6) 6%, transparent);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-6) 6%, transparent);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-6) 6%, transparent);
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #d3931b;
|
||||
--flxn-silver: #a08a70;
|
||||
--flxn-bronze: #b05c33;
|
||||
--flxn-toast-success: var(--mantine-color-green-6);
|
||||
--flxn-toast-error: var(--mantine-color-red-6);
|
||||
--flxn-showcase-bg: #fdf7ea;
|
||||
--flxn-overlay: rgba(36, 26, 18, 0.45);
|
||||
--flxn-dotgrid-color: rgba(63, 45, 32, 0.22);
|
||||
--flxn-pop-shadow: rgba(63, 45, 32, 0.35);
|
||||
|
||||
/* wood-paneled podium tiers */
|
||||
--flxn-podium-1-bg: repeating-linear-gradient(
|
||||
90deg,
|
||||
rgba(63, 45, 32, 0.06) 0 2px,
|
||||
transparent 2px 12px
|
||||
),
|
||||
linear-gradient(180deg, #f2dca6, #e9c878);
|
||||
--flxn-podium-1-border: #b07c1c;
|
||||
--flxn-podium-1-label: #6b4a11;
|
||||
--flxn-podium-2-bg: repeating-linear-gradient(
|
||||
90deg,
|
||||
rgba(63, 45, 32, 0.06) 0 2px,
|
||||
transparent 2px 12px
|
||||
),
|
||||
linear-gradient(180deg, #eee0c8, #e0cba6);
|
||||
--flxn-podium-2-border: #97826a;
|
||||
--flxn-podium-2-label: #5f4e3e;
|
||||
--flxn-podium-3-bg: repeating-linear-gradient(
|
||||
90deg,
|
||||
rgba(63, 45, 32, 0.06) 0 2px,
|
||||
transparent 2px 12px
|
||||
),
|
||||
linear-gradient(180deg, #f2cdb4, #e6b18c);
|
||||
--flxn-podium-3-border: #a2542f;
|
||||
--flxn-podium-3-label: #782f1a;
|
||||
}
|
||||
|
||||
[data-theme="seventies"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #241a12;
|
||||
--mantine-color-text: #f2e6d0;
|
||||
--mantine-color-bright: #fdf6e4;
|
||||
--mantine-color-dimmed: #b39a7d;
|
||||
--mantine-color-placeholder: #8a7258;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-light-color);
|
||||
--mantine-color-error: var(--mantine-color-red-3);
|
||||
--mantine-color-default: #33261a;
|
||||
--mantine-color-default-hover: #40301f;
|
||||
--mantine-color-default-color: #f2e6d0;
|
||||
--mantine-color-default-border: #5f4832;
|
||||
|
||||
--seventies-ink: #f2e6d0;
|
||||
--seventies-surface: #2c2015;
|
||||
--seventies-tray: #362818;
|
||||
--seventies-contour: rgba(242, 230, 208, 0.06);
|
||||
|
||||
/* filled variants stay mid-ramp (default shade 8 vanishes on espresso);
|
||||
primary aliases follow via Mantine's var indirection, so the user's
|
||||
accent picks these up automatically */
|
||||
--mantine-color-yellow-filled: var(--mantine-color-yellow-5);
|
||||
--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-4);
|
||||
--mantine-color-orange-filled: var(--mantine-color-orange-6);
|
||||
--mantine-color-orange-filled-hover: var(--mantine-color-orange-5);
|
||||
--mantine-color-red-filled: var(--mantine-color-red-6);
|
||||
--mantine-color-red-filled-hover: var(--mantine-color-red-5);
|
||||
--mantine-color-green-filled: var(--mantine-color-green-6);
|
||||
--mantine-color-green-filled-hover: var(--mantine-color-green-5);
|
||||
--mantine-color-lime-filled: var(--mantine-color-lime-6);
|
||||
--mantine-color-lime-filled-hover: var(--mantine-color-lime-5);
|
||||
--mantine-color-teal-filled: var(--mantine-color-teal-6);
|
||||
--mantine-color-teal-filled-hover: var(--mantine-color-teal-5);
|
||||
--mantine-color-cyan-filled: var(--mantine-color-cyan-6);
|
||||
--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-5);
|
||||
--mantine-color-blue-filled: var(--mantine-color-blue-6);
|
||||
--mantine-color-blue-filled-hover: var(--mantine-color-blue-5);
|
||||
--mantine-color-indigo-filled: var(--mantine-color-indigo-6);
|
||||
--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-5);
|
||||
--mantine-color-violet-filled: var(--mantine-color-violet-6);
|
||||
--mantine-color-violet-filled-hover: var(--mantine-color-violet-5);
|
||||
--mantine-color-grape-filled: var(--mantine-color-grape-6);
|
||||
--mantine-color-grape-filled-hover: var(--mantine-color-grape-5);
|
||||
--mantine-color-pink-filled: var(--mantine-color-pink-6);
|
||||
--mantine-color-pink-filled-hover: var(--mantine-color-pink-5);
|
||||
|
||||
/* alpha tints + tint text colors */
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-4) 16%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-4) 22%, transparent);
|
||||
--mantine-color-yellow-light-color: var(--mantine-color-yellow-3);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-4) 16%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-4) 22%, transparent);
|
||||
--mantine-color-orange-light-color: var(--mantine-color-orange-3);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-4) 16%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-4) 22%, transparent);
|
||||
--mantine-color-red-light-color: var(--mantine-color-red-3);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-4) 16%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-4) 22%, transparent);
|
||||
--mantine-color-green-light-color: var(--mantine-color-green-3);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-4) 16%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-4) 22%, transparent);
|
||||
--mantine-color-lime-light-color: var(--mantine-color-lime-3);
|
||||
--mantine-color-teal-light: color-mix(in srgb, var(--mantine-color-teal-4) 16%, transparent);
|
||||
--mantine-color-teal-light-hover: color-mix(in srgb, var(--mantine-color-teal-4) 22%, transparent);
|
||||
--mantine-color-teal-light-color: var(--mantine-color-teal-3);
|
||||
--mantine-color-cyan-light: color-mix(in srgb, var(--mantine-color-cyan-4) 16%, transparent);
|
||||
--mantine-color-cyan-light-hover: color-mix(in srgb, var(--mantine-color-cyan-4) 22%, transparent);
|
||||
--mantine-color-cyan-light-color: var(--mantine-color-cyan-3);
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-4) 16%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-4) 22%, transparent);
|
||||
--mantine-color-blue-light-color: var(--mantine-color-blue-3);
|
||||
--mantine-color-indigo-light: color-mix(in srgb, var(--mantine-color-indigo-4) 16%, transparent);
|
||||
--mantine-color-indigo-light-hover: color-mix(in srgb, var(--mantine-color-indigo-4) 22%, transparent);
|
||||
--mantine-color-indigo-light-color: var(--mantine-color-indigo-3);
|
||||
--mantine-color-violet-light: color-mix(in srgb, var(--mantine-color-violet-4) 16%, transparent);
|
||||
--mantine-color-violet-light-hover: color-mix(in srgb, var(--mantine-color-violet-4) 22%, transparent);
|
||||
--mantine-color-violet-light-color: var(--mantine-color-violet-3);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-4) 16%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-4) 22%, transparent);
|
||||
--mantine-color-grape-light-color: var(--mantine-color-grape-3);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-4) 16%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-4) 22%, transparent);
|
||||
--mantine-color-pink-light-color: var(--mantine-color-pink-3);
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-4) 14%, transparent);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-4) 20%, transparent);
|
||||
--mantine-color-gray-light-color: var(--mantine-color-gray-2);
|
||||
|
||||
/* outline-hover tints for the pickable accents (Mantine's are stock-hue rgba) */
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-4) 10%, transparent);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-4) 10%, transparent);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-4) 10%, transparent);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-4) 10%, transparent);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-4) 10%, transparent);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-4) 10%, transparent);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-4) 10%, transparent);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-4) 10%, transparent);
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #e6b544;
|
||||
--flxn-silver: #b5a083;
|
||||
--flxn-bronze: #d87b50;
|
||||
--flxn-toast-success: var(--mantine-color-green-3);
|
||||
--flxn-toast-error: var(--mantine-color-red-3);
|
||||
--flxn-showcase-bg: #2c2015;
|
||||
--flxn-overlay: rgba(18, 12, 8, 0.6);
|
||||
--flxn-dotgrid-color: rgba(242, 230, 208, 0.14);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.5);
|
||||
|
||||
--flxn-podium-1-bg: repeating-linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 0, 0, 0.18) 0 2px,
|
||||
transparent 2px 12px
|
||||
),
|
||||
linear-gradient(180deg, #4a3a1c, #3a2d15);
|
||||
--flxn-podium-1-border: #a37a20;
|
||||
--flxn-podium-1-label: #e6b544;
|
||||
--flxn-podium-2-bg: repeating-linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 0, 0, 0.18) 0 2px,
|
||||
transparent 2px 12px
|
||||
),
|
||||
linear-gradient(180deg, #3d3123, #322718);
|
||||
--flxn-podium-2-border: #6b5138;
|
||||
--flxn-podium-2-label: #cbb391;
|
||||
--flxn-podium-3-bg: repeating-linear-gradient(
|
||||
90deg,
|
||||
rgba(0, 0, 0, 0.18) 0 2px,
|
||||
transparent 2px 12px
|
||||
),
|
||||
linear-gradient(180deg, #4a2c1c, #3a2115);
|
||||
--flxn-podium-3-border: #8a4a28;
|
||||
--flxn-podium-3-label: #e09a72;
|
||||
}
|
||||
|
||||
/* ---------- 3. Component restyles ---------- */
|
||||
|
||||
/* app shell: warm surfaces, sunburst band under the header */
|
||||
[data-theme="seventies"] .mantine-AppShell-header {
|
||||
background-color: var(--seventies-surface);
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-AppShell-header::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 5px;
|
||||
background: var(--seventies-band);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-AppShell-navbar {
|
||||
background-color: var(--seventies-surface);
|
||||
border-inline-end: 2px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
/* surfaces: chunky 2px chocolate borders (covers cards, sheets, the
|
||||
floating mobile nav pill, modal content — all Paper-based) */
|
||||
[data-theme="seventies"] .mantine-Paper-root {
|
||||
background-color: var(--seventies-surface);
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
/* retro contour-line arcs in card corners */
|
||||
[data-theme="seventies"] .mantine-Card-root {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Card-root::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 7rem;
|
||||
height: 7rem;
|
||||
pointer-events: none;
|
||||
border-top-right-radius: calc(var(--mantine-radius-default) - 2px);
|
||||
background: repeating-radial-gradient(
|
||||
circle at 100% 0%,
|
||||
var(--seventies-contour) 0 2px,
|
||||
transparent 2px 14px
|
||||
);
|
||||
-webkit-mask-image: radial-gradient(circle at 100% 0%, #000 30%, transparent 72%);
|
||||
mask-image: radial-gradient(circle at 100% 0%, #000 30%, transparent 72%);
|
||||
}
|
||||
|
||||
/* buttons: solid warm fills with a darker chunky bottom edge */
|
||||
[data-theme="seventies"] .mantine-Button-root {
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.02em;
|
||||
transition: box-shadow 120ms cubic-bezier(0.32, 0.72, 0, 1);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="seventies"] .mantine-Button-root[data-variant="light"],
|
||||
[data-theme="seventies"] .mantine-Button-root[data-variant="default"] {
|
||||
box-shadow: 0 3px 0 color-mix(in srgb, var(--button-bg) 60%, #120c08);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="seventies"] .mantine-Button-root[data-variant="outline"] {
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Button-root[data-variant="filled"]:active:not(:disabled):not([data-disabled]):not([data-loading]),
|
||||
[data-theme="seventies"] .mantine-Button-root[data-variant="light"]:active:not(:disabled):not([data-disabled]):not([data-loading]),
|
||||
[data-theme="seventies"] .mantine-Button-root[data-variant="default"]:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
box-shadow: 0 1px 0 color-mix(in srgb, var(--button-bg) 60%, #120c08);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-ActionIcon-root[data-variant="filled"],
|
||||
[data-theme="seventies"] .mantine-ActionIcon-root[data-variant="light"],
|
||||
[data-theme="seventies"] .mantine-ActionIcon-root[data-variant="default"] {
|
||||
box-shadow: 0 2px 0 color-mix(in srgb, var(--ai-bg) 60%, #120c08);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-ActionIcon-root[data-variant="filled"]:active:not(:disabled):not([data-disabled]):not([data-loading]),
|
||||
[data-theme="seventies"] .mantine-ActionIcon-root[data-variant="light"]:active:not(:disabled):not([data-disabled]):not([data-loading]),
|
||||
[data-theme="seventies"] .mantine-ActionIcon-root[data-variant="default"]:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
box-shadow: 0 0 0 transparent;
|
||||
}
|
||||
|
||||
/* press feedback: sink instead of scale */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="seventies"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transform: translateY(2px);
|
||||
}
|
||||
}
|
||||
|
||||
/* inputs */
|
||||
[data-theme="seventies"] .mantine-Input-input {
|
||||
border-width: 2px;
|
||||
background-color: var(--seventies-surface);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* badges as retro patches: bold border + inner stitch line */
|
||||
[data-theme="seventies"] .mantine-Badge-root {
|
||||
position: relative;
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Badge-root::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 2px;
|
||||
border: 1px dashed color-mix(in srgb, currentColor 55%, transparent);
|
||||
border-radius: calc(var(--mantine-radius-sm) - 3px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* tabs + segmented control */
|
||||
[data-theme="seventies"] .mantine-Tabs-tab {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Tabs-tab[data-active] {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-SegmentedControl-root {
|
||||
background-color: color-mix(in srgb, var(--seventies-ink) 8%, var(--mantine-color-body));
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-SegmentedControl-indicator {
|
||||
background-color: light-dark(#e9c46b, #8c6216);
|
||||
box-shadow: 0 2px 0 rgba(18, 12, 8, 0.25);
|
||||
}
|
||||
|
||||
/* overlays & floating surfaces */
|
||||
[data-theme="seventies"] .mantine-Modal-header {
|
||||
background-color: var(--seventies-surface);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Modal-header::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: var(--mantine-spacing-md);
|
||||
right: var(--mantine-spacing-md);
|
||||
bottom: 0;
|
||||
height: 4px;
|
||||
border-radius: 2px;
|
||||
background: var(--seventies-band);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Popover-dropdown {
|
||||
background-color: var(--seventies-surface);
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Tooltip-tooltip {
|
||||
background-color: #33261a;
|
||||
color: #f2e6d0;
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Notification-root {
|
||||
background-color: var(--seventies-surface);
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Alert-root {
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
/* controls */
|
||||
[data-theme="seventies"] .mantine-Switch-track {
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Checkbox-input {
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .mantine-Progress-root {
|
||||
background-color: color-mix(in srgb, var(--seventies-ink) 12%, transparent);
|
||||
}
|
||||
|
||||
/* ---------- 4. App component hooks ---------- */
|
||||
|
||||
/* tab strip: docks as a cream strip closed off by a chocolate rule */
|
||||
[data-theme="seventies"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--seventies-surface);
|
||||
border-bottom: 2px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .flxn-tab {
|
||||
font-weight: 600;
|
||||
color: var(--mantine-color-dimmed);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .flxn-tab[data-active] {
|
||||
color: light-dark(
|
||||
var(--mantine-primary-color-filled),
|
||||
var(--mantine-primary-color-light-color)
|
||||
);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .flxn-tabs-indicator {
|
||||
border-bottom: 3px solid var(--mantine-primary-color-filled);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* nav tiles: chunky bordered cards with a chocolate ledge; sink on press */
|
||||
[data-theme="seventies"] .flxn-tile {
|
||||
background-color: var(--seventies-surface);
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
box-shadow: 0 3px 0 var(--mantine-color-default-border);
|
||||
transition: box-shadow 120ms cubic-bezier(0.32, 0.72, 0, 1);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .flxn-tile:active {
|
||||
box-shadow: 0 1px 0 var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .flxn-tile-icon {
|
||||
color: light-dark(
|
||||
var(--mantine-primary-color-filled),
|
||||
var(--mantine-primary-color-light-color)
|
||||
);
|
||||
}
|
||||
|
||||
/* "see all" as a sew-on patch chip: light accent wash + wash text */
|
||||
[data-theme="seventies"] .flxn-see-all {
|
||||
position: relative;
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-sm);
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .flxn-see-all::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 2px;
|
||||
border: 1px dashed color-mix(in srgb, currentColor 55%, transparent);
|
||||
border-radius: calc(var(--mantine-radius-sm) - 3px);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* match card + reaction tray: one construction — matching chocolate
|
||||
borders, tray reads as a wood-panel shelf under the card */
|
||||
[data-theme="seventies"] .flxn-match-card {
|
||||
background-color: var(--seventies-surface);
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
[data-theme="seventies"] .flxn-reaction-row {
|
||||
background: repeating-linear-gradient(
|
||||
90deg,
|
||||
color-mix(in srgb, var(--seventies-ink) 7%, transparent) 0 2px,
|
||||
transparent 2px 12px
|
||||
),
|
||||
var(--seventies-tray);
|
||||
border: 2px solid var(--mantine-color-default-border);
|
||||
border-radius: var(--mantine-radius-md);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "sketch",
|
||||
label: msg`Sketchbook`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Caveat:wght@500;600;700&family=Patrick+Hand&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#f9f4e8", dimmed: "#e9e1cf" },
|
||||
dark: { base: "#232a26", dimmed: "#1a201d" },
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,749 @@
|
||||
/* Sketchbook — hand-drawn ink on warm paper (light) / chalk on slate (dark).
|
||||
The look is carried by 2px "pen" borders with asymmetric wobbly radii
|
||||
(varied per component so each element reads as individually drawn), a faint
|
||||
feTurbulence grain overlay, and watercolor washes derived from the user's
|
||||
accent via color-mix. No SVG displacement filters (perf). */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 1. Scheme-independent tokens */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"][data-theme] {
|
||||
--mantine-font-family: "Patrick Hand", "Segoe Print", "Comic Sans MS", cursive;
|
||||
--mantine-font-family-headings: "Caveat", "Patrick Hand", cursive;
|
||||
--mantine-heading-font-weight: 600;
|
||||
/* Caveat runs small for its em box — headings get larger sizes */
|
||||
--mantine-h1-font-size: 2.75rem;
|
||||
--mantine-h1-line-height: 1.15;
|
||||
--mantine-h2-font-size: 2.25rem;
|
||||
--mantine-h2-line-height: 1.18;
|
||||
--mantine-h3-font-size: 1.85rem;
|
||||
--mantine-h3-line-height: 1.2;
|
||||
--mantine-h4-font-size: 1.55rem;
|
||||
--mantine-h4-line-height: 1.25;
|
||||
--mantine-h5-font-size: 1.3rem;
|
||||
--mantine-h5-line-height: 1.3;
|
||||
--mantine-h6-font-size: 1.15rem;
|
||||
--mantine-h6-line-height: 1.35;
|
||||
|
||||
--mantine-radius-xs: 6px;
|
||||
--mantine-radius-sm: 8px;
|
||||
--mantine-radius-md: 10px;
|
||||
--mantine-radius-lg: 14px;
|
||||
--mantine-radius-xl: 20px;
|
||||
--mantine-radius-default: 10px;
|
||||
|
||||
--flxn-avatar-radius: 42%; /* hand-drawn "circle" */
|
||||
--flxn-avatar-border: 2px solid var(--sk-ink); /* single pen ring on the frame */
|
||||
--flxn-badge-radius: 14px;
|
||||
|
||||
/* pencil-smudge shadows: soft, gray, slightly offset */
|
||||
--mantine-shadow-xs: 0 1px 2px var(--sk-smudge);
|
||||
--mantine-shadow-sm: 1px 2px 5px var(--sk-smudge);
|
||||
--mantine-shadow-md: 2px 3px 9px var(--sk-smudge);
|
||||
--mantine-shadow-lg: 3px 5px 14px var(--sk-smudge);
|
||||
--mantine-shadow-xl: 4px 7px 20px var(--sk-smudge);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 2a. Light — ink on warm paper */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--sk-ink: #333333;
|
||||
--sk-ink-soft: rgba(51, 51, 51, 0.55);
|
||||
--sk-on-fill: #2f2c26;
|
||||
--sk-paper: #f9f4e8;
|
||||
--sk-paper-raised: #fffdf6;
|
||||
--sk-wash: color-mix(in srgb, var(--mantine-primary-color-6) 18%, #fffdf6);
|
||||
--sk-accent-ink: color-mix(in srgb, var(--mantine-primary-color-6) 65%, #333333);
|
||||
--sk-smudge: rgba(88, 80, 62, 0.2);
|
||||
--sk-hatch: rgba(51, 51, 51, 0.22);
|
||||
--sk-skeleton: #ebe3d0;
|
||||
--sk-squiggle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='5' viewBox='0 0 22 5'%3E%3Cpath d='M0 3 Q 5.5 0.8 11 3 T 22 3' fill='none' stroke='%23333333' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
|
||||
|
||||
--mantine-color-body: #f9f4e8;
|
||||
--mantine-color-text: #333333;
|
||||
--mantine-color-bright: #1f1d18;
|
||||
--mantine-color-dimmed: #6b655a;
|
||||
--mantine-color-placeholder: #8a8375;
|
||||
--mantine-color-anchor: var(--sk-accent-ink);
|
||||
--mantine-color-error: #a44e46;
|
||||
--mantine-color-default: #fffdf6;
|
||||
--mantine-color-default-hover: #f1ead9;
|
||||
--mantine-color-default-color: #333333;
|
||||
--mantine-color-default-border: #333333;
|
||||
--mantine-primary-color-contrast: #2f2c26;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #dca815; /* crayon yellow */
|
||||
--flxn-silver: #8f8a80; /* pencil gray */
|
||||
--flxn-bronze: #b0744a; /* crayon sienna */
|
||||
--flxn-toast-success: #5f8f5f;
|
||||
--flxn-toast-error: #c26e63;
|
||||
--flxn-podium-1-bg: #f8eecb;
|
||||
--flxn-podium-1-border: #8c7a35;
|
||||
--flxn-podium-1-label: #7c6614;
|
||||
--flxn-podium-2-bg: #f0ede4;
|
||||
--flxn-podium-2-border: #77746c;
|
||||
--flxn-podium-2-label: #5f5c54;
|
||||
--flxn-podium-3-bg: #f4e5d3;
|
||||
--flxn-podium-3-border: #8f6a45;
|
||||
--flxn-podium-3-label: #82552e;
|
||||
--flxn-showcase-bg: #fffdf6;
|
||||
--flxn-overlay: rgba(56, 50, 38, 0.45);
|
||||
--flxn-dotgrid-color: rgba(51, 51, 51, 0.3); /* pencil dots */
|
||||
--flxn-pop-shadow: rgba(88, 80, 62, 0.3);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 2b. Dark — chalk on slate */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--sk-ink: #dfdcd0; /* chalk */
|
||||
--sk-ink-soft: rgba(223, 220, 208, 0.5);
|
||||
--sk-on-fill: #232a26;
|
||||
--sk-paper: #232a26;
|
||||
--sk-paper-raised: #2a322d;
|
||||
--sk-wash: color-mix(in srgb, var(--mantine-primary-color-4) 22%, #2a322d);
|
||||
--sk-accent-ink: color-mix(in srgb, var(--mantine-primary-color-3) 70%, #dfdcd0);
|
||||
--sk-smudge: rgba(0, 0, 0, 0.45);
|
||||
--sk-hatch: rgba(35, 42, 38, 0.4);
|
||||
--sk-skeleton: #38423b;
|
||||
--sk-squiggle: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='5' viewBox='0 0 22 5'%3E%3Cpath d='M0 3 Q 5.5 0.8 11 3 T 22 3' fill='none' stroke='%23dfdcd0' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
|
||||
|
||||
--mantine-color-body: #232a26;
|
||||
--mantine-color-text: #e8e5da;
|
||||
--mantine-color-bright: #f6f4ec;
|
||||
--mantine-color-dimmed: #a3ac9f;
|
||||
--mantine-color-placeholder: #8b948a;
|
||||
--mantine-color-anchor: var(--sk-accent-ink);
|
||||
--mantine-color-error: #e8a198;
|
||||
--mantine-color-default: #2a322d;
|
||||
--mantine-color-default-hover: #333c36;
|
||||
--mantine-color-default-color: #e8e5da;
|
||||
--mantine-color-default-border: #d7d4c6;
|
||||
--mantine-primary-color-contrast: #232a26;
|
||||
|
||||
/* app tokens — dusty chalk pastels */
|
||||
--flxn-gold: #ecd27a;
|
||||
--flxn-silver: #b9beb3;
|
||||
--flxn-bronze: #d9a06b;
|
||||
--flxn-toast-success: #b3d7ae;
|
||||
--flxn-toast-error: #eaa79b;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, #ecd27a 12%, #2a322d);
|
||||
--flxn-podium-1-border: #cdb96b;
|
||||
--flxn-podium-1-label: #e9d78f;
|
||||
--flxn-podium-2-bg: color-mix(in srgb, #b9beb3 10%, #2a322d);
|
||||
--flxn-podium-2-border: #a4a99e;
|
||||
--flxn-podium-2-label: #c9cec2;
|
||||
--flxn-podium-3-bg: color-mix(in srgb, #d9a06b 12%, #2a322d);
|
||||
--flxn-podium-3-border: #c08f5c;
|
||||
--flxn-podium-3-label: #e0b384;
|
||||
--flxn-showcase-bg: #2a322d;
|
||||
--flxn-overlay: rgba(6, 9, 8, 0.6);
|
||||
--flxn-dotgrid-color: rgba(223, 220, 208, 0.22); /* chalk dots */
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 3. Paper grain / chalk dust — one fixed overlay, feTurbulence */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998;
|
||||
pointer-events: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23g)'/%3E%3C/svg%3E");
|
||||
background-repeat: repeat;
|
||||
mix-blend-mode: multiply;
|
||||
opacity: 0.05;
|
||||
}
|
||||
|
||||
[data-theme="sketch"][data-mantine-color-scheme="dark"] body::before {
|
||||
mix-blend-mode: screen;
|
||||
opacity: 0.07;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 4. Surfaces — every card its own doodle */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"] .mantine-Paper-root {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 255px 15px 225px 15px / 15px 225px 15px 255px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Card-root {
|
||||
border-radius: 15px 225px 15px 255px / 225px 15px 255px 15px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Modal-content {
|
||||
border-radius: 18px 225px 22px 255px / 255px 22px 225px 18px;
|
||||
box-shadow: var(--mantine-shadow-xl);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Modal-header {
|
||||
background-color: var(--sk-paper-raised);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Drawer-content {
|
||||
border-radius: 20px 235px 16px 245px / 245px 16px 235px 20px;
|
||||
box-shadow: var(--mantine-shadow-xl);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Popover-dropdown,
|
||||
[data-theme="sketch"] .mantine-Menu-dropdown {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 255px 25px 225px 22px / 22px 225px 25px 255px;
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Menu-item {
|
||||
border-radius: 215px 14px 195px 16px / 16px 195px 14px 215px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Notification-root {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 15px 245px 18px 235px / 235px 18px 245px 15px;
|
||||
box-shadow: var(--mantine-shadow-md);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Alert-root {
|
||||
border: 2px solid var(--sk-ink-soft);
|
||||
border-radius: 20px 240px 16px 250px / 250px 16px 240px 20px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Tooltip-tooltip {
|
||||
background-color: var(--sk-ink);
|
||||
color: var(--sk-paper);
|
||||
border-radius: 205px 12px 225px 14px / 14px 225px 12px 205px;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 5. Shell */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"] .mantine-AppShell-header {
|
||||
border-bottom: 2px solid var(--sk-ink);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-AppShell-navbar {
|
||||
border-inline-end: 2px solid var(--sk-ink);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-AppShell-aside {
|
||||
border-inline-start: 2px solid var(--sk-ink);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Divider-root {
|
||||
--divider-color: var(--sk-ink-soft);
|
||||
--divider-size: 2px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Divider-root[data-orientation="horizontal"] {
|
||||
border-top-style: dashed;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Divider-root[data-orientation="vertical"] {
|
||||
border-inline-start-style: dashed;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 6. Buttons — sketched boxes */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"] .mantine-Button-root {
|
||||
border-radius: 225px 20px 255px 15px / 15px 255px 20px 225px;
|
||||
box-shadow: none;
|
||||
font-weight: 400; /* Patrick Hand ships 400 only; avoid faux bold */
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Button-root:where([data-variant="filled"], [data-variant="default"], [data-variant="outline"], [data-variant="light"], [data-variant="white"]) {
|
||||
border: 2px solid var(--sk-ink);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-ActionIcon-root {
|
||||
border-radius: 160px 25px 185px 28px / 28px 185px 25px 160px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-ActionIcon-root:where([data-variant="filled"], [data-variant="default"], [data-variant="outline"], [data-variant="light"], [data-variant="white"]) {
|
||||
border: 2px solid var(--sk-ink);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="sketch"] .mantine-ActionIcon-root[data-variant="filled"],
|
||||
[data-theme="sketch"] .mantine-Badge-root[data-variant="filled"],
|
||||
[data-theme="sketch"] .mantine-ThemeIcon-root[data-variant="filled"] {
|
||||
color: var(--sk-on-fill); /* ink on watercolor wash, chalkboard on pastel */
|
||||
}
|
||||
|
||||
/* press feedback: a slight crooked stamp */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="sketch"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transform: scale(0.96) rotate(-0.7deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 7. Inputs */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"] .mantine-Input-input {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 12px 255px 18px 225px / 225px 18px 255px 12px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Input-input:focus,
|
||||
[data-theme="sketch"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--sk-accent-ink);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-InputWrapper-label {
|
||||
font-family: var(--mantine-font-family-headings);
|
||||
font-size: 1.15rem;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-PinInput-input {
|
||||
border-radius: 190px 16px 210px 14px / 14px 210px 16px 190px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Checkbox-input {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 155px 8px 145px 10px / 10px 145px 8px 155px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Checkbox-icon {
|
||||
color: var(--sk-on-fill);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Radio-radio {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 48% 52% 51% 49% / 52% 48% 52% 48%;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Radio-icon {
|
||||
color: var(--sk-on-fill);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Switch-track {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 120px 40px 110px 45px / 45px 110px 40px 120px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Switch-thumb {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 50% 46% 54% 48% / 48% 54% 46% 52%;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 8. Tabs — scribbled underline on the active tab */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"] .mantine-Tabs-tab {
|
||||
border-radius: 200px 12px 190px 14px / 14px 190px 12px 200px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Tabs-tab[data-active] {
|
||||
border-color: transparent;
|
||||
background-image: var(--sk-squiggle);
|
||||
background-repeat: repeat-x;
|
||||
background-position: left bottom 1px;
|
||||
background-size: 22px 5px;
|
||||
color: var(--mantine-color-text);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-SegmentedControl-root {
|
||||
background-color: transparent;
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 225px 18px 255px 15px / 15px 255px 18px 225px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--sk-wash);
|
||||
border: 2px solid var(--sk-ink-soft);
|
||||
border-radius: 205px 15px 235px 12px / 12px 235px 15px 205px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-NavLink-root {
|
||||
border: 2px solid transparent;
|
||||
border-radius: 235px 18px 215px 20px / 20px 215px 18px 235px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-NavLink-root[data-active] {
|
||||
border-color: var(--sk-ink-soft);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 9. Small pieces */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"] .mantine-Badge-root {
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 255px 10px 225px 12px / 12px 225px 10px 255px;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-ThemeIcon-root {
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 170px 30px 150px 35px / 35px 150px 30px 170px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Indicator-indicator {
|
||||
border: 1.5px solid var(--sk-ink);
|
||||
border-radius: 50% 45% 55% 48% / 52% 50% 46% 54%;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Skeleton-root {
|
||||
border-radius: 225px 20px 245px 18px / 18px 245px 20px 225px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Skeleton-root::after {
|
||||
background-color: var(--sk-skeleton);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Loader-root {
|
||||
--loader-color: var(--sk-accent-ink);
|
||||
}
|
||||
|
||||
/* progress bar: wobbly pill with pencil cross-hatch fill */
|
||||
[data-theme="sketch"] .mantine-Progress-root {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 100px 30px 90px 35px / 35px 90px 30px 100px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Progress-section {
|
||||
background-image: repeating-linear-gradient(45deg, transparent 0 4px, var(--sk-hatch) 4px 6px);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .mantine-Progress-label {
|
||||
color: var(--sk-on-fill);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 9b. App component hooks */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
/* Tab strip: flat on the page when resting; the raised paper strip with
|
||||
its pencil rule appears only while docked. Resting keeps the 2px dashed
|
||||
border transparent so docking doesn't shift layout. */
|
||||
[data-theme="sketch"] .flxn-tabs {
|
||||
border-bottom: 2px dashed transparent;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border-bottom-color: var(--sk-ink-soft);
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .flxn-tab.flxn-tab {
|
||||
position: relative;
|
||||
border-radius: 200px 12px 190px 14px / 14px 190px 12px 200px;
|
||||
}
|
||||
|
||||
/* active tab: accent watercolor wash + accent scribble underline */
|
||||
[data-theme="sketch"] .flxn-tab.flxn-tab[data-active] {
|
||||
background-color: var(--sk-wash);
|
||||
color: var(--sk-accent-ink);
|
||||
font-weight: 400; /* Patrick Hand has no bold */
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .flxn-tab.flxn-tab[data-active]::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset-inline: 0.6rem;
|
||||
bottom: 2px;
|
||||
height: 5px;
|
||||
background-color: var(--sk-accent-ink);
|
||||
-webkit-mask-image: var(--sk-squiggle);
|
||||
mask-image: var(--sk-squiggle);
|
||||
-webkit-mask-repeat: repeat-x;
|
||||
mask-repeat: repeat-x;
|
||||
-webkit-mask-size: 22px 5px;
|
||||
mask-size: 22px 5px;
|
||||
}
|
||||
|
||||
/* the tab treatment carries the state — drop the straight underline */
|
||||
[data-theme="sketch"] .flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Nav grid tiles: sketched boxes, each drawn slightly differently */
|
||||
[data-theme="sketch"] .flxn-tile {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 255px 15px 225px 18px / 18px 225px 15px 255px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .flxn-tile:nth-child(even) {
|
||||
border-radius: 15px 235px 18px 245px / 235px 15px 245px 18px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .flxn-tile:nth-child(3n) {
|
||||
border-radius: 225px 22px 245px 15px / 15px 245px 22px 225px;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .flxn-tile-icon {
|
||||
color: var(--sk-accent-ink);
|
||||
}
|
||||
|
||||
/* "See all" chip: hand-drawn pill; wash bg/hover come from the retuned
|
||||
primary variant vars in hooks.css */
|
||||
[data-theme="sketch"] .flxn-see-all.flxn-see-all {
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 255px 12px 225px 14px / 14px 225px 12px 255px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* Match card + reaction tray: one construction, matching 2px pen border */
|
||||
[data-theme="sketch"] .flxn-match-card.flxn-match-card {
|
||||
background-color: var(--sk-paper-raised);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 18px 235px 16px 245px / 235px 18px 245px 16px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="sketch"] .flxn-reaction-row.flxn-reaction-row {
|
||||
background-color: var(--sk-paper);
|
||||
border: 2px solid var(--sk-ink);
|
||||
border-radius: 15px 225px 18px 235px / 225px 15px 235px 18px;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
/* 10. Watercolor washes (light) / dusty chalk pastels (dark) */
|
||||
/* Every palette color's variant vars are re-derived from its own */
|
||||
/* numbered shades, so the user's accent (and any colored variant) */
|
||||
/* shows through as a low-saturation wash instead of a solid fill. */
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
||||
[data-theme="sketch"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-red-filled: color-mix(in srgb, var(--mantine-color-red-6) 45%, #fffdf6);
|
||||
--mantine-color-red-filled-hover: color-mix(in srgb, var(--mantine-color-red-6) 58%, #fffdf6);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-6) 15%, #fffdf6);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-6) 23%, #fffdf6);
|
||||
--mantine-color-red-light-color: color-mix(in srgb, var(--mantine-color-red-9) 72%, #333333);
|
||||
--mantine-color-red-outline: color-mix(in srgb, var(--mantine-color-red-7) 65%, #333333);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-6) 15%, #fffdf6);
|
||||
--mantine-color-red-text: color-mix(in srgb, var(--mantine-color-red-8) 75%, #333333);
|
||||
--mantine-color-pink-filled: color-mix(in srgb, var(--mantine-color-pink-6) 45%, #fffdf6);
|
||||
--mantine-color-pink-filled-hover: color-mix(in srgb, var(--mantine-color-pink-6) 58%, #fffdf6);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-6) 15%, #fffdf6);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-6) 23%, #fffdf6);
|
||||
--mantine-color-pink-light-color: color-mix(in srgb, var(--mantine-color-pink-9) 72%, #333333);
|
||||
--mantine-color-pink-outline: color-mix(in srgb, var(--mantine-color-pink-7) 65%, #333333);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-6) 15%, #fffdf6);
|
||||
--mantine-color-pink-text: color-mix(in srgb, var(--mantine-color-pink-8) 75%, #333333);
|
||||
--mantine-color-grape-filled: color-mix(in srgb, var(--mantine-color-grape-6) 45%, #fffdf6);
|
||||
--mantine-color-grape-filled-hover: color-mix(in srgb, var(--mantine-color-grape-6) 58%, #fffdf6);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-6) 15%, #fffdf6);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-6) 23%, #fffdf6);
|
||||
--mantine-color-grape-light-color: color-mix(in srgb, var(--mantine-color-grape-9) 72%, #333333);
|
||||
--mantine-color-grape-outline: color-mix(in srgb, var(--mantine-color-grape-7) 65%, #333333);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-6) 15%, #fffdf6);
|
||||
--mantine-color-grape-text: color-mix(in srgb, var(--mantine-color-grape-8) 75%, #333333);
|
||||
--mantine-color-violet-filled: color-mix(in srgb, var(--mantine-color-violet-6) 45%, #fffdf6);
|
||||
--mantine-color-violet-filled-hover: color-mix(in srgb, var(--mantine-color-violet-6) 58%, #fffdf6);
|
||||
--mantine-color-violet-light: color-mix(in srgb, var(--mantine-color-violet-6) 15%, #fffdf6);
|
||||
--mantine-color-violet-light-hover: color-mix(in srgb, var(--mantine-color-violet-6) 23%, #fffdf6);
|
||||
--mantine-color-violet-light-color: color-mix(in srgb, var(--mantine-color-violet-9) 72%, #333333);
|
||||
--mantine-color-violet-outline: color-mix(in srgb, var(--mantine-color-violet-7) 65%, #333333);
|
||||
--mantine-color-violet-outline-hover: color-mix(in srgb, var(--mantine-color-violet-6) 15%, #fffdf6);
|
||||
--mantine-color-violet-text: color-mix(in srgb, var(--mantine-color-violet-8) 75%, #333333);
|
||||
--mantine-color-indigo-filled: color-mix(in srgb, var(--mantine-color-indigo-6) 45%, #fffdf6);
|
||||
--mantine-color-indigo-filled-hover: color-mix(in srgb, var(--mantine-color-indigo-6) 58%, #fffdf6);
|
||||
--mantine-color-indigo-light: color-mix(in srgb, var(--mantine-color-indigo-6) 15%, #fffdf6);
|
||||
--mantine-color-indigo-light-hover: color-mix(in srgb, var(--mantine-color-indigo-6) 23%, #fffdf6);
|
||||
--mantine-color-indigo-light-color: color-mix(in srgb, var(--mantine-color-indigo-9) 72%, #333333);
|
||||
--mantine-color-indigo-outline: color-mix(in srgb, var(--mantine-color-indigo-7) 65%, #333333);
|
||||
--mantine-color-indigo-outline-hover: color-mix(in srgb, var(--mantine-color-indigo-6) 15%, #fffdf6);
|
||||
--mantine-color-indigo-text: color-mix(in srgb, var(--mantine-color-indigo-8) 75%, #333333);
|
||||
--mantine-color-blue-filled: color-mix(in srgb, var(--mantine-color-blue-6) 45%, #fffdf6);
|
||||
--mantine-color-blue-filled-hover: color-mix(in srgb, var(--mantine-color-blue-6) 58%, #fffdf6);
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-6) 15%, #fffdf6);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-6) 23%, #fffdf6);
|
||||
--mantine-color-blue-light-color: color-mix(in srgb, var(--mantine-color-blue-9) 72%, #333333);
|
||||
--mantine-color-blue-outline: color-mix(in srgb, var(--mantine-color-blue-7) 65%, #333333);
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-6) 15%, #fffdf6);
|
||||
--mantine-color-blue-text: color-mix(in srgb, var(--mantine-color-blue-8) 75%, #333333);
|
||||
--mantine-color-cyan-filled: color-mix(in srgb, var(--mantine-color-cyan-6) 45%, #fffdf6);
|
||||
--mantine-color-cyan-filled-hover: color-mix(in srgb, var(--mantine-color-cyan-6) 58%, #fffdf6);
|
||||
--mantine-color-cyan-light: color-mix(in srgb, var(--mantine-color-cyan-6) 15%, #fffdf6);
|
||||
--mantine-color-cyan-light-hover: color-mix(in srgb, var(--mantine-color-cyan-6) 23%, #fffdf6);
|
||||
--mantine-color-cyan-light-color: color-mix(in srgb, var(--mantine-color-cyan-9) 72%, #333333);
|
||||
--mantine-color-cyan-outline: color-mix(in srgb, var(--mantine-color-cyan-7) 65%, #333333);
|
||||
--mantine-color-cyan-outline-hover: color-mix(in srgb, var(--mantine-color-cyan-6) 15%, #fffdf6);
|
||||
--mantine-color-cyan-text: color-mix(in srgb, var(--mantine-color-cyan-8) 75%, #333333);
|
||||
--mantine-color-teal-filled: color-mix(in srgb, var(--mantine-color-teal-6) 45%, #fffdf6);
|
||||
--mantine-color-teal-filled-hover: color-mix(in srgb, var(--mantine-color-teal-6) 58%, #fffdf6);
|
||||
--mantine-color-teal-light: color-mix(in srgb, var(--mantine-color-teal-6) 15%, #fffdf6);
|
||||
--mantine-color-teal-light-hover: color-mix(in srgb, var(--mantine-color-teal-6) 23%, #fffdf6);
|
||||
--mantine-color-teal-light-color: color-mix(in srgb, var(--mantine-color-teal-9) 72%, #333333);
|
||||
--mantine-color-teal-outline: color-mix(in srgb, var(--mantine-color-teal-7) 65%, #333333);
|
||||
--mantine-color-teal-outline-hover: color-mix(in srgb, var(--mantine-color-teal-6) 15%, #fffdf6);
|
||||
--mantine-color-teal-text: color-mix(in srgb, var(--mantine-color-teal-8) 75%, #333333);
|
||||
--mantine-color-green-filled: color-mix(in srgb, var(--mantine-color-green-6) 45%, #fffdf6);
|
||||
--mantine-color-green-filled-hover: color-mix(in srgb, var(--mantine-color-green-6) 58%, #fffdf6);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-6) 15%, #fffdf6);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-6) 23%, #fffdf6);
|
||||
--mantine-color-green-light-color: color-mix(in srgb, var(--mantine-color-green-9) 72%, #333333);
|
||||
--mantine-color-green-outline: color-mix(in srgb, var(--mantine-color-green-7) 65%, #333333);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-6) 15%, #fffdf6);
|
||||
--mantine-color-green-text: color-mix(in srgb, var(--mantine-color-green-8) 75%, #333333);
|
||||
--mantine-color-lime-filled: color-mix(in srgb, var(--mantine-color-lime-6) 45%, #fffdf6);
|
||||
--mantine-color-lime-filled-hover: color-mix(in srgb, var(--mantine-color-lime-6) 58%, #fffdf6);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-6) 15%, #fffdf6);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-6) 23%, #fffdf6);
|
||||
--mantine-color-lime-light-color: color-mix(in srgb, var(--mantine-color-lime-9) 72%, #333333);
|
||||
--mantine-color-lime-outline: color-mix(in srgb, var(--mantine-color-lime-7) 65%, #333333);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-6) 15%, #fffdf6);
|
||||
--mantine-color-lime-text: color-mix(in srgb, var(--mantine-color-lime-8) 75%, #333333);
|
||||
--mantine-color-yellow-filled: color-mix(in srgb, var(--mantine-color-yellow-6) 45%, #fffdf6);
|
||||
--mantine-color-yellow-filled-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 58%, #fffdf6);
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-6) 15%, #fffdf6);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 23%, #fffdf6);
|
||||
--mantine-color-yellow-light-color: color-mix(in srgb, var(--mantine-color-yellow-9) 72%, #333333);
|
||||
--mantine-color-yellow-outline: color-mix(in srgb, var(--mantine-color-yellow-7) 65%, #333333);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-6) 15%, #fffdf6);
|
||||
--mantine-color-yellow-text: color-mix(in srgb, var(--mantine-color-yellow-8) 75%, #333333);
|
||||
--mantine-color-orange-filled: color-mix(in srgb, var(--mantine-color-orange-6) 45%, #fffdf6);
|
||||
--mantine-color-orange-filled-hover: color-mix(in srgb, var(--mantine-color-orange-6) 58%, #fffdf6);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-6) 15%, #fffdf6);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-6) 23%, #fffdf6);
|
||||
--mantine-color-orange-light-color: color-mix(in srgb, var(--mantine-color-orange-9) 72%, #333333);
|
||||
--mantine-color-orange-outline: color-mix(in srgb, var(--mantine-color-orange-7) 65%, #333333);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-6) 15%, #fffdf6);
|
||||
--mantine-color-orange-text: color-mix(in srgb, var(--mantine-color-orange-8) 75%, #333333);
|
||||
--mantine-color-gray-filled: color-mix(in srgb, var(--mantine-color-gray-6) 45%, #fffdf6);
|
||||
--mantine-color-gray-filled-hover: color-mix(in srgb, var(--mantine-color-gray-6) 58%, #fffdf6);
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-6) 15%, #fffdf6);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-6) 23%, #fffdf6);
|
||||
--mantine-color-gray-light-color: color-mix(in srgb, var(--mantine-color-gray-9) 72%, #333333);
|
||||
--mantine-color-gray-outline: color-mix(in srgb, var(--mantine-color-gray-7) 65%, #333333);
|
||||
--mantine-color-gray-outline-hover: color-mix(in srgb, var(--mantine-color-gray-6) 15%, #fffdf6);
|
||||
--mantine-color-gray-text: color-mix(in srgb, var(--mantine-color-gray-8) 75%, #333333);
|
||||
}
|
||||
|
||||
[data-theme="sketch"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-red-filled: color-mix(in srgb, var(--mantine-color-red-3) 62%, #d9d5c7);
|
||||
--mantine-color-red-filled-hover: color-mix(in srgb, var(--mantine-color-red-3) 76%, #d9d5c7);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-4) 20%, #2a322d);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-4) 30%, #2a322d);
|
||||
--mantine-color-red-light-color: color-mix(in srgb, var(--mantine-color-red-2) 78%, #e8e5da);
|
||||
--mantine-color-red-outline: color-mix(in srgb, var(--mantine-color-red-2) 80%, #dfdcd0);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-4) 22%, #2a322d);
|
||||
--mantine-color-red-text: color-mix(in srgb, var(--mantine-color-red-2) 80%, #e8e5da);
|
||||
--mantine-color-pink-filled: color-mix(in srgb, var(--mantine-color-pink-3) 62%, #d9d5c7);
|
||||
--mantine-color-pink-filled-hover: color-mix(in srgb, var(--mantine-color-pink-3) 76%, #d9d5c7);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-4) 20%, #2a322d);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-4) 30%, #2a322d);
|
||||
--mantine-color-pink-light-color: color-mix(in srgb, var(--mantine-color-pink-2) 78%, #e8e5da);
|
||||
--mantine-color-pink-outline: color-mix(in srgb, var(--mantine-color-pink-2) 80%, #dfdcd0);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-4) 22%, #2a322d);
|
||||
--mantine-color-pink-text: color-mix(in srgb, var(--mantine-color-pink-2) 80%, #e8e5da);
|
||||
--mantine-color-grape-filled: color-mix(in srgb, var(--mantine-color-grape-3) 62%, #d9d5c7);
|
||||
--mantine-color-grape-filled-hover: color-mix(in srgb, var(--mantine-color-grape-3) 76%, #d9d5c7);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-4) 20%, #2a322d);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-4) 30%, #2a322d);
|
||||
--mantine-color-grape-light-color: color-mix(in srgb, var(--mantine-color-grape-2) 78%, #e8e5da);
|
||||
--mantine-color-grape-outline: color-mix(in srgb, var(--mantine-color-grape-2) 80%, #dfdcd0);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-4) 22%, #2a322d);
|
||||
--mantine-color-grape-text: color-mix(in srgb, var(--mantine-color-grape-2) 80%, #e8e5da);
|
||||
--mantine-color-violet-filled: color-mix(in srgb, var(--mantine-color-violet-3) 62%, #d9d5c7);
|
||||
--mantine-color-violet-filled-hover: color-mix(in srgb, var(--mantine-color-violet-3) 76%, #d9d5c7);
|
||||
--mantine-color-violet-light: color-mix(in srgb, var(--mantine-color-violet-4) 20%, #2a322d);
|
||||
--mantine-color-violet-light-hover: color-mix(in srgb, var(--mantine-color-violet-4) 30%, #2a322d);
|
||||
--mantine-color-violet-light-color: color-mix(in srgb, var(--mantine-color-violet-2) 78%, #e8e5da);
|
||||
--mantine-color-violet-outline: color-mix(in srgb, var(--mantine-color-violet-2) 80%, #dfdcd0);
|
||||
--mantine-color-violet-outline-hover: color-mix(in srgb, var(--mantine-color-violet-4) 22%, #2a322d);
|
||||
--mantine-color-violet-text: color-mix(in srgb, var(--mantine-color-violet-2) 80%, #e8e5da);
|
||||
--mantine-color-indigo-filled: color-mix(in srgb, var(--mantine-color-indigo-3) 62%, #d9d5c7);
|
||||
--mantine-color-indigo-filled-hover: color-mix(in srgb, var(--mantine-color-indigo-3) 76%, #d9d5c7);
|
||||
--mantine-color-indigo-light: color-mix(in srgb, var(--mantine-color-indigo-4) 20%, #2a322d);
|
||||
--mantine-color-indigo-light-hover: color-mix(in srgb, var(--mantine-color-indigo-4) 30%, #2a322d);
|
||||
--mantine-color-indigo-light-color: color-mix(in srgb, var(--mantine-color-indigo-2) 78%, #e8e5da);
|
||||
--mantine-color-indigo-outline: color-mix(in srgb, var(--mantine-color-indigo-2) 80%, #dfdcd0);
|
||||
--mantine-color-indigo-outline-hover: color-mix(in srgb, var(--mantine-color-indigo-4) 22%, #2a322d);
|
||||
--mantine-color-indigo-text: color-mix(in srgb, var(--mantine-color-indigo-2) 80%, #e8e5da);
|
||||
--mantine-color-blue-filled: color-mix(in srgb, var(--mantine-color-blue-3) 62%, #d9d5c7);
|
||||
--mantine-color-blue-filled-hover: color-mix(in srgb, var(--mantine-color-blue-3) 76%, #d9d5c7);
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-4) 20%, #2a322d);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-4) 30%, #2a322d);
|
||||
--mantine-color-blue-light-color: color-mix(in srgb, var(--mantine-color-blue-2) 78%, #e8e5da);
|
||||
--mantine-color-blue-outline: color-mix(in srgb, var(--mantine-color-blue-2) 80%, #dfdcd0);
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-4) 22%, #2a322d);
|
||||
--mantine-color-blue-text: color-mix(in srgb, var(--mantine-color-blue-2) 80%, #e8e5da);
|
||||
--mantine-color-cyan-filled: color-mix(in srgb, var(--mantine-color-cyan-3) 62%, #d9d5c7);
|
||||
--mantine-color-cyan-filled-hover: color-mix(in srgb, var(--mantine-color-cyan-3) 76%, #d9d5c7);
|
||||
--mantine-color-cyan-light: color-mix(in srgb, var(--mantine-color-cyan-4) 20%, #2a322d);
|
||||
--mantine-color-cyan-light-hover: color-mix(in srgb, var(--mantine-color-cyan-4) 30%, #2a322d);
|
||||
--mantine-color-cyan-light-color: color-mix(in srgb, var(--mantine-color-cyan-2) 78%, #e8e5da);
|
||||
--mantine-color-cyan-outline: color-mix(in srgb, var(--mantine-color-cyan-2) 80%, #dfdcd0);
|
||||
--mantine-color-cyan-outline-hover: color-mix(in srgb, var(--mantine-color-cyan-4) 22%, #2a322d);
|
||||
--mantine-color-cyan-text: color-mix(in srgb, var(--mantine-color-cyan-2) 80%, #e8e5da);
|
||||
--mantine-color-teal-filled: color-mix(in srgb, var(--mantine-color-teal-3) 62%, #d9d5c7);
|
||||
--mantine-color-teal-filled-hover: color-mix(in srgb, var(--mantine-color-teal-3) 76%, #d9d5c7);
|
||||
--mantine-color-teal-light: color-mix(in srgb, var(--mantine-color-teal-4) 20%, #2a322d);
|
||||
--mantine-color-teal-light-hover: color-mix(in srgb, var(--mantine-color-teal-4) 30%, #2a322d);
|
||||
--mantine-color-teal-light-color: color-mix(in srgb, var(--mantine-color-teal-2) 78%, #e8e5da);
|
||||
--mantine-color-teal-outline: color-mix(in srgb, var(--mantine-color-teal-2) 80%, #dfdcd0);
|
||||
--mantine-color-teal-outline-hover: color-mix(in srgb, var(--mantine-color-teal-4) 22%, #2a322d);
|
||||
--mantine-color-teal-text: color-mix(in srgb, var(--mantine-color-teal-2) 80%, #e8e5da);
|
||||
--mantine-color-green-filled: color-mix(in srgb, var(--mantine-color-green-3) 62%, #d9d5c7);
|
||||
--mantine-color-green-filled-hover: color-mix(in srgb, var(--mantine-color-green-3) 76%, #d9d5c7);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-4) 20%, #2a322d);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-4) 30%, #2a322d);
|
||||
--mantine-color-green-light-color: color-mix(in srgb, var(--mantine-color-green-2) 78%, #e8e5da);
|
||||
--mantine-color-green-outline: color-mix(in srgb, var(--mantine-color-green-2) 80%, #dfdcd0);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-4) 22%, #2a322d);
|
||||
--mantine-color-green-text: color-mix(in srgb, var(--mantine-color-green-2) 80%, #e8e5da);
|
||||
--mantine-color-lime-filled: color-mix(in srgb, var(--mantine-color-lime-3) 62%, #d9d5c7);
|
||||
--mantine-color-lime-filled-hover: color-mix(in srgb, var(--mantine-color-lime-3) 76%, #d9d5c7);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-4) 20%, #2a322d);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-4) 30%, #2a322d);
|
||||
--mantine-color-lime-light-color: color-mix(in srgb, var(--mantine-color-lime-2) 78%, #e8e5da);
|
||||
--mantine-color-lime-outline: color-mix(in srgb, var(--mantine-color-lime-2) 80%, #dfdcd0);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-4) 22%, #2a322d);
|
||||
--mantine-color-lime-text: color-mix(in srgb, var(--mantine-color-lime-2) 80%, #e8e5da);
|
||||
--mantine-color-yellow-filled: color-mix(in srgb, var(--mantine-color-yellow-3) 62%, #d9d5c7);
|
||||
--mantine-color-yellow-filled-hover: color-mix(in srgb, var(--mantine-color-yellow-3) 76%, #d9d5c7);
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-4) 20%, #2a322d);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-4) 30%, #2a322d);
|
||||
--mantine-color-yellow-light-color: color-mix(in srgb, var(--mantine-color-yellow-2) 78%, #e8e5da);
|
||||
--mantine-color-yellow-outline: color-mix(in srgb, var(--mantine-color-yellow-2) 80%, #dfdcd0);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-4) 22%, #2a322d);
|
||||
--mantine-color-yellow-text: color-mix(in srgb, var(--mantine-color-yellow-2) 80%, #e8e5da);
|
||||
--mantine-color-orange-filled: color-mix(in srgb, var(--mantine-color-orange-3) 62%, #d9d5c7);
|
||||
--mantine-color-orange-filled-hover: color-mix(in srgb, var(--mantine-color-orange-3) 76%, #d9d5c7);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-4) 20%, #2a322d);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-4) 30%, #2a322d);
|
||||
--mantine-color-orange-light-color: color-mix(in srgb, var(--mantine-color-orange-2) 78%, #e8e5da);
|
||||
--mantine-color-orange-outline: color-mix(in srgb, var(--mantine-color-orange-2) 80%, #dfdcd0);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-4) 22%, #2a322d);
|
||||
--mantine-color-orange-text: color-mix(in srgb, var(--mantine-color-orange-2) 80%, #e8e5da);
|
||||
--mantine-color-gray-filled: color-mix(in srgb, var(--mantine-color-gray-3) 62%, #d9d5c7);
|
||||
--mantine-color-gray-filled-hover: color-mix(in srgb, var(--mantine-color-gray-3) 76%, #d9d5c7);
|
||||
--mantine-color-gray-light: color-mix(in srgb, var(--mantine-color-gray-4) 20%, #2a322d);
|
||||
--mantine-color-gray-light-hover: color-mix(in srgb, var(--mantine-color-gray-4) 30%, #2a322d);
|
||||
--mantine-color-gray-light-color: color-mix(in srgb, var(--mantine-color-gray-2) 78%, #e8e5da);
|
||||
--mantine-color-gray-outline: color-mix(in srgb, var(--mantine-color-gray-2) 80%, #dfdcd0);
|
||||
--mantine-color-gray-outline-hover: color-mix(in srgb, var(--mantine-color-gray-4) 22%, #2a322d);
|
||||
--mantine-color-gray-text: color-mix(in srgb, var(--mantine-color-gray-2) 80%, #e8e5da);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "skeuo",
|
||||
label: msg`Skeuomorphic`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=Lato:wght@400;700;900&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#b7bdc5", dimmed: "#8b929b" },
|
||||
dark: { base: "#2a2d31", dimmed: "#141619" },
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,947 @@
|
||||
/* Skeuomorphic — 2010 machined realism (iOS 4 / brushed aluminum era).
|
||||
Light: warm linen body, machined-pill controls, deeply inset inputs.
|
||||
Dark: graphite/leather with subtle white inset highlights.
|
||||
All textures are inline data-URIs; real 1px borders everywhere so
|
||||
forced-colors mode keeps usable outlines. */
|
||||
|
||||
/* ---------- 1. Tokens, any scheme ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-theme] {
|
||||
--mantine-font-family: "Lato", "Inter", "Helvetica Neue", Helvetica, sans-serif;
|
||||
--mantine-font-family-headings: "Lato", "Inter", "Helvetica Neue", Helvetica, sans-serif;
|
||||
--mantine-heading-font-weight: 900;
|
||||
|
||||
--mantine-radius-xs: 0.25rem;
|
||||
--mantine-radius-sm: 0.375rem;
|
||||
--mantine-radius-md: 0.5rem;
|
||||
--mantine-radius-lg: 0.75rem;
|
||||
--mantine-radius-xl: 1rem;
|
||||
--mantine-radius-default: 0.5rem;
|
||||
|
||||
--flxn-avatar-radius: 50%;
|
||||
--flxn-avatar-border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
--flxn-badge-radius: 10px;
|
||||
|
||||
/* anodized accent ramps — interactive shades 5-9 deepened and slightly
|
||||
desaturated so filled surfaces read as lacquered metal in any hue */
|
||||
--mantine-color-blue-5: #3a8ad3;
|
||||
--mantine-color-blue-6: #1f78c8;
|
||||
--mantine-color-blue-7: #1a67ad;
|
||||
--mantine-color-blue-8: #165890;
|
||||
--mantine-color-blue-9: #124874;
|
||||
--mantine-color-red-5: #e05c56;
|
||||
--mantine-color-red-6: #d64545;
|
||||
--mantine-color-red-7: #bb3a3a;
|
||||
--mantine-color-red-8: #9e3131;
|
||||
--mantine-color-red-9: #822928;
|
||||
--mantine-color-green-5: #4bb35c;
|
||||
--mantine-color-green-6: #379f4d;
|
||||
--mantine-color-green-7: #2e8841;
|
||||
--mantine-color-green-8: #267136;
|
||||
--mantine-color-green-9: #1e5c2c;
|
||||
--mantine-color-yellow-5: #ecad14;
|
||||
--mantine-color-yellow-6: #d99a06;
|
||||
--mantine-color-yellow-7: #bb8405;
|
||||
--mantine-color-yellow-8: #9c6e04;
|
||||
--mantine-color-yellow-9: #7f5a04;
|
||||
--mantine-color-grape-5: #b355cb;
|
||||
--mantine-color-grape-6: #a341bd;
|
||||
--mantine-color-grape-7: #8d37a4;
|
||||
--mantine-color-grape-8: #762e8a;
|
||||
--mantine-color-grape-9: #612671;
|
||||
--mantine-color-orange-5: #ef8221;
|
||||
--mantine-color-orange-6: #dd6f13;
|
||||
--mantine-color-orange-7: #c05f10;
|
||||
--mantine-color-orange-8: #a2500d;
|
||||
--mantine-color-orange-9: #86420b;
|
||||
--mantine-color-pink-5: #d75a86;
|
||||
--mantine-color-pink-6: #c8406f;
|
||||
--mantine-color-pink-7: #ad365f;
|
||||
--mantine-color-pink-8: #922d50;
|
||||
--mantine-color-pink-9: #782542;
|
||||
--mantine-color-lime-5: #83bb2f;
|
||||
--mantine-color-lime-6: #71ab1d;
|
||||
--mantine-color-lime-7: #619219;
|
||||
--mantine-color-lime-8: #517a15;
|
||||
--mantine-color-lime-9: #426311;
|
||||
|
||||
/* fractal-noise grain, tiled; ~4% opacity baked into the rect */
|
||||
--skeuo-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.045'/%3E%3C/svg%3E");
|
||||
/* fine horizontal brushing for metal surfaces */
|
||||
--skeuo-brush: repeating-linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.05) 0 1px,
|
||||
rgba(0, 0, 0, 0.03) 1px 2px,
|
||||
transparent 2px 3px
|
||||
);
|
||||
}
|
||||
|
||||
/* ---------- 2. Per-scheme tokens ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-color-body: #e8e4da;
|
||||
--mantine-color-text: #3b362e;
|
||||
--mantine-color-bright: #1f1b15;
|
||||
--mantine-color-dimmed: #665e4e;
|
||||
--mantine-color-placeholder: #7d745f;
|
||||
--mantine-color-anchor: #3a6ea5;
|
||||
--mantine-color-error: #b0382e;
|
||||
--mantine-color-default: #eeebe2;
|
||||
--mantine-color-default-hover: #e3dfd2;
|
||||
--mantine-color-default-color: #3b362e;
|
||||
--mantine-color-default-border: #a99f8c;
|
||||
|
||||
/* warm machined grays */
|
||||
--mantine-color-gray-0: #faf8f3;
|
||||
--mantine-color-gray-1: #f1eee6;
|
||||
--mantine-color-gray-2: #e6e2d6;
|
||||
--mantine-color-gray-3: #d7d2c3;
|
||||
--mantine-color-gray-4: #c3bcaa;
|
||||
--mantine-color-gray-5: #a99f8c;
|
||||
--mantine-color-gray-6: #857c6c;
|
||||
--mantine-color-gray-7: #5f584b;
|
||||
--mantine-color-gray-8: #403a30;
|
||||
--mantine-color-gray-9: #29241d;
|
||||
|
||||
/* raised-panel shadow stacks: inset top highlight + soft drop */
|
||||
--mantine-shadow-xs: inset 0 1px 0 rgba(255, 255, 255, 0.65),
|
||||
0 1px 2px rgba(46, 41, 33, 0.16);
|
||||
--mantine-shadow-sm: inset 0 1px 0 rgba(255, 255, 255, 0.7),
|
||||
0 1px 2px rgba(46, 41, 33, 0.18), 0 3px 8px rgba(46, 41, 33, 0.1);
|
||||
--mantine-shadow-md: inset 0 1px 0 rgba(255, 255, 255, 0.75),
|
||||
0 2px 4px rgba(46, 41, 33, 0.16), 0 7px 16px rgba(46, 41, 33, 0.13);
|
||||
--mantine-shadow-lg: inset 0 1px 0 rgba(255, 255, 255, 0.75),
|
||||
0 4px 8px rgba(46, 41, 33, 0.18), 0 14px 28px rgba(46, 41, 33, 0.16);
|
||||
--mantine-shadow-xl: inset 0 1px 0 rgba(255, 255, 255, 0.8),
|
||||
0 6px 12px rgba(46, 41, 33, 0.2), 0 22px 44px rgba(46, 41, 33, 0.2);
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #cf9312;
|
||||
--flxn-silver: #8f97a1;
|
||||
--flxn-bronze: #b06f36;
|
||||
--flxn-toast-success: #3d8f43;
|
||||
--flxn-toast-error: #bf4136;
|
||||
/* labels: engraved neutral inks — never the plate's own metal hue */
|
||||
--flxn-podium-1-bg: linear-gradient(180deg, #fbecbb 0%, #efd489 48%, #e0b955 52%, #d8ad42 100%);
|
||||
--flxn-podium-1-border: #b18a2b;
|
||||
--flxn-podium-1-label: #46402e;
|
||||
--flxn-podium-2-bg: linear-gradient(180deg, #f7f8fa 0%, #e2e5e9 48%, #ccd0d6 52%, #c2c7ce 100%);
|
||||
--flxn-podium-2-border: #969da6;
|
||||
--flxn-podium-2-label: #3f444b;
|
||||
--flxn-podium-3-bg: linear-gradient(180deg, #f0d3b4 0%, #ddad7d 48%, #ca9257 52%, #c08a4e 100%);
|
||||
--flxn-podium-3-border: #99672f;
|
||||
--flxn-podium-3-label: #2f2822;
|
||||
--flxn-showcase-bg: linear-gradient(180deg, #fbf9f4 0%, #efece2 100%);
|
||||
--flxn-overlay: rgba(30, 26, 20, 0.45);
|
||||
--flxn-dotgrid-color: #c9c2b1;
|
||||
--flxn-pop-shadow: rgba(46, 41, 33, 0.35);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #1a1b1e;
|
||||
--mantine-color-text: #d5d2ca;
|
||||
--mantine-color-bright: #f2efe8;
|
||||
--mantine-color-dimmed: #8f8c84;
|
||||
--mantine-color-placeholder: #6f6c64;
|
||||
--mantine-color-anchor: #82abdd;
|
||||
--mantine-color-error: #e05e52;
|
||||
--mantine-color-default: #2b2d31;
|
||||
--mantine-color-default-hover: #34373c;
|
||||
--mantine-color-default-color: #d5d2ca;
|
||||
--mantine-color-default-border: #46484d;
|
||||
|
||||
/* graphite darks */
|
||||
--mantine-color-dark-0: #e0ddd6;
|
||||
--mantine-color-dark-1: #c7c4bd;
|
||||
--mantine-color-dark-2: #94918a;
|
||||
--mantine-color-dark-3: #4c4f55;
|
||||
--mantine-color-dark-4: #3a3d42;
|
||||
--mantine-color-dark-5: #2b2d31;
|
||||
--mantine-color-dark-6: #222428;
|
||||
--mantine-color-dark-7: #1a1b1e;
|
||||
--mantine-color-dark-8: #141518;
|
||||
--mantine-color-dark-9: #0e0f11;
|
||||
|
||||
--mantine-shadow-xs: inset 0 1px 0 rgba(255, 255, 255, 0.06),
|
||||
0 1px 2px rgba(0, 0, 0, 0.5);
|
||||
--mantine-shadow-sm: inset 0 1px 0 rgba(255, 255, 255, 0.07),
|
||||
0 1px 3px rgba(0, 0, 0, 0.55), 0 3px 8px rgba(0, 0, 0, 0.35);
|
||||
--mantine-shadow-md: inset 0 1px 0 rgba(255, 255, 255, 0.08),
|
||||
0 2px 5px rgba(0, 0, 0, 0.55), 0 8px 18px rgba(0, 0, 0, 0.4);
|
||||
--mantine-shadow-lg: inset 0 1px 0 rgba(255, 255, 255, 0.08),
|
||||
0 4px 10px rgba(0, 0, 0, 0.6), 0 16px 32px rgba(0, 0, 0, 0.45);
|
||||
--mantine-shadow-xl: inset 0 1px 0 rgba(255, 255, 255, 0.09),
|
||||
0 6px 14px rgba(0, 0, 0, 0.65), 0 24px 48px rgba(0, 0, 0, 0.5);
|
||||
|
||||
--flxn-gold: #e7b93c;
|
||||
--flxn-silver: #a9b0ba;
|
||||
--flxn-bronze: #cd8a4c;
|
||||
--flxn-toast-success: #6fca75;
|
||||
--flxn-toast-error: #ef8078;
|
||||
--flxn-podium-1-bg: linear-gradient(180deg, #4d3f1c 0%, #3a3016 48%, #2c2510 52%, #272009 100%);
|
||||
--flxn-podium-1-border: #7c6425;
|
||||
--flxn-podium-1-label: #ecc65a;
|
||||
--flxn-podium-2-bg: linear-gradient(180deg, #3c3f45 0%, #2f3237 48%, #26282c 52%, #222428 100%);
|
||||
--flxn-podium-2-border: #5c6069;
|
||||
--flxn-podium-2-label: #bcc2cb;
|
||||
--flxn-podium-3-bg: linear-gradient(180deg, #46311c 0%, #372613 48%, #2a1d0d 52%, #251a09 100%);
|
||||
--flxn-podium-3-border: #7a5528;
|
||||
--flxn-podium-3-label: #dc9c5c;
|
||||
--flxn-showcase-bg: linear-gradient(180deg, #26282c 0%, #1d1f22 100%);
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.55);
|
||||
--flxn-dotgrid-color: #33363b;
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* Light scheme only: Mantine pins --mantine-primary-color-contrast to white
|
||||
(no JS autoContrast), unreadable on the light shade-6 fills (yellow,
|
||||
orange, lime, green). Recompute from the fill's lightness — dark-scheme
|
||||
shade-8 fills all carry white fine and keep the default. */
|
||||
@supports (color: oklch(from red calc((0.5 - l) * infinity) 0 h)) {
|
||||
[data-theme="skeuo"][data-theme][data-mantine-color-scheme="light"] {
|
||||
--mantine-primary-color-contrast: oklch(
|
||||
from var(--mantine-primary-color-filled) calc((0.59 - l) * infinity) 0 h
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Body texture (linen / leather grain) ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] body {
|
||||
background-color: var(--mantine-color-body);
|
||||
background-image: var(--skeuo-noise),
|
||||
repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px 3px),
|
||||
repeating-linear-gradient(90deg, rgba(66, 56, 40, 0.025) 0 1px, transparent 1px 3px);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] body {
|
||||
background-color: var(--mantine-color-body);
|
||||
background-image: var(--skeuo-noise),
|
||||
radial-gradient(130% 80% at 50% 0%, rgba(255, 255, 255, 0.035), transparent 60%);
|
||||
}
|
||||
|
||||
/* ---------- Typography: embossed / debossed labels ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Title-root {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Title-root {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.7);
|
||||
}
|
||||
|
||||
/* ---------- Buttons & ActionIcons: machined pills ---------- */
|
||||
|
||||
[data-theme="skeuo"] .mantine-Button-root,
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
||||
/* default variant — bare aluminum */
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-ActionIcon-root[data-variant="default"] {
|
||||
background-color: #e3dfd2;
|
||||
background-image: linear-gradient(180deg, #fdfcf8 0%, #ece8dc 48%, #dcd7c8 52%, #d0cabb 100%);
|
||||
border-color: #9d947f;
|
||||
color: #3b362e;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
|
||||
inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 2px rgba(46, 41, 33, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Button-root[data-variant="default"]:hover,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-ActionIcon-root[data-variant="default"]:hover {
|
||||
background-image: linear-gradient(180deg, #fffefb 0%, #f2eee3 48%, #e3decf 52%, #d8d2c3 100%);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-ActionIcon-root[data-variant="default"] {
|
||||
background-color: #2b2d31;
|
||||
background-image: linear-gradient(180deg, #40434a 0%, #303338 48%, #26282c 52%, #202226 100%);
|
||||
border-color: #0d0e10;
|
||||
color: #d5d2ca;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.6);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12),
|
||||
inset 0 -1px 0 rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Button-root[data-variant="default"]:hover,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-ActionIcon-root[data-variant="default"]:hover {
|
||||
background-image: linear-gradient(180deg, #474a52 0%, #363940 48%, #2b2d32 52%, #24262b 100%);
|
||||
}
|
||||
|
||||
/* filled variant — glossy accent metal (keeps the user's accent) */
|
||||
[data-theme="skeuo"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root[data-variant="filled"] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 62%, white) 0%,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 92%, white) 48%,
|
||||
var(--mantine-primary-color-filled) 52%,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 82%, black) 100%
|
||||
);
|
||||
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 55%, black);
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.35);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45),
|
||||
inset 0 -1px 0 rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
/* prop-less Button/ActionIcon default to the filled variant without a
|
||||
data-variant attribute — give them the same on-color */
|
||||
[data-theme="skeuo"] .mantine-Button-root:not([data-variant]),
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root:not([data-variant]) {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Button-root[data-variant="filled"]:hover,
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root[data-variant="filled"]:hover {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 52%, white) 0%,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 84%, white) 48%,
|
||||
var(--mantine-primary-color-filled) 52%,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 78%, black) 100%
|
||||
);
|
||||
}
|
||||
|
||||
/* light / subtle / outline — etched into the surface */
|
||||
[data-theme="skeuo"] .mantine-Button-root[data-variant="light"],
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root[data-variant="light"] {
|
||||
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 35%, transparent);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Button-root[data-variant="outline"],
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root[data-variant="outline"] {
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1),
|
||||
inset 0 -1px 0 rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Button-root[data-variant="subtle"],
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root[data-variant="subtle"],
|
||||
[data-theme="skeuo"] .mantine-Button-root[data-variant="transparent"],
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root[data-variant="transparent"] {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
/* pressed — inverted gradient + sunk-in inset */
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Button-root[data-variant="default"]:active,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-ActionIcon-root[data-variant="default"]:active {
|
||||
background-image: linear-gradient(180deg, #c8c2b1 0%, #d5d0c0 48%, #e4e0d3 52%, #efece2 100%);
|
||||
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.28),
|
||||
inset 0 1px 2px rgba(0, 0, 0, 0.22), 0 1px 0 rgba(255, 255, 255, 0.6);
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Button-root[data-variant="default"]:active,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-ActionIcon-root[data-variant="default"]:active {
|
||||
background-image: linear-gradient(180deg, #17181b 0%, #202226 48%, #2b2d32 52%, #34363c 100%);
|
||||
box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.65),
|
||||
0 1px 0 rgba(255, 255, 255, 0.06);
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Button-root[data-variant="filled"]:active,
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root[data-variant="filled"]:active {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 75%, black) 0%,
|
||||
var(--mantine-primary-color-filled) 52%,
|
||||
color-mix(in srgb, var(--mantine-primary-color-filled) 85%, white) 100%
|
||||
);
|
||||
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.4);
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Button-root:disabled,
|
||||
[data-theme="skeuo"] .mantine-Button-root[data-disabled],
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root:disabled,
|
||||
[data-theme="skeuo"] .mantine-ActionIcon-root[data-disabled] {
|
||||
background-image: none;
|
||||
box-shadow: none;
|
||||
text-shadow: none;
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
/* press feedback stays subtle — machined buttons sink, not shrink */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="skeuo"] .flxn-press:active {
|
||||
transform: scale(0.98) translateY(1px);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- Inputs: deeply inset wells ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Input-input {
|
||||
background-color: #fbfaf5;
|
||||
background-image: linear-gradient(180deg, #efece2 0%, #f8f6ef 18%, #fdfcf8 100%);
|
||||
border: 1px solid #a1977f;
|
||||
border-radius: var(--mantine-radius-md);
|
||||
color: var(--mantine-color-text);
|
||||
box-shadow: inset 0 1px 3px rgba(46, 41, 33, 0.24),
|
||||
inset 0 2px 6px rgba(46, 41, 33, 0.08), 0 1px 0 rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Input-input {
|
||||
background-color: #121316;
|
||||
background-image: linear-gradient(180deg, #0c0d0f 0%, #121316 25%, #17181c 100%);
|
||||
border: 1px solid #0a0b0c;
|
||||
border-radius: var(--mantine-radius-md);
|
||||
color: var(--mantine-color-text);
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.65),
|
||||
inset 0 2px 8px rgba(0, 0, 0, 0.3), 0 1px 0 rgba(255, 255, 255, 0.07);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Input-input:focus,
|
||||
[data-theme="skeuo"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
outline: none;
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.25),
|
||||
0 0 0 3px color-mix(in srgb, var(--mantine-primary-color-filled) 30%, transparent);
|
||||
}
|
||||
|
||||
/* ---------- Panels: Paper, Card, dropdowns, Modal ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Paper-root,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Card-root,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Popover-dropdown,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Modal-content {
|
||||
background-color: #f6f3ec;
|
||||
background-image: linear-gradient(180deg, #fcfbf7 0%, #f1eee5 100%);
|
||||
border: 1px solid #c2bbaa;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Paper-root,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Card-root,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Popover-dropdown,
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Modal-content {
|
||||
background-color: #222428;
|
||||
background-image: linear-gradient(180deg, #27292e 0%, #1e2023 100%);
|
||||
border: 1px solid #0d0e10;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Paper-root,
|
||||
[data-theme="skeuo"] .mantine-Card-root {
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Modal-content {
|
||||
box-shadow: var(--mantine-shadow-xl);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Modal-header {
|
||||
background-color: #d5dae0;
|
||||
background-image: var(--skeuo-brush),
|
||||
linear-gradient(180deg, #f2f4f6 0%, #d9dde2 48%, #c2c8cf 52%, #ced3da 100%);
|
||||
border-bottom: 1px solid #8f97a1;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Modal-header {
|
||||
background-color: #2b2d31;
|
||||
background-image: var(--skeuo-brush),
|
||||
linear-gradient(180deg, #3c3f45 0%, #2c2e33 48%, #222428 52%, #26282c 100%);
|
||||
border-bottom: 1px solid #0a0b0c;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
/* ---------- AppShell: brushed-metal header, machined dock ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-AppShell-header {
|
||||
background-color: #b7bdc5;
|
||||
background-image: var(--skeuo-noise), var(--skeuo-brush),
|
||||
linear-gradient(180deg, #f4f6f8 0%, #d3d8de 45%, #b3bac3 50%, #a9b0ba 96%, #99a1ab 100%);
|
||||
border-bottom: 1px solid #6f7681;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.75),
|
||||
0 1px 0 rgba(255, 255, 255, 0.25), 0 2px 8px rgba(46, 41, 33, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-AppShell-header .mantine-Title-root {
|
||||
color: #2e333a;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-AppShell-header {
|
||||
background-color: #26282c;
|
||||
background-image: var(--skeuo-noise), var(--skeuo-brush),
|
||||
linear-gradient(180deg, #3e4147 0%, #2c2e33 45%, #212327 50%, #1d1f22 100%);
|
||||
border-bottom: 1px solid #0a0b0c;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14),
|
||||
0 2px 10px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-AppShell-header .mantine-Title-root {
|
||||
color: #e9e6df;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-AppShell-navbar {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-AppShell-navbar {
|
||||
background-image: linear-gradient(90deg, #e3dfd3 0%, #ece8dd 100%);
|
||||
border-right: 1px solid #b3ab99;
|
||||
box-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-AppShell-navbar {
|
||||
background-image: linear-gradient(90deg, #1d1f22 0%, #222428 100%);
|
||||
border-right: 1px solid #0d0e10;
|
||||
box-shadow: inset -1px 0 0 rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
/* mobile bottom dock (Paper nav) — polished metal slab */
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] nav[role="navigation"].mantine-Paper-root {
|
||||
background-color: #d9dde2;
|
||||
background-image: var(--skeuo-brush),
|
||||
linear-gradient(180deg, #f3f5f7 0%, #d8dce1 48%, #c3c9d0 52%, #cdd2d9 100%);
|
||||
border: 1px solid #868e98;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8),
|
||||
0 4px 10px rgba(46, 41, 33, 0.28), 0 10px 24px rgba(46, 41, 33, 0.18);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] nav[role="navigation"].mantine-Paper-root {
|
||||
background-color: #26282c;
|
||||
background-image: var(--skeuo-brush),
|
||||
linear-gradient(180deg, #393c42 0%, #2a2c30 48%, #202226 52%, #24262a 100%);
|
||||
border: 1px solid #0a0b0c;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12),
|
||||
0 4px 12px rgba(0, 0, 0, 0.55), 0 12px 28px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
/* ---------- Tabs & SegmentedControl: machined switches ---------- */
|
||||
|
||||
[data-theme="skeuo"] .mantine-Tabs-list {
|
||||
--tabs-list-border-size: 1px;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Tabs-tab:where([data-active]) {
|
||||
box-shadow: inset 0 1px 3px rgba(46, 41, 33, 0.12);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-SegmentedControl-root {
|
||||
background-color: #d3cec0;
|
||||
background-image: linear-gradient(180deg, #c8c2b2 0%, #d6d1c3 30%, #dedacd 100%);
|
||||
border: 1px solid #a1977f;
|
||||
border-radius: 100px;
|
||||
box-shadow: inset 0 1px 3px rgba(46, 41, 33, 0.25),
|
||||
0 1px 0 rgba(255, 255, 255, 0.65);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-SegmentedControl-root {
|
||||
background-color: #141518;
|
||||
background-image: linear-gradient(180deg, #0e0f11 0%, #16171a 40%, #1b1c20 100%);
|
||||
border: 1px solid #0a0b0c;
|
||||
border-radius: 100px;
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6),
|
||||
0 1px 0 rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-SegmentedControl-indicator {
|
||||
background-color: #f4f1e9;
|
||||
background-image: linear-gradient(180deg, #fdfcf8 0%, #efebe0 48%, #e0dbcc 52%, #d8d2c3 100%);
|
||||
border: 1px solid #998f7a;
|
||||
border-radius: 100px;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
|
||||
0 1px 3px rgba(46, 41, 33, 0.35);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-SegmentedControl-indicator {
|
||||
background-color: #34363c;
|
||||
background-image: linear-gradient(180deg, #45484f 0%, #34373c 48%, #2a2c31 52%, #26282c 100%);
|
||||
border: 1px solid #0d0e10;
|
||||
border-radius: 100px;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14),
|
||||
0 1px 3px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-SegmentedControl-label {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-SegmentedControl-label {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
/* ---------- App hooks: tab strip, nav tiles, see-all, match card ---------- */
|
||||
|
||||
/* tab strip — flat while resting; docked = brushed band, same alloy as
|
||||
the header */
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .flxn-tabs[data-stuck] {
|
||||
background-color: #ccd1d8;
|
||||
background-image: var(--skeuo-brush),
|
||||
linear-gradient(180deg, #eef0f3 0%, #d3d8de 48%, #bfc5cd 52%, #c8cdd4 100%);
|
||||
border-bottom-color: #868e98;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .flxn-tabs[data-stuck] {
|
||||
background-color: #26282c;
|
||||
background-image: var(--skeuo-brush),
|
||||
linear-gradient(180deg, #35383e 0%, #292b2f 48%, #202226 52%, #24262a 100%);
|
||||
border-bottom-color: #0a0b0c;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .flxn-tab {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .flxn-tab {
|
||||
color: #4d5560;
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .flxn-tab {
|
||||
color: #94918a;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
/* active tab — accent-tinted engraving ink; the pressed-well chrome only
|
||||
appears when the strip is DOCKED (resting strip stays flat paper) */
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .flxn-tab[data-active] {
|
||||
/* ≥4.5:1 over both the page and the brushed strip for all eight accents */
|
||||
color: color-mix(in srgb, var(--mantine-primary-color-filled) 45%, black);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .flxn-tab[data-active] {
|
||||
color: color-mix(in srgb, var(--mantine-primary-color-filled) 50%, white);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"]
|
||||
.flxn-tabs[data-stuck]
|
||||
.flxn-tab[data-active] {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(46, 41, 33, 0.12) 0%,
|
||||
rgba(46, 41, 33, 0.03) 40%,
|
||||
rgba(255, 255, 255, 0.14) 100%
|
||||
);
|
||||
box-shadow: inset 0 2px 4px rgba(46, 41, 33, 0.22);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"]
|
||||
.flxn-tabs[data-stuck]
|
||||
.flxn-tab[data-active] {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 0.35) 0%,
|
||||
rgba(0, 0, 0, 0.1) 40%,
|
||||
rgba(255, 255, 255, 0.04) 100%
|
||||
);
|
||||
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
/* indicator — plain accent underline, no glow */
|
||||
[data-theme="skeuo"] .flxn-tabs-indicator {
|
||||
border-bottom: 3px solid var(--mantine-primary-color-filled);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* nav grid tiles — raised machined slabs, pressed state sinks */
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .flxn-tile {
|
||||
background-color: #eeebe0;
|
||||
background-image: linear-gradient(180deg, #fdfcf8 0%, #f0ede2 48%, #e2ddce 52%, #d8d2c3 100%);
|
||||
border: 1px solid #9d947f;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85),
|
||||
inset 0 -1px 0 rgba(0, 0, 0, 0.08), 0 1px 2px rgba(46, 41, 33, 0.22),
|
||||
0 4px 10px rgba(46, 41, 33, 0.12);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .flxn-tile {
|
||||
background-color: #2b2d31;
|
||||
background-image: linear-gradient(180deg, #3d4046 0%, #2e3035 48%, #25272b 52%, #202226 100%);
|
||||
border: 1px solid #0d0e10;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12),
|
||||
inset 0 -1px 0 rgba(0, 0, 0, 0.4), 0 1px 2px rgba(0, 0, 0, 0.5),
|
||||
0 4px 12px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .flxn-tile:active {
|
||||
background-image: linear-gradient(180deg, #c8c2b1 0%, #d5d0c0 48%, #e4e0d3 52%, #efece2 100%);
|
||||
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.26),
|
||||
0 1px 0 rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .flxn-tile:active {
|
||||
background-image: linear-gradient(180deg, #17181b 0%, #202226 48%, #2b2d32 52%, #34363c 100%);
|
||||
box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.65),
|
||||
0 1px 0 rgba(255, 255, 255, 0.06);
|
||||
}
|
||||
|
||||
/* tile icon — flat anodized tint */
|
||||
[data-theme="skeuo"] .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* see-all — small glossy accent pill. Base fill stays primary-filled under
|
||||
contrast text; the gloss is a translucent overlay so it never shifts the
|
||||
fill toward the text color. */
|
||||
[data-theme="skeuo"] .flxn-see-all {
|
||||
border-radius: 100px;
|
||||
border: 1px solid color-mix(in srgb, var(--mantine-primary-color-filled) 50%, black);
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.28) 0%,
|
||||
rgba(255, 255, 255, 0.08) 48%,
|
||||
rgba(255, 255, 255, 0) 52%,
|
||||
rgba(0, 0, 0, 0.16) 100%
|
||||
);
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45),
|
||||
0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="skeuo"] .flxn-see-all:hover {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.36) 0%,
|
||||
rgba(255, 255, 255, 0.14) 48%,
|
||||
rgba(255, 255, 255, 0.05) 52%,
|
||||
rgba(0, 0, 0, 0.12) 100%
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/* match card raised, reaction tray recessed as an inset well beneath it */
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .flxn-match-card {
|
||||
background-color: #f6f3ec;
|
||||
background-image: linear-gradient(180deg, #fcfbf7 0%, #f1eee5 100%);
|
||||
border: 1px solid #c2bbaa;
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .flxn-match-card {
|
||||
background-color: #222428;
|
||||
background-image: linear-gradient(180deg, #27292e 0%, #1e2023 100%);
|
||||
border: 1px solid #0d0e10;
|
||||
box-shadow: var(--mantine-shadow-sm);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .flxn-reaction-row {
|
||||
background-color: #ddd7c8;
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(46, 41, 33, 0.14) 0%,
|
||||
rgba(46, 41, 33, 0.03) 45%,
|
||||
rgba(255, 255, 255, 0.25) 100%
|
||||
);
|
||||
border: 1px solid #c2bbaa;
|
||||
box-shadow: inset 0 2px 4px rgba(46, 41, 33, 0.18),
|
||||
0 1px 0 rgba(255, 255, 255, 0.55);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .flxn-reaction-row {
|
||||
background-color: #17181b;
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(0, 0, 0, 0.45) 0%,
|
||||
rgba(0, 0, 0, 0.1) 45%,
|
||||
rgba(255, 255, 255, 0.04) 100%
|
||||
);
|
||||
border: 1px solid #0d0e10;
|
||||
box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.55),
|
||||
0 1px 0 rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
/* ---------- Badges: glossy enamel pills ---------- */
|
||||
|
||||
[data-theme="skeuo"] .mantine-Badge-root {
|
||||
border: 1px solid rgba(0, 0, 0, 0.28);
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.4) 0%,
|
||||
rgba(255, 255, 255, 0.12) 48%,
|
||||
rgba(0, 0, 0, 0.06) 52%,
|
||||
rgba(0, 0, 0, 0.16) 100%
|
||||
);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35),
|
||||
0 1px 2px rgba(0, 0, 0, 0.25);
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* accent-fill on-colors (Mantine hardcodes white on filled variants,
|
||||
selected combobox options and check glyphs) */
|
||||
[data-theme="skeuo"] .mantine-Badge-root[data-variant="filled"],
|
||||
[data-theme="skeuo"] .mantine-Badge-root:not([data-variant]),
|
||||
[data-theme="skeuo"] .mantine-ThemeIcon-root[data-variant="filled"],
|
||||
[data-theme="skeuo"] .mantine-ThemeIcon-root:not([data-variant]) {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
[data-theme="skeuo"] [data-combobox-selected] {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
[data-theme="skeuo"] .mantine-Checkbox-root {
|
||||
--checkbox-icon-color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
[data-theme="skeuo"] .mantine-Radio-root {
|
||||
--radio-icon-color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
/* ---------- Toasts: glossy pills ---------- */
|
||||
|
||||
[data-theme="skeuo"] .mantine-Notification-root {
|
||||
border-radius: 100px;
|
||||
padding-block: 0.5rem;
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Notification-root {
|
||||
background-color: #f8f6f0;
|
||||
background-image: linear-gradient(180deg, #fefdfb 0%, #f4f1e9 48%, #e9e5d8 52%, #efece2 100%);
|
||||
border: 1px solid #a99f8c;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
|
||||
0 3px 8px rgba(46, 41, 33, 0.28), 0 10px 24px rgba(46, 41, 33, 0.18);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Notification-root {
|
||||
background-color: #2b2d31;
|
||||
background-image: linear-gradient(180deg, #3b3e44 0%, #2c2e33 48%, #232529 52%, #27292d 100%);
|
||||
border: 1px solid #0a0b0c;
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12),
|
||||
0 3px 10px rgba(0, 0, 0, 0.55), 0 12px 28px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
/* ---------- Switch: chrome knob in a well ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Switch-track {
|
||||
border: 1px solid #968c77;
|
||||
background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.18) 0%, rgba(0, 0, 0, 0.04) 40%, rgba(255, 255, 255, 0.1) 100%);
|
||||
box-shadow: inset 0 1px 3px rgba(46, 41, 33, 0.3);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Switch-track {
|
||||
border: 1px solid #0a0b0c;
|
||||
background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.45) 0%, rgba(0, 0, 0, 0.1) 40%, rgba(255, 255, 255, 0.05) 100%);
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Switch-thumb {
|
||||
border: 1px solid rgba(0, 0, 0, 0.4);
|
||||
background-color: #f2f2f0;
|
||||
background-image: linear-gradient(180deg, #ffffff 0%, #e8e8e4 48%, #d4d4ce 52%, #dededa 100%);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9),
|
||||
0 1px 3px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
/* ---------- Checkbox / Radio: inset wells, glossy when checked ---------- */
|
||||
|
||||
[data-theme="skeuo"] .mantine-Checkbox-input,
|
||||
[data-theme="skeuo"] .mantine-Radio-radio {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Checkbox-input:checked,
|
||||
[data-theme="skeuo"] .mantine-Radio-radio:checked {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.35) 0%,
|
||||
rgba(255, 255, 255, 0.08) 48%,
|
||||
rgba(0, 0, 0, 0.1) 52%,
|
||||
rgba(0, 0, 0, 0.2) 100%
|
||||
);
|
||||
border-color: color-mix(in srgb, var(--mantine-primary-color-filled) 60%, black);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35),
|
||||
0 1px 2px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
/* ---------- Progress: candy bar in a machined groove ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Progress-root {
|
||||
background-color: #cfc9ba;
|
||||
background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.14), transparent 60%);
|
||||
border: 1px solid #a1977f;
|
||||
box-shadow: inset 0 1px 3px rgba(46, 41, 33, 0.28);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Progress-root {
|
||||
background-color: #121316;
|
||||
background-image: linear-gradient(180deg, rgba(0, 0, 0, 0.5), transparent 60%);
|
||||
border: 1px solid #0a0b0c;
|
||||
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Progress-section {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.45) 0%,
|
||||
rgba(255, 255, 255, 0.12) 48%,
|
||||
rgba(0, 0, 0, 0.08) 52%,
|
||||
rgba(0, 0, 0, 0.18) 100%
|
||||
);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
|
||||
/* ---------- Misc: dividers, tooltips, avatars, alerts, skeleton ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Divider-root {
|
||||
--divider-color: #c4bcab;
|
||||
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.65);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-Divider-root {
|
||||
--divider-color: #0f1012;
|
||||
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Tooltip-tooltip {
|
||||
background-color: #26282c;
|
||||
background-image: linear-gradient(180deg, #3a3d43 0%, #26282c 55%, #1e2023 100%);
|
||||
color: #ece9e2;
|
||||
border: 1px solid #0d0e10;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.6);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12),
|
||||
0 2px 6px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
/* polished bezel: dark rim + inner highlight ring */
|
||||
[data-theme="skeuo"] .mantine-ThemeIcon-root {
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35),
|
||||
inset 0 0 0 1px rgba(255, 255, 255, 0.18),
|
||||
0 1px 2px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
/* avatar bezel lives on the frame; the metal rim is --flxn-avatar-border */
|
||||
[data-theme="skeuo"] .flxn-avatar-frame {
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35),
|
||||
inset 0 0 0 1px rgba(255, 255, 255, 0.18),
|
||||
0 1px 2px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-ThemeIcon-root[data-variant="filled"] {
|
||||
background-image: linear-gradient(
|
||||
180deg,
|
||||
rgba(255, 255, 255, 0.35) 0%,
|
||||
rgba(255, 255, 255, 0.08) 48%,
|
||||
rgba(0, 0, 0, 0.08) 52%,
|
||||
rgba(0, 0, 0, 0.18) 100%
|
||||
);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"] .mantine-Alert-root {
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25),
|
||||
0 1px 3px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-Skeleton-root::after {
|
||||
background-color: #ddd8ca;
|
||||
}
|
||||
|
||||
/* ---------- PinInput inherits Input wells; keep digits engraved ---------- */
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="light"] .mantine-PinInput-field {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
[data-theme="skeuo"][data-mantine-color-scheme="dark"] .mantine-PinInput-field {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Aggregates all theme CSS. Import once from the client provider tree only —
|
||||
// never from server-fn modules.
|
||||
// The glob stays in theme-styles.ts: Vite hoists eager-glob imports above a
|
||||
// module's own static imports, which would load theme CSS before base/hooks.
|
||||
import "./base.css";
|
||||
import "./hooks.css";
|
||||
import "./theme-styles";
|
||||
@@ -0,0 +1,19 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "terminal",
|
||||
label: msg`Terminal`,
|
||||
colorSchemes: "dark",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
dark: { base: "#050805", dimmed: "#020402" },
|
||||
},
|
||||
mantine: {
|
||||
defaultRadius: 0,
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,599 @@
|
||||
/* CRT Terminal — phosphor monochrome in the user's accent hue, dark only.
|
||||
The accent picks the tube: green = classic CRT, orange = amber terminal,
|
||||
blue = blue phosphor, etc. Error stays red-phosphor. */
|
||||
|
||||
/* 1. Tokens, any scheme */
|
||||
[data-theme="terminal"][data-theme] {
|
||||
--mantine-font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
--mantine-font-family-headings: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
--mantine-font-family-monospace: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
--mantine-heading-font-weight: 600;
|
||||
|
||||
--mantine-radius-default: 0;
|
||||
--mantine-radius-xs: 0;
|
||||
--mantine-radius-sm: 0;
|
||||
--mantine-radius-md: 0;
|
||||
--mantine-radius-lg: 0;
|
||||
--mantine-radius-xl: 0;
|
||||
--flxn-avatar-radius: 0;
|
||||
--flxn-avatar-border: 1px solid var(--mantine-primary-color-6);
|
||||
--flxn-badge-radius: 0;
|
||||
|
||||
/* flat / glow elevation — no soft shadows (sm is preview-contract: neutral) */
|
||||
--mantine-shadow-xs: 0 0 0 1px color-mix(in srgb, var(--mantine-primary-color-5) 12%, transparent);
|
||||
--mantine-shadow-sm: 0 0 0 1px rgba(200, 212, 200, 0.15);
|
||||
--mantine-shadow-md: 0 0 0 1px color-mix(in srgb, var(--mantine-primary-color-5) 20%, transparent),
|
||||
0 0 12px color-mix(in srgb, var(--mantine-primary-color-5) 12%, transparent);
|
||||
--mantine-shadow-lg: 0 0 0 1px color-mix(in srgb, var(--mantine-primary-color-5) 25%, transparent),
|
||||
0 0 18px color-mix(in srgb, var(--mantine-primary-color-5) 15%, transparent);
|
||||
--mantine-shadow-xl: 0 0 0 1px color-mix(in srgb, var(--mantine-primary-color-5) 30%, transparent),
|
||||
0 0 26px color-mix(in srgb, var(--mantine-primary-color-5) 18%, transparent);
|
||||
|
||||
/* eight phosphor ramps — bright tube core at 4-5, dim glass below */
|
||||
--mantine-color-green-0: #eaffea;
|
||||
--mantine-color-green-1: #ccffcc;
|
||||
--mantine-color-green-2: #a8ffa8;
|
||||
--mantine-color-green-3: #7dff7d;
|
||||
--mantine-color-green-4: #55ff55;
|
||||
--mantine-color-green-5: #33ff33;
|
||||
--mantine-color-green-6: #21d621;
|
||||
--mantine-color-green-7: #17a317;
|
||||
--mantine-color-green-8: #0e700e;
|
||||
--mantine-color-green-9: #084008;
|
||||
|
||||
--mantine-color-red-0: #ffeaea;
|
||||
--mantine-color-red-1: #ffcccc;
|
||||
--mantine-color-red-2: #ffa8a8;
|
||||
--mantine-color-red-3: #ff7d7d;
|
||||
--mantine-color-red-4: #ff5555;
|
||||
--mantine-color-red-5: #ff3333;
|
||||
--mantine-color-red-6: #d62121;
|
||||
--mantine-color-red-7: #a31717;
|
||||
--mantine-color-red-8: #700e0e;
|
||||
--mantine-color-red-9: #400808;
|
||||
|
||||
--mantine-color-blue-0: #eaf4ff;
|
||||
--mantine-color-blue-1: #cce6ff;
|
||||
--mantine-color-blue-2: #a8d5ff;
|
||||
--mantine-color-blue-3: #7dc1ff;
|
||||
--mantine-color-blue-4: #55aeff;
|
||||
--mantine-color-blue-5: #339cff;
|
||||
--mantine-color-blue-6: #217fd6;
|
||||
--mantine-color-blue-7: #1760a3;
|
||||
--mantine-color-blue-8: #0e4170;
|
||||
--mantine-color-blue-9: #082440;
|
||||
|
||||
--mantine-color-yellow-0: #fffbea;
|
||||
--mantine-color-yellow-1: #fff6cc;
|
||||
--mantine-color-yellow-2: #fff0a8;
|
||||
--mantine-color-yellow-3: #ffe97d;
|
||||
--mantine-color-yellow-4: #ffe255;
|
||||
--mantine-color-yellow-5: #ffdb33;
|
||||
--mantine-color-yellow-6: #d6b421;
|
||||
--mantine-color-yellow-7: #a38817;
|
||||
--mantine-color-yellow-8: #705d0e;
|
||||
--mantine-color-yellow-9: #403408;
|
||||
|
||||
--mantine-color-orange-0: #fff5e0;
|
||||
--mantine-color-orange-1: #ffeab8;
|
||||
--mantine-color-orange-2: #ffdd85;
|
||||
--mantine-color-orange-3: #ffcf5c;
|
||||
--mantine-color-orange-4: #ffc133;
|
||||
--mantine-color-orange-5: #ffb000;
|
||||
--mantine-color-orange-6: #d69200;
|
||||
--mantine-color-orange-7: #a37000;
|
||||
--mantine-color-orange-8: #704d00;
|
||||
--mantine-color-orange-9: #402c00;
|
||||
|
||||
--mantine-color-grape-0: #f6eaff;
|
||||
--mantine-color-grape-1: #eaccff;
|
||||
--mantine-color-grape-2: #dba8ff;
|
||||
--mantine-color-grape-3: #c97dff;
|
||||
--mantine-color-grape-4: #b855ff;
|
||||
--mantine-color-grape-5: #a833ff;
|
||||
--mantine-color-grape-6: #8c21d6;
|
||||
--mantine-color-grape-7: #6a17a3;
|
||||
--mantine-color-grape-8: #490e70;
|
||||
--mantine-color-grape-9: #290840;
|
||||
|
||||
--mantine-color-pink-0: #ffeaf6;
|
||||
--mantine-color-pink-1: #ffccea;
|
||||
--mantine-color-pink-2: #ffa8db;
|
||||
--mantine-color-pink-3: #ff7dc9;
|
||||
--mantine-color-pink-4: #ff55b8;
|
||||
--mantine-color-pink-5: #ff33a8;
|
||||
--mantine-color-pink-6: #d6218c;
|
||||
--mantine-color-pink-7: #a3176a;
|
||||
--mantine-color-pink-8: #700e49;
|
||||
--mantine-color-pink-9: #400829;
|
||||
|
||||
--mantine-color-lime-0: #f6ffea;
|
||||
--mantine-color-lime-1: #eaffcc;
|
||||
--mantine-color-lime-2: #dbffa8;
|
||||
--mantine-color-lime-3: #c9ff7d;
|
||||
--mantine-color-lime-4: #b8ff55;
|
||||
--mantine-color-lime-5: #a8ff33;
|
||||
--mantine-color-lime-6: #8cd621;
|
||||
--mantine-color-lime-7: #6aa317;
|
||||
--mantine-color-lime-8: #49700e;
|
||||
--mantine-color-lime-9: #294008;
|
||||
|
||||
/* preview contract (neutral-phosphor; mirrored in scheme block below) */
|
||||
--mantine-color-body: #050505;
|
||||
--mantine-color-text: #c8d4c8;
|
||||
--mantine-color-dimmed: #7c887c;
|
||||
--mantine-color-default-border: #333a33;
|
||||
}
|
||||
|
||||
/* 2. Scheme tokens (engine forces dark) */
|
||||
[data-theme="terminal"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
--mantine-color-body: #050505;
|
||||
--mantine-color-text: #c8d4c8;
|
||||
--mantine-color-bright: #e8efe8;
|
||||
--mantine-color-dimmed: #7c887c;
|
||||
--mantine-color-anchor: var(--mantine-primary-color-3);
|
||||
--mantine-color-placeholder: #5a655a;
|
||||
--mantine-color-error: #ff5c5c;
|
||||
--mantine-color-default: #0b0d0b;
|
||||
--mantine-color-default-hover: #141714;
|
||||
--mantine-color-default-color: #c8d4c8;
|
||||
--mantine-color-default-border: #333a33;
|
||||
|
||||
/* per-color variant vars, phosphor-tuned (beat Mantine's :root[scheme]) */
|
||||
--mantine-color-green-filled: var(--mantine-color-green-5);
|
||||
--mantine-color-green-filled-hover: var(--mantine-color-green-4);
|
||||
--mantine-color-green-light: color-mix(in srgb, var(--mantine-color-green-5) 12%, transparent);
|
||||
--mantine-color-green-light-hover: color-mix(in srgb, var(--mantine-color-green-5) 20%, transparent);
|
||||
--mantine-color-green-light-color: var(--mantine-color-green-4);
|
||||
--mantine-color-green-outline: var(--mantine-color-green-5);
|
||||
--mantine-color-green-outline-hover: color-mix(in srgb, var(--mantine-color-green-5) 12%, transparent);
|
||||
--mantine-color-green-text: var(--mantine-color-green-4);
|
||||
|
||||
--mantine-color-red-filled: var(--mantine-color-red-5);
|
||||
--mantine-color-red-filled-hover: var(--mantine-color-red-4);
|
||||
--mantine-color-red-light: color-mix(in srgb, var(--mantine-color-red-5) 12%, transparent);
|
||||
--mantine-color-red-light-hover: color-mix(in srgb, var(--mantine-color-red-5) 20%, transparent);
|
||||
--mantine-color-red-light-color: var(--mantine-color-red-4);
|
||||
--mantine-color-red-outline: var(--mantine-color-red-5);
|
||||
--mantine-color-red-outline-hover: color-mix(in srgb, var(--mantine-color-red-5) 12%, transparent);
|
||||
--mantine-color-red-text: var(--mantine-color-red-4);
|
||||
|
||||
--mantine-color-blue-filled: var(--mantine-color-blue-5);
|
||||
--mantine-color-blue-filled-hover: var(--mantine-color-blue-4);
|
||||
--mantine-color-blue-light: color-mix(in srgb, var(--mantine-color-blue-5) 12%, transparent);
|
||||
--mantine-color-blue-light-hover: color-mix(in srgb, var(--mantine-color-blue-5) 20%, transparent);
|
||||
--mantine-color-blue-light-color: var(--mantine-color-blue-4);
|
||||
--mantine-color-blue-outline: var(--mantine-color-blue-5);
|
||||
--mantine-color-blue-outline-hover: color-mix(in srgb, var(--mantine-color-blue-5) 12%, transparent);
|
||||
--mantine-color-blue-text: var(--mantine-color-blue-4);
|
||||
|
||||
--mantine-color-yellow-filled: var(--mantine-color-yellow-5);
|
||||
--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-4);
|
||||
--mantine-color-yellow-light: color-mix(in srgb, var(--mantine-color-yellow-5) 12%, transparent);
|
||||
--mantine-color-yellow-light-hover: color-mix(in srgb, var(--mantine-color-yellow-5) 20%, transparent);
|
||||
--mantine-color-yellow-light-color: var(--mantine-color-yellow-4);
|
||||
--mantine-color-yellow-outline: var(--mantine-color-yellow-5);
|
||||
--mantine-color-yellow-outline-hover: color-mix(in srgb, var(--mantine-color-yellow-5) 12%, transparent);
|
||||
--mantine-color-yellow-text: var(--mantine-color-yellow-4);
|
||||
|
||||
--mantine-color-orange-filled: var(--mantine-color-orange-5);
|
||||
--mantine-color-orange-filled-hover: var(--mantine-color-orange-4);
|
||||
--mantine-color-orange-light: color-mix(in srgb, var(--mantine-color-orange-5) 12%, transparent);
|
||||
--mantine-color-orange-light-hover: color-mix(in srgb, var(--mantine-color-orange-5) 20%, transparent);
|
||||
--mantine-color-orange-light-color: var(--mantine-color-orange-4);
|
||||
--mantine-color-orange-outline: var(--mantine-color-orange-5);
|
||||
--mantine-color-orange-outline-hover: color-mix(in srgb, var(--mantine-color-orange-5) 12%, transparent);
|
||||
--mantine-color-orange-text: var(--mantine-color-orange-4);
|
||||
|
||||
--mantine-color-grape-filled: var(--mantine-color-grape-5);
|
||||
--mantine-color-grape-filled-hover: var(--mantine-color-grape-4);
|
||||
--mantine-color-grape-light: color-mix(in srgb, var(--mantine-color-grape-5) 12%, transparent);
|
||||
--mantine-color-grape-light-hover: color-mix(in srgb, var(--mantine-color-grape-5) 20%, transparent);
|
||||
--mantine-color-grape-light-color: var(--mantine-color-grape-4);
|
||||
--mantine-color-grape-outline: var(--mantine-color-grape-5);
|
||||
--mantine-color-grape-outline-hover: color-mix(in srgb, var(--mantine-color-grape-5) 12%, transparent);
|
||||
--mantine-color-grape-text: var(--mantine-color-grape-4);
|
||||
|
||||
--mantine-color-pink-filled: var(--mantine-color-pink-5);
|
||||
--mantine-color-pink-filled-hover: var(--mantine-color-pink-4);
|
||||
--mantine-color-pink-light: color-mix(in srgb, var(--mantine-color-pink-5) 12%, transparent);
|
||||
--mantine-color-pink-light-hover: color-mix(in srgb, var(--mantine-color-pink-5) 20%, transparent);
|
||||
--mantine-color-pink-light-color: var(--mantine-color-pink-4);
|
||||
--mantine-color-pink-outline: var(--mantine-color-pink-5);
|
||||
--mantine-color-pink-outline-hover: color-mix(in srgb, var(--mantine-color-pink-5) 12%, transparent);
|
||||
--mantine-color-pink-text: var(--mantine-color-pink-4);
|
||||
|
||||
--mantine-color-lime-filled: var(--mantine-color-lime-5);
|
||||
--mantine-color-lime-filled-hover: var(--mantine-color-lime-4);
|
||||
--mantine-color-lime-light: color-mix(in srgb, var(--mantine-color-lime-5) 12%, transparent);
|
||||
--mantine-color-lime-light-hover: color-mix(in srgb, var(--mantine-color-lime-5) 20%, transparent);
|
||||
--mantine-color-lime-light-color: var(--mantine-color-lime-4);
|
||||
--mantine-color-lime-outline: var(--mantine-color-lime-5);
|
||||
--mantine-color-lime-outline-hover: color-mix(in srgb, var(--mantine-color-lime-5) 12%, transparent);
|
||||
--mantine-color-lime-text: var(--mantine-color-lime-4);
|
||||
|
||||
/* app tokens — monochrome ranks in the tube's hue */
|
||||
--flxn-gold: var(--mantine-primary-color-4);
|
||||
--flxn-silver: var(--mantine-primary-color-6);
|
||||
--flxn-bronze: var(--mantine-primary-color-7);
|
||||
--flxn-toast-success: var(--mantine-primary-color-4);
|
||||
--flxn-toast-error: #ff7a7a;
|
||||
--flxn-podium-1-bg: color-mix(in srgb, var(--mantine-primary-color-5) 10%, #050505);
|
||||
--flxn-podium-1-border: var(--mantine-primary-color-5);
|
||||
--flxn-podium-1-label: var(--mantine-primary-color-3);
|
||||
--flxn-podium-2-bg: color-mix(in srgb, var(--mantine-primary-color-5) 6%, #050505);
|
||||
--flxn-podium-2-border: var(--mantine-primary-color-6);
|
||||
--flxn-podium-2-label: var(--mantine-primary-color-5);
|
||||
--flxn-podium-3-bg: color-mix(in srgb, var(--mantine-primary-color-5) 3%, #050505);
|
||||
--flxn-podium-3-border: var(--mantine-primary-color-7);
|
||||
--flxn-podium-3-label: var(--mantine-primary-color-6);
|
||||
--flxn-showcase-bg: color-mix(in srgb, var(--mantine-primary-color-5) 5%, #050505);
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.74);
|
||||
--flxn-dotgrid-color: color-mix(in srgb, var(--mantine-primary-color-5) 15%, transparent);
|
||||
--flxn-pop-shadow: color-mix(in srgb, var(--mantine-primary-color-5) 20%, transparent);
|
||||
}
|
||||
|
||||
/* App-side phosphor text/borders: re-driven from the accent on body so the
|
||||
preview contract above stays neutral (previews render in divs, no body). */
|
||||
[data-theme="terminal"] body {
|
||||
color: var(--mantine-primary-color-4);
|
||||
--mantine-color-text: var(--mantine-primary-color-4);
|
||||
--mantine-color-bright: var(--mantine-primary-color-2);
|
||||
--mantine-color-dimmed: color-mix(in srgb, var(--mantine-primary-color-4) 62%, #050505);
|
||||
--mantine-color-placeholder: color-mix(in srgb, var(--mantine-primary-color-4) 45%, #050505);
|
||||
--mantine-color-default-color: var(--mantine-primary-color-4);
|
||||
--mantine-color-default-border: color-mix(in srgb, var(--mantine-primary-color-5) 55%, #050505);
|
||||
--mantine-primary-color-contrast: #050505;
|
||||
--mantine-shadow-sm: 0 0 0 1px color-mix(in srgb, var(--mantine-primary-color-5) 15%, transparent);
|
||||
}
|
||||
|
||||
/* 3. Component restyles */
|
||||
|
||||
/* selection & focus: inverse video */
|
||||
[data-theme="terminal"] ::selection {
|
||||
background: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
text-shadow: none;
|
||||
}
|
||||
[data-theme="terminal"] :focus-visible {
|
||||
outline: 1px solid var(--mantine-primary-color-4);
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
/* phosphor glow on headings */
|
||||
[data-theme="terminal"] :is(h1, h2, h3, h4, h5, h6),
|
||||
[data-theme="terminal"] .mantine-Title-root {
|
||||
color: var(--mantine-primary-color-4);
|
||||
text-shadow: 0 0 6px color-mix(in srgb, var(--mantine-primary-color-5) 50%, transparent),
|
||||
0 0 18px color-mix(in srgb, var(--mantine-primary-color-5) 20%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="terminal"] a {
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* surfaces: flat panels with 1px phosphor rule */
|
||||
[data-theme="terminal"] .mantine-Paper-root,
|
||||
[data-theme="terminal"] .mantine-Card-root {
|
||||
background-color: color-mix(in srgb, var(--mantine-primary-color-5) 4%, #050505);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="terminal"] .mantine-AppShell-header,
|
||||
[data-theme="terminal"] .mantine-AppShell-navbar {
|
||||
background-color: rgba(5, 5, 5, 0.96);
|
||||
border-color: var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
/* buttons: bracketed bordered blocks */
|
||||
[data-theme="terminal"] .mantine-Button-root {
|
||||
border: 1px solid var(--mantine-primary-color-filled);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
font-weight: 600;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Button-root .mantine-Button-label::before {
|
||||
content: "[ ";
|
||||
opacity: 0.55;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Button-root .mantine-Button-label::after {
|
||||
content: " ]";
|
||||
opacity: 0.55;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="terminal"] .mantine-Button-root[data-variant="outline"],
|
||||
[data-theme="terminal"] .mantine-Button-root[data-variant="light"],
|
||||
[data-theme="terminal"] .mantine-Button-root[data-variant="subtle"] {
|
||||
background-color: transparent;
|
||||
color: var(--mantine-primary-color-4);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Button-root[data-variant="subtle"] {
|
||||
border-color: transparent;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Button-root[data-variant="filled"] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
box-shadow: 0 0 10px color-mix(in srgb, var(--mantine-primary-color-5) 35%, transparent);
|
||||
}
|
||||
@media (hover: hover) {
|
||||
[data-theme="terminal"] .mantine-Button-root:not([data-disabled]):hover {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
text-shadow: none;
|
||||
}
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Button-root[data-disabled] {
|
||||
border-color: color-mix(in srgb, var(--mantine-primary-color-5) 45%, #050505);
|
||||
color: color-mix(in srgb, var(--mantine-primary-color-5) 35%, #050505);
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
[data-theme="terminal"] .mantine-ActionIcon-root {
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-ActionIcon-root[data-variant="filled"] {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-ActionIcon-root[data-variant="subtle"],
|
||||
[data-theme="terminal"] .mantine-ActionIcon-root[data-variant="transparent"] {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
/* inputs: block-cursor terminal fields */
|
||||
[data-theme="terminal"] .mantine-Input-input {
|
||||
background-color: #030303;
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
color: var(--mantine-primary-color-4);
|
||||
caret-color: var(--mantine-primary-color-4);
|
||||
caret-shape: block;
|
||||
font-family: var(--mantine-font-family-monospace);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Input-input:focus,
|
||||
[data-theme="terminal"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: 0 0 8px color-mix(in srgb, var(--mantine-primary-color-5) 35%, transparent);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-InputWrapper-label {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
font-size: 0.72em;
|
||||
color: var(--mantine-color-dimmed);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-PinInput-input {
|
||||
background-color: #030303;
|
||||
border-color: var(--mantine-color-default-border);
|
||||
color: var(--mantine-primary-color-4);
|
||||
}
|
||||
|
||||
/* tabs & segmented control: active = inverse video */
|
||||
[data-theme="terminal"] .mantine-Tabs-list {
|
||||
border-color: var(--mantine-color-default-border);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Tabs-tab {
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Tabs-tab[data-active] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-SegmentedControl-root {
|
||||
background-color: #030303;
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-SegmentedControl-label[data-active] {
|
||||
color: #050505;
|
||||
}
|
||||
|
||||
/* badges, chips, indicators */
|
||||
[data-theme="terminal"] .mantine-Badge-root {
|
||||
background-color: transparent;
|
||||
border: 1px solid var(--mantine-primary-color-6);
|
||||
color: var(--mantine-primary-color-4);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Badge-root[data-variant="filled"] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Indicator-indicator {
|
||||
border: 1px solid #050505;
|
||||
}
|
||||
|
||||
/* overlays */
|
||||
[data-theme="terminal"] .mantine-Modal-content,
|
||||
[data-theme="terminal"] .mantine-Popover-dropdown {
|
||||
background-color: #050505;
|
||||
border: 1px solid var(--mantine-primary-color-filled);
|
||||
box-shadow: 0 0 24px color-mix(in srgb, var(--mantine-primary-color-5) 18%, transparent);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Modal-header {
|
||||
background-color: #050505;
|
||||
border-bottom: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Tooltip-tooltip {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
border-radius: 0;
|
||||
}
|
||||
/* selected option = inverse video (Mantine hardcodes white on the fill) */
|
||||
[data-theme="terminal"] [data-combobox-selected] {
|
||||
color: #050505;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Notification-root {
|
||||
background-color: color-mix(in srgb, var(--mantine-primary-color-5) 4%, #050505);
|
||||
border: 1px solid var(--mantine-primary-color-6);
|
||||
box-shadow: 0 0 14px color-mix(in srgb, var(--mantine-primary-color-5) 18%, transparent);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Alert-root {
|
||||
background-color: color-mix(in srgb, var(--mantine-primary-color-5) 8%, transparent);
|
||||
border: 1px solid var(--mantine-primary-color-6);
|
||||
}
|
||||
|
||||
/* controls */
|
||||
[data-theme="terminal"] .mantine-Switch-track {
|
||||
background-color: #030303;
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Switch-input:checked + .mantine-Switch-track {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Switch-thumb {
|
||||
background-color: var(--mantine-primary-color-6);
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Switch-input:checked + .mantine-Switch-track .mantine-Switch-thumb {
|
||||
background-color: #050505;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Checkbox-input {
|
||||
background-color: #030303;
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Checkbox-input:checked {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Checkbox-icon {
|
||||
color: #050505;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Progress-root {
|
||||
background-color: #0b0d0b;
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Progress-section {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Skeleton-root::before {
|
||||
background-color: #0f110f;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Skeleton-root::after {
|
||||
background-color: #191c19;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-Divider-root {
|
||||
--divider-color: var(--mantine-color-default-border);
|
||||
}
|
||||
|
||||
/* nav */
|
||||
[data-theme="terminal"] .mantine-NavLink-root[data-active] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
}
|
||||
[data-theme="terminal"] .mantine-NavLink-root[data-active] .mantine-NavLink-label,
|
||||
[data-theme="terminal"] .mantine-NavLink-root[data-active] .mantine-NavLink-section {
|
||||
color: #050505;
|
||||
}
|
||||
|
||||
/* theme icons stay in the phosphor family */
|
||||
[data-theme="terminal"] .mantine-ThemeIcon-root {
|
||||
border: 1px solid var(--mantine-primary-color-5);
|
||||
}
|
||||
|
||||
/* app hooks: swipeable tab strip — flat while resting; docked = ruled
|
||||
readout band. Transparent resting top border keeps the strip height
|
||||
stable across the state change. Active = inverse video. */
|
||||
[data-theme="terminal"] .flxn-tabs {
|
||||
border-top: 1px solid transparent;
|
||||
}
|
||||
[data-theme="terminal"] .flxn-tabs[data-stuck] {
|
||||
background-color: var(--mantine-color-body);
|
||||
border-top-color: var(--mantine-color-default-border);
|
||||
border-bottom-color: var(--mantine-color-default-border);
|
||||
}
|
||||
[data-theme="terminal"] .flxn-tab.flxn-tab {
|
||||
color: var(--mantine-color-dimmed);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
font-weight: 500;
|
||||
}
|
||||
[data-theme="terminal"] .flxn-tab.flxn-tab[data-active] {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
font-weight: 600;
|
||||
text-shadow: none;
|
||||
}
|
||||
[data-theme="terminal"] .flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: 2px solid var(--mantine-primary-color-filled);
|
||||
padding-inline: 0;
|
||||
}
|
||||
|
||||
/* app hooks: nav grid tiles as bordered readout boxes */
|
||||
[data-theme="terminal"] .flxn-tile {
|
||||
background-color: color-mix(in srgb, var(--mantine-primary-color-5) 4%, #050505);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="terminal"] .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-4);
|
||||
}
|
||||
|
||||
/* app hooks: "see all" as a bracketed [link] */
|
||||
[data-theme="terminal"] .flxn-see-all.flxn-see-all {
|
||||
background-color: transparent;
|
||||
border-radius: 0;
|
||||
color: var(--mantine-primary-color-4);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
[data-theme="terminal"] .flxn-see-all.flxn-see-all::before {
|
||||
content: "[ ";
|
||||
opacity: 0.55;
|
||||
}
|
||||
[data-theme="terminal"] .flxn-see-all.flxn-see-all::after {
|
||||
content: " ]";
|
||||
opacity: 0.55;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
[data-theme="terminal"] .flxn-see-all.flxn-see-all:hover {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
color: #050505;
|
||||
}
|
||||
}
|
||||
|
||||
/* app hooks: match card + reaction tray read as one bordered construction */
|
||||
[data-theme="terminal"] .flxn-match-card {
|
||||
background-color: color-mix(in srgb, var(--mantine-primary-color-5) 4%, #050505);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
box-shadow: none;
|
||||
}
|
||||
[data-theme="terminal"] .flxn-reaction-row.flxn-reaction-row {
|
||||
background-color: color-mix(in srgb, var(--mantine-primary-color-5) 2%, #030303);
|
||||
border: 1px solid var(--mantine-color-default-border);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
/* 4. Decoration: fixed scanline overlay + faint RGB aperture mask */
|
||||
[data-theme="terminal"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 9998;
|
||||
pointer-events: none;
|
||||
background:
|
||||
linear-gradient(rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.22) 50%),
|
||||
linear-gradient(90deg, rgba(255, 0, 0, 0.05), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.05));
|
||||
background-size: 100% 2px, 3px 100%;
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
[data-theme="terminal"] body::before {
|
||||
animation: terminal-phosphor-drift 9s ease-in-out infinite;
|
||||
}
|
||||
@keyframes terminal-phosphor-drift {
|
||||
0%, 100% { opacity: 0.35; }
|
||||
50% { opacity: 0.3; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { useEffect } from "react";
|
||||
import type { ThemeManifest } from "./types";
|
||||
|
||||
export const THEME_STORAGE_KEY = "flxn-theme";
|
||||
export const THEME_SCHEME_STORAGE_KEY = "flxn-theme-scheme";
|
||||
export const THEME_FONTS_STORAGE_KEY = "flxn-theme-fonts";
|
||||
|
||||
/** Applies html[data-theme] and mirrors theme id / forced scheme / font links
|
||||
* to localStorage for the pre-hydration script in __root; injects the active
|
||||
* theme's font stylesheets and removes stale ones from other themes.
|
||||
* Writes nothing until `ready` (post-hydration with real metadata) so the
|
||||
* pre-hydration default render can't clobber the mirror. */
|
||||
const ThemeProvider = ({
|
||||
manifest,
|
||||
ready,
|
||||
children,
|
||||
}: {
|
||||
manifest: ThemeManifest;
|
||||
ready: boolean;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
const root = document.documentElement;
|
||||
if (root.getAttribute("data-theme") !== manifest.id) {
|
||||
root.setAttribute("data-theme", manifest.id);
|
||||
}
|
||||
try {
|
||||
localStorage.setItem(THEME_STORAGE_KEY, manifest.id);
|
||||
if (manifest.colorSchemes === "both") {
|
||||
localStorage.removeItem(THEME_SCHEME_STORAGE_KEY);
|
||||
} else {
|
||||
localStorage.setItem(THEME_SCHEME_STORAGE_KEY, manifest.colorSchemes);
|
||||
}
|
||||
localStorage.setItem(
|
||||
THEME_FONTS_STORAGE_KEY,
|
||||
JSON.stringify(manifest.fontLinks ?? [])
|
||||
);
|
||||
} catch {
|
||||
// storage unavailable (private mode) — theme still applies for session
|
||||
}
|
||||
}, [manifest, ready]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) return;
|
||||
const links = Array.from(
|
||||
document.querySelectorAll<HTMLLinkElement>("link[data-flxn-theme-font]")
|
||||
);
|
||||
const wanted = new Set(manifest.fontLinks ?? []);
|
||||
const present = new Set<string>();
|
||||
for (const link of links) {
|
||||
const href = link.getAttribute("href");
|
||||
if (!href || !wanted.has(href)) {
|
||||
link.remove();
|
||||
} else {
|
||||
present.add(href);
|
||||
}
|
||||
}
|
||||
for (const href of wanted) {
|
||||
if (present.has(href)) continue;
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = href;
|
||||
link.dataset.flxnThemeFont = manifest.id;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
}, [manifest, ready]);
|
||||
|
||||
return children;
|
||||
};
|
||||
|
||||
export default ThemeProvider;
|
||||
@@ -0,0 +1,6 @@
|
||||
const themeCss = import.meta.glob("./*/theme.css", { eager: true });
|
||||
|
||||
// The glob result must stay used, or Rollup tree-shakes every theme.css out
|
||||
// of the production bundle.
|
||||
(globalThis as Record<string, unknown>).__flxnThemeCssCount =
|
||||
Object.keys(themeCss).length;
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { MessageDescriptor } from "@lingui/core";
|
||||
import type { MantineThemeOverride } from "@mantine/core";
|
||||
|
||||
export type ThemeColorSchemes = "both" | "light" | "dark";
|
||||
|
||||
export interface ThemeChromeColors {
|
||||
light?: { base: string; dimmed: string };
|
||||
dark?: { base: string; dimmed: string };
|
||||
}
|
||||
|
||||
export interface ThemeManifest {
|
||||
/** Must match the theme's folder name; becomes the html[data-theme] value. */
|
||||
id: string;
|
||||
label: MessageDescriptor;
|
||||
/** "light"/"dark" force that scheme while the theme is active. */
|
||||
colorSchemes: ThemeColorSchemes;
|
||||
/** Sort position in the picker; default theme is 0, unset sorts last. */
|
||||
order?: number;
|
||||
/** Stylesheet URLs (e.g. Google Fonts) injected while the theme is active. */
|
||||
fontLinks?: string[];
|
||||
/** Browser chrome theme-color meta overrides; falls back to defaults. */
|
||||
chromeColors?: ThemeChromeColors;
|
||||
/** JS-side Mantine override (defaultProps, component vars, variants…).
|
||||
* Must never set primaryColor — the user's accent choice always applies. */
|
||||
mantine?: MantineThemeOverride;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import { msg } from "@lingui/core/macro";
|
||||
import type { ThemeManifest } from "../types";
|
||||
|
||||
/* Viewport gizmo ramps, declared in JS (not theme.css) so Mantine regenerates
|
||||
every derived variant var (-filled, -light rgba, autoContrast picks) from
|
||||
the retuned shades. Shade 6 is the fill in BOTH schemes (primaryShade
|
||||
below) — each shade-6 hand-checked against its autoContrast on-color
|
||||
(white or the custom ink black) for 4.5:1+. */
|
||||
const gizmoColors = {
|
||||
// Z-axis blue
|
||||
blue: [
|
||||
"#eaf2ff",
|
||||
"#d2e4fe",
|
||||
"#a8cbfd",
|
||||
"#7aaffa",
|
||||
"#4f92f5",
|
||||
"#2f7cf0",
|
||||
"#1c64d6",
|
||||
"#154fb0",
|
||||
"#103e8a",
|
||||
"#0a2c62",
|
||||
],
|
||||
// X-axis red
|
||||
red: [
|
||||
"#ffecec",
|
||||
"#ffd2d2",
|
||||
"#ffa8a8",
|
||||
"#fd7c7c",
|
||||
"#f85454",
|
||||
"#ef3535",
|
||||
"#d0231f",
|
||||
"#a91b19",
|
||||
"#821513",
|
||||
"#5c0f0e",
|
||||
],
|
||||
// Y-axis green
|
||||
green: [
|
||||
"#e7fbf0",
|
||||
"#c9f5da",
|
||||
"#98e8b8",
|
||||
"#64d692",
|
||||
"#38c072",
|
||||
"#1a9e5a",
|
||||
"#0e7d3f",
|
||||
"#0a6432",
|
||||
"#074b26",
|
||||
"#05331a",
|
||||
],
|
||||
// measurement/annotation yellow
|
||||
yellow: [
|
||||
"#fff8dc",
|
||||
"#ffedad",
|
||||
"#ffdf76",
|
||||
"#ffce46",
|
||||
"#f9bc24",
|
||||
"#daa00e",
|
||||
"#bd870a",
|
||||
"#946909",
|
||||
"#6c4c07",
|
||||
"#463005",
|
||||
],
|
||||
// rotate-gizmo violet
|
||||
grape: [
|
||||
"#f3edff",
|
||||
"#e2d3fd",
|
||||
"#c8adfa",
|
||||
"#ac85f5",
|
||||
"#9163ec",
|
||||
"#7a47df",
|
||||
"#6535c0",
|
||||
"#522a9c",
|
||||
"#3f2077",
|
||||
"#2c1653",
|
||||
],
|
||||
// classic viewport selection orange
|
||||
orange: [
|
||||
"#fff1e3",
|
||||
"#ffddb8",
|
||||
"#ffc182",
|
||||
"#ffa350",
|
||||
"#ee8a2c",
|
||||
"#cc6a0f",
|
||||
"#b04f06",
|
||||
"#8f4005",
|
||||
"#6e3104",
|
||||
"#4d2203",
|
||||
],
|
||||
// magenta gizmo tag
|
||||
pink: [
|
||||
"#ffeef7",
|
||||
"#ffd3ea",
|
||||
"#ffa8d6",
|
||||
"#fd7cc0",
|
||||
"#f552a9",
|
||||
"#db308f",
|
||||
"#c22174",
|
||||
"#9a1a5b",
|
||||
"#731442",
|
||||
"#4d0d2c",
|
||||
],
|
||||
// chartreuse highlight
|
||||
lime: [
|
||||
"#f6ffe0",
|
||||
"#e8feb0",
|
||||
"#d3f47a",
|
||||
"#bce34a",
|
||||
"#a3ce27",
|
||||
"#8db518",
|
||||
"#7a9c12",
|
||||
"#607b0d",
|
||||
"#475c09",
|
||||
"#2f3d06",
|
||||
],
|
||||
} as const;
|
||||
|
||||
const manifest: ThemeManifest = {
|
||||
id: "wireframe",
|
||||
label: msg`Viewport`,
|
||||
colorSchemes: "both",
|
||||
fontLinks: [
|
||||
"https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap",
|
||||
],
|
||||
chromeColors: {
|
||||
light: { base: "#f2f3f5", dimmed: "#dcdfe3" },
|
||||
dark: { base: "#17191c", dimmed: "#0d0e10" },
|
||||
},
|
||||
mantine: {
|
||||
autoContrast: true,
|
||||
luminanceThreshold: 0.25,
|
||||
black: "#15181c",
|
||||
primaryShade: { light: 6, dark: 6 },
|
||||
colors: gizmoColors,
|
||||
},
|
||||
};
|
||||
|
||||
export default manifest;
|
||||
@@ -0,0 +1,545 @@
|
||||
/* Wireframe "Viewport" — an untextured 3D-modeling viewport. Surfaces are
|
||||
unshaded mesh objects: flat fills, thin vector edges, vertex dots at the
|
||||
four corners. Selection follows the classic viewport convention: the
|
||||
user's accent as a 1px outline + accent vertex dots + a light accent
|
||||
wash. Isometric-cube divider motif; mono annotation labels (JetBrains
|
||||
Mono) against clean, heavier Inter headings. */
|
||||
|
||||
/* ---------- 1. Tokens, any scheme ---------- */
|
||||
|
||||
[data-theme="wireframe"][data-theme] {
|
||||
--mantine-font-family: "Inter", sans-serif;
|
||||
--mantine-font-family-headings: "Inter", sans-serif;
|
||||
--mantine-font-family-monospace: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
||||
--mantine-heading-font-weight: 800;
|
||||
|
||||
--mantine-radius-default: 3px;
|
||||
--mantine-radius-xs: 2px;
|
||||
--mantine-radius-sm: 3px;
|
||||
--mantine-radius-md: 4px;
|
||||
--mantine-radius-lg: 4px;
|
||||
--mantine-radius-xl: 6px;
|
||||
|
||||
--mantine-shadow-xs: none;
|
||||
--mantine-shadow-sm: none;
|
||||
--mantine-shadow-md: none;
|
||||
--mantine-shadow-lg: none;
|
||||
--mantine-shadow-xl: none;
|
||||
|
||||
/* square viewport avatar, vertex-dotted corners applied via .flxn-avatar-frame */
|
||||
--flxn-avatar-radius: 3px;
|
||||
--flxn-badge-radius: 3px;
|
||||
}
|
||||
|
||||
/* ---------- 2. Per-scheme tokens ---------- */
|
||||
|
||||
[data-theme="wireframe"][data-theme][data-mantine-color-scheme="light"] {
|
||||
/* thin vector edge ink + vertex-dot color */
|
||||
--wf-edge: #445;
|
||||
--wf-edge-dim: rgba(68, 68, 85, 0.32);
|
||||
--wf-vertex: #445;
|
||||
--wf-surface: #ffffff;
|
||||
--wf-panel: #f8f9fa;
|
||||
/* the user's accent, kept legible as ink on the mesh */
|
||||
--wf-accent-ink: var(--mantine-primary-color-6);
|
||||
--wf-cube-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolygon points='12,2 20.7,7 20.7,17 12,22 3.3,17 3.3,7' fill='none' stroke='%23445' stroke-width='1.5'/%3E%3Cpath d='M12 12 L12 2 M12 12 L3.3 17 M12 12 L20.7 17' stroke='%23445' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
|
||||
|
||||
--flxn-avatar-border: 1px solid var(--wf-edge);
|
||||
|
||||
--mantine-color-body: #f2f3f5;
|
||||
--mantine-color-text: #20242a;
|
||||
--mantine-color-bright: #0e1013;
|
||||
--mantine-color-dimmed: #55606b;
|
||||
--mantine-color-anchor: var(--wf-accent-ink);
|
||||
--mantine-color-error: #d0231f;
|
||||
--mantine-color-placeholder: #7d8590;
|
||||
--mantine-color-default: #ffffff;
|
||||
--mantine-color-default-hover: #eaecef;
|
||||
--mantine-color-default-color: #20242a;
|
||||
--mantine-color-default-border: rgba(68, 68, 85, 0.45);
|
||||
|
||||
/* cool viewport gray ramp */
|
||||
--mantine-color-gray-0: #f8f9fa;
|
||||
--mantine-color-gray-1: #eef0f2;
|
||||
--mantine-color-gray-2: #e2e5e9;
|
||||
--mantine-color-gray-3: #d1d5db;
|
||||
--mantine-color-gray-4: #b7bcc4;
|
||||
--mantine-color-gray-5: #9aa1a8;
|
||||
--mantine-color-gray-6: #7d8590;
|
||||
--mantine-color-gray-7: #5f666f;
|
||||
--mantine-color-gray-8: #454b52;
|
||||
--mantine-color-gray-9: #2c3136;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #9a6700;
|
||||
--flxn-silver: #5f666f;
|
||||
--flxn-bronze: #a05a1e;
|
||||
--flxn-toast-success: #0e7d3f;
|
||||
--flxn-toast-error: #d0231f;
|
||||
--flxn-podium-1-bg: rgba(154, 103, 0, 0.06);
|
||||
--flxn-podium-1-border: rgba(154, 103, 0, 0.5);
|
||||
--flxn-podium-1-label: #855800;
|
||||
--flxn-podium-2-bg: rgba(95, 102, 111, 0.07);
|
||||
--flxn-podium-2-border: rgba(95, 102, 111, 0.5);
|
||||
--flxn-podium-2-label: #4d545c;
|
||||
--flxn-podium-3-bg: rgba(160, 90, 30, 0.06);
|
||||
--flxn-podium-3-border: rgba(160, 90, 30, 0.45);
|
||||
--flxn-podium-3-label: #a05a1e;
|
||||
--flxn-showcase-bg: #ffffff;
|
||||
--flxn-overlay: rgba(15, 17, 20, 0.4);
|
||||
--flxn-dotgrid-color: rgba(68, 68, 85, 0.28);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"][data-theme][data-mantine-color-scheme="dark"] {
|
||||
/* pale vector edge on the night viewport */
|
||||
--wf-edge: #aab2bc;
|
||||
--wf-edge-dim: rgba(170, 178, 188, 0.3);
|
||||
--wf-vertex: #aab2bc;
|
||||
--wf-surface: #1d2024;
|
||||
--wf-panel: #131518;
|
||||
--wf-accent-ink: var(--mantine-primary-color-4);
|
||||
--wf-cube-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpolygon points='12,2 20.7,7 20.7,17 12,22 3.3,17 3.3,7' fill='none' stroke='%23aab2bc' stroke-width='1.5'/%3E%3Cpath d='M12 12 L12 2 M12 12 L3.3 17 M12 12 L20.7 17' stroke='%23aab2bc' stroke-width='1.5' fill='none'/%3E%3C/svg%3E");
|
||||
|
||||
--flxn-avatar-border: 1px solid var(--wf-edge);
|
||||
|
||||
--mantine-color-body: #17191c;
|
||||
--mantine-color-text: #e4e6e9;
|
||||
--mantine-color-bright: #ffffff;
|
||||
--mantine-color-dimmed: #9aa1a8;
|
||||
--mantine-color-anchor: var(--wf-accent-ink);
|
||||
--mantine-color-error: #ff6b6b;
|
||||
--mantine-color-placeholder: #6e747b;
|
||||
--mantine-color-default: #1d2024;
|
||||
--mantine-color-default-hover: #232629;
|
||||
--mantine-color-default-color: #e4e6e9;
|
||||
--mantine-color-default-border: rgba(170, 178, 188, 0.32);
|
||||
|
||||
/* steel-cast dark ramp, tuned to the night viewport body */
|
||||
--mantine-color-dark-0: #eef0f2;
|
||||
--mantine-color-dark-1: #d6dadd;
|
||||
--mantine-color-dark-2: #b0b7bd;
|
||||
--mantine-color-dark-3: #868f97;
|
||||
--mantine-color-dark-4: #5b636b;
|
||||
--mantine-color-dark-5: #383d43;
|
||||
--mantine-color-dark-6: #232629;
|
||||
--mantine-color-dark-7: #17191c;
|
||||
--mantine-color-dark-8: #131518;
|
||||
--mantine-color-dark-9: #0d0f11;
|
||||
|
||||
/* app tokens */
|
||||
--flxn-gold: #ffc861;
|
||||
--flxn-silver: #c3cad1;
|
||||
--flxn-bronze: #e0a06a;
|
||||
--flxn-toast-success: #4bd08a;
|
||||
--flxn-toast-error: #ff6b6b;
|
||||
--flxn-podium-1-bg: rgba(255, 200, 97, 0.08);
|
||||
--flxn-podium-1-border: rgba(255, 200, 97, 0.5);
|
||||
--flxn-podium-1-label: #ffc861;
|
||||
--flxn-podium-2-bg: rgba(195, 202, 209, 0.08);
|
||||
--flxn-podium-2-border: rgba(195, 202, 209, 0.45);
|
||||
--flxn-podium-2-label: #c3cad1;
|
||||
--flxn-podium-3-bg: rgba(224, 160, 106, 0.08);
|
||||
--flxn-podium-3-border: rgba(224, 160, 106, 0.45);
|
||||
--flxn-podium-3-label: #e0a06a;
|
||||
--flxn-showcase-bg: #1d2024;
|
||||
--flxn-overlay: rgba(0, 0, 0, 0.6);
|
||||
--flxn-dotgrid-color: rgba(170, 178, 188, 0.16);
|
||||
--flxn-pop-shadow: rgba(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/* ---------- 3. Decoration: static perspective floor-grid hint ---------- */
|
||||
|
||||
[data-theme="wireframe"] body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
left: -30vw;
|
||||
right: -30vw;
|
||||
bottom: -4vh;
|
||||
height: 26vh;
|
||||
z-index: 9998;
|
||||
pointer-events: none;
|
||||
opacity: 0.22;
|
||||
background-image:
|
||||
repeating-linear-gradient(90deg, var(--wf-edge) 0 1px, transparent 1px 64px),
|
||||
repeating-linear-gradient(0deg, var(--wf-edge) 0 1px, transparent 1px 32px);
|
||||
transform: perspective(280px) rotateX(62deg);
|
||||
transform-origin: 50% 100%;
|
||||
-webkit-mask-image: linear-gradient(to top, #000 45%, transparent 100%);
|
||||
mask-image: linear-gradient(to top, #000 45%, transparent 100%);
|
||||
}
|
||||
|
||||
/* ---------- 4. Mesh surfaces: flat fill, thin edge, vertex dots ---------- */
|
||||
|
||||
[data-theme="wireframe"] .mantine-Paper-root,
|
||||
[data-theme="wireframe"] .mantine-Card-root,
|
||||
[data-theme="wireframe"] .flxn-tile,
|
||||
[data-theme="wireframe"] .flxn-match-card {
|
||||
position: relative;
|
||||
background-color: var(--wf-surface);
|
||||
border: 1px solid var(--wf-edge-dim);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Card-root,
|
||||
[data-theme="wireframe"] .flxn-tile,
|
||||
[data-theme="wireframe"] .flxn-match-card {
|
||||
border-color: var(--wf-edge);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Card-root::after,
|
||||
[data-theme="wireframe"] .flxn-tile::after,
|
||||
[data-theme="wireframe"] .flxn-match-card::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background-repeat: no-repeat;
|
||||
background-image:
|
||||
radial-gradient(var(--wf-vertex) 0%, var(--wf-vertex) 100%),
|
||||
radial-gradient(var(--wf-vertex) 0%, var(--wf-vertex) 100%),
|
||||
radial-gradient(var(--wf-vertex) 0%, var(--wf-vertex) 100%),
|
||||
radial-gradient(var(--wf-vertex) 0%, var(--wf-vertex) 100%);
|
||||
background-size: 4px 4px;
|
||||
background-position:
|
||||
-2px -2px,
|
||||
calc(100% + 2px) -2px,
|
||||
-2px calc(100% + 2px),
|
||||
calc(100% + 2px) calc(100% + 2px);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Divider-root,
|
||||
[data-theme="wireframe"] .mantine-Divider-root::before,
|
||||
[data-theme="wireframe"] .mantine-Divider-root::after {
|
||||
--divider-color: var(--wf-edge-dim);
|
||||
}
|
||||
|
||||
/* isometric-cube divider motif on labeled dividers */
|
||||
[data-theme="wireframe"] .mantine-Divider-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.4em;
|
||||
font-family: var(--mantine-font-family-monospace);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.07em;
|
||||
font-size: 0.72rem;
|
||||
color: var(--mantine-color-dimmed);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Divider-label::before {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
flex: none;
|
||||
background-image: var(--wf-cube-icon);
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
/* ---------- 5. Annotation type: mono, uppercase, tracked ---------- */
|
||||
|
||||
[data-theme="wireframe"] .mantine-InputWrapper-label,
|
||||
[data-theme="wireframe"] .mantine-Badge-label,
|
||||
[data-theme="wireframe"] .mantine-Tabs-tab,
|
||||
[data-theme="wireframe"] .mantine-SegmentedControl-label,
|
||||
[data-theme="wireframe"] .mantine-Notification-title,
|
||||
[data-theme="wireframe"] .mantine-Modal-title,
|
||||
[data-theme="wireframe"] .mantine-Menu-label,
|
||||
[data-theme="wireframe"] .mantine-Alert-title,
|
||||
[data-theme="wireframe"] .mantine-Tooltip-tooltip {
|
||||
font-family: var(--mantine-font-family-monospace);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-InputWrapper-label {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
color: var(--mantine-color-dimmed);
|
||||
}
|
||||
|
||||
/* ---------- 6. Controls: outlined technical boxes ---------- */
|
||||
|
||||
[data-theme="wireframe"] .mantine-Button-root {
|
||||
font-family: var(--mantine-font-family-monospace);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
font-weight: 600;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Button-root[data-variant="default"],
|
||||
[data-theme="wireframe"] .mantine-ActionIcon-root[data-variant="default"] {
|
||||
background-color: var(--wf-surface);
|
||||
border: 1px solid var(--wf-edge);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Button-root[data-variant="filled"],
|
||||
[data-theme="wireframe"] .mantine-ActionIcon-root[data-variant="filled"] {
|
||||
border: 1px solid var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Input-input {
|
||||
background-color: var(--wf-surface);
|
||||
border-color: var(--wf-edge-dim);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Input-input:focus,
|
||||
[data-theme="wireframe"] .mantine-Input-input:focus-within {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
outline: 1px solid var(--mantine-primary-color-filled);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Checkbox-input {
|
||||
border-color: var(--wf-edge);
|
||||
background-color: var(--wf-surface);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Checkbox-input:checked {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Switch-track {
|
||||
border-radius: 2px;
|
||||
border: 1px solid var(--wf-edge);
|
||||
background-color: var(--wf-surface);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Switch-thumb {
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-SegmentedControl-root {
|
||||
background-color: var(--wf-panel);
|
||||
border: 1px solid var(--wf-edge-dim);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-SegmentedControl-indicator {
|
||||
background-color: var(--mantine-primary-color-filled);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-SegmentedControl-label[data-active] {
|
||||
color: var(--mantine-primary-color-contrast);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Badge-root {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Badge-root[data-variant="light"],
|
||||
[data-theme="wireframe"] .mantine-Badge-root[data-variant="default"],
|
||||
[data-theme="wireframe"] .mantine-Badge-root[data-variant="outline"] {
|
||||
border: 1px solid color-mix(in srgb, currentColor 55%, transparent);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Progress-root {
|
||||
border: 1px solid var(--wf-edge-dim);
|
||||
background-color: var(--wf-panel);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Avatar-root,
|
||||
[data-theme="wireframe"] .mantine-Avatar-root .mantine-Avatar-image,
|
||||
[data-theme="wireframe"] .mantine-ThemeIcon-root {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* selection: accent 1px ring on the highlighted combobox option */
|
||||
[data-theme="wireframe"] [data-combobox-selected] {
|
||||
box-shadow: inset 0 0 0 1px var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
/* ---------- 7. Overlays: opaque panels, no shadow ---------- */
|
||||
|
||||
[data-theme="wireframe"] .mantine-Modal-content {
|
||||
background-color: var(--wf-surface);
|
||||
border: 1px solid var(--wf-edge);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Modal-header {
|
||||
background-color: var(--wf-surface);
|
||||
border-bottom: 1px solid var(--wf-edge-dim);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Popover-dropdown,
|
||||
[data-theme="wireframe"] .mantine-Menu-dropdown,
|
||||
[data-theme="wireframe"] .mantine-Combobox-dropdown {
|
||||
background-color: var(--wf-surface);
|
||||
border: 1px solid var(--wf-edge);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Tooltip-tooltip {
|
||||
font-size: 0.68rem;
|
||||
background-color: var(--wf-panel);
|
||||
color: var(--mantine-color-text);
|
||||
border: 1px solid var(--wf-edge);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Notification-root {
|
||||
background-color: var(--wf-surface);
|
||||
border: 1px solid var(--wf-edge);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-Alert-root {
|
||||
border: 1px solid color-mix(in srgb, currentColor 40%, transparent);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* ---------- 8. Shell ---------- */
|
||||
|
||||
[data-theme="wireframe"] .mantine-AppShell-root {
|
||||
--app-shell-border-color: var(--wf-edge-dim);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-AppShell-header,
|
||||
[data-theme="wireframe"] .mantine-AppShell-navbar {
|
||||
background-color: var(--mantine-color-body);
|
||||
border-color: var(--wf-edge-dim);
|
||||
}
|
||||
|
||||
/* ---------- 9. Selection convention: accent outline + wash + vertex ---------- */
|
||||
|
||||
[data-theme="wireframe"] .mantine-NavLink-root[data-active] {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
box-shadow: inset 0 0 0 1px var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .mantine-NavLink-root[data-active] .mantine-NavLink-label,
|
||||
[data-theme="wireframe"] .mantine-NavLink-root[data-active] .mantine-NavLink-section {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* ---------- 10. App hooks: viewport language ---------- */
|
||||
|
||||
/* tab strip: resting stays flat; docked = title strip with heavy edge rule */
|
||||
[data-theme="wireframe"] .flxn-tabs[data-stuck] {
|
||||
border-bottom: 2px solid var(--wf-edge);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .flxn-tab.flxn-tab {
|
||||
font-family: var(--mantine-font-family-monospace);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
font-size: 0.75rem;
|
||||
color: var(--mantine-color-dimmed);
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .flxn-tab.flxn-tab[data-active] {
|
||||
color: var(--wf-accent-ink);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .flxn-tabs-indicator.flxn-tabs-indicator {
|
||||
border-bottom: 2px solid var(--mantine-primary-color-filled);
|
||||
padding-inline: 0.5rem;
|
||||
}
|
||||
|
||||
/* nav tiles: mesh surface (border + vertex dots from rule 4); selecting them
|
||||
(hover/focus) takes on the accent selection convention */
|
||||
[data-theme="wireframe"] .flxn-tile-icon {
|
||||
color: var(--wf-accent-ink);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="wireframe"] .flxn-tile:hover {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
}
|
||||
[data-theme="wireframe"] .flxn-tile:hover::after {
|
||||
background-image:
|
||||
radial-gradient(var(--mantine-primary-color-filled) 0%, var(--mantine-primary-color-filled) 100%),
|
||||
radial-gradient(var(--mantine-primary-color-filled) 0%, var(--mantine-primary-color-filled) 100%),
|
||||
radial-gradient(var(--mantine-primary-color-filled) 0%, var(--mantine-primary-color-filled) 100%),
|
||||
radial-gradient(var(--mantine-primary-color-filled) 0%, var(--mantine-primary-color-filled) 100%);
|
||||
}
|
||||
/* accent icon over the light accent wash needs the wash's own on-color */
|
||||
[data-theme="wireframe"] .flxn-tile:hover .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .flxn-tile:focus-visible {
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .flxn-tile:focus-visible .flxn-tile-icon {
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
}
|
||||
|
||||
/* "see all": annotation chip */
|
||||
[data-theme="wireframe"] .flxn-see-all.flxn-see-all {
|
||||
font-family: var(--mantine-font-family-monospace);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
border: 1px solid var(--wf-edge-dim);
|
||||
background-color: transparent;
|
||||
color: var(--wf-accent-ink);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
[data-theme="wireframe"] .flxn-see-all.flxn-see-all:hover {
|
||||
background-color: var(--mantine-primary-color-light);
|
||||
border-color: var(--mantine-primary-color-filled);
|
||||
color: var(--mantine-primary-color-light-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* reaction tray: properties-panel strip under the match-card mesh object */
|
||||
[data-theme="wireframe"] .flxn-reaction-row.flxn-reaction-row {
|
||||
background-color: var(--wf-panel);
|
||||
border: 1px solid var(--wf-edge-dim);
|
||||
font-family: var(--mantine-font-family-monospace);
|
||||
}
|
||||
|
||||
/* square avatar, vertex-dotted corners just outside the frame */
|
||||
[data-theme="wireframe"] .flxn-avatar-frame {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .flxn-avatar-frame::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: -2px;
|
||||
pointer-events: none;
|
||||
background-repeat: no-repeat;
|
||||
background-image:
|
||||
radial-gradient(var(--wf-vertex) 0%, var(--wf-vertex) 100%),
|
||||
radial-gradient(var(--wf-vertex) 0%, var(--wf-vertex) 100%),
|
||||
radial-gradient(var(--wf-vertex) 0%, var(--wf-vertex) 100%),
|
||||
radial-gradient(var(--wf-vertex) 0%, var(--wf-vertex) 100%);
|
||||
background-size: 4px 4px;
|
||||
background-position: 0 0, 100% 0, 0 100%, 100% 100%;
|
||||
}
|
||||
|
||||
/* press feedback: a light scale-down + accent selection-ring flash */
|
||||
[data-theme="wireframe"] .flxn-press {
|
||||
outline: 1px solid transparent;
|
||||
outline-offset: -1px;
|
||||
transition: transform 150ms cubic-bezier(0.32, 0.72, 0, 1), outline-color 150ms ease;
|
||||
}
|
||||
|
||||
[data-theme="wireframe"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transform: scale(0.97);
|
||||
outline-color: var(--mantine-primary-color-filled);
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
[data-theme="wireframe"] .flxn-press,
|
||||
[data-theme="wireframe"] .flxn-press:active:not(:disabled):not([data-disabled]):not([data-loading]) {
|
||||
transition: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,6 @@ const verifySuperTokensSession = async (request: Request) => {
|
||||
const userAuthId = session?.userId;
|
||||
|
||||
if (!userAuthId || !session) {
|
||||
logger.info("No authenticated user");
|
||||
return { context: { userAuthId: null, roles: [] } };
|
||||
}
|
||||
|
||||
@@ -109,7 +108,6 @@ export const getSessionContextCore = async (
|
||||
}
|
||||
|
||||
if (!session.context.userAuthId) {
|
||||
logger.error("Unauthenticated user", session.context);
|
||||
throw new Error("Unauthenticated");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user