Files
narlblog/frontend/src/styles/global.css
T
2026-05-16 18:45:49 +02:00

3054 lines
96 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@import "tailwindcss";
/*
* SALON HANG — gallery theme.
* Aged parchment ground, oxblood ink, ochre+cobalt+vermillion accents.
* Romantic gravity (Friedrich, Dix, Goya) + raw scrawl (Basquiat) + bold cutout (Matisse, Kahlo).
*/
@theme {
--color-crust: var(--crust);
--color-mantle: var(--mantle);
--color-bg: var(--base);
--color-surface0: var(--surface0);
--color-surface1: var(--surface1);
--color-surface2: var(--surface2);
--color-overlay0: var(--overlay0);
--color-overlay1: var(--overlay1);
--color-overlay2: var(--overlay2);
--color-text: var(--text);
--color-subtext0: var(--subtext0);
--color-subtext1: var(--subtext1);
--color-blue: var(--blue);
--color-lavender: var(--lavender);
--color-sapphire: var(--sapphire);
--color-sky: var(--sky);
--color-teal: var(--teal);
--color-green: var(--green);
--color-yellow: var(--yellow);
--color-peach: var(--peach);
--color-maroon: var(--maroon);
--color-red: var(--red);
--color-mauve: var(--mauve);
--color-pink: var(--pink);
--color-flamingo: var(--flamingo);
--color-rosewater: var(--rosewater);
--font-sans: 'EB Garamond Variable', 'EB Garamond', Georgia, 'Times New Roman', serif;
--font-display: 'Fraunces Variable', 'Fraunces', Georgia, 'Times New Roman', serif;
--font-hand: 'Caveat', 'Bradley Hand', cursive;
--font-mono: 'JetBrains Mono Variable', ui-monospace, 'SF Mono', Menlo, monospace;
}
/* SALON — default. Aged parchment with romantic weight. */
:root, .salon {
--crust: #14100C;
--mantle: #2A1F18;
--base: #ECE0C6;
--surface0: #DDCEB0;
--surface1: #B69C70;
--surface2: #826846;
--overlay0: #5C463A;
--overlay1: #463226;
--overlay2: #2E1F17;
--text: #1A120C;
--subtext0: #5C463A;
--subtext1: #3D2B1E;
/* accents — mapped to the original token names so existing UI flows pick them up */
--blue: #1F3A78; /* Kahlo cobalt */
--lavender: #5C4D7A; /* faded violet */
--sapphire: #2B3E5C; /* deep ink-blue */
--sky: #4A6FA0; /* muted azure */
--teal: #4C7264; /* verdigris */
--green: #6A7341; /* olive */
--yellow: #C9882B; /* Friedrich ochre */
--peach: #C26847; /* terracotta */
--maroon: #6B2B2A; /* wine */
--red: #B83A2B; /* Matisse/Goya vermillion */
--mauve: #6B1F1A; /* oxblood — primary accent */
--pink: #B85A6C; /* rosehip */
--flamingo: #C77A6C; /* faded coral */
--rosewater: #E8D9BD; /* bone */
}
/* Salon Noir — black gallery wall variant (Goya black paintings, Abramović stark). */
.salon-noir {
--crust: #050402;
--mantle: #0E0A06;
--base: #16110B;
--surface0: #221A12;
--surface1: #3A2B1E;
--surface2: #5C4530;
--overlay0: #7A5D43;
--overlay1: #93755A;
--overlay2: #B69779;
--text: #ECE0C6;
--subtext0: #B69C70;
--subtext1: #D6C49E;
--blue: #5A7DC4;
--lavender: #9A8DBE;
--sapphire: #87A9D8;
--sky: #B0C4E0;
--teal: #84A89A;
--green: #B9C076;
--yellow: #E9B854;
--peach: #E89570;
--maroon: #A04A47;
--red: #E25940;
--mauve: #C24336; /* lifted oxblood for dark bg contrast */
--pink: #E090A0;
--flamingo: #EBA797;
--rosewater: #F4E5C9;
}
/* BREAKCORE — early-2000s web rot + breakcore. CRT-violet ground, hot
* magenta primary, acid green / electric cyan / hazard yellow accents.
* Glitchy, blown-out, MSN-era saturation. */
.breakcore {
--crust: #02000A;
--mantle: #06031A;
--base: #0A0612;
--surface0: #150929;
--surface1: #22113F;
--surface2: #3A1B62;
--overlay0: #5A2D8E;
--overlay1: #7B45B8;
--overlay2: #A06AD8;
--text: #F2F0FF;
--subtext0: #B9A8E0;
--subtext1: #D8CCFA;
--blue: #00B7FF; /* MSN cyan */
--lavender: #B98CFF; /* CRT violet */
--sapphire: #4B6BFF; /* hyperlink */
--sky: #66E1FF; /* aqua chrome */
--teal: #00F5C8; /* matrix mint */
--green: #B6FF00; /* acid */
--yellow: #FFD400; /* hazard */
--peach: #FF8A3D; /* GIF-era flame */
--maroon: #8B0A4B;
--red: #FF1F4F; /* siren */
--mauve: #FF2EA6; /* hot magenta — primary accent */
--pink: #FF7AD8; /* bubblegum */
--flamingo: #FFA2C4;
--rosewater: #FFE8F6;
}
/* GOTHIC — cathedral nightfall. Midnight violet ground, blood crimson,
* tarnished candle gold, stained-glass indigo. Catholic-gothic + Sisters of
* Mercy + Bauhaus stark. Primary accent: cathedral velvet mauve. */
.gothic {
--crust: #030104;
--mantle: #0A0710;
--base: #110B18;
--surface0: #1A1224;
--surface1: #261A36;
--surface2: #382550;
--overlay0: #4F3970;
--overlay1: #6E5293;
--overlay2: #8D72B1;
--text: #EDE3F2; /* bone, violet wash */
--subtext0: #9B8AB0;
--subtext1: #C0AED2;
--blue: #4239A4; /* stained-glass deep */
--lavender: #9B7BD4; /* candlelight through purple glass */
--sapphire: #5947B2;
--sky: #7C68C9;
--teal: #487B8A; /* verdigris on bronze */
--green: #5E7842; /* cemetery moss */
--yellow: #D4A82B; /* taper / tarnished brass */
--peach: #B45A38; /* rust */
--maroon: #5B1A24;
--red: #A41827; /* arterial */
--mauve: #8B2C9E; /* cathedral velvet — primary accent */
--pink: #B25288; /* dried rose */
--flamingo: #C57B96;
--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";
}
body {
background-color: var(--base);
color: var(--text);
min-height: 100vh;
transition: background-color 0.3s ease, color 0.3s ease;
-webkit-font-smoothing: antialiased;
font-size: 1.0625rem;
line-height: 1.65;
position: relative;
}
/* Paper grain — applied as a fixed overlay so every page gets the texture.
* All three layers sit behind content (negative z-index) so fixed-positioned
* modals (e.g. the search palette) can escape ancestor stacking traps. */
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: -3;
background-color: var(--base);
}
body::after {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: -1;
opacity: 0.32;
mix-blend-mode: multiply;
background-image:
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.10 0 0 0 0 0.07 0 0 0 0 0.04 0 0 0 0.22 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
}
.salon-noir body::after,
html.salon-noir body::after {
opacity: 0.5;
}
.gothic body::after,
html.gothic body::after {
opacity: 0.55;
background-image:
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.08 0 0 0 0 0.05 0 0 0 0 0.10 0 0 0 0.28 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
mix-blend-mode: screen;
}
/* Breakcore: blown-out RGB-tinted digital noise + CRT scanlines. */
.breakcore body::after,
html.breakcore body::after {
opacity: 0.55;
background-image:
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.2' numOctaves='3' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 0.18 0 0 0 0 0.65 0 0 0 0.45 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"),
repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0) 0,
rgba(0, 0, 0, 0) 2px,
rgba(0, 0, 0, 0.28) 3px,
rgba(0, 0, 0, 0) 4px
);
mix-blend-mode: screen;
}
.breakcore .salon-atmosphere::before { opacity: 0.32; }
.breakcore .salon-atmosphere::after { opacity: 0.28; }
/* Floating motes of pigment — far background, very subtle. */
.salon-atmosphere {
position: fixed;
inset: 0;
z-index: -2;
pointer-events: none;
overflow: hidden;
}
.salon-atmosphere::before,
.salon-atmosphere::after {
content: "";
position: absolute;
border-radius: 50%;
filter: blur(120px);
opacity: 0.18;
}
.salon-atmosphere::before {
width: 55vw; height: 55vw;
top: -15vw; left: -10vw;
background: var(--mauve);
}
.salon-atmosphere::after {
width: 45vw; height: 45vw;
bottom: -10vw; right: -10vw;
background: var(--blue);
opacity: 0.12;
}
code, pre, kbd, samp {
font-family: var(--font-mono);
}
/* Selection */
::selection {
background: var(--mauve);
color: var(--rosewater);
}
/* Breakcore: chromatic-aberration glow on display headings + nameplate. */
.breakcore .prose h1,
.breakcore .prose h2,
.breakcore h1.font-display,
.breakcore .nameplate-title {
text-shadow:
-1px 0 0 color-mix(in srgb, var(--teal) 70%, transparent),
1px 0 0 color-mix(in srgb, var(--mauve) 70%, transparent),
0 0 18px color-mix(in srgb, var(--mauve) 35%, transparent);
}
.breakcore ::selection {
background: var(--green);
color: var(--crust);
text-shadow: 0 0 6px var(--mauve);
}
/* ───── Display utilities ───── */
.font-display {
font-family: var(--font-display);
font-feature-settings: "kern", "liga", "calt", "lnum", "ss01";
letter-spacing: -0.01em;
}
.font-hand {
font-family: var(--font-hand);
font-weight: 400;
}
.font-display-italic {
font-family: var(--font-display);
font-style: italic;
font-feature-settings: "kern", "liga", "calt", "ss01";
}
/* Roman numerals get small-caps treatment */
.numeral {
font-family: var(--font-display);
font-variant-numeric: lining-nums;
letter-spacing: 0.08em;
font-weight: 500;
}
/* ───── Salon prose — exhibit plaque body ───── */
.prose {
color: var(--text);
max-width: none;
line-height: 1.75;
font-size: 1.125rem;
font-family: var(--font-sans);
}
@media (min-width: 768px) {
.prose { font-size: 1.1875rem; }
}
.prose > *:first-child { margin-top: 0; }
.prose h1 {
font-family: var(--font-display);
font-size: clamp(2rem, 1.5rem + 2vw, 3rem);
font-weight: 600;
font-style: italic;
color: var(--text);
margin: 0 0 1.25rem;
line-height: 1.15;
letter-spacing: -0.02em;
padding-bottom: 0.06em;
}
.prose h2 {
font-family: var(--font-display);
font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem);
font-weight: 500;
color: var(--text);
margin: 3rem 0 1rem;
padding-bottom: 0.35rem;
line-height: 1.2;
letter-spacing: -0.01em;
border-bottom: 1px solid color-mix(in srgb, var(--mauve) 30%, transparent);
}
.prose h3 {
font-family: var(--font-display);
font-size: 1.4rem;
font-weight: 500;
font-style: italic;
color: var(--text);
margin: 2.25rem 0 0.75rem;
}
.prose h4 {
font-family: var(--font-display);
font-size: 1.2rem;
font-weight: 500;
color: var(--subtext1);
margin: 1.75rem 0 0.5rem;
}
.prose h5 {
font-size: 0.85rem;
font-weight: 600;
color: var(--subtext0);
text-transform: uppercase;
letter-spacing: 0.18em;
margin: 1.5rem 0 0.5rem;
}
.prose h6 {
font-size: 0.85rem;
font-weight: 500;
color: var(--overlay0);
font-style: italic;
margin: 1rem 0 0.5rem;
}
.prose :is(h1, h2, h3, h4, h5, h6) { scroll-margin-top: 5rem; }
.prose p { margin: 0 0 1.15rem; }
.prose blockquote {
border-left: 3px solid var(--mauve);
padding: 0.25rem 0 0.25rem 1.4rem;
margin: 1.75rem 0;
color: var(--subtext1);
font-style: italic;
}
.prose blockquote p { margin: 0 0 0.6rem; }
.prose blockquote p:last-child { margin: 0; }
.prose pre {
padding: 1rem 1.1rem;
border-radius: 0;
border: 1px solid var(--surface2);
border-left-width: 3px;
border-left-color: var(--mauve);
margin: 1.75rem 0;
background-color: color-mix(in srgb, var(--surface0) 70%, transparent);
font-size: 0.875rem;
line-height: 1.55;
overflow-x: auto;
}
.prose code {
background-color: color-mix(in srgb, var(--surface0) 90%, transparent);
padding: 0.1rem 0.4rem;
border-radius: 0;
border-bottom: 1px solid var(--surface1);
font-size: 0.9em;
color: var(--mauve);
}
.prose pre code {
background: transparent;
padding: 0;
border: 0;
color: inherit;
font-size: inherit;
}
.prose a code,
.prose :is(h1, h2, h3, h4) code { color: inherit; }
.prose a {
color: var(--mauve);
text-decoration: underline;
text-decoration-color: var(--surface1);
text-decoration-thickness: 1px;
text-underline-offset: 3px;
transition: color 0.15s, text-decoration-color 0.15s;
}
.prose a:hover {
color: var(--red);
text-decoration-color: var(--red);
}
.prose ul, .prose ol {
margin: 0 0 1.15rem;
padding-left: 1.6rem;
}
.prose ul { list-style: none; }
.prose ul > li { position: relative; padding-left: 0.2rem; }
.prose ul > li::before {
content: "";
position: absolute;
left: -1.1rem;
top: 0.62em;
width: 0.42em;
height: 0.42em;
background: var(--mauve);
transform: rotate(45deg);
}
.prose ol { list-style: decimal-leading-zero; }
.prose ol > li::marker { color: var(--mauve); font-family: var(--font-display); font-style: italic; }
.prose li { margin: 0.3rem 0; }
/* Loose lists wrap items in <p>; drop the paragraph block-margin inside li. */
.prose li > p { margin: 0; }
.prose li > p + p { margin-top: 0.6rem; }
/* GFM task lists — kill the diamond, keep the checkbox. */
.prose ul > li:has(input[type="checkbox"]) { padding-left: 0; }
.prose ul > li:has(input[type="checkbox"])::before { content: none; }
.prose li > input[type="checkbox"] {
margin: 0 0.5rem 0 0;
vertical-align: 0.04em;
accent-color: var(--mauve);
}
.prose hr {
margin: 3rem auto;
border: 0;
height: 1px;
width: 100%;
background: linear-gradient(
90deg,
transparent 0%,
color-mix(in srgb, var(--mauve) 55%, transparent) 22%,
transparent 45%,
transparent 55%,
color-mix(in srgb, var(--mauve) 55%, transparent) 78%,
transparent 100%
);
position: relative;
overflow: visible;
}
.prose hr::before {
content: "";
position: absolute;
top: 50%;
left: 50%;
width: 0.5rem;
height: 0.5rem;
transform: translate(-50%, -50%) rotate(45deg);
background: var(--mauve);
}
.prose strong { color: inherit; font-weight: 700; }
.prose em { color: inherit; font-style: italic; font-family: var(--font-display); }
.prose del { color: var(--overlay0); text-decoration: line-through; }
/* ───── Figure / image plate — the heart of the gallery body ───── */
.prose figure {
display: block;
text-align: center;
margin: 2.5rem 0;
}
.prose figure img,
.prose img {
display: block;
max-width: 100%;
height: auto;
margin: 0 auto;
border: 1px solid var(--surface2);
padding: 6px;
background:
linear-gradient(var(--rosewater), var(--rosewater)) padding-box,
linear-gradient(135deg, var(--surface2), var(--surface1)) border-box;
box-shadow:
0 1px 0 var(--surface0),
0 18px 38px -22px rgba(20, 16, 12, 0.45),
0 2px 6px -2px rgba(20, 16, 12, 0.2);
border-radius: 2px;
}
.salon-noir .prose figure img,
.salon-noir .prose img,
.gothic .prose figure img,
.gothic .prose img,
.breakcore .prose figure img,
.breakcore .prose img {
background:
linear-gradient(var(--surface0), var(--surface0)) padding-box,
linear-gradient(135deg, var(--surface2), var(--surface1)) border-box;
box-shadow:
0 18px 38px -22px rgba(0, 0, 0, 0.7),
0 2px 6px -2px rgba(0, 0, 0, 0.5);
}
.gothic .prose figure img,
.gothic .prose img {
box-shadow:
0 18px 38px -22px rgba(0, 0, 0, 0.85),
0 2px 6px -2px rgba(0, 0, 0, 0.6),
0 0 0 1px color-mix(in srgb, var(--mauve) 22%, transparent);
}
.prose figure figcaption {
font-family: var(--font-display);
font-style: italic;
font-size: 0.9rem;
color: var(--subtext0);
margin-top: 0.85rem;
letter-spacing: 0.02em;
line-height: 1.4;
}
/* Multi-image rows. Consecutive markdown images auto-collapse into a flex
* row; each figure gets `flex: <aspect-ratio>` inline so widths divide
* proportionally and heights line up. Wraps to a column on narrow screens. */
.prose .figure-row {
/* Target row height. Each figure's flex-basis is ratio × this value, so
* rows pack as many figures as fit at roughly --row-h tall, then wrap.
* --row-max caps how tall a sparsely-filled final row can grow. */
--row-h: 16rem;
--row-max: 30rem;
display: flex;
flex-wrap: wrap;
gap: 0.9rem;
align-items: flex-start;
margin: 2.5rem 0;
width: 100%;
}
@media (min-width: 1024px) {
.prose .figure-row {
--row-h: 18rem;
--row-max: 34rem;
}
}
.prose .figure-row figure {
margin: 0;
min-width: 0; /* allow flex children to shrink below content width */
flex-basis: 0;
}
.prose .figure-row figure img {
width: 100%;
max-width: 100%;
height: auto;
margin: 0;
}
.prose .figure-row figure figcaption {
text-align: left;
margin-top: 0.55rem;
font-size: 0.82rem;
}
@media (max-width: 640px) {
.prose .figure-row {
flex-direction: column;
width: 100%;
margin-left: 0;
gap: 1.4rem;
}
.prose .figure-row figure {
flex: 1 1 100% !important;
}
.prose .figure-row figure figcaption {
text-align: center;
}
}
.prose figure figcaption::before {
content: "— ";
color: var(--mauve);
}
/* GFM tables — keep, slightly more editorial */
.prose table {
display: block;
width: 100%;
max-width: 100%;
overflow-x: auto;
margin: 1.75rem 0;
border-collapse: collapse;
border: 1px solid var(--surface2);
font-size: 0.95rem;
font-family: var(--font-sans);
}
.prose thead { background-color: color-mix(in srgb, var(--surface0) 80%, transparent); }
.prose th {
padding: 0.55rem 0.9rem;
text-align: left;
font-weight: 600;
color: var(--text);
border-bottom: 1px solid var(--surface2);
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.75rem;
}
.prose td {
padding: 0.5rem 0.9rem;
border-bottom: 1px solid color-mix(in srgb, var(--surface1) 60%, transparent);
}
.prose tr:last-child td { border-bottom: 0; }
/* ───── Salon plate — a single framed image card used on the gallery index ───── */
.plate {
position: relative;
background: var(--rosewater);
padding: 14px 14px 0 14px;
border: 1px solid var(--surface2);
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--surface1) 50%, transparent),
0 1px 0 var(--surface0),
0 22px 42px -28px rgba(20, 16, 12, 0.5),
0 4px 12px -6px rgba(20, 16, 12, 0.25);
border-radius: 2px;
transition: transform 0.4s cubic-bezier(0.2, 0.6, 0.2, 1),
box-shadow 0.4s cubic-bezier(0.2, 0.6, 0.2, 1);
}
.salon-noir .plate,
.gothic .plate,
.breakcore .plate {
background: var(--surface0);
}
.salon-noir .plate,
.gothic .plate {
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--surface1) 50%, transparent),
0 22px 42px -28px rgba(0, 0, 0, 0.7),
0 4px 12px -6px rgba(0, 0, 0, 0.45);
}
.breakcore .plate {
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--mauve) 35%, transparent),
0 0 0 1px color-mix(in srgb, var(--mauve) 20%, transparent),
0 22px 42px -28px rgba(255, 46, 166, 0.35),
0 0 24px -8px color-mix(in srgb, var(--mauve) 40%, transparent);
}
.plate:hover {
transform: translateY(-4px) rotate(-0.25deg);
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--surface1) 60%, transparent),
0 1px 0 var(--surface0),
0 32px 60px -28px rgba(20, 16, 12, 0.55),
0 8px 20px -8px rgba(20, 16, 12, 0.3);
}
.salon-noir .plate:hover,
.gothic .plate:hover {
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--surface1) 60%, transparent),
0 32px 60px -28px rgba(0, 0, 0, 0.8),
0 8px 20px -8px rgba(0, 0, 0, 0.55);
}
.breakcore .plate:hover {
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--mauve) 45%, transparent),
0 0 0 1px color-mix(in srgb, var(--mauve) 30%, transparent),
0 32px 60px -28px rgba(255, 46, 166, 0.45),
0 0 32px -8px color-mix(in srgb, var(--mauve) 50%, transparent);
}
/* Keyboard focus for the card link — salon-appropriate inset frame + ring. */
.plate:focus-visible {
outline: none;
box-shadow:
inset 0 0 0 2px var(--mauve),
0 0 0 3px color-mix(in srgb, var(--mauve) 40%, transparent),
0 22px 42px -28px rgba(20, 16, 12, 0.5);
}
.breakcore .plate:focus-visible {
box-shadow:
inset 0 0 0 2px var(--mauve),
0 0 0 2px var(--green),
0 0 28px -6px color-mix(in srgb, var(--mauve) 60%, transparent);
}
.plate .plate-image {
position: relative;
overflow: hidden;
background: var(--mantle);
}
.plate .plate-image img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
filter: saturate(0.94) contrast(1.02);
transition: transform 0.8s cubic-bezier(0.2, 0.6, 0.2, 1), filter 0.4s ease;
}
/* Natural mode — container drops fixed aspect so image shows its true ratio. */
.plate .plate-image.is-natural {
height: auto;
}
.plate .plate-image.is-natural img {
height: auto;
object-fit: contain;
}
.plate:hover .plate-image img {
transform: scale(1.03);
filter: saturate(1.05) contrast(1.04);
}
.plate .plate-caption {
padding: 14px 6px 16px 6px;
margin-top: 2px;
border-top: 1px solid color-mix(in srgb, var(--surface2) 50%, transparent);
display: flex;
flex-direction: column;
gap: 0.4rem;
}
.plate .plate-caption-title {
font-family: var(--font-display);
font-style: italic;
font-weight: 500;
font-size: 1.18rem;
line-height: 1.3;
color: var(--text);
letter-spacing: -0.005em;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
/* line-clamp's overflow:hidden clips italic-Fraunces descenders (g, y, p).
* Pad the clip box and pull the layout back with a matching negative
* margin so descenders survive without shifting siblings. */
padding-bottom: 0.16em;
margin-bottom: -0.16em;
transition: color 0.25s ease;
}
.plate:hover .plate-caption-title {
color: var(--mauve);
}
.plate .plate-caption-summary {
font-family: var(--font-sans);
font-style: italic;
font-size: 0.82rem;
line-height: 1.45;
color: var(--subtext0);
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
padding-bottom: 0.14em;
margin-bottom: -0.14em;
}
.plate .plate-caption-meta {
font-family: var(--font-sans);
font-size: 0.68rem;
text-transform: uppercase;
letter-spacing: 0.22em;
color: var(--subtext0);
white-space: nowrap;
display: flex;
align-items: center;
gap: 0.5rem;
padding-top: 0.25rem;
}
.plate .plate-caption-sep {
color: var(--mauve);
opacity: 0.55;
}
.plate-tag-mini {
position: absolute;
bottom: 16px;
right: 16px;
background: color-mix(in srgb, var(--crust) 70%, transparent);
color: var(--rosewater);
border: 1px solid color-mix(in srgb, var(--rosewater) 18%, transparent);
border-radius: 999px;
font-family: var(--font-sans);
font-size: 0.6rem;
font-weight: 600;
letter-spacing: 0.22em;
padding: 4px 11px;
text-transform: uppercase;
backdrop-filter: blur(3px);
}
/* Draft/"Sketch" marker — same chip, pinned bottom-left, amber instead of
* the neutral catalogue tag. Themed per skin below (no inline colors). */
.plate-tag-mini--draft {
left: 16px;
right: auto;
background: color-mix(in srgb, var(--peach) 88%, var(--crust));
color: var(--crust);
border-color: color-mix(in srgb, var(--peach) 45%, transparent);
}
/* Breakcore: hard neon catalogue tag — sharp rect, offset shadow, glow.
* Matches the layer's hazard-tape / hard-offset chrome language. */
.breakcore .plate-tag-mini {
background: var(--crust);
color: var(--green);
border: 1px solid var(--mauve);
border-radius: 0;
font-family: var(--font-mono);
font-weight: 500;
letter-spacing: 0.14em;
text-shadow: 0 0 6px color-mix(in srgb, var(--green) 60%, transparent);
box-shadow:
2px 2px 0 var(--mauve),
0 0 14px -2px color-mix(in srgb, var(--mauve) 65%, transparent);
backdrop-filter: none;
}
.breakcore .plate-tag-mini--draft {
color: var(--peach);
border-color: var(--peach);
text-shadow: 0 0 6px color-mix(in srgb, var(--peach) 60%, transparent);
box-shadow:
2px 2px 0 var(--peach),
0 0 14px -2px color-mix(in srgb, var(--peach) 65%, transparent);
}
/* Nameplate — the museum-style header used in the site chrome */
.nameplate {
display: inline-flex;
flex-direction: column;
align-items: flex-start;
gap: 2px;
position: relative;
}
.nameplate::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -6px;
height: 2px;
background: linear-gradient(to right,
var(--mauve) 0%,
var(--mauve) 35%,
var(--surface2) 35%,
var(--surface2) 100%);
}
.nameplate-title {
font-family: var(--font-display);
font-weight: 600;
font-style: italic;
font-size: 1.6rem;
letter-spacing: -0.01em;
color: var(--text);
/* Loose enough that italic-Fraunces descenders (g, y, p) and the
* breakcore chromatic glow clear the line box — nothing slices them. */
line-height: 1.2;
padding-bottom: 0.06em;
}
.nameplate-subtitle {
font-family: var(--font-sans);
font-size: 0.65rem;
letter-spacing: 0.32em;
text-transform: uppercase;
color: var(--subtext0);
}
/* Section ornaments */
.section-rule {
display: flex;
align-items: center;
gap: 1rem;
color: var(--subtext0);
font-family: var(--font-display);
font-style: italic;
font-size: 0.95rem;
letter-spacing: 0.04em;
}
.section-rule::before,
.section-rule::after {
content: "";
flex: 1;
height: 1px;
background: var(--surface2);
}
.section-rule .ornament {
color: var(--mauve);
}
/* Scrawled handwritten margin notes */
.scrawl {
font-family: var(--font-hand);
color: var(--mauve);
font-size: 1.4rem;
line-height: 1;
transform: rotate(-6deg);
display: inline-block;
}
.scrawl-mark::before {
content: "✕";
font-family: var(--font-hand);
color: var(--red);
margin-right: 0.35em;
}
/* Stripe (Matisse cutout) chip used for tags */
.chip {
display: inline-flex;
align-items: center;
gap: 0.3rem;
font-family: var(--font-display);
font-style: italic;
font-size: 0.78rem;
padding: 0.15rem 0.6rem;
background: color-mix(in srgb, var(--surface0) 80%, transparent);
border: 1px solid var(--surface2);
color: var(--subtext1);
border-radius: 1px;
letter-spacing: 0.02em;
}
.chip-accent {
background: var(--mauve);
color: var(--rosewater);
border-color: var(--mauve);
}
.chip-draft {
background: color-mix(in srgb, var(--peach) 18%, transparent);
color: var(--peach);
border-color: color-mix(in srgb, var(--peach) 50%, transparent);
}
/* Card / glass — keep the name but reinterpret as a paper card */
.glass {
background-color: color-mix(in srgb, var(--surface0) 80%, transparent);
border: 1px solid var(--surface2);
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--surface1) 50%, transparent),
0 10px 30px -20px rgba(20, 16, 12, 0.45);
border-radius: 2px;
}
.salon-noir .glass,
.gothic .glass,
.breakcore .glass {
background-color: color-mix(in srgb, var(--surface0) 70%, transparent);
}
.salon-noir .glass {
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--surface1) 50%, transparent),
0 14px 40px -24px rgba(0, 0, 0, 0.8);
}
.gothic .glass {
border-color: color-mix(in srgb, var(--mauve) 35%, var(--surface2));
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--mauve) 18%, transparent),
0 14px 40px -24px rgba(0, 0, 0, 0.85);
}
.breakcore .glass {
border-color: color-mix(in srgb, var(--mauve) 45%, var(--surface2));
box-shadow:
inset 0 0 0 1px color-mix(in srgb, var(--mauve) 25%, transparent),
0 0 0 1px color-mix(in srgb, var(--teal) 15%, transparent),
0 14px 40px -24px rgba(0, 0, 0, 0.9);
}
/* ───── Buttons — one system ─────
* Base .btn = layout + size + focus/disabled. One variant for color
* (--primary / --ghost / --danger), one size modifier (--sm / --lg),
* shape modifiers (--icon / --block). Never restyle buttons ad-hoc. */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
height: 2.5rem;
padding: 0 1.2rem;
font-family: var(--font-display);
font-style: italic;
font-weight: 500;
font-size: 0.95rem;
line-height: 1;
letter-spacing: 0.02em;
background: transparent;
color: var(--text);
border: 1px solid transparent;
border-radius: 1px;
text-decoration: none;
white-space: nowrap;
cursor: pointer;
transition: transform 0.15s ease, background 0.15s ease, color 0.15s ease,
border-color 0.15s ease, box-shadow 0.15s ease;
}
.btn:focus-visible {
outline: none;
border-color: var(--mauve);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--mauve) 35%, transparent);
}
.btn:disabled,
.btn[aria-disabled="true"] {
opacity: 0.55;
cursor: default;
pointer-events: none;
}
.btn svg { width: 1.05em; height: 1.05em; flex-shrink: 0; }
/* Variants */
.btn--primary {
background: var(--mauve);
color: var(--rosewater);
border-color: color-mix(in srgb, var(--mauve) 80%, var(--crust));
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.22);
}
.btn--primary:hover {
transform: translateY(-1px);
background: var(--red);
border-color: color-mix(in srgb, var(--red) 80%, var(--crust));
box-shadow: 0 7px 16px -7px color-mix(in srgb, var(--red) 65%, transparent);
}
.btn--primary:active {
transform: translateY(0);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.3);
}
.btn--ghost {
color: var(--subtext1);
border-color: var(--surface2);
background: color-mix(in srgb, var(--surface0) 45%, transparent);
}
.btn--ghost:hover {
color: var(--mauve);
border-color: color-mix(in srgb, var(--mauve) 50%, var(--surface2));
background: color-mix(in srgb, var(--surface0) 80%, transparent);
}
.btn--danger {
color: var(--red);
border-color: color-mix(in srgb, var(--red) 55%, var(--surface2));
background: color-mix(in srgb, var(--red) 12%, transparent);
}
.btn--danger:hover {
color: var(--rosewater);
background: var(--red);
border-color: var(--red);
}
/* Pressed/selected state for toggle & tab buttons */
.btn.is-active {
color: var(--mauve);
border-color: color-mix(in srgb, var(--mauve) 55%, var(--surface2));
background: color-mix(in srgb, var(--mauve) 14%, transparent);
}
/* Sizes */
.btn--sm { height: 2rem; padding: 0 0.85rem; font-size: 0.85rem; gap: 0.35rem; }
.btn--lg { height: 3rem; padding: 0 1.6rem; font-size: 1.05rem; }
/* Shapes */
.btn--icon { padding: 0; width: 2.5rem; }
.btn--icon.btn--sm { width: 2rem; }
.btn--block { width: 100%; }
/* Back-link — a real affordance, not bare body text. One markup for
* every "← back" return link (post, admin, login). */
.back-link {
display: inline-flex;
align-items: center;
gap: 0.5rem;
font-family: var(--font-display);
font-style: italic;
font-size: 0.9rem;
line-height: 1;
color: var(--subtext1);
text-decoration: none;
padding: 0.35rem 0.1rem;
border-bottom: 1px solid color-mix(in srgb, var(--subtext1) 35%, transparent);
transition: color 0.15s ease, border-color 0.15s ease, gap 0.15s ease;
}
.back-link:hover,
.back-link:focus-visible {
color: var(--mauve);
border-color: var(--mauve);
gap: 0.7rem;
outline: none;
}
.back-link .bl-arrow {
display: inline-block;
transition: transform 0.15s ease;
}
.back-link:hover .bl-arrow,
.back-link:focus-visible .bl-arrow { transform: translateX(-3px); }
/* ───── Top-bar controls — one height, one language ─────
* `.topbar-cluster` lays the chrome controls out as one tidy, right-aligned
* group that wraps as a unit (never a ragged full-width column on mobile).
* Every control is the same 2rem height; icon-only variants are exact
* squares so they line up cleanly next to each other. */
.topbar-cluster {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.4rem;
justify-content: flex-start;
}
@media (min-width: 768px) {
.topbar-cluster { justify-content: flex-end; }
}
/* A hairline divider between the public controls and the admin group. */
.topbar-divider {
align-self: stretch;
width: 1px;
margin: 0.15rem 0.15rem;
background: var(--surface2);
flex: none;
}
.topbar-control {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
height: 2rem;
padding: 0 0.7rem;
flex: none;
font-family: var(--font-display);
font-style: italic;
font-size: 0.85rem;
line-height: 1;
color: var(--subtext1);
background: color-mix(in srgb, var(--surface0) 55%, transparent);
border: 1px solid var(--surface2);
border-radius: 1px;
text-decoration: none;
cursor: pointer;
white-space: nowrap;
transition: color 0.15s, background 0.15s, border-color 0.15s;
}
.topbar-control:hover {
color: var(--mauve);
background: color-mix(in srgb, var(--surface0) 85%, transparent);
border-color: color-mix(in srgb, var(--mauve) 45%, var(--surface2));
}
.topbar-control:focus-visible {
outline: none;
border-color: var(--mauve);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--mauve) 40%, transparent);
}
.topbar-control:disabled { opacity: 0.5; cursor: default; }
.topbar-control svg { width: 15px; height: 15px; flex-shrink: 0; }
/* Exact-square icon-only variant — keeps the row aligned. */
.topbar-control--icon { width: 2rem; padding: 0; }
/* Keyboard-shortcut hover/focus tooltip — kept out of the button label,
* surfaced only on hover or keyboard focus. */
.kbd-tip-host { position: relative; }
.kbd-tip {
position: absolute;
top: calc(100% + 8px);
left: 50%;
display: flex;
align-items: center;
gap: 0.3rem;
white-space: nowrap;
padding: 4px 8px;
font-family: var(--font-sans);
font-size: 0.6rem;
font-style: normal;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--subtext1);
background: color-mix(in srgb, var(--crust) 90%, transparent);
border: 1px solid color-mix(in srgb, var(--surface2) 70%, transparent);
border-radius: 4px;
box-shadow: 0 8px 20px -10px rgba(0, 0, 0, 0.5);
opacity: 0;
transform: translate(-50%, 4px);
pointer-events: none;
transition: opacity 0.16s ease, transform 0.16s ease;
z-index: 60;
}
.kbd-tip kbd {
font-family: var(--font-mono);
font-size: 0.62rem;
line-height: 1;
padding: 2px 5px;
color: var(--text);
background: color-mix(in srgb, var(--surface0) 70%, transparent);
border: 1px solid color-mix(in srgb, var(--surface2) 80%, transparent);
border-radius: 3px;
}
.kbd-tip-host:hover .kbd-tip,
.kbd-tip-host:focus-visible .kbd-tip {
opacity: 1;
transform: translate(-50%, 0);
}
/* Breakcore: hard neon tooltip — matches the layer's offset-shadow chrome. */
.breakcore .kbd-tip {
background: var(--crust);
border-color: var(--mauve);
border-radius: 0;
color: var(--green);
box-shadow: 2px 2px 0 var(--mauve);
}
.breakcore .kbd-tip kbd {
color: var(--rosewater);
background: var(--surface0);
border-color: var(--mauve);
border-radius: 0;
}
@media (prefers-reduced-motion: reduce) {
.kbd-tip { transition: opacity 0.16s ease; transform: translate(-50%, 0); }
}
.topbar-control--danger:hover {
color: var(--red);
border-color: color-mix(in srgb, var(--red) 55%, var(--surface2));
}
/* Native <select> variant — leave room for the chevron overlay.
* Fixed width so switching themes never resizes the whole top bar. */
select.topbar-control {
appearance: none;
-webkit-appearance: none;
padding-right: 1.9rem;
}
select.topbar-control.theme-select {
width: 8.75rem;
justify-content: flex-start;
text-align: left;
}
.topbar-control kbd {
display: inline-flex;
align-items: center;
gap: 0.15rem;
font-family: var(--font-mono, monospace);
font-style: normal;
font-size: 0.62rem;
padding: 0.05rem 0.3rem;
border: 1px solid var(--surface2);
border-radius: 1px;
color: var(--subtext0);
}
/* Responsive collapse — below a breakpoint a control drops its label and
* becomes an exact 2rem square so the cluster stays a tidy aligned row on
* phones. Written unlayered (not Tailwind utilities) so it reliably wins
* over the `.topbar-control` base in the Tailwind v4 cascade. */
.topbar-control .tc-label { display: inline; }
@media (max-width: 767px) {
.topbar-control.tc-collapse-md { width: 2rem; padding: 0; }
.topbar-control.tc-collapse-md .tc-label { display: none; }
}
@media (max-width: 639px) {
.topbar-control.tc-collapse-sm { width: 2rem; padding: 0; }
.topbar-control.tc-collapse-sm .tc-label { display: none; }
}
/* Form input look */
.field-input {
width: 100%;
background: color-mix(in srgb, var(--surface0) 60%, transparent);
border: 1px solid var(--surface2);
border-radius: 1px;
padding: 0.65rem 0.9rem;
color: var(--text);
font-family: var(--font-sans);
font-size: 1rem;
transition: border-color 0.15s, background 0.15s;
}
.field-input:focus {
outline: none;
border-color: var(--mauve);
background: color-mix(in srgb, var(--surface0) 85%, var(--mauve) 8%);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--mauve) 22%, transparent);
}
.field-label {
display: block;
font-family: var(--font-sans);
font-size: 0.72rem;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--subtext0);
margin-bottom: 0.4rem;
}
/* hljs token colors — driven by theme tokens, slightly muted for parchment bg */
.hljs { color: var(--text); background: transparent; }
.hljs-keyword, .hljs-selector-tag, .hljs-built_in, .hljs-operator { color: var(--mauve); font-weight: 600; }
.hljs-string, .hljs-attr, .hljs-regexp, .hljs-addition { color: var(--green); }
.hljs-number, .hljs-literal, .hljs-symbol, .hljs-bullet { color: var(--peach); }
.hljs-comment, .hljs-quote { color: var(--overlay0); font-style: italic; }
.hljs-title, .hljs-section, .hljs-name, .hljs-title.function_ { color: var(--blue); }
.hljs-type, .hljs-class .hljs-title, .hljs-title.class_ { color: var(--yellow); }
.hljs-variable, .hljs-template-variable, .hljs-params, .hljs-property { color: var(--red); }
.hljs-attribute, .hljs-meta, .hljs-meta .hljs-keyword { color: var(--subtext0); }
.hljs-deletion { color: var(--red); }
.hljs-emphasis { font-style: italic; }
.hljs-strong { font-weight: 700; }
/* KaTeX */
.katex { color: var(--text); }
/* Skeleton loader */
.skeleton {
background: linear-gradient(
90deg,
color-mix(in srgb, var(--surface0) 50%, transparent) 0%,
color-mix(in srgb, var(--surface1) 50%, transparent) 50%,
color-mix(in srgb, var(--surface0) 50%, transparent) 100%
);
background-size: 200% 100%;
animation: skeleton-shimmer 1.5s ease-in-out infinite;
border-radius: 1px;
}
@keyframes skeleton-shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* Toast */
.toast {
position: fixed;
bottom: 1.5rem;
left: 50%;
transform: translateX(-50%);
background: var(--mantle);
border: 1px solid var(--surface2);
color: var(--rosewater);
padding: 0.65rem 1.1rem;
border-radius: 1px;
box-shadow: 0 12px 30px -10px rgba(0, 0, 0, 0.45);
font-family: var(--font-display);
font-style: italic;
font-size: 0.9rem;
z-index: 200;
animation: toast-in 0.2s ease;
}
@keyframes toast-in {
from { opacity: 0; transform: translate(-50%, 8px); }
to { opacity: 1; transform: translate(-50%, 0); }
}
/* Salon grid spans driven by --col-span custom prop (avoids Tailwind dynamic class issue). */
@media (min-width: 768px) {
.md-col-span {
grid-column: span var(--col-span, 6) / span var(--col-span, 6);
}
}
/* Subtle page enter animation for gallery / plaque */
@keyframes plate-fade-up {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.plate-enter {
opacity: 0;
animation: plate-fade-up 0.6s cubic-bezier(0.2, 0.7, 0.2, 1) forwards;
}
/* Custom checkbox accent for form bits inside the salon */
input[type="checkbox"] { accent-color: var(--mauve); }
input[type="date"] { color-scheme: light; }
.salon-noir input[type="date"] { color-scheme: dark; }
.gothic input[type="date"] { color-scheme: dark; }
.breakcore input[type="date"] { color-scheme: dark; }
/* Reading progress bar - thin terracotta line */
.reading-progress {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 2px;
background: var(--mauve);
z-index: 150;
transform-origin: left;
transform: scaleX(0);
transition: transform 80ms linear;
}
/* ═══════════════════════════════════════════════════════════════════════
* BREAKCORE — refined-neon layer.
* Everything below is scoped to `.breakcore`; salon / salon-noir / gothic
* are untouched. Aesthetic: editorial serif body in deliberate tension with
* hard-edged web-rot chrome — RGB split, hazard tape, neon outline, hard
* offset shadows. Motion is *reactive only* (hover / focus / one-shot on
* load) and settles fast. All motion is killed by prefers-reduced-motion
* at the very end of this file.
* ═══════════════════════════════════════════════════════════════════════ */
/* CRT tube depth — static vignette layered on the existing base fill. */
.breakcore body::before {
background-image: radial-gradient(
ellipse at center,
transparent 52%,
color-mix(in srgb, var(--crust) 75%, transparent) 100%
);
}
/* Nameplate — breakcore reworks the underline: hard cyan offset + magenta
* neon glow (the layer's hard-offset chrome language) instead of the
* default two-tone rule. Plus a glitch-shear burst on hover. */
.breakcore .nameplate::after {
height: 2px;
bottom: -7px;
background: var(--mauve);
box-shadow:
2px 2px 0 var(--blue),
0 0 10px color-mix(in srgb, var(--mauve) 70%, transparent);
}
@keyframes bc-shear {
0% { clip-path: inset(0 0 0 0); transform: translateX(0);
text-shadow: -1px 0 0 var(--teal), 1px 0 0 var(--mauve); }
20% { clip-path: inset(16% 0 56% 0); transform: translateX(-5px);
text-shadow: -5px 0 0 var(--green), 5px 0 0 var(--mauve); }
40% { clip-path: inset(62% 0 10% 0); transform: translateX(5px);
text-shadow: 5px 0 0 var(--teal), -5px 0 0 var(--red); }
60% { clip-path: inset(30% 0 42% 0); transform: translateX(-3px);
text-shadow: -3px 0 0 var(--mauve), 3px 0 0 var(--green); }
80% { clip-path: inset(6% 0 78% 0); transform: translateX(2px);
text-shadow: 2px 0 0 var(--teal), -2px 0 0 var(--mauve); }
100% { clip-path: inset(0 0 0 0); transform: translateX(0);
text-shadow: -1px 0 0 var(--teal), 1px 0 0 var(--mauve); }
}
.breakcore .nameplate:hover .nameplate-title {
animation: bc-shear 200ms steps(3, jump-none) 1;
}
/* Display headings — one-shot glitch-in on page load. The static chromatic
* text-shadow (defined earlier) remains as the resting state. */
@keyframes bc-load-glitch {
0% { opacity: 0; clip-path: inset(46% 0 46% 0); transform: translateX(-9px); }
20% { opacity: 1; clip-path: inset(8% 0 70% 0); transform: translateX(7px); }
40% { clip-path: inset(68% 0 8% 0); transform: translateX(-5px); }
60% { clip-path: inset(24% 0 36% 0); transform: translateX(3px); }
80% { clip-path: inset(4% 0 84% 0); transform: translateX(-2px); }
/* End unclipped (none, not inset(0)) so italic-Fraunces descenders
* (g, y, p) aren't sliced at the box edge once the glitch settles. */
100% { opacity: 1; clip-path: none; transform: translateX(0); }
}
.breakcore .prose h1,
.breakcore h1.font-display {
/* `backwards` (not `both`): after the one-shot, props revert to base —
* clip-path: none — instead of persisting the final inset clip. */
animation: bc-load-glitch 460ms steps(5, jump-none) backwards;
}
/* Plate — hard hover (no soft lift), RGB-split image, scanline sweep. */
.breakcore .plate:hover {
transform: translateY(-3px);
}
.breakcore .plate:hover .plate-caption-title {
text-shadow: -1px 0 0 var(--teal), 1px 0 0 var(--mauve);
}
.breakcore .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(--teal) 70%, transparent))
saturate(1.12) contrast(1.06);
}
.breakcore .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) 28%, transparent) 46%,
color-mix(in srgb, var(--mauve) 70%, transparent) 49%,
color-mix(in srgb, var(--green) 55%, transparent) 51%,
color-mix(in srgb, var(--sky) 28%, transparent) 54%,
transparent 100%
);
}
@keyframes bc-scan {
0% { transform: translateY(-110%); opacity: 0; }
12% { opacity: 1; }
88% { opacity: 1; }
100% { transform: translateY(110%); opacity: 0; }
}
.breakcore .plate:hover .plate-image::after,
.breakcore .plate:focus-visible .plate-image::after {
animation: bc-scan 0.62s cubic-bezier(0.4, 0, 0.2, 1) 1;
}
/* Section rule — hazard tape. Used on footer, post header, 404. */
.breakcore .section-rule {
color: var(--green);
font-family: var(--font-mono);
font-style: normal;
font-size: 0.78rem;
text-transform: uppercase;
letter-spacing: 0.22em;
}
.breakcore .section-rule::before,
.breakcore .section-rule::after {
height: 1px;
opacity: 0.85;
background: linear-gradient(
to right,
transparent,
color-mix(in srgb, var(--mauve) 70%, transparent) 45%,
color-mix(in srgb, var(--teal) 70%, transparent) 55%,
transparent
);
}
.breakcore .section-rule .ornament {
color: var(--mauve);
}
/* Readability — `--overlay0` (#5A2D8E) is near-invisible on the breakcore
* ground. Lift the spots that use it as actual copy to the readable
* subtext ramp. */
.breakcore .prose h6,
.breakcore .prose del,
.breakcore .hljs-comment,
.breakcore .hljs-quote,
.breakcore .site-copyright,
.breakcore .slug-hint {
color: var(--subtext0);
}
/* Chips — neon outline, monospace caps. */
.breakcore .chip {
background: transparent;
border-color: color-mix(in srgb, var(--teal) 55%, transparent);
color: var(--teal);
font-family: var(--font-mono);
font-style: normal;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.1em;
border-radius: 0;
}
.breakcore .chip-accent {
background: var(--mauve);
color: var(--crust);
border-color: var(--mauve);
}
.breakcore .chip-draft {
background: transparent;
border-color: color-mix(in srgb, var(--green) 60%, transparent);
color: var(--green);
}
/* Plate caption meta — bracketed mono coordinates. */
.breakcore .plate-caption-meta {
font-family: var(--font-mono);
letter-spacing: 0.16em;
}
.breakcore .plate-caption-sep {
color: var(--green);
opacity: 1;
}
/* Buttons & inputs — square, hard offset block-shadow, neon focus. */
.breakcore .btn,
.breakcore .field-input,
.breakcore .topbar-control,
.breakcore .topbar-control kbd { border-radius: 0; }
.breakcore .btn--primary {
color: var(--crust);
border-color: var(--mauve);
box-shadow: 3px 3px 0 0 var(--green);
}
.breakcore .btn--primary:hover {
background: var(--green);
border-color: var(--green);
color: var(--crust);
box-shadow: 3px 3px 0 0 var(--mauve);
}
.breakcore .btn--primary:active {
transform: translate(2px, 2px);
box-shadow: 1px 1px 0 0 var(--mauve);
}
.breakcore .btn--danger {
box-shadow: 3px 3px 0 0 color-mix(in srgb, var(--red) 60%, var(--crust));
}
.breakcore .btn--danger:hover {
box-shadow: 3px 3px 0 0 var(--mauve);
}
.breakcore .btn--danger:active {
transform: translate(2px, 2px);
box-shadow: 1px 1px 0 0 var(--mauve);
}
.breakcore .btn:focus-visible {
border-color: var(--green);
box-shadow: 0 0 0 2px var(--green);
}
.breakcore .field-input:focus {
border-color: var(--green);
background: color-mix(in srgb, var(--surface0) 85%, var(--green) 8%);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--green) 35%, transparent);
}
/* Ghost had no breakcore identity — drab subtext on faint surface,
* near-invisible on the violet ground. Give it the neon outline. */
.breakcore .btn--ghost {
color: var(--teal);
border-color: color-mix(in srgb, var(--teal) 55%, transparent);
background: color-mix(in srgb, var(--surface0) 60%, transparent);
box-shadow: 3px 3px 0 0 color-mix(in srgb, var(--teal) 35%, var(--crust));
}
.breakcore .btn--ghost:hover {
color: var(--crust);
background: var(--teal);
border-color: var(--teal);
box-shadow: 3px 3px 0 0 var(--mauve);
}
.breakcore .btn--ghost:active {
transform: translate(2px, 2px);
box-shadow: 1px 1px 0 0 var(--mauve);
}
/* Back-link → hard neon return tab. Impossible to miss against the
* CRT-violet ground; same offset-block language as .btn--primary. */
.breakcore .back-link {
font-family: var(--font-mono);
font-style: normal;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.16em;
color: var(--green);
padding: 7px 13px;
background: color-mix(in srgb, var(--crust) 65%, transparent);
border: 1px solid var(--mauve);
box-shadow: 3px 3px 0 0 var(--mauve);
text-shadow: 0 0 6px color-mix(in srgb, var(--green) 50%, transparent);
}
.breakcore .back-link:hover,
.breakcore .back-link:focus-visible {
color: var(--crust);
background: var(--green);
border-color: var(--green);
box-shadow: 3px 3px 0 0 var(--mauve);
text-shadow: none;
}
.breakcore .back-link:active {
transform: translate(3px, 3px);
box-shadow: 0 0 0 0 var(--mauve);
}
/* Top-bar chrome — neon UI, not drab subtext. Mono caps + hard offset. */
.breakcore .topbar-control {
font-family: var(--font-mono);
font-style: normal;
font-size: 0.72rem;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--teal);
background: color-mix(in srgb, var(--crust) 55%, transparent);
border-color: color-mix(in srgb, var(--teal) 50%, transparent);
}
.breakcore .topbar-control:hover {
color: var(--crust);
background: var(--mauve);
border-color: var(--mauve);
box-shadow: 2px 2px 0 0 var(--green);
}
.breakcore .topbar-control:focus-visible {
border-color: var(--green);
box-shadow: 0 0 0 2px var(--green);
}
.breakcore .topbar-control--danger:hover {
background: var(--red);
border-color: var(--red);
color: var(--rosewater);
box-shadow: 2px 2px 0 0 var(--mauve);
}
.breakcore .topbar-divider {
width: 2px;
background: repeating-linear-gradient(
180deg,
var(--mauve) 0 4px,
transparent 4px 7px
);
}
/* Post prev/next nav — neon offset panels + acid eyebrow (was dim text). */
.breakcore .post-nav a { transition: box-shadow 0.15s ease, border-color 0.15s ease; }
.breakcore .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);
}
.breakcore .post-nav .pn-eyebrow {
color: var(--green);
font-family: var(--font-mono);
letter-spacing: 0.18em;
text-shadow: 0 0 6px color-mix(in srgb, var(--green) 45%, transparent);
}
/* Prose / code — CRT pass: terminal block, hazard inline code, neon
* blockquote, hazard-tape rule. */
.breakcore .prose pre {
color: var(--teal);
background-color: color-mix(in srgb, var(--crust) 92%, transparent);
background-image: repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0) 0 2px,
color-mix(in srgb, var(--mauve) 9%, transparent) 2px 3px,
rgba(0, 0, 0, 0) 3px 4px
);
border-color: var(--mauve);
border-left-color: var(--green);
box-shadow:
0 0 0 1px color-mix(in srgb, var(--mauve) 28%, transparent),
4px 4px 0 0 color-mix(in srgb, var(--mauve) 35%, var(--crust));
}
.breakcore .prose pre code { color: inherit; }
.breakcore .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);
}
.breakcore .prose blockquote {
border-left-color: var(--mauve);
background: color-mix(in srgb, var(--mauve) 7%, transparent);
box-shadow: -3px 0 14px -5px color-mix(in srgb, var(--mauve) 55%, transparent);
padding: 0.5rem 0 0.5rem 1.4rem;
}
.breakcore .prose hr {
height: 3px;
opacity: 0.85;
background: repeating-linear-gradient(
90deg,
var(--mauve) 0 14px,
var(--green) 14px 28px
);
box-shadow: 0 0 10px color-mix(in srgb, var(--mauve) 40%, transparent);
}
.breakcore .prose hr::before {
background: var(--green);
box-shadow: 0 0 8px var(--green);
}
.breakcore .prose h3 { color: var(--pink); }
.breakcore .prose h4 { color: var(--teal); }
.breakcore .prose h5 { color: var(--green); font-family: var(--font-mono); }
/* Scrollbar + caret — full-immersion chrome (no default OS bar). */
.breakcore {
scrollbar-color: var(--mauve) var(--crust);
caret-color: var(--mauve);
}
.breakcore ::-webkit-scrollbar { width: 11px; height: 11px; }
.breakcore ::-webkit-scrollbar-track { background: var(--crust); }
.breakcore ::-webkit-scrollbar-thumb {
background: var(--mauve);
border: 2px solid var(--crust);
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--green) 50%, transparent);
}
.breakcore ::-webkit-scrollbar-thumb:hover { background: var(--green); }
.breakcore ::-webkit-scrollbar-corner { background: var(--crust); }
/* Prose links — magenta resting, acid-green on hover. */
.breakcore .prose a {
text-decoration-color: color-mix(in srgb, var(--mauve) 55%, transparent);
}
.breakcore .prose a:hover {
color: var(--green);
text-decoration-color: var(--green);
}
/* Reading progress — acid scan with bloom. */
.breakcore .reading-progress {
background: var(--green);
box-shadow: 0 0 8px var(--green), 0 0 3px var(--mauve);
}
/* ───── Confirm dialog (replaces window.confirm) ───── */
.cdialog-overlay {
position: fixed;
inset: 0;
z-index: 300;
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
}
.cdialog-backdrop {
position: absolute;
inset: 0;
background: color-mix(in srgb, var(--crust) 60%, transparent);
backdrop-filter: blur(8px);
}
.cdialog-panel {
position: relative;
width: 100%;
max-width: 26rem;
padding: 1.6rem 1.6rem 1.4rem;
animation: cdialog-in 0.18s cubic-bezier(0.2, 0.7, 0.2, 1);
}
@keyframes cdialog-in {
from { opacity: 0; transform: translateY(10px) scale(0.98); }
to { opacity: 1; transform: none; }
}
.cdialog-title {
font-family: var(--font-display);
font-style: italic;
font-weight: 600;
font-size: 1.4rem;
line-height: 1.15;
color: var(--text);
letter-spacing: -0.01em;
}
.cdialog-msg {
font-family: var(--font-sans);
font-size: 0.98rem;
line-height: 1.55;
color: var(--subtext1);
margin-top: 0.6rem;
}
.cdialog-actions {
display: flex;
justify-content: flex-end;
gap: 0.6rem;
margin-top: 1.5rem;
}
/* Breakcore: hard edges + neon cap + chromatic title. */
.breakcore .cdialog-panel {
border-radius: 0;
padding-top: 1.85rem;
}
.breakcore .cdialog-panel::before {
content: "";
position: absolute;
inset: 0 0 auto 0;
height: 2px;
background: linear-gradient(90deg, var(--mauve), var(--teal));
}
.breakcore .cdialog-title {
text-shadow: -1px 0 0 var(--teal), 1px 0 0 var(--mauve);
}
/* Toast error variant (replaces window.alert). */
.toast--error {
border-left: 3px solid var(--red);
color: var(--rosewater);
cursor: pointer;
}
.toast--error::before {
content: "⚠ ";
color: var(--red);
}
/* ═══════════════════════════════════════════════════════════════════════
* CYBERSIGIL — 0xPORTFOLIO // SYSTEM.BREAK()
* Scoped to `.cybersigil`; salon / salon-noir / gothic / breakcore untouched.
* 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.
* ═══════════════════════════════════════════════════════════════════════ */
/* 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,<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>");
}
/* 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 34%,
color-mix(in srgb, var(--crust) 96%, transparent) 100%
);
}
/* Corrupted-tube grain: cold static + tight scanlines, blue-shifted. */
.cybersigil body::after,
html.cybersigil body::after {
opacity: 0.24;
background-image:
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.31 0 0 0 0 0.91 0 0 0 0 1 0 0 0 0.4 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>"),
repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0) 0,
rgba(0, 0, 0, 0) 2px,
rgba(0, 0, 0, 0.36) 3px,
rgba(0, 0, 0, 0) 4px
);
mix-blend-mode: screen;
}
/* 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;
}
.cybersigil .cs-fx-halftone,
.cybersigil .cs-fx-wire,
.cybersigil .cs-fx-tear,
.cybersigil .cs-fx-corner {
position: fixed;
pointer-events: none;
}
/* 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;
}
/* Background growth — one generated sigil (DOM injected by CyberFx),
* spreading from its central spine out to both sides. Its strokes carve
* in and wipe out forever (staggered per --i) so the whole figure is
* perpetually redrawing itself. Sits behind the imagery. */
.cybersigil .cs-fx-wire {
top: 50%;
left: 50%;
width: 92vmin;
height: 92vmin;
opacity: 0.14;
transform: translate(-50%, -50%);
}
.cybersigil .cs-fx-wire .cs-sigil {
filter: drop-shadow(0 0 6px color-mix(in srgb, var(--sky) 35%, transparent));
}
.cybersigil .cs-fx-wire .cs-sigil path {
animation: cs-redraw 5.5s ease-in-out infinite;
/* negative, per-stroke offset: the field is always mid-carve, never blank */
animation-delay: calc(var(--i, 0) * -0.34s);
}
@keyframes cs-redraw {
0% { stroke-dashoffset: 1; }
35% { stroke-dashoffset: 0; }
60% { stroke-dashoffset: 0; }
100% { stroke-dashoffset: -1; }
}
/* 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; }
/* ─── Generated sigils (cs-sigil markup from lib/cybersigil.ts) ──────────
* Inert/hidden everywhere; only cybersigil draws them. Strokes start fully
* dashed-out and "carve" in via cs-carve. `forwards` fill means the reduced-
* motion kill-switch resolves them to the finished (fully drawn) state. */
.cs-sigil { display: none; }
.cybersigil .cs-sigil {
display: block;
width: 100%;
height: 100%;
overflow: visible;
}
.cybersigil .cs-sigil path {
fill: none;
stroke: var(--sky);
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
vector-effect: non-scaling-stroke;
stroke-dasharray: 1;
stroke-dashoffset: 1;
}
/* Stroke-weight tiers — heavy growth, hair filaments, prickly barbs, motifs. */
.cybersigil .cs-sigil .cs-sig-main { stroke-width: 2.4; }
.cybersigil .cs-sigil .cs-sig-fil { stroke-width: 0.9; opacity: 0.5; }
.cybersigil .cs-sigil .cs-sig-barb { stroke-width: 1.3; }
.cybersigil .cs-sigil .cs-sig-orn { stroke-width: 1.7; opacity: 0.92; }
@keyframes cs-carve {
to { stroke-dashoffset: 0; }
}
/* Corner growths: swap the static mask box for the live SVG, keep the box's
* size / placement / flicker opacity. Strokes carve in and wipe out forever
* (same perpetual self-redraw as the background sigil). */
.cybersigil .cs-fx-corner--sig {
background: none;
-webkit-mask: none;
mask: none;
}
.cybersigil .cs-fx-corner--sig .cs-sigil path,
.cybersigil .cs-fx-corner--sig .cs-sigil line {
animation: cs-redraw 5.5s ease-in-out infinite;
animation-delay: calc(var(--i, 0) * -0.34s);
}
/* Selection — magenta block, bone glyph, cyan bleed. */
.cybersigil ::selection {
background: var(--mauve);
color: var(--rosewater);
text-shadow: 0 0 6px var(--sky);
}
/* 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) 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 = 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;
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: -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);
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;
}
/* 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); }
}
.cybersigil .prose h1,
.cybersigil h1.font-display {
animation: cs-load-glitch 620ms steps(5, jump-none) backwards;
}
/* 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:
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) 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);
}
/* Thin engraved corner brackets. The deliberate sigil motif now comes from
* the generated cs-plate-sig, so the old organic leaf masks are dropped. */
.cybersigil .plate::before,
.cybersigil .plate::after {
content: "";
position: absolute;
width: 20px;
height: 20px;
pointer-events: none;
border: 0 solid color-mix(in srgb, var(--sky) 55%, transparent);
filter: drop-shadow(0 0 3px color-mix(in srgb, var(--sky) 32%, transparent));
transition: border-color 0.18s ease, filter 0.18s ease;
}
.cybersigil .plate::before { top: 6px; left: 6px; border-top-width: 2px; border-left-width: 2px; }
.cybersigil .plate::after { right: 6px; bottom: 6px; border-right-width: 2px; border-bottom-width: 2px; }
.cybersigil .plate:hover {
transform: translateY(-3px);
box-shadow:
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 6px 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);
}
/* The plate-fade-up entrance leaves `transform: translateY(0)` (forwards)
* permanently on .plate-enter — a stacking context that traps the lifted
* images below the fixed FX. Raise the whole entrance wrapper (catalogue
* tiles AND the post-page article) above the ambient layer so the looping
* background sigil can no longer bleed through any post image. */
.cybersigil .plate-enter {
position: relative;
z-index: 13;
}
/* Lift the imagery clear of the ambient FX/grain so photos read solid —
* only the hover sigil (cs-plate-sig, z-index above this) sits over them. */
.cybersigil .plate-image {
background: var(--mantle);
position: relative;
z-index: 12;
}
/* Drop the salon hang-tilt under cybersigil: the rigid terminal look wants
* square tiles, and removing the inline transform frees images from its
* stacking context so the z-index lift actually beats the fixed FX. */
.cybersigil a.plate { transform: none !important; }
.cybersigil .plate:hover { transform: translateY(-3px) !important; }
.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.9) contrast(1.06) brightness(0.95);
}
.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;
}
/* Per-plate sigil — spiky bruised-magenta growth that carves over the tile
* on contact, then fades back out. Screen-blended so it etches into the
* panel rather than masking it. */
.cs-plate-sig { display: none; }
.cybersigil .cs-plate-sig {
display: block;
position: absolute;
top: -9%;
left: 50%;
width: 46%;
height: 118%;
transform: translateX(-50%);
z-index: 14;
pointer-events: none;
opacity: 0;
mix-blend-mode: screen;
transition: opacity 0.24s ease;
}
.cybersigil .cs-plate-sig .cs-sigil path,
.cybersigil .cs-plate-sig .cs-sigil line {
stroke: color-mix(in srgb, var(--mauve) 68%, var(--sky));
filter: drop-shadow(0 0 4px color-mix(in srgb, var(--mauve) 55%, transparent));
}
.cybersigil .plate-enter:hover .cs-plate-sig,
.cybersigil .plate-enter:focus-within .cs-plate-sig {
opacity: 0.5;
}
.cybersigil .plate-enter:hover .cs-plate-sig .cs-sigil path,
.cybersigil .plate-enter:hover .cs-plate-sig .cs-sigil line,
.cybersigil .plate-enter:focus-within .cs-plate-sig .cs-sigil path,
.cybersigil .plate-enter:focus-within .cs-plate-sig .cs-sigil line {
animation: cs-carve 600ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
animation-delay: calc(var(--i, 0) * 55ms);
}
/* 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 — cold gradient edge only. Old corner leaf masks
* removed; figural sigils are no longer pinned to post images. */
.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;
position: relative;
z-index: 12;
}
/* Section rule — terminal divider `// ……… [sigil] ……… //`. */
.cybersigil .section-rule {
color: var(--sky);
font-family: var(--font-sans);
font-style: normal;
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.22em;
}
.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: 2.4em;
height: 1.2em;
background-color: var(--sky);
-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-void copy 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 — `[ TAG ]` bracketed mono. */
.cybersigil .chip {
background: transparent;
border-color: color-mix(in srgb, var(--sky) 55%, transparent);
color: var(--sky);
font-family: var(--font-sans);
font-style: normal;
font-size: 0.68rem;
text-transform: uppercase;
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);
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-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 — 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);
}
/* 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 {
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 .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);
}
.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 — ` RETURN_` command prompt with live caret + barb mark. */
.cybersigil .back-link {
display: inline-flex;
align-items: center;
gap: 0.5em;
font-family: var(--font-sans);
font-style: normal;
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.14em;
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::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 {
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 — `> CMD` prompts with a blinking caret. */
.cybersigil .topbar-control {
font-family: var(--font-sans);
font-style: normal;
font-size: 0.72rem;
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;
}
/* Icon-only / collapsed controls have no room for the `>` prompt + blink
* caret — they overflow the 2rem square on phones. Drop the pseudo when
* the label is hidden (matches each collapse class's own breakpoint). */
.cybersigil .topbar-control--icon::before,
.cybersigil .topbar-control--icon::after { content: none; }
@media (max-width: 767px) {
.cybersigil .topbar-control.tc-collapse-md::before,
.cybersigil .topbar-control.tc-collapse-md::after { content: none; }
}
@media (max-width: 639px) {
.cybersigil .topbar-control.tc-collapse-sm::before,
.cybersigil .topbar-control.tc-collapse-sm::after { content: none; }
}
.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 — 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);
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-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 — terminal log. Cold console, amber inline, magenta quote. */
.cybersigil .prose pre {
color: var(--sky);
background-color: color-mix(in srgb, var(--crust) 90%, 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 :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;
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,
.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 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-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 — hard 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 / tag — square cold terminal parity. */
.cybersigil .glass {
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),
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-sans);
font-weight: 700;
text-transform: uppercase;
}
/* Sketch marker reads as an unstable/draft signal — magenta glyph on a
* dashed (unfinished) border, sky chromatic split, matching the theme. */
.cybersigil .plate-tag-mini--draft {
color: var(--mauve);
border-style: dashed;
border-color: var(--mauve);
box-shadow: 2px 2px 0 color-mix(in srgb, var(--sky) 55%, transparent);
text-shadow:
-1px 0 0 color-mix(in srgb, var(--mauve) 65%, transparent),
1px 0 0 color-mix(in srgb, var(--sky) 55%, transparent);
}
.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; }
/* Search palette — a terminal query console. Hard edges, ice→magenta cap
* bar, `> ` prompt input + live caret, scanline body, bracketed results. */
.cybersigil .search-backdrop {
background: color-mix(in srgb, var(--crust) 78%, transparent);
}
.cybersigil .search-panel {
border-radius: 0 !important;
border-color: var(--mauve);
background:
repeating-linear-gradient(
0deg,
rgba(0, 0, 0, 0) 0 2px,
color-mix(in srgb, var(--sky) 5%, transparent) 2px 3px,
rgba(0, 0, 0, 0) 3px 4px
),
var(--base);
box-shadow:
0 0 0 1px color-mix(in srgb, var(--sky) 30%, transparent),
8px 8px 0 0 color-mix(in srgb, var(--mauve) 40%, var(--crust)),
0 30px 70px -22px rgba(0, 0, 0, 0.9) !important;
}
.cybersigil .search-panel::before {
content: "// SEARCH.CATALOGUE";
display: flex;
align-items: center;
height: 1.4rem;
padding: 0 0.7rem;
font-family: var(--font-sans);
font-size: 0.6rem;
letter-spacing: 0.2em;
color: var(--crust);
background: linear-gradient(90deg, var(--sky), var(--mauve));
}
.cybersigil .search-bar {
background: color-mix(in srgb, var(--crust) 55%, transparent);
border-bottom-color: color-mix(in srgb, var(--sky) 35%, transparent);
}
.cybersigil .search-bar svg { color: var(--sky) !important; }
.cybersigil .search-input {
font-family: var(--font-sans) !important;
font-style: normal !important;
text-transform: uppercase;
letter-spacing: 0.06em;
font-size: 0.95rem !important;
color: var(--sky) !important;
caret-color: var(--mauve);
}
.cybersigil .search-bar::before {
content: ">";
order: -1;
color: var(--mauve);
font-family: var(--font-sans);
font-weight: 700;
}
.cybersigil .search-result {
border-left-width: 2px;
font-family: var(--font-sans);
}
.cybersigil .search-result:hover {
background: color-mix(in srgb, var(--sky) 9%, transparent) !important;
border-left-color: var(--sky) !important;
}
.cybersigil .search-result--active {
background: color-mix(in srgb, var(--mauve) 14%, transparent) !important;
border-left-color: var(--mauve) !important;
}
.cybersigil .search-result [class*="font-display"] {
font-family: var(--font-display) !important;
font-style: normal !important;
text-transform: uppercase;
letter-spacing: 0.02em;
}
.cybersigil .search-result--active [class*="font-display"] {
text-shadow: -1px 0 0 var(--sky), 1px 0 0 var(--mauve);
}
.cybersigil .search-result--active::after {
content: "_";
color: var(--mauve);
font-family: var(--font-sans);
animation: cs-blink 1.05s steps(1, jump-none) infinite;
}
.cybersigil .search-result [class*="line-clamp"] {
font-family: var(--font-sans) !important;
font-style: normal !important;
}
.cybersigil .search-foot {
background: color-mix(in srgb, var(--crust) 55%, transparent);
border-top-color: color-mix(in srgb, var(--sky) 30%, transparent);
font-family: var(--font-sans) !important;
font-style: normal !important;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--subtext0);
}
.cybersigil .search-panel kbd {
border-radius: 0 !important;
border-color: var(--mauve) !important;
background: var(--crust) !important;
color: var(--sky) !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;
}
/* No corner decoration on asset tiles — neither leaf nor bracket. */
.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-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. */
.cybersigil .cdialog-panel {
border-radius: 0;
padding-top: 1.95rem;
}
.cybersigil .cdialog-panel::before {
content: "// SYSTEM.HALT?";
position: absolute;
inset: 0 0 auto 0;
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-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; }
}
/* ═══ 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). ═══ */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
/* The looping sigils would otherwise collapse to their hidden end-state —
* pin them fully drawn instead so they stay visible, just still. */
.cybersigil .cs-fx-wire .cs-sigil path,
.cybersigil .cs-fx-corner--sig .cs-sigil path {
animation: none !important;
stroke-dashoffset: 0 !important;
}
}