diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b58d8a9..2900289 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -21,6 +21,8 @@ "@fontsource-variable/fraunces": "^5.2.9", "@fontsource-variable/inter": "^5.2.5", "@fontsource-variable/jetbrains-mono": "^5.2.5", + "@fontsource/space-mono": "^5.2.9", + "@fontsource/vt323": "^5.2.7", "@replit/codemirror-vim": "^6.3.0", "@tailwindcss/vite": "^4.2.2", "astro": "^6.0.8", @@ -1722,6 +1724,24 @@ "url": "https://github.com/sponsors/ayuhito" } }, + "node_modules/@fontsource/space-mono": { + "version": "5.2.9", + "resolved": "https://registry.npmjs.org/@fontsource/space-mono/-/space-mono-5.2.9.tgz", + "integrity": "sha512-b61faFOHEISQ/pD25G+cfGY9o/WW6lRv6hBQQfpWvEJ4y1V+S4gmth95EVyBE2VL3qDYHeVQ8nBzrplzdXTDDg==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/vt323": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@fontsource/vt323/-/vt323-5.2.7.tgz", + "integrity": "sha512-8JTMM23vMhQxin9Cn/ijty8cNwXW4INrln0VAJ2227Rz0CVfkzM3qr3l/CqudZJ6BXCnbCGUTdf2ym3cTNex8A==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, "node_modules/@img/colour": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 46a023a..5ba44fd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,6 +25,8 @@ "@fontsource-variable/fraunces": "^5.2.9", "@fontsource-variable/inter": "^5.2.5", "@fontsource-variable/jetbrains-mono": "^5.2.5", + "@fontsource/space-mono": "^5.2.9", + "@fontsource/vt323": "^5.2.7", "@replit/codemirror-vim": "^6.3.0", "@tailwindcss/vite": "^4.2.2", "astro": "^6.0.8", diff --git a/frontend/src/components/CyberFx.astro b/frontend/src/components/CyberFx.astro new file mode 100644 index 0000000..0e61587 --- /dev/null +++ b/frontend/src/components/CyberFx.astro @@ -0,0 +1,110 @@ +--- +/* + * CyberFx — ambient + interactive layer for the `.cybersigil` theme. + * + * Renders an aria-hidden overlay root on every page. All visuals are CSS, + * scoped to `.cybersigil .cs-fx*` in global.css, so this is an inert, + * display:none no-op under every other theme. The bundled script only wires + * the JS-driven mechanics (custom sigil cursor + fading trail, scroll-entry + * databend on images) and self-disables off-theme, on touch, or under + * prefers-reduced-motion. + */ +--- + + + + diff --git a/frontend/src/layouts/Layout.astro b/frontend/src/layouts/Layout.astro index 92d9e77..d128be9 100644 --- a/frontend/src/layouts/Layout.astro +++ b/frontend/src/layouts/Layout.astro @@ -3,6 +3,10 @@ import '../styles/global.css'; import '@fontsource-variable/fraunces'; import '@fontsource-variable/eb-garamond'; import '@fontsource-variable/jetbrains-mono'; +import '@fontsource/vt323'; +import '@fontsource/space-mono'; +import '@fontsource/space-mono/700.css'; +import CyberFx from '../components/CyberFx.astro'; import Search from '../components/react/Search'; import LogoutButton from '../components/react/LogoutButton'; import EditableText from '../components/react/EditableText'; @@ -188,5 +192,7 @@ const hasContact = (siteConfig.contact_links?.length ?? 0) > 0; © {year} · {siteConfig.title} + + diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css index d1fb418..f207dd1 100644 --- a/frontend/src/styles/global.css +++ b/frontend/src/styles/global.css @@ -1873,71 +1873,252 @@ input[type="date"] { color-scheme: light; } } /* ═══════════════════════════════════════════════════════════════════════ - * CYBERSIGIL — Frostbite layer. + * CYBERSIGIL — 0xPORTFOLIO // SYSTEM.BREAK() * 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. + * An ancient corrupted terminal reclaimed by digital occultism: bitmap VT323 + * heads + Space Mono terminal body, raw [ BRACKET ] / > PROMPT_ chrome, + * organic thorny sigil growths (not HUD corners), CRT scanlines + halftone + + * film grain, slow wireframe drift, random line-tears, a delicate sigil + * crosshair cursor with a fading trail (wired in CyberFx.astro). Palette + * tokens are inherited untouched. Motion dies at the file's reduced-motion + * kill-switch; JS mechanics self-disable on touch / reduced-motion. * ═══════════════════════════════════════════════════════════════════════ */ -/* Deep tube vignette — blacker, tighter than breakcore. */ +/* Typeface swap — bitmap display, terminal-log body. Code stays JetBrains. */ +.cybersigil { + --font-sans: 'Space Mono', 'Courier New', ui-monospace, monospace; + --font-display: 'VT323', 'Space Mono', 'Courier New', monospace; + --cs-corner: url("data:image/svg+xml;utf8,"); + --cs-barb: url("data:image/svg+xml;utf8,"); + --cs-cursor: url("data:image/svg+xml;utf8,"); +} + +/* Heads — VT323 bitmap, hard, uppercase, slight tracking so the dot-matrix + * reads as a corrupted readout rather than a soft retro logo. */ +.cybersigil .prose h1, +.cybersigil .prose h2, +.cybersigil h1.font-display, +.cybersigil h2.font-display, +.cybersigil .nameplate-title { + font-family: var(--font-display); + font-weight: 400; + text-transform: uppercase; + letter-spacing: 0.03em; + line-height: 1.05; +} + +/* Deeper void vignette than breakcore — tube falloff into pure black. */ .cybersigil body::before { background-image: radial-gradient( ellipse at center, - transparent 40%, - color-mix(in srgb, var(--crust) 92%, transparent) 100% + transparent 34%, + color-mix(in srgb, var(--crust) 96%, transparent) 100% ); } -/* Fine cold grain + tight scanlines. Lower opacity than breakcore, blue- - * shifted — atmospheric, not blown out. */ +/* Corrupted-tube grain: cold static + tight scanlines, blue-shifted. */ .cybersigil body::after, html.cybersigil body::after { - opacity: 0.4; + opacity: 0.42; background-image: - url("data:image/svg+xml;utf8,"), + 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.36) 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; +/* Atmosphere glows — barely-lit cold pools. */ +.cybersigil .salon-atmosphere::before { background: var(--sky); opacity: 0.06; } +.cybersigil .salon-atmosphere::after { background: var(--mauve); opacity: 0.05; } + +/* ─── cs-fx overlay system (DOM in CyberFx.astro) ───────────────────────── + * Inert everywhere; only the cybersigil theme switches it on. Decorative + * layers ride above content at low opacity (pointer-events:none); the sigil + * cursor sits on top of everything. */ +.cs-fx { display: none; } +.cybersigil .cs-fx { + display: block; + position: fixed; + inset: 0; + z-index: 9; + pointer-events: none; + contain: strict; } -.cybersigil .salon-atmosphere::after { - background: var(--mauve); - opacity: 0.06; +.cybersigil .cs-fx-halftone, +.cybersigil .cs-fx-wire, +.cybersigil .cs-fx-tear, +.cybersigil .cs-fx-corner { + position: fixed; + pointer-events: none; } -/* Selection — magenta block, bone text, cyan bleed. */ +/* Halftone dot screen — fine occult mesh over the whole tube. */ +.cybersigil .cs-fx-halftone { + inset: 0; + opacity: 0.05; + mix-blend-mode: screen; + background-image: radial-gradient( + var(--sky) 0.6px, + transparent 1.4px + ); + background-size: 7px 7px; +} + +/* Slow wireframe mesh drift — a derelict orbital, almost subliminal. */ +.cybersigil .cs-fx-wire { + top: 50%; + left: 50%; + width: 78vmin; + height: 78vmin; + opacity: 0.07; + mix-blend-mode: screen; + background: center / contain no-repeat + url("data:image/svg+xml;utf8,"); + animation: cs-wire-spin 96s linear infinite; +} + +/* Random horizontal databend tears — bright displaced bars, mostly absent. */ +.cybersigil .cs-fx-tear { + left: 0; + width: 100vw; + height: 2px; + opacity: 0; + mix-blend-mode: screen; + background: var(--sky); + box-shadow: + 0 0 10px var(--sky), + 0 -3px 0 color-mix(in srgb, var(--mauve) 70%, transparent), + 0 3px 0 color-mix(in srgb, var(--teal) 60%, transparent); + animation: cs-tear 8.5s steps(1, jump-none) infinite; +} +.cybersigil .cs-fx-tear::after { + content: ""; + position: absolute; + inset: -22px 0 auto 0; + height: 46px; + background: repeating-linear-gradient( + 0deg, + transparent 0 2px, + color-mix(in srgb, var(--sky) 22%, transparent) 2px 3px + ); +} + +/* Thorny sigil growths anchoring the four screen corners. */ +.cybersigil .cs-fx-corner { + width: clamp(96px, 13vw, 188px); + height: clamp(96px, 13vw, 188px); + background-color: var(--sky); + opacity: 0.26; + -webkit-mask: var(--cs-corner) center / contain no-repeat; + mask: var(--cs-corner) center / contain no-repeat; + filter: drop-shadow(0 0 5px color-mix(in srgb, var(--sky) 45%, transparent)); + animation: cs-flicker 7s steps(1, jump-none) infinite; +} +.cybersigil .cs-fx-corner--tl { top: 0; left: 0; } +.cybersigil .cs-fx-corner--tr { top: 0; right: 0; transform: scaleX(-1); animation-delay: -1.7s; } +.cybersigil .cs-fx-corner--bl { bottom: 0; left: 0; transform: scaleY(-1); animation-delay: -3.4s; } +.cybersigil .cs-fx-corner--br { bottom: 0; right: 0; transform: scale(-1); animation-delay: -5.1s; } + +/* ─── Sigil crosshair cursor + fading trail ─── */ +.cybersigil .cs-cursor { + position: fixed; + top: 0; + left: 0; + width: 34px; + height: 34px; + margin: -17px 0 0 -17px; + z-index: 99999; + opacity: 0; + will-change: transform; + transition: opacity 0.16s linear; +} +html.cs-cursor-on.cybersigil, +html.cs-cursor-on.cybersigil * { cursor: none !important; } +html.cs-cursor-on .cybersigil .cs-cursor, +html.cs-cursor-on.cybersigil .cs-cursor { opacity: 1; } +.cybersigil .cs-cursor-ring { + position: absolute; + inset: 0; + background-color: var(--sky); + -webkit-mask: var(--cs-cursor) center / contain no-repeat; + mask: var(--cs-cursor) center / contain no-repeat; + filter: drop-shadow(0 0 4px color-mix(in srgb, var(--sky) 65%, transparent)); + transition: transform 0.12s cubic-bezier(0.2, 0.8, 0.2, 1), + background-color 0.12s linear, filter 0.12s linear; +} +.cybersigil .cs-cursor--hot .cs-cursor-ring { + background-color: var(--mauve); + transform: scale(1.32) rotate(45deg); + filter: drop-shadow(0 0 7px color-mix(in srgb, var(--mauve) 75%, transparent)); +} +.cybersigil .cs-cursor--down .cs-cursor-ring { transform: scale(0.78); } +.cybersigil .cs-cursor--hot.cs-cursor--down .cs-cursor-ring { transform: scale(1.05) rotate(45deg); } +.cybersigil .cs-cursor--gone { opacity: 0; } +.cybersigil .cs-trail { + position: fixed; + width: 5px; + height: 5px; + margin: -2.5px 0 0 -2.5px; + z-index: 99998; + pointer-events: none; + background: var(--sky); + transform: rotate(45deg); + animation: cs-trail-fade 480ms linear forwards; +} + +/* Selection — magenta block, bone glyph, 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). */ +/* Resting chromatic split on display heads + nameplate. */ .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); + -1px 0 0 color-mix(in srgb, var(--sky) 75%, transparent), + 1px 0 0 color-mix(in srgb, var(--mauve) 75%, transparent), + 0 0 22px color-mix(in srgb, var(--sky) 26%, transparent); } -/* Nameplate underline → ice rule, hard magenta offset + cyan bloom. */ +/* Nameplate = the system handle. `> ` prompt + live block caret. */ +.cybersigil .nameplate-title::before { + content: "> "; + color: var(--sky); + -webkit-text-fill-color: var(--sky); +} +.cybersigil .nameplate-title::after { + content: ""; + display: inline-block; + width: 0.52em; + height: 1em; + margin-left: 0.14em; + vertical-align: -0.12em; + background: var(--mauve); + box-shadow: 0 0 8px color-mix(in srgb, var(--mauve) 70%, transparent); + animation: cs-blink 1.05s steps(1, jump-none) infinite; +} +.cybersigil .nameplate-subtitle { + font-family: var(--font-sans); + font-style: normal; + text-transform: uppercase; + letter-spacing: 0.16em; + font-size: 0.72rem; + color: var(--subtext0); +} +.cybersigil .nameplate-subtitle::before { + content: "// "; + color: var(--sky); + opacity: 0.8; +} .cybersigil .nameplate::after { height: 2px; bottom: -7px; @@ -1950,7 +2131,7 @@ html.cybersigil body::after { 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); } + text-shadow: -7px 0 0 var(--sky), 7px 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); @@ -1962,70 +2143,65 @@ html.cybersigil body::after { 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). */ +/* Slow melancholic glitch-in on display heads. */ @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); } + 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. */ +/* Plate — corrupted terminal panel. Scanline fill, thorny sigil growth at + * two corners (organic, not HUD brackets), ignites magenta on contact. */ .cybersigil .plate { position: relative; - background: var(--surface0); + background: + repeating-linear-gradient( + 0deg, + rgba(0, 0, 0, 0) 0 2px, + color-mix(in srgb, var(--sky) 6%, transparent) 2px 3px, + rgba(0, 0, 0, 0) 3px 4px + ), + 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); + inset 0 0 0 1px color-mix(in srgb, var(--sky) 24%, transparent), + 0 0 0 1px color-mix(in srgb, var(--sky) 12%, transparent), + 0 22px 44px -28px rgba(79, 233, 255, 0.26), + 0 0 26px -10px color-mix(in srgb, var(--mauve) 34%, 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)); + width: 34px; + height: 34px; + background-color: color-mix(in srgb, var(--sky) 78%, transparent); + -webkit-mask: var(--cs-corner) center / contain no-repeat; + mask: var(--cs-corner) center / contain no-repeat; + filter: drop-shadow(0 0 3px 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); + transition: background-color 0.18s ease, filter 0.18s ease; } +.cybersigil .plate::before { top: 5px; left: 5px; } +.cybersigil .plate::after { right: 5px; bottom: 5px; transform: scale(-1); } .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), + inset 0 0 0 1px color-mix(in srgb, var(--mauve) 38%, transparent), + 0 0 0 1px color-mix(in srgb, var(--mauve) 24%, 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)); + background-color: var(--mauve); + filter: drop-shadow(0 0 6px color-mix(in srgb, var(--mauve) 60%, transparent)); } .cybersigil .plate:focus-visible { box-shadow: @@ -2036,14 +2212,12 @@ html.cybersigil body::after { .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-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); + saturate(0.9) contrast(1.06) brightness(0.95); } .cybersigil .plate .plate-image::after { content: ""; @@ -2073,6 +2247,38 @@ html.cybersigil body::after { .cybersigil .plate:focus-visible .plate-image::after { animation: cs-scan 0.78s cubic-bezier(0.4, 0, 0.2, 1) 1; } + +/* Scroll-entry databend (class toggled by CyberFx IntersectionObserver). */ +@keyframes cs-databend { + 0% { clip-path: inset(0 0 0 0); transform: translateX(0); filter: none; } + 12% { clip-path: inset(38% 0 30% 0); transform: translateX(-9px); + filter: drop-shadow(-5px 0 0 var(--mauve)) drop-shadow(5px 0 0 var(--sky)); } + 28% { clip-path: inset(8% 0 72% 0); transform: translateX(7px); + filter: drop-shadow(4px 0 0 var(--teal)) drop-shadow(-4px 0 0 var(--mauve)); } + 46% { clip-path: inset(64% 0 10% 0); transform: translateX(-4px); filter: saturate(1.3) contrast(1.1); } + 64% { clip-path: inset(24% 0 50% 0); transform: translateX(2px); filter: none; } + 100% { clip-path: inset(0 0 0 0); transform: translateX(0); filter: none; } +} +.cybersigil img.cs-databent { + animation: cs-databend 560ms steps(5, jump-none) 1; +} + +/* Prose image framing — thorny growth at opposing corners + cold edge. */ +.cybersigil .prose figure { position: relative; } +.cybersigil .prose figure::before, +.cybersigil .prose figure::after { + content: ""; + position: absolute; + width: 40px; + height: 40px; + background-color: color-mix(in srgb, var(--sky) 70%, transparent); + -webkit-mask: var(--cs-corner) center / contain no-repeat; + mask: var(--cs-corner) center / contain no-repeat; + pointer-events: none; + z-index: 1; +} +.cybersigil .prose figure::before { top: -8px; left: -8px; } +.cybersigil .prose figure::after { right: -8px; bottom: -8px; transform: scale(-1); } .cybersigil .prose figure img, .cybersigil .prose img { background: @@ -2080,14 +2286,14 @@ html.cybersigil body::after { 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. */ +/* Section rule — terminal divider `// ……… [sigil] ……… //`. */ .cybersigil .section-rule { color: var(--sky); - font-family: var(--font-mono); + font-family: var(--font-sans); font-style: normal; - font-size: 0.76rem; + font-size: 0.72rem; text-transform: uppercase; - letter-spacing: 0.24em; + letter-spacing: 0.22em; } .cybersigil .section-rule::before, .cybersigil .section-rule::after { @@ -2103,18 +2309,15 @@ html.cybersigil body::after { } .cybersigil .section-rule .ornament { color: transparent; - width: 1.1em; - height: 1.1em; + width: 2.4em; + height: 1.2em; 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,"); + -webkit-mask: var(--cs-barb) center / contain no-repeat; + mask: var(--cs-barb) center / contain no-repeat; + filter: drop-shadow(0 0 4px color-mix(in srgb, var(--sky) 55%, transparent)); } -/* Readability — lift dim-on-near-black copy spots to the subtext ramp. */ +/* Readability — lift dim-on-void copy to the subtext ramp. */ .cybersigil .prose h6, .cybersigil .prose del, .cybersigil .hljs-comment, @@ -2124,18 +2327,20 @@ html.cybersigil body::after { color: var(--subtext0); } -/* Chips — thin ice outline, mono caps. */ +/* Chips — `[ TAG ]` bracketed mono. */ .cybersigil .chip { background: transparent; border-color: color-mix(in srgb, var(--sky) 55%, transparent); color: var(--sky); - font-family: var(--font-mono); + font-family: var(--font-sans); font-style: normal; - font-size: 0.7rem; + font-size: 0.68rem; text-transform: uppercase; - letter-spacing: 0.1em; + letter-spacing: 0.08em; border-radius: 0; } +.cybersigil .chip::before { content: "["; margin-right: 0.3em; opacity: 0.7; } +.cybersigil .chip::after { content: "]"; margin-left: 0.3em; opacity: 0.7; } .cybersigil .chip-accent { background: var(--mauve); color: var(--rosewater); @@ -2147,19 +2352,32 @@ html.cybersigil body::after { 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; + font-family: var(--font-sans); + letter-spacing: 0.12em; + text-transform: uppercase; + font-size: 0.7rem; } +.cybersigil .plate-caption-sep { color: var(--sky); opacity: 1; } +.cybersigil .plate-caption-sep::after { content: "//"; } -/* Buttons & inputs — square, hard offset, ice→magenta neon. */ +/* Buttons — raw `[ LABEL ]` chrome, square, hard cold offset. */ .cybersigil .btn, .cybersigil .field-input, .cybersigil .topbar-control, .cybersigil .topbar-control kbd { border-radius: 0; } +.cybersigil .btn { + font-family: var(--font-sans); + text-transform: uppercase; + letter-spacing: 0.1em; +} +.cybersigil .btn::before { + content: "[\00a0"; + color: color-mix(in srgb, currentColor 70%, transparent); +} +.cybersigil .btn::after { + content: "\00a0]"; + color: color-mix(in srgb, currentColor 70%, transparent); +} .cybersigil .btn--primary { color: var(--rosewater); border-color: var(--mauve); @@ -2178,9 +2396,7 @@ html.cybersigil body::after { .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: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); @@ -2189,11 +2405,6 @@ html.cybersigil body::after { 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); @@ -2210,17 +2421,25 @@ html.cybersigil body::after { transform: translate(2px, 2px); box-shadow: 1px 1px 0 0 var(--mauve); } +.cybersigil .field-input { + font-family: var(--font-sans); +} +.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); +} -/* Back-link → sigil-marked neon return tab. */ +/* Back-link — `‹ RETURN_` command prompt with live caret + barb mark. */ .cybersigil .back-link { display: inline-flex; align-items: center; gap: 0.5em; - font-family: var(--font-mono); + font-family: var(--font-sans); font-style: normal; font-size: 0.7rem; text-transform: uppercase; - letter-spacing: 0.16em; + letter-spacing: 0.14em; color: var(--sky); padding: 7px 13px; background: color-mix(in srgb, var(--crust) 70%, transparent); @@ -2230,13 +2449,18 @@ html.cybersigil body::after { } .cybersigil .back-link::before { content: ""; - width: 0.95em; + width: 1.5em; 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); + -webkit-mask: var(--cs-barb) center / contain no-repeat; + mask: var(--cs-barb) center / contain no-repeat; + transform: scaleX(-1); +} +.cybersigil .back-link::after { + content: "_"; + margin-left: -0.1em; + animation: cs-blink 1.05s steps(1, jump-none) infinite; } .cybersigil .back-link:hover, .cybersigil .back-link:focus-visible { @@ -2251,17 +2475,27 @@ html.cybersigil body::after { box-shadow: 0 0 0 0 var(--mauve); } -/* Top-bar chrome — cold mono caps, hard offset. */ +/* Top-bar chrome — `> CMD` prompts with a blinking caret. */ .cybersigil .topbar-control { - font-family: var(--font-mono); + font-family: var(--font-sans); font-style: normal; font-size: 0.72rem; - letter-spacing: 0.12em; + letter-spacing: 0.1em; 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::before { + content: ">\00a0"; + color: color-mix(in srgb, currentColor 75%, transparent); +} +.cybersigil .topbar-control::after { + content: "_"; + margin-left: 0.18em; + opacity: 0.85; + animation: cs-blink 1.05s steps(1, jump-none) infinite; +} .cybersigil .topbar-control:hover { color: var(--crust); background: var(--mauve); @@ -2289,7 +2523,7 @@ html.cybersigil body::after { ); } -/* Post prev/next — neon offset panels + cyan eyebrow. */ +/* Post prev/next — terminal jump panels. */ .cybersigil .post-nav a { transition: box-shadow 0.15s ease, border-color 0.15s ease; } .cybersigil .post-nav a:hover { border-color: var(--mauve); @@ -2299,15 +2533,17 @@ html.cybersigil body::after { } .cybersigil .post-nav .pn-eyebrow { color: var(--sky); - font-family: var(--font-mono); - letter-spacing: 0.18em; + font-family: var(--font-sans); + text-transform: uppercase; + letter-spacing: 0.16em; text-shadow: 0 0 6px color-mix(in srgb, var(--sky) 45%, transparent); } +.cybersigil .post-nav .pn-eyebrow::before { content: "// "; opacity: 0.7; } -/* Prose / code — cold terminal, amber inline, magenta quote, barbed rule. */ +/* Prose / code — terminal log. Cold console, amber inline, magenta quote. */ .cybersigil .prose pre { color: var(--sky); - background-color: color-mix(in srgb, var(--crust) 88%, transparent); + background-color: color-mix(in srgb, var(--crust) 90%, transparent); background-image: repeating-linear-gradient( 0deg, rgba(0, 0, 0, 0) 0 2px, @@ -2326,11 +2562,19 @@ html.cybersigil body::after { background: color-mix(in srgb, var(--yellow) 12%, transparent); border-bottom-color: color-mix(in srgb, var(--yellow) 55%, transparent); } +.cybersigil .prose :not(pre) code::before, +.cybersigil .prose :not(pre) code::after { content: "`"; opacity: 0.5; } .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; + font-style: normal; +} +.cybersigil .prose blockquote p:first-of-type::before { + content: "> "; + color: var(--mauve); + font-weight: 700; } .cybersigil .prose hr { height: 3px; @@ -2346,18 +2590,30 @@ html.cybersigil body::after { background: var(--sky); box-shadow: 0 0 8px var(--sky); } +.cybersigil .prose h3, +.cybersigil .prose h4, +.cybersigil .prose h5 { + font-family: var(--font-sans); + text-transform: uppercase; + letter-spacing: 0.06em; +} .cybersigil .prose h3 { color: var(--pink); } +.cybersigil .prose h3::before { content: "## "; color: var(--sky); opacity: 0.65; } .cybersigil .prose h4 { color: var(--teal); } -.cybersigil .prose h5 { color: var(--green); font-family: var(--font-mono); } +.cybersigil .prose h4::before { content: "### "; color: var(--sky); opacity: 0.6; } +.cybersigil .prose h5 { color: var(--green); } +.cybersigil .prose h5::before { content: "#### "; color: var(--sky); opacity: 0.55; } .cybersigil .prose a { - text-decoration-color: color-mix(in srgb, var(--sky) 55%, transparent); + text-decoration-style: dotted; + text-decoration-color: color-mix(in srgb, var(--sky) 60%, transparent); } .cybersigil .prose a:hover { color: var(--mauve); text-decoration-color: var(--mauve); + text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve); } -/* Scrollbar + caret — full-immersion cold chrome. */ +/* Scrollbar + caret — hard cold chrome. */ .cybersigil { scrollbar-color: var(--sky) var(--crust); caret-color: var(--mauve); @@ -2378,9 +2634,9 @@ html.cybersigil body::after { box-shadow: 0 0 8px var(--sky), 0 0 3px var(--mauve); } -/* Glass / tooltip / catalogue tag — cold neon parity with breakcore. */ +/* Glass / tooltip / tag — square cold terminal parity. */ .cybersigil .glass { - background-color: color-mix(in srgb, var(--surface0) 72%, transparent); + background-color: color-mix(in srgb, var(--surface0) 74%, 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), @@ -2392,8 +2648,9 @@ html.cybersigil body::after { color: var(--sky); border: 1px solid var(--mauve); border-radius: 0; - font-family: var(--font-mono); - font-weight: 500; + font-family: var(--font-sans); + font-weight: 700; + text-transform: uppercase; } .cybersigil .kbd-tip { background: var(--crust); @@ -2410,22 +2667,65 @@ html.cybersigil body::after { } .cybersigil input[type="date"] { color-scheme: dark; } -/* Confirm dialog — hard edge, ice→magenta cap, chromatic title. */ +/* Confirm dialog — hard terminal halt prompt. */ .cybersigil .cdialog-panel { border-radius: 0; - padding-top: 1.85rem; + padding-top: 1.95rem; } .cybersigil .cdialog-panel::before { - content: ""; + content: "// SYSTEM.HALT?"; position: absolute; inset: 0 0 auto 0; - height: 2px; + height: 1.5rem; + display: flex; + align-items: center; + padding: 0 0.75rem; + font-family: var(--font-sans); + font-size: 0.62rem; + letter-spacing: 0.18em; + color: var(--crust); background: linear-gradient(90deg, var(--sky), var(--mauve)); } .cybersigil .cdialog-title { + font-family: var(--font-display); + text-transform: uppercase; text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve); } +/* ─── Theme keyframes ─── */ +@keyframes cs-blink { + 0%, 49% { opacity: 1; } + 50%, 100% { opacity: 0; } +} +@keyframes cs-wire-spin { + from { transform: translate(-50%, -50%) rotate(0deg); } + to { transform: translate(-50%, -50%) rotate(360deg); } +} +@keyframes cs-flicker { + 0%, 8% { opacity: 0.26; } + 9% { opacity: 0.46; } + 10%, 70% { opacity: 0.26; } + 71% { opacity: 0.08; } + 72% { opacity: 0.34; } + 73%, 100% { opacity: 0.26; } +} +@keyframes cs-tear { + 0%, 21% { opacity: 0; top: 18%; } + 22% { opacity: 0.85; top: 18%; transform: translateX(-7px); } + 23% { opacity: 0; } + 46% { opacity: 0; top: 63%; } + 47% { opacity: 0.7; top: 63%; transform: translateX(6px) skewX(-12deg); } + 48%, 49% { opacity: 0; } + 79% { opacity: 0; top: 41%; } + 80% { opacity: 0.9; top: 41%; transform: translateX(-4px); } + 81% { opacity: 0.2; } + 82%, 100% { opacity: 0; } +} +@keyframes cs-trail-fade { + 0% { opacity: 0.7; transform: rotate(45deg) scale(1); } + 100% { opacity: 0; transform: rotate(45deg) scale(0.2); } +} + /* ═══ 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). ═══ */