diff --git a/frontend/src/components/react/admin/Settings.tsx b/frontend/src/components/react/admin/Settings.tsx index fb9cb90..5c391ee 100644 --- a/frontend/src/components/react/admin/Settings.tsx +++ b/frontend/src/components/react/admin/Settings.tsx @@ -99,8 +99,9 @@ export default function Settings() { + -

Salon trio tuned for the gallery aesthetic. Breakcore swaps that for early-2000s web rot — hot magenta on CRT violet, acid green, scanline noise.

+

Salon trio tuned for the gallery aesthetic. Breakcore swaps that for early-2000s web rot — hot magenta on CRT violet, acid green, scanline noise. Cybersigil is the moody cut — near-black ground, ice-cyan barbed sigil linework, bruised-magenta on contact, lingering chromatic glitch.

diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css index 5c6cbbf..d1fb418 100644 --- a/frontend/src/styles/global.css +++ b/frontend/src/styles/global.css @@ -165,6 +165,39 @@ --rosewater: #F0DDE8; } +/* CYBERSIGIL — Frostbite. Near-black ground, ice-cyan sigil linework, + * bruised-magenta primary accent, sterile bone-white text. Modern-breakcore + * melancholy: chromatic-aberration glitch, barbed sigil ornament, deep + * vignette + fine cold grain. Primary accent: bruised magenta (--mauve). */ +.cybersigil { + --crust: #020203; + --mantle: #050507; + --base: #070709; + --surface0: #0C0D11; + --surface1: #13151B; + --surface2: #1E2129; + --overlay0: #2A2F3A; + --overlay1: #3D4654; + --overlay2: #566174; + --text: #DCE6EC; /* sterile bone-white, cool cast */ + --subtext0: #7E8B99; + --subtext1: #AAB8C4; + --blue: #3FB4FF; /* cold electric */ + --lavender: #8E7CFF; /* cold violet */ + --sapphire: #3A5BFF; /* deep cold hyperlink */ + --sky: #4FE9FF; /* ice-cyan — primary sigil line */ + --teal: #2FD8D2; /* frost mint — secondary neon */ + --green: #5BE0A8; /* cold jade */ + --yellow: #E8C24A; /* muted amber — inline code only */ + --peach: #E07A5F; + --maroon: #5A1530; + --red: #FF3B5C; /* siren — danger only */ + --mauve: #C8327A; /* bruised magenta — primary accent */ + --pink: #E86AAE; /* faded neon pink */ + --flamingo: #E8A0C4; + --rosewater: #EAF2F6; /* brightest bone — on-accent text */ +} + html { font-family: var(--font-sans); font-feature-settings: "kern", "liga", "calt", "onum"; @@ -1839,6 +1872,560 @@ input[type="date"] { color-scheme: light; } color: var(--red); } +/* ═══════════════════════════════════════════════════════════════════════ + * CYBERSIGIL — Frostbite layer. + * Scoped to `.cybersigil`; salon / salon-noir / gothic / breakcore untouched. + * Aesthetic: modern-breakcore melancholy. Editorial serif body in tension + * with cold-mono sigil chrome — thin barbed vector linework, ice-cyan rest + * state, bruised-magenta on contact, RGB chromatic split that lingers + * (slower + sadder than breakcore's snap). Every control is a visible neon + * affordance — no bare text. Motion is reactive only; killed by + * prefers-reduced-motion at the very end of this file. + * ═══════════════════════════════════════════════════════════════════════ */ + +/* Deep tube vignette — blacker, tighter than breakcore. */ +.cybersigil body::before { + background-image: radial-gradient( + ellipse at center, + transparent 40%, + color-mix(in srgb, var(--crust) 92%, transparent) 100% + ); +} + +/* Fine cold grain + tight scanlines. Lower opacity than breakcore, blue- + * shifted — atmospheric, not blown out. */ +.cybersigil body::after, +html.cybersigil body::after { + opacity: 0.4; + background-image: + url("data:image/svg+xml;utf8,"), + repeating-linear-gradient( + 0deg, + rgba(0, 0, 0, 0) 0, + rgba(0, 0, 0, 0) 2px, + rgba(0, 0, 0, 0.34) 3px, + rgba(0, 0, 0, 0) 4px + ); + mix-blend-mode: screen; +} + +/* Glow pools — ice-cyan + bruised magenta, large + faint. Moody, not lit. */ +.cybersigil .salon-atmosphere::before { + background: var(--sky); + opacity: 0.07; +} +.cybersigil .salon-atmosphere::after { + background: var(--mauve); + opacity: 0.06; +} + +/* Selection — magenta block, bone text, cyan bleed. */ +.cybersigil ::selection { + background: var(--mauve); + color: var(--rosewater); + text-shadow: 0 0 6px var(--sky); +} + +/* Static chromatic aberration on display heads + nameplate (resting state). */ +.cybersigil .prose h1, +.cybersigil .prose h2, +.cybersigil h1.font-display, +.cybersigil .nameplate-title { + text-shadow: + -1px 0 0 color-mix(in srgb, var(--sky) 72%, transparent), + 1px 0 0 color-mix(in srgb, var(--mauve) 72%, transparent), + 0 0 22px color-mix(in srgb, var(--sky) 28%, transparent); +} + +/* Nameplate underline → ice rule, hard magenta offset + cyan bloom. */ +.cybersigil .nameplate::after { + height: 2px; + bottom: -7px; + background: var(--sky); + box-shadow: + 2px 2px 0 var(--mauve), + 0 0 12px color-mix(in srgb, var(--sky) 70%, transparent); +} +@keyframes cs-shear { + 0% { clip-path: inset(0 0 0 0); transform: translateX(0); + text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve); } + 22% { clip-path: inset(14% 0 58% 0); transform: translateX(-6px); + text-shadow: -6px 0 0 var(--sky), 6px 0 0 var(--mauve); } + 45% { clip-path: inset(60% 0 12% 0); transform: translateX(5px); + text-shadow: 5px 0 0 var(--teal), -5px 0 0 var(--mauve); } + 68% { clip-path: inset(28% 0 44% 0); transform: translateX(-3px); + text-shadow: -3px 0 0 var(--mauve), 3px 0 0 var(--sky); } + 100% { clip-path: inset(0 0 0 0); transform: translateX(0); + text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve); } +} +.cybersigil .nameplate:hover .nameplate-title { + animation: cs-shear 320ms steps(4, jump-none) 1; +} + +/* Display heads — slow melancholic glitch-in on load (sadder than the + * breakcore snap; longer settle, deeper offsets). */ +@keyframes cs-load-glitch { + 0% { opacity: 0; clip-path: inset(48% 0 48% 0); transform: translateX(-12px); } + 18% { opacity: 1; clip-path: inset(6% 0 74% 0); transform: translateX(9px); } + 38% { clip-path: inset(70% 0 6% 0); transform: translateX(-6px); } + 58% { clip-path: inset(22% 0 40% 0); transform: translateX(4px); } + 78% { clip-path: inset(4% 0 86% 0); transform: translateX(-2px); } + 100% { opacity: 1; clip-path: none; transform: translateX(0); } +} +.cybersigil .prose h1, +.cybersigil h1.font-display { + animation: cs-load-glitch 620ms steps(5, jump-none) backwards; +} + +/* Plate — dark glass card, ice frame, barbed sigil corner-brackets. The + * brackets are the theme signature: thin angular vector marks that ignite + * magenta on contact. */ +.cybersigil .plate { + position: relative; + background: var(--surface0); + box-shadow: + inset 0 0 0 1px color-mix(in srgb, var(--sky) 26%, transparent), + 0 0 0 1px color-mix(in srgb, var(--sky) 14%, transparent), + 0 22px 44px -28px rgba(79, 233, 255, 0.28), + 0 0 26px -10px color-mix(in srgb, var(--mauve) 36%, transparent); +} +.cybersigil .plate::before, +.cybersigil .plate::after { + content: ""; + position: absolute; + width: 26px; + height: 26px; + border: 1.5px solid color-mix(in srgb, var(--sky) 70%, transparent); + filter: drop-shadow(0 0 4px color-mix(in srgb, var(--sky) 45%, transparent)); + pointer-events: none; + transition: border-color 0.18s ease, filter 0.18s ease; +} +.cybersigil .plate::before { + top: -1px; + left: -1px; + border-right: 0; + border-bottom: 0; + clip-path: polygon(0 0, 100% 0, 100% 20%, 32% 20%, 32% 100%, 0 100%); +} +.cybersigil .plate::after { + right: -1px; + bottom: -1px; + border-left: 0; + border-top: 0; + clip-path: polygon(100% 0, 100% 100%, 0 100%, 0 80%, 68% 80%, 68% 0); +} +.cybersigil .plate:hover { + transform: translateY(-3px); + box-shadow: + inset 0 0 0 1px color-mix(in srgb, var(--mauve) 40%, transparent), + 0 0 0 1px color-mix(in srgb, var(--mauve) 26%, transparent), + 0 32px 60px -28px rgba(200, 50, 122, 0.42), + 0 0 34px -8px color-mix(in srgb, var(--mauve) 48%, transparent); +} +.cybersigil .plate:hover::before, +.cybersigil .plate:hover::after { + border-color: var(--mauve); + filter: drop-shadow(0 0 7px color-mix(in srgb, var(--mauve) 60%, transparent)); +} +.cybersigil .plate:focus-visible { + box-shadow: + inset 0 0 0 2px var(--sky), + 0 0 0 2px var(--mauve), + 0 0 30px -6px color-mix(in srgb, var(--sky) 60%, transparent); +} +.cybersigil .plate:hover .plate-caption-title { + text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve); +} +.cybersigil .plate-image { + background: var(--mantle); +} +.cybersigil .plate:hover .plate-image img { + filter: + drop-shadow(-3px 0 0 color-mix(in srgb, var(--mauve) 70%, transparent)) + drop-shadow(3px 0 0 color-mix(in srgb, var(--sky) 70%, transparent)) + saturate(0.92) contrast(1.05) brightness(0.96); +} +.cybersigil .plate .plate-image::after { + content: ""; + position: absolute; + inset: 0; + pointer-events: none; + opacity: 0; + transform: translateY(-110%); + mix-blend-mode: screen; + background: linear-gradient( + 180deg, + transparent 0%, + color-mix(in srgb, var(--sky) 24%, transparent) 46%, + color-mix(in srgb, var(--mauve) 64%, transparent) 49%, + color-mix(in srgb, var(--sky) 40%, transparent) 51%, + color-mix(in srgb, var(--sky) 22%, transparent) 54%, + transparent 100% + ); +} +@keyframes cs-scan { + 0% { transform: translateY(-110%); opacity: 0; } + 14% { opacity: 1; } + 86% { opacity: 1; } + 100% { transform: translateY(110%); opacity: 0; } +} +.cybersigil .plate:hover .plate-image::after, +.cybersigil .plate:focus-visible .plate-image::after { + animation: cs-scan 0.78s cubic-bezier(0.4, 0, 0.2, 1) 1; +} +.cybersigil .prose figure img, +.cybersigil .prose img { + background: + linear-gradient(var(--surface0), var(--surface0)) padding-box, + linear-gradient(135deg, color-mix(in srgb, var(--sky) 40%, var(--surface2)), color-mix(in srgb, var(--mauve) 40%, var(--surface1))) border-box; +} + +/* Section rule — masked barbed sigil glyph between cyan→magenta filaments. */ +.cybersigil .section-rule { + color: var(--sky); + font-family: var(--font-mono); + font-style: normal; + font-size: 0.76rem; + text-transform: uppercase; + letter-spacing: 0.24em; +} +.cybersigil .section-rule::before, +.cybersigil .section-rule::after { + height: 1px; + opacity: 0.9; + background: linear-gradient( + to right, + transparent, + color-mix(in srgb, var(--sky) 75%, transparent) 45%, + color-mix(in srgb, var(--mauve) 75%, transparent) 55%, + transparent + ); +} +.cybersigil .section-rule .ornament { + color: transparent; + width: 1.1em; + height: 1.1em; + background-color: var(--sky); + -webkit-mask: var(--cs-sigil) center / contain no-repeat; + mask: var(--cs-sigil) center / contain no-repeat; + filter: drop-shadow(0 0 5px color-mix(in srgb, var(--sky) 60%, transparent)); +} +.cybersigil { + --cs-sigil: url("data:image/svg+xml;utf8,"); +} + +/* Readability — lift dim-on-near-black copy spots to the subtext ramp. */ +.cybersigil .prose h6, +.cybersigil .prose del, +.cybersigil .hljs-comment, +.cybersigil .hljs-quote, +.cybersigil .site-copyright, +.cybersigil .slug-hint { + color: var(--subtext0); +} + +/* Chips — thin ice outline, mono caps. */ +.cybersigil .chip { + background: transparent; + border-color: color-mix(in srgb, var(--sky) 55%, transparent); + color: var(--sky); + font-family: var(--font-mono); + font-style: normal; + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.1em; + border-radius: 0; +} +.cybersigil .chip-accent { + background: var(--mauve); + color: var(--rosewater); + border-color: var(--mauve); +} +.cybersigil .chip-draft { + background: transparent; + border-color: color-mix(in srgb, var(--green) 60%, transparent); + color: var(--green); +} +.cybersigil .plate-caption-meta { + font-family: var(--font-mono); + letter-spacing: 0.16em; +} +.cybersigil .plate-caption-sep { + color: var(--sky); + opacity: 1; +} + +/* Buttons & inputs — square, hard offset, ice→magenta neon. */ +.cybersigil .btn, +.cybersigil .field-input, +.cybersigil .topbar-control, +.cybersigil .topbar-control kbd { border-radius: 0; } +.cybersigil .btn--primary { + color: var(--rosewater); + border-color: var(--mauve); + box-shadow: 3px 3px 0 0 var(--sky); +} +.cybersigil .btn--primary:hover { + background: var(--sky); + border-color: var(--sky); + color: var(--crust); + box-shadow: 3px 3px 0 0 var(--mauve); +} +.cybersigil .btn--primary:active { + transform: translate(2px, 2px); + box-shadow: 1px 1px 0 0 var(--mauve); +} +.cybersigil .btn--danger { + box-shadow: 3px 3px 0 0 color-mix(in srgb, var(--red) 60%, var(--crust)); +} +.cybersigil .btn--danger:hover { + box-shadow: 3px 3px 0 0 var(--mauve); +} +.cybersigil .btn--danger:active { + transform: translate(2px, 2px); + box-shadow: 1px 1px 0 0 var(--mauve); +} +.cybersigil .btn:focus-visible { + border-color: var(--sky); + box-shadow: 0 0 0 2px var(--sky); +} +.cybersigil .field-input:focus { + border-color: var(--sky); + background: color-mix(in srgb, var(--surface0) 85%, var(--sky) 8%); + box-shadow: 0 0 0 2px color-mix(in srgb, var(--sky) 35%, transparent); +} +.cybersigil .btn--ghost { + color: var(--sky); + border-color: color-mix(in srgb, var(--sky) 55%, transparent); + background: color-mix(in srgb, var(--surface0) 60%, transparent); + box-shadow: 3px 3px 0 0 color-mix(in srgb, var(--sky) 32%, var(--crust)); +} +.cybersigil .btn--ghost:hover { + color: var(--crust); + background: var(--sky); + border-color: var(--sky); + box-shadow: 3px 3px 0 0 var(--mauve); +} +.cybersigil .btn--ghost:active { + transform: translate(2px, 2px); + box-shadow: 1px 1px 0 0 var(--mauve); +} + +/* Back-link → sigil-marked neon return tab. */ +.cybersigil .back-link { + display: inline-flex; + align-items: center; + gap: 0.5em; + font-family: var(--font-mono); + font-style: normal; + font-size: 0.7rem; + text-transform: uppercase; + letter-spacing: 0.16em; + color: var(--sky); + padding: 7px 13px; + background: color-mix(in srgb, var(--crust) 70%, transparent); + border: 1px solid var(--mauve); + box-shadow: 3px 3px 0 0 var(--mauve); + text-shadow: 0 0 6px color-mix(in srgb, var(--sky) 50%, transparent); +} +.cybersigil .back-link::before { + content: ""; + width: 0.95em; + height: 0.95em; + flex: none; + background-color: currentColor; + -webkit-mask: var(--cs-sigil) center / contain no-repeat; + mask: var(--cs-sigil) center / contain no-repeat; + transform: rotate(-90deg); +} +.cybersigil .back-link:hover, +.cybersigil .back-link:focus-visible { + color: var(--crust); + background: var(--sky); + border-color: var(--sky); + box-shadow: 3px 3px 0 0 var(--mauve); + text-shadow: none; +} +.cybersigil .back-link:active { + transform: translate(3px, 3px); + box-shadow: 0 0 0 0 var(--mauve); +} + +/* Top-bar chrome — cold mono caps, hard offset. */ +.cybersigil .topbar-control { + font-family: var(--font-mono); + font-style: normal; + font-size: 0.72rem; + letter-spacing: 0.12em; + text-transform: uppercase; + color: var(--sky); + background: color-mix(in srgb, var(--crust) 60%, transparent); + border-color: color-mix(in srgb, var(--sky) 50%, transparent); +} +.cybersigil .topbar-control:hover { + color: var(--crust); + background: var(--mauve); + border-color: var(--mauve); + box-shadow: 2px 2px 0 0 var(--sky); +} +.cybersigil .topbar-control:focus-visible { + border-color: var(--sky); + box-shadow: 0 0 0 2px var(--sky); +} +.cybersigil .topbar-control--danger:hover { + background: var(--red); + border-color: var(--red); + color: var(--rosewater); + box-shadow: 2px 2px 0 0 var(--mauve); +} +.cybersigil .topbar-divider { + width: 2px; + background: repeating-linear-gradient( + 180deg, + var(--sky) 0 3px, + transparent 3px 5px, + var(--mauve) 5px 8px, + transparent 8px 10px + ); +} + +/* Post prev/next — neon offset panels + cyan eyebrow. */ +.cybersigil .post-nav a { transition: box-shadow 0.15s ease, border-color 0.15s ease; } +.cybersigil .post-nav a:hover { + border-color: var(--mauve); + box-shadow: + inset 0 0 0 1px color-mix(in srgb, var(--mauve) 40%, transparent), + 4px 4px 0 0 var(--mauve); +} +.cybersigil .post-nav .pn-eyebrow { + color: var(--sky); + font-family: var(--font-mono); + letter-spacing: 0.18em; + text-shadow: 0 0 6px color-mix(in srgb, var(--sky) 45%, transparent); +} + +/* Prose / code — cold terminal, amber inline, magenta quote, barbed rule. */ +.cybersigil .prose pre { + color: var(--sky); + background-color: color-mix(in srgb, var(--crust) 88%, transparent); + background-image: repeating-linear-gradient( + 0deg, + rgba(0, 0, 0, 0) 0 2px, + color-mix(in srgb, var(--sky) 8%, transparent) 2px 3px, + rgba(0, 0, 0, 0) 3px 4px + ); + border-color: var(--mauve); + border-left-color: var(--sky); + box-shadow: + 0 0 0 1px color-mix(in srgb, var(--sky) 24%, transparent), + 4px 4px 0 0 color-mix(in srgb, var(--mauve) 32%, var(--crust)); +} +.cybersigil .prose pre code { color: inherit; } +.cybersigil .prose :not(pre) code { + color: var(--yellow); + background: color-mix(in srgb, var(--yellow) 12%, transparent); + border-bottom-color: color-mix(in srgb, var(--yellow) 55%, transparent); +} +.cybersigil .prose blockquote { + border-left-color: var(--mauve); + background: color-mix(in srgb, var(--mauve) 8%, transparent); + box-shadow: -3px 0 16px -5px color-mix(in srgb, var(--mauve) 55%, transparent); + padding: 0.5rem 0 0.5rem 1.4rem; +} +.cybersigil .prose hr { + height: 3px; + opacity: 0.9; + background: repeating-linear-gradient( + 90deg, + var(--sky) 0 12px, + var(--mauve) 12px 24px + ); + box-shadow: 0 0 12px color-mix(in srgb, var(--sky) 42%, transparent); +} +.cybersigil .prose hr::before { + background: var(--sky); + box-shadow: 0 0 8px var(--sky); +} +.cybersigil .prose h3 { color: var(--pink); } +.cybersigil .prose h4 { color: var(--teal); } +.cybersigil .prose h5 { color: var(--green); font-family: var(--font-mono); } +.cybersigil .prose a { + text-decoration-color: color-mix(in srgb, var(--sky) 55%, transparent); +} +.cybersigil .prose a:hover { + color: var(--mauve); + text-decoration-color: var(--mauve); +} + +/* Scrollbar + caret — full-immersion cold chrome. */ +.cybersigil { + scrollbar-color: var(--sky) var(--crust); + caret-color: var(--mauve); +} +.cybersigil ::-webkit-scrollbar { width: 11px; height: 11px; } +.cybersigil ::-webkit-scrollbar-track { background: var(--crust); } +.cybersigil ::-webkit-scrollbar-thumb { + background: var(--sky); + border: 2px solid var(--crust); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--mauve) 55%, transparent); +} +.cybersigil ::-webkit-scrollbar-thumb:hover { background: var(--mauve); } +.cybersigil ::-webkit-scrollbar-corner { background: var(--crust); } + +/* Reading progress — ice scan with cold bloom. */ +.cybersigil .reading-progress { + background: var(--sky); + box-shadow: 0 0 8px var(--sky), 0 0 3px var(--mauve); +} + +/* Glass / tooltip / catalogue tag — cold neon parity with breakcore. */ +.cybersigil .glass { + background-color: color-mix(in srgb, var(--surface0) 72%, transparent); + border-color: color-mix(in srgb, var(--sky) 42%, var(--surface2)); + box-shadow: + inset 0 0 0 1px color-mix(in srgb, var(--sky) 22%, transparent), + 0 0 0 1px color-mix(in srgb, var(--mauve) 14%, transparent), + 0 14px 40px -24px rgba(0, 0, 0, 0.92); +} +.cybersigil .plate-tag-mini { + background: var(--crust); + color: var(--sky); + border: 1px solid var(--mauve); + border-radius: 0; + font-family: var(--font-mono); + font-weight: 500; +} +.cybersigil .kbd-tip { + background: var(--crust); + border-color: var(--mauve); + border-radius: 0; + color: var(--sky); + box-shadow: 2px 2px 0 var(--mauve); +} +.cybersigil .kbd-tip kbd { + color: var(--rosewater); + background: var(--surface0); + border-color: var(--mauve); + border-radius: 0; +} +.cybersigil input[type="date"] { color-scheme: dark; } + +/* Confirm dialog — hard edge, ice→magenta cap, chromatic title. */ +.cybersigil .cdialog-panel { + border-radius: 0; + padding-top: 1.85rem; +} +.cybersigil .cdialog-panel::before { + content: ""; + position: absolute; + inset: 0 0 auto 0; + height: 2px; + background: linear-gradient(90deg, var(--sky), var(--mauve)); +} +.cybersigil .cdialog-title { + text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve); +} + /* ═══ Reduced motion — universal kill-switch. Final word in the file so it * overrides every animation/transition above, all themes. Content still * resolves to its final state (forwards-filled keyframes complete). ═══ */