Compare commits

..

2 Commits

Author SHA1 Message Date
nvrl c576794951 removed cursor 2026-05-16 17:39:57 +02:00
nvrl 9a3d3c89f3 fixed assets manager spacing 2026-05-16 17:37:29 +02:00
3 changed files with 159 additions and 163 deletions
+1 -60
View File
@@ -5,8 +5,7 @@
* Renders an aria-hidden overlay root on every page. All visuals are CSS, * 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, * 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 * display:none no-op under every other theme. The bundled script only wires
* the JS-driven mechanics (custom sigil cursor + fading trail, scroll-entry * the scroll-entry databend on images and self-disables off-theme or under
* databend on images) and self-disables off-theme, on touch, or under
* prefers-reduced-motion. * prefers-reduced-motion.
*/ */
--- ---
@@ -21,70 +20,12 @@
<i class="cs-fx-corner cs-fx-corner--br"></i> <i class="cs-fx-corner cs-fx-corner--br"></i>
</div> </div>
<!-- Cursor lives in its own top-level, un-contained, max-z root so it floats
above every modal/library (Search + AssetManager are z-[200]). -->
<div class="cs-cursor-root" aria-hidden="true">
<div class="cs-cursor">
<span class="cs-cursor-ring"></span>
<span class="cs-cursor-core"></span>
</div>
</div>
<script> <script>
function initCyberFx() { function initCyberFx() {
const root = document.documentElement; const root = document.documentElement;
if (!root.classList.contains('cybersigil')) return; if (!root.classList.contains('cybersigil')) return;
const fx = document.querySelector('.cs-fx') as HTMLElement | null;
const cursorRoot = document.querySelector('.cs-cursor-root') as HTMLElement | null;
if (!fx || !cursorRoot) return;
const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches; const reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const finePointer = window.matchMedia('(pointer: fine)').matches;
const noHover = window.matchMedia('(hover: none)').matches;
/* ─── Custom sigil cursor + fading trail ─── */
const cursor = cursorRoot.querySelector('.cs-cursor') as HTMLElement | null;
if (cursor && finePointer && !noHover) {
root.classList.add('cs-cursor-on');
let cx = window.innerWidth / 2;
let cy = window.innerHeight / 2;
let raf = 0;
let lastTrail = 0;
const HOT = 'a,button,input,textarea,select,[role="button"],.btn,.plate,.topbar-control,.back-link,.chip';
function paint() {
raf = 0;
cursor!.style.transform = `translate3d(${cx}px, ${cy}px, 0)`;
}
window.addEventListener(
'mousemove',
(e) => {
cx = e.clientX;
cy = e.clientY;
if (!raf) raf = requestAnimationFrame(paint);
const t = e.target as Element | null;
const hot = !!(t && t.closest && t.closest(HOT));
cursor!.classList.toggle('cs-cursor--hot', hot);
if (!reduced && e.timeStamp - lastTrail > 28) {
lastTrail = e.timeStamp;
const dot = document.createElement('span');
dot.className = 'cs-trail';
dot.style.left = cx + 'px';
dot.style.top = cy + 'px';
cursorRoot!.appendChild(dot);
dot.addEventListener('animationend', () => dot.remove(), { once: true });
}
},
{ passive: true }
);
window.addEventListener('mousedown', () => cursor!.classList.add('cs-cursor--down'));
window.addEventListener('mouseup', () => cursor!.classList.remove('cs-cursor--down'));
document.addEventListener('mouseleave', () => cursor!.classList.add('cs-cursor--gone'));
document.addEventListener('mouseenter', () => cursor!.classList.remove('cs-cursor--gone'));
}
/* ─── Scroll-entry databend on images ─── */ /* ─── Scroll-entry databend on images ─── */
if (!reduced && 'IntersectionObserver' in window) { if (!reduced && 'IntersectionObserver' in window) {
@@ -61,13 +61,13 @@ export default function AssetManager({ mode = 'manage', onSelect }: Props) {
const isImage = (name: string) => /\.(jpg|jpeg|png|webp|gif|svg)$/i.test(name); const isImage = (name: string) => /\.(jpg|jpeg|png|webp|gif|svg)$/i.test(name);
return ( return (
<div className="space-y-8"> <div className="asset-mgr space-y-8">
{alert && ( {alert && (
<div <div
className={`p-4 mb-6 text-sm font-display italic border ${ className={`asset-alert p-4 mb-6 text-sm font-display italic border ${
alert.type === 'success' alert.type === 'success'
? 'bg-[color-mix(in_srgb,var(--green)_18%,transparent)] text-[var(--green)] border-[var(--green)]/40' ? 'asset-alert--ok bg-[color-mix(in_srgb,var(--green)_18%,transparent)] text-[var(--green)] border-[var(--green)]/40'
: 'bg-[color-mix(in_srgb,var(--red)_18%,transparent)] text-[var(--red)] border-[var(--red)]/40' : 'asset-alert--err bg-[color-mix(in_srgb,var(--red)_18%,transparent)] text-[var(--red)] border-[var(--red)]/40'
}`} }`}
style={{ borderRadius: 2 }} style={{ borderRadius: 2 }}
> >
@@ -77,31 +77,31 @@ export default function AssetManager({ mode = 'manage', onSelect }: Props) {
{/* Upload Zone */} {/* Upload Zone */}
<div <div
className="glass p-6 border-dashed border-2 border-[var(--surface2)] hover:border-[var(--mauve)] transition-colors group relative cursor-pointer" className="asset-drop glass p-6 border-dashed border-2 border-[var(--surface2)] hover:border-[var(--mauve)] transition-colors group relative cursor-pointer"
onClick={() => fileRef.current?.click()} onClick={() => fileRef.current?.click()}
onDragOver={e => { e.preventDefault(); e.stopPropagation(); }} onDragOver={e => { e.preventDefault(); e.stopPropagation(); }}
onDrop={e => { e.preventDefault(); e.stopPropagation(); if (e.dataTransfer.files.length) handleUpload(e.dataTransfer.files); }} onDrop={e => { e.preventDefault(); e.stopPropagation(); if (e.dataTransfer.files.length) handleUpload(e.dataTransfer.files); }}
> >
<input ref={fileRef} type="file" multiple className="hidden" onChange={e => { if (e.target.files?.length) handleUpload(e.target.files); }} /> <input ref={fileRef} type="file" multiple className="hidden" onChange={e => { if (e.target.files?.length) handleUpload(e.target.files); }} />
<div className="text-center py-4"> <div className="asset-drop-body text-center py-4">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="mx-auto mb-4 text-[var(--subtext0)] group-hover:text-[var(--mauve)] transition-colors"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" strokeLinecap="round" strokeLinejoin="round" className="mx-auto mb-4 text-[var(--subtext0)] group-hover:text-[var(--mauve)] transition-colors"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" x2="12" y1="3" y2="15"/></svg>
<p className="font-display italic text-xl text-[var(--text)] group-hover:text-[var(--mauve)] transition-colors">Click or drag to upload assets</p> <p className="asset-drop-title font-display italic text-xl text-[var(--text)] group-hover:text-[var(--mauve)] transition-colors">Click or drag to upload assets</p>
<p className="font-sans text-xs uppercase tracking-[0.2em] text-[var(--subtext0)] mt-2">Any file type · up to 50 MB</p> <p className="font-sans text-xs uppercase tracking-[0.2em] text-[var(--subtext0)] mt-2">Any file type · up to 50 MB</p>
</div> </div>
</div> </div>
{/* Grid */} {/* Grid */}
{assets.length === 0 ? ( {assets.length === 0 ? (
<div className="text-center py-20 font-display italic text-[var(--subtext0)]">No assets uploaded yet.</div> <div className="asset-empty text-center py-20 font-display italic text-[var(--subtext0)]">No assets uploaded yet.</div>
) : ( ) : (
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-4"> <div className="asset-grid grid grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-4">
{assets.map(asset => ( {assets.map(asset => (
<div <div
key={asset.name} key={asset.name}
className="group relative aspect-square overflow-hidden bg-[var(--surface0)] border border-[var(--surface2)]/60 hover:border-[var(--mauve)]/60 transition-colors shadow-md flex flex-col" className="asset-tile group relative aspect-square overflow-hidden bg-[var(--surface0)] border border-[var(--surface2)]/60 hover:border-[var(--mauve)]/60 transition-colors shadow-md flex flex-col"
style={{ borderRadius: 2 }} style={{ borderRadius: 2 }}
> >
<div className="flex-1 overflow-hidden bg-[var(--mantle)] relative cursor-pointer"> <div className="asset-thumb flex-1 overflow-hidden bg-[var(--mantle)] relative cursor-pointer">
{isImage(asset.name) ? ( {isImage(asset.name) ? (
<img src={asset.url} className="w-full h-full object-cover opacity-90 group-hover:opacity-100 transition-opacity" alt={asset.name} /> <img src={asset.url} className="w-full h-full object-cover opacity-90 group-hover:opacity-100 transition-opacity" alt={asset.name} />
) : ( ) : (
@@ -111,7 +111,7 @@ export default function AssetManager({ mode = 'manage', onSelect }: Props) {
</div> </div>
)} )}
{/* Hover overlay */} {/* Hover overlay */}
<div className="absolute inset-0 bg-[var(--crust)]/75 backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-3"> <div className="asset-actions absolute inset-0 bg-[var(--crust)]/75 backdrop-blur-sm opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center gap-3">
{mode === 'select' && onSelect && ( {mode === 'select' && onSelect && (
<button <button
onClick={() => onSelect(asset)} onClick={() => onSelect(asset)}
@@ -129,7 +129,7 @@ export default function AssetManager({ mode = 'manage', onSelect }: Props) {
</button> </button>
</div> </div>
</div> </div>
<div className="p-2 bg-[var(--surface0)] text-[10px] truncate border-t border-[var(--surface2)]/50 text-[var(--subtext1)] font-mono">{asset.name}</div> <div className="asset-name p-2 bg-[var(--surface0)] text-[10px] truncate border-t border-[var(--surface2)]/50 text-[var(--subtext1)] font-mono">{asset.name}</div>
</div> </div>
))} ))}
</div> </div>
+145 -90
View File
@@ -1890,7 +1890,6 @@ input[type="date"] { color-scheme: light; }
--font-display: 'VT323', 'Space Mono', 'Courier New', monospace; --font-display: 'VT323', 'Space Mono', 'Courier New', monospace;
--cs-corner: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round'><path stroke-width='2.4' d='M3 3 C 26 10 33 26 36 44 C 38 60 46 70 60 78 C 74 86 84 86 97 84 M16 7 C 22 2 30 1 40 2 M14 17 C 8 24 5 33 4 45 M35 40 C 45 36 56 37 66 41 M34 49 C 30 60 30 71 33 83 M52 73 C 60 66 70 64 82 65 M58 80 C 55 90 56 97 60 99'/><path stroke-width='1' opacity='0.8' d='M24 9 L30 3 M10 31 L3 34 M41 38 L47 31 M33 61 L26 66 M71 66 L79 61 M49 55 L44 49 M22 24 L17 20'/></svg>"); --cs-corner: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round'><path stroke-width='2.4' d='M3 3 C 26 10 33 26 36 44 C 38 60 46 70 60 78 C 74 86 84 86 97 84 M16 7 C 22 2 30 1 40 2 M14 17 C 8 24 5 33 4 45 M35 40 C 45 36 56 37 66 41 M34 49 C 30 60 30 71 33 83 M52 73 C 60 66 70 64 82 65 M58 80 C 55 90 56 97 60 99'/><path stroke-width='1' opacity='0.8' d='M24 9 L30 3 M10 31 L3 34 M41 38 L47 31 M33 61 L26 66 M71 66 L79 61 M49 55 L44 49 M22 24 L17 20'/></svg>");
--cs-barb: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 22' fill='none' stroke='%23fff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M2 11 C 24 4 40 18 60 11 C 80 4 96 18 118 11'/><path stroke-width='1.3' d='M18 8 L22 1 M30 13 L27 21 M48 12 L48 2 M60 11 L60 1 M72 12 L76 20 M90 9 L87 1 M104 13 L108 21'/></svg>"); --cs-barb: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 22' fill='none' stroke='%23fff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M2 11 C 24 4 40 18 60 11 C 80 4 96 18 118 11'/><path stroke-width='1.3' d='M18 8 L22 1 M30 13 L27 21 M48 12 L48 2 M60 11 L60 1 M72 12 L76 20 M90 9 L87 1 M104 13 L108 21'/></svg>");
--cs-cursor: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 36 36' fill='none' stroke='%23fff' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'><path d='M18 1 L18 11 M18 25 L18 35 M1 18 L11 18 M25 18 L35 18 M18 1 L14 6 M18 1 L22 6 M18 35 L14 30 M18 35 L22 30 M1 18 L6 14 M1 18 L6 22 M35 18 L30 14 M35 18 L30 22'/><path fill='%23fff' stroke='none' d='M18 13 L23 18 L18 23 L13 18 Z'/></svg>");
} }
/* Heads — VT323 bitmap, hard, uppercase, slight tracking so the dot-matrix /* Heads — VT323 bitmap, hard, uppercase, slight tracking so the dot-matrix
@@ -1940,8 +1939,7 @@ html.cybersigil body::after {
* Inert everywhere; only the cybersigil theme switches it on. Decorative * Inert everywhere; only the cybersigil theme switches it on. Decorative
* layers ride above content at low opacity (pointer-events:none); the sigil * layers ride above content at low opacity (pointer-events:none); the sigil
* cursor sits on top of everything. */ * cursor sits on top of everything. */
.cs-fx, .cs-fx { display: none; }
.cs-cursor-root { display: none; }
.cybersigil .cs-fx { .cybersigil .cs-fx {
display: block; display: block;
position: fixed; position: fixed;
@@ -2024,88 +2022,6 @@ html.cybersigil body::after {
.cybersigil .cs-fx-corner--bl { bottom: 0; left: 0; transform: scaleY(-1); animation-delay: -3.4s; } .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; } .cybersigil .cs-fx-corner--br { bottom: 0; right: 0; transform: scale(-1); animation-delay: -5.1s; }
/* ─── Sigil crosshair cursor + fading trail ───
* Lives in its own un-contained, max-z root (CyberFx.astro) so it floats
* above every modal/library (Search + AssetManager are z-[200]). A solid
* bright core dot gives a precise aim point; a black hairline + colored
* bloom keep the sigil legible on dark void AND light asset thumbnails. */
.cybersigil .cs-cursor-root {
display: block;
position: fixed;
inset: 0;
z-index: 2147483647;
pointer-events: none;
}
.cybersigil .cs-cursor {
position: fixed;
top: 0;
left: 0;
width: 42px;
height: 42px;
margin: -21px 0 0 -21px;
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 { 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 1px #000)
drop-shadow(0 0 1px #000)
drop-shadow(0 0 6px color-mix(in srgb, var(--sky) 80%, 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-core {
position: absolute;
top: 50%;
left: 50%;
width: 6px;
height: 6px;
margin: -3px 0 0 -3px;
background: var(--rosewater);
box-shadow:
0 0 0 1.5px var(--crust),
0 0 7px 1px var(--mauve);
transition: background-color 0.12s linear, box-shadow 0.12s linear,
transform 0.12s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.cybersigil .cs-cursor--hot .cs-cursor-ring {
background-color: var(--mauve);
transform: scale(1.3) rotate(45deg);
filter:
drop-shadow(0 0 1px #000)
drop-shadow(0 0 1px #000)
drop-shadow(0 0 9px color-mix(in srgb, var(--mauve) 85%, transparent));
}
.cybersigil .cs-cursor--hot .cs-cursor-core {
background: var(--sky);
box-shadow: 0 0 0 1.5px var(--crust), 0 0 9px 2px var(--sky);
transform: scale(1.25);
}
.cybersigil .cs-cursor--down .cs-cursor-ring { transform: scale(0.8); }
.cybersigil .cs-cursor--hot.cs-cursor--down .cs-cursor-ring { transform: scale(1.05) rotate(45deg); }
.cybersigil .cs-cursor--down .cs-cursor-core { transform: scale(0.7); }
.cybersigil .cs-cursor--gone { opacity: 0; }
.cybersigil .cs-trail {
position: fixed;
width: 6px;
height: 6px;
margin: -3px 0 0 -3px;
pointer-events: none;
background: var(--sky);
box-shadow: 0 0 5px 1px color-mix(in srgb, var(--sky) 70%, transparent);
transform: rotate(45deg);
animation: cs-trail-fade 460ms linear forwards;
}
/* Selection — magenta block, bone glyph, cyan bleed. */ /* Selection — magenta block, bone glyph, cyan bleed. */
.cybersigil ::selection { .cybersigil ::selection {
background: var(--mauve); background: var(--mauve);
@@ -2413,6 +2329,21 @@ html.cs-cursor-on.cybersigil .cs-cursor { opacity: 1; }
content: "\00a0]"; content: "\00a0]";
color: color-mix(in srgb, currentColor 70%, transparent); color: color-mix(in srgb, currentColor 70%, transparent);
} }
/* Icon-only buttons get no brackets — `[ icon ]` reads odd and overflows
* fixed-width chrome. */
.cybersigil .btn--icon::before,
.cybersigil .btn--icon::after { content: none; }
/* Asset-tile hover actions: drop brackets + tighten so Insert+Delete fit
* the small square tiles. */
.cybersigil .asset-actions { gap: 0.4rem; }
.cybersigil .asset-actions .btn::before,
.cybersigil .asset-actions .btn::after { content: none; }
.cybersigil .asset-actions .btn {
letter-spacing: 0.03em;
font-size: 0.66rem;
padding: 0 0.5rem;
}
.cybersigil .asset-actions .btn--icon { padding: 0; }
.cybersigil .btn--primary { .cybersigil .btn--primary {
color: var(--rosewater); color: var(--rosewater);
border-color: var(--mauve); border-color: var(--mauve);
@@ -2804,6 +2735,135 @@ html.cs-cursor-on.cybersigil .cs-cursor { opacity: 1; }
font-family: var(--font-sans) !important; font-family: var(--font-sans) !important;
} }
/* Asset library — a file-sector readout. Dashed drop-sector, scanline tile
* panels with a thorny sigil growth, `/path` filename bars, log-line alerts. */
.cybersigil .asset-alert {
border-radius: 0 !important;
font-family: var(--font-sans) !important;
font-style: normal !important;
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.74rem !important;
}
.cybersigil .asset-alert::before {
font-weight: 700;
margin-right: 0.5em;
}
.cybersigil .asset-alert--ok::before { content: ">> "; }
.cybersigil .asset-alert--err::before { content: "!! "; }
.cybersigil .asset-drop {
border-style: dashed !important;
border-color: color-mix(in srgb, var(--sky) 55%, transparent) !important;
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
),
color-mix(in srgb, var(--surface0) 74%, transparent) !important;
}
.cybersigil .asset-drop:hover {
border-color: var(--mauve) !important;
box-shadow: 0 0 0 1px color-mix(in srgb, var(--mauve) 40%, transparent);
}
.cybersigil .asset-drop svg { stroke-width: 1.5; }
.cybersigil .asset-drop-title {
font-family: var(--font-display) !important;
font-style: normal !important;
text-transform: uppercase;
letter-spacing: 0.04em;
text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve);
}
.cybersigil .asset-drop-title::before {
content: "> ";
color: var(--sky);
}
.cybersigil .asset-drop-title::after {
content: "_";
color: var(--mauve);
animation: cs-blink 1.05s steps(1, jump-none) infinite;
}
.cybersigil .asset-empty {
font-family: var(--font-sans);
font-style: normal;
text-transform: uppercase;
letter-spacing: 0.16em;
color: var(--subtext0);
}
.cybersigil .asset-empty::before { content: "// "; color: var(--sky); opacity: 0.7; }
.cybersigil .asset-tile {
border-radius: 0 !important;
border-color: color-mix(in srgb, var(--sky) 26%, transparent) !important;
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--sky) 16%, transparent),
0 0 0 1px color-mix(in srgb, var(--sky) 10%, transparent) !important;
transition: border-color 0.16s ease, box-shadow 0.16s ease, transform 0.16s ease;
}
.cybersigil .asset-tile::after {
content: "";
position: absolute;
top: 3px;
left: 3px;
width: 26px;
height: 26px;
z-index: 2;
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;
transition: background-color 0.16s ease;
}
.cybersigil .asset-tile:hover {
border-color: var(--mauve) !important;
transform: translateY(-2px);
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--mauve) 36%, transparent),
4px 4px 0 0 var(--mauve) !important;
}
.cybersigil .asset-tile:hover::after {
background-color: var(--mauve);
}
.cybersigil .asset-thumb {
background:
repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0) 0 2px,
color-mix(in srgb, var(--sky) 7%, transparent) 2px 3px,
rgba(0, 0, 0, 0) 3px 4px
),
var(--mantle);
}
.cybersigil .asset-thumb > div span {
font-family: var(--font-sans) !important;
color: var(--sky);
letter-spacing: 0.1em;
}
.cybersigil .asset-tile:hover .asset-thumb img {
filter:
drop-shadow(-2px 0 0 color-mix(in srgb, var(--mauve) 60%, transparent))
drop-shadow(2px 0 0 color-mix(in srgb, var(--sky) 60%, transparent))
saturate(0.92) contrast(1.05);
}
.cybersigil .asset-actions {
background: color-mix(in srgb, var(--crust) 82%, transparent) !important;
}
.cybersigil .asset-name {
font-family: var(--font-sans) !important;
color: var(--sky);
border-top-color: color-mix(in srgb, var(--sky) 30%, transparent) !important;
background: var(--crust) !important;
letter-spacing: 0.02em;
}
.cybersigil .asset-name::before { content: "/"; opacity: 0.55; }
.cybersigil .asset-tile:hover .asset-name {
color: var(--mauve);
border-top-color: color-mix(in srgb, var(--mauve) 45%, transparent) !important;
}
/* Confirm dialog — hard terminal halt prompt. */ /* Confirm dialog — hard terminal halt prompt. */
.cybersigil .cdialog-panel { .cybersigil .cdialog-panel {
border-radius: 0; border-radius: 0;
@@ -2858,11 +2918,6 @@ html.cs-cursor-on.cybersigil .cs-cursor { opacity: 1; }
81% { opacity: 0.2; } 81% { opacity: 0.2; }
82%, 100% { opacity: 0; } 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 /* ═══ Reduced motion — universal kill-switch. Final word in the file so it
* overrides every animation/transition above, all themes. Content still * overrides every animation/transition above, all themes. Content still
* resolves to its final state (forwards-filled keyframes complete). ═══ */ * resolves to its final state (forwards-filled keyframes complete). ═══ */