/*
 * stuxie.dev - the whole site's styles, in one file. No framework, no build step.
 * Colours come from the bi flag: pink #d60270, purple #9b4f96, blue #0038a8.
 * Copyright (c) 2016-2026 StuxieDev. All Rights Reserved.
 */

/* Self-hosted variable fonts (SIL Open Font License, see static/fonts/OFL-*.txt): JetBrains Mono for
   headings, the name and UI labels; IBM Plex Sans for reading text. */
@font-face { font-family: "JetBrains Mono"; src: url("../fonts/jetbrains-mono.woff2") format("woff2"); font-weight: 100 800; font-style: normal; font-display: swap; }
@font-face { font-family: "IBM Plex Sans"; src: url("../fonts/ibm-plex-sans.woff2") format("woff2"); font-weight: 100 700; font-style: normal; font-display: swap; }

:root {
    --pink: #d60270;
    --purple: #9b4f96;
    --blue: #0038a8;
    --bi: linear-gradient(100deg, #e0157e 0%, #b45cae 50%, #3f6df0 100%);

    --bg: #120915;
    --bg-raised: #190d1e;
    --surface: #1e1124;
    --surface-2: #28172f;
    --border: rgba(255, 255, 255, 0.08);
    --border-strong: rgba(255, 255, 255, 0.16);
    --text: #f7eff8;
    --muted: #bea7c2;
    --faint: #8f7a94;
    --accent: #d382cd;
    --accent-ink: #1a0b1d;
    --shadow: 0 20px 50px -24px rgba(0, 0, 0, 0.7);

    --active: #3ddc97;
    --development: #ff6ec4;
    --archived: #6aa8ff;
    --replaced: #ffbf47;
    --defunct: #ff6b6b;

    --radius: 18px;
    --radius-sm: 10px;
    --wrap: 1160px;
    --font: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
    --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color-scheme: dark;
}

/* Light theme: the system setting, unless the visitor picked dark with the header's switch... */
@media (prefers-color-scheme: light) {
    :root:not([data-theme="dark"]) {
        --bg: #fbf7fc;
        --bg-raised: #f4ecf6;
        --surface: #ffffff;
        --surface-2: #f6eff8;
        --border: rgba(40, 10, 45, 0.1);
        --border-strong: rgba(40, 10, 45, 0.2);
        --text: #1e0f22;
        --muted: #634f68;
        --faint: #8b7790;
        --accent: #8b3d85;
        --accent-ink: #ffffff;
        --shadow: 0 20px 50px -28px rgba(60, 10, 70, 0.35);

        --active: #0f8a55;
    --development: #c2187a;
        --development: #c2187a;
        --archived: #1f5fc7;
        --replaced: #a86400;
        --defunct: #c62828;
        color-scheme: light;
    }
}
/* ...or the switch set light. (Dark is the default above; data-theme="dark" just blocks the media query.) */
:root[data-theme="light"] {
    --bg: #fbf7fc;
    --bg-raised: #f4ecf6;
    --surface: #ffffff;
    --surface-2: #f6eff8;
    --border: rgba(40, 10, 45, 0.1);
    --border-strong: rgba(40, 10, 45, 0.2);
    --text: #1e0f22;
    --muted: #634f68;
    --faint: #8b7790;
    --accent: #8b3d85;
    --accent-ink: #ffffff;
    --shadow: 0 20px 50px -28px rgba(60, 10, 70, 0.35);

    --active: #0f8a55;
    --development: #c2187a;
    --archived: #1f5fc7;
    --replaced: #a86400;
    --defunct: #c62828;
    color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 88px; }
@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}
body {
    margin: 0;
    font-family: var(--font);
    font-size: 17px;
    line-height: 1.6;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}
img, svg { display: block; max-width: 100%; }
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { text-decoration-thickness: 2px; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 6px; }
h1, h2, h3 { font-family: var(--mono); font-weight: 750; line-height: 1.15; letter-spacing: -0.03em; margin: 0; text-wrap: balance; }
/* The developer bits: everything that labels, counts or navigates is set in the mono face. */
.brand, .eyebrow, .button, .site-nav a, .card-meta, .status, .tags, .chips, .stats, .status-filters, .filter-form,
.result-count, .details dt, .crumb, .more, .footer-links h2, .footer-bottom, .browser em, .cl-badge, .dev-banner { font-family: var(--mono); }
/* The name always wears the bi flag. */
.brand span, .eyebrow strong { background: var(--bi); -webkit-background-clip: text; background-clip: text; color: transparent; }
p { margin: 0 0 1em; }
code { font-family: var(--mono); font-size: 0.9em; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.icon { width: 1.15em; height: 1.15em; flex: none; }
/* The Twitter link shows the old bird and says "Twitter", and becomes the X mark and "X" while Shift is held (an easter
   egg from links.stuxie.dev). */
:root:not(.shift-held) .x-mark, :root.shift-held .x-bird { display: none !important; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }
.wrap.narrow { max-width: 780px; }
@media (max-width: 560px) { .wrap { padding: 0 16px; } }

.skip { position: absolute; left: 16px; top: -60px; z-index: 100; padding: 10px 16px; background: var(--accent); color: var(--accent-ink); border-radius: var(--radius-sm); }
.skip:focus { top: 16px; }

.dev-banner { padding: 8px 16px; font-size: 14px; text-align: center; color: #1a0b1d; background: var(--bi); }
.dev-banner strong { margin-right: 8px; text-transform: uppercase; letter-spacing: 0.08em; font-size: 12px; }
.dev-banner code { background: rgba(255, 255, 255, 0.35); padding: 1px 6px; border-radius: 4px; }

/* Header */
.site-header {
    position: sticky; top: 0; z-index: 50;
    background: color-mix(in srgb, var(--bg) 78%, transparent);
    backdrop-filter: saturate(160%) blur(14px);
    -webkit-backdrop-filter: saturate(160%) blur(14px);
    border-bottom: 1px solid var(--border);
}
.header-inner { display: flex; align-items: center; justify-content: space-between; gap: 16px; min-height: 68px; }
.brand { display: inline-flex; align-items: center; gap: 10px; color: var(--text); text-decoration: none; font-weight: 800; font-size: 18px; letter-spacing: -0.03em; }
.brand img { border-radius: 50%; }
.site-nav { display: flex; align-items: center; gap: 4px; }
.theme-toggle {
    display: none; place-items: center; width: 38px; height: 38px; margin-left: 6px; padding: 0; flex: none;
    border-radius: 50%; border: 1px solid var(--border); background: var(--surface); color: var(--muted); cursor: pointer;
    transition: color 0.15s, border-color 0.15s, transform 0.3s;
}
.js .theme-toggle { display: grid; }
.theme-toggle:hover { color: var(--text); border-color: var(--accent); }
.theme-toggle:active { transform: rotate(-30deg); }
.theme-toggle .icon { width: 18px; height: 18px; }
/* Show the theme you'd switch to: a sun while it's dark, a moon while it's light. */
.theme-toggle .icon-moon { display: none; }
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .theme-toggle .icon-sun { display: none; } :root:not([data-theme="dark"]) .theme-toggle .icon-moon { display: block; } }
:root[data-theme="light"] .theme-toggle .icon-sun { display: none; }
:root[data-theme="light"] .theme-toggle .icon-moon { display: block; }
.site-nav a { padding: 8px 14px; border-radius: 999px; color: var(--muted); text-decoration: none; font-weight: 500; font-size: 14px; transition: color 0.15s, background 0.15s; }
.site-nav a:hover { color: var(--text); background: var(--surface-2); }
.site-nav a[aria-current="page"] { color: var(--text); background: var(--surface-2); box-shadow: inset 0 0 0 1px var(--border); }
@media (max-width: 620px) {
    .header-inner { flex-wrap: wrap; justify-content: center; padding-top: 10px; padding-bottom: 8px; gap: 6px; }
    .site-nav { width: 100%; justify-content: center; }
    .site-nav a { padding: 6px 10px; font-size: 13px; }
    .theme-toggle { width: 34px; height: 34px; margin-left: 2px; }
}
/* The narrowest phones (320px): tighter links so the nav and the theme switch fit on one line. */
@media (max-width: 360px) {
    .site-nav { gap: 0; }
    .site-nav a { padding: 6px 8px; }
}

/* Shared bits */
.eyebrow { margin: 0 0 12px; font-size: 13px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent); }
.lead { font-size: clamp(17px, 1.6vw, 20px); color: var(--muted); max-width: 62ch; }
.button {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 11px 20px; border-radius: 999px;
    font: inherit; font-size: 15px; font-weight: 650; text-decoration: none; cursor: pointer;
    color: var(--text); background: var(--surface-2); border: 1px solid var(--border-strong);
    transition: transform 0.15s, background 0.15s, border-color 0.15s, box-shadow 0.15s;
}
.button:hover { transform: translateY(-1px); border-color: var(--accent); }
.button.primary { color: #fff; background: var(--bi); border-color: transparent; box-shadow: 0 10px 30px -12px rgba(214, 2, 112, 0.7); }
.button.primary:hover { box-shadow: 0 14px 34px -12px rgba(214, 2, 112, 0.9); }
.section { padding: clamp(56px, 8vw, 96px) 0; }
.section + .section { padding-top: 0; }
.section h2 { font-size: clamp(28px, 3.6vw, 40px); }
.section-head { display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between; gap: 12px 16px; margin-bottom: 32px; }
.more { display: inline-flex; align-items: center; gap: 6px; font-weight: 650; text-decoration: none; white-space: nowrap; }
.page-head { padding: clamp(40px, 7vw, 80px) 0 8px; }
.page-head h1 { font-size: clamp(30px, 4.8vw, 52px); letter-spacing: -0.04em; margin-bottom: 14px; }
.crumb { display: inline-flex; align-items: center; gap: 6px; margin-bottom: 20px; color: var(--muted); font-size: 15px; font-weight: 600; text-decoration: none; }
.crumb:hover { color: var(--text); }

/* Hero */
.hero { position: relative; overflow: hidden; padding: clamp(48px, 9vw, 112px) 0 clamp(40px, 6vw, 72px); }
.hero-glow {
    position: absolute; inset: -30% -10% auto; height: 120%; z-index: -1; pointer-events: none;
    background:
        radial-gradient(40% 50% at 18% 30%, rgba(214, 2, 112, 0.22), transparent 70%),
        radial-gradient(35% 45% at 55% 10%, rgba(155, 79, 150, 0.25), transparent 70%),
        radial-gradient(40% 50% at 85% 45%, rgba(0, 56, 168, 0.28), transparent 70%);
    filter: blur(10px);
    animation: drift 18s ease-in-out infinite alternate;
}
@keyframes drift { to { transform: translate3d(0, 4%, 0) scale(1.06); } }
.hero-inner { display: grid; grid-template-columns: 1.35fr 1fr; align-items: center; gap: 48px; }
.hero h1 { font-size: clamp(34px, 5.6vw, 68px); letter-spacing: -0.045em; margin-bottom: 22px; }
.bi, .typed { background: var(--bi); -webkit-background-clip: text; background-clip: text; color: transparent; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.button-season[hidden] { display: none; }
.season-note { margin: 14px 0 0; font-size: 13px; color: var(--faint); }
.season-note a { color: var(--accent); }
.hero-avatar { display: flex; justify-content: center; }
.avatar { width: min(300px, 70vw); aspect-ratio: 1; max-width: 100%; animation: float 6s ease-in-out infinite; }
/* The icon carries its own bi-flag ring, so it's shown as-is. */
/* The big avatar: no tap flash, selection, callout or double-tap zoom on phones. */
.avatar img { -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; touch-action: manipulation; }
.avatar img { width: 100%; height: 100%; border-radius: 50%; filter: drop-shadow(0 26px 50px rgba(214, 2, 112, 0.35)); }
@keyframes float { 50% { transform: translateY(-10px); } }
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin: clamp(40px, 6vw, 72px) 0 0; }
.stats div { padding: 18px 20px; border-radius: var(--radius); background: color-mix(in srgb, var(--surface) 80%, transparent); border: 1px solid var(--border); }
.stats dt { font-size: 13px; color: var(--muted); font-weight: 600; }
.stats dd { margin: 2px 0 0; font-size: clamp(28px, 3.5vw, 38px); font-weight: 800; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
@media (max-width: 860px) {
    .hero-inner { grid-template-columns: 1fr; text-align: center; gap: 36px; }
    .hero-avatar { order: -1; }
    .avatar { width: min(220px, 60vw); }
    .hero .lead { margin-inline: auto; }
    .hero-actions { justify-content: center; }
    .stats { grid-template-columns: repeat(2, 1fr); }
}

/* Project cards */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 330px), 1fr)); gap: 22px; }
.card {
    position: relative; display: flex; flex-direction: column;
    background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
    overflow: hidden; transition: transform 0.2s, border-color 0.2s, box-shadow 0.2s;
}
.card:hover { transform: translateY(-4px); border-color: var(--border-strong); box-shadow: var(--shadow); }
.card:focus-within { border-color: var(--accent); }
.card-visual { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--surface-2); border-bottom: 1px solid var(--border); }
.card-visual .shot { width: 100%; height: 100%; object-fit: cover; object-position: top; transition: transform 0.5s; }
.card:hover .card-visual .shot { transform: scale(1.03); }
.card-visual .status { position: absolute; top: 12px; left: 12px; }
.card[data-status="defunct"] .card-visual img.shot, .card[data-status="archived"] .card-visual img.shot { filter: saturate(0.55); }
.card-body { display: flex; flex-direction: column; flex: 1; padding: 18px 20px 20px; }
.card-meta { margin: 0 0 6px; font-size: 13px; font-weight: 600; color: var(--faint); }
.card h3 { font-size: 21px; margin-bottom: 6px; }
.card-link { color: var(--text); text-decoration: none; }
.card-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.card-tagline { color: var(--muted); font-size: 15px; margin-bottom: 14px; }
.card-replaced { font-size: 14px; color: var(--muted); margin: -6px 0 14px; }
.card-replaced a, .card-links a { position: relative; z-index: 2; }
.card-foot { display: flex; align-items: end; justify-content: space-between; gap: 12px; margin-top: auto; }
.card-links { display: flex; gap: 6px; }
.card-links a { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 50%; color: var(--muted); background: var(--surface-2); border: 1px solid var(--border); transition: color 0.15s, border-color 0.15s; }
.card-links a:hover { color: var(--text); border-color: var(--accent); }
.card-links .icon { width: 17px; height: 17px; }

.placeholder {
    display: grid; place-items: center; width: 100%; height: 100%;
    background:
        radial-gradient(70% 90% at 20% 10%, hsl(var(--hue) 70% 55% / 0.45), transparent 70%),
        radial-gradient(70% 90% at 90% 100%, hsl(calc(var(--hue) + 70) 70% 50% / 0.4), transparent 70%),
        var(--surface-2);
}
.placeholder img { width: 72px; height: 72px; border-radius: 18px; box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.6); }
.placeholder span { font-size: 44px; font-weight: 800; letter-spacing: -0.04em; color: rgba(255, 255, 255, 0.92); text-shadow: 0 4px 20px rgba(0, 0, 0, 0.35); }

.status {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 4px 11px; border-radius: 999px;
    font-size: 12px; font-weight: 700; letter-spacing: 0.04em;
    color: var(--c); background: color-mix(in srgb, var(--bg) 82%, transparent);
    border: 1px solid color-mix(in srgb, var(--c) 45%, transparent);
    backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.status-icon { width: 12px; height: 12px; flex: none; color: var(--c); }
.chip-icon { display: inline-flex; }
.status-active { --c: var(--active); }
.status-development { --c: var(--development); }
.status-archived { --c: var(--archived); }
.status-replaced { --c: var(--replaced); }
.status-defunct { --c: var(--defunct); }

/* Status effects, on the badges only (never the filter chips, which share the colour classes): each badge moves the way its status feels. Quiet loops, staggered across the grid
   so cards don't pulse in step, and off entirely under prefers-reduced-motion (see the top). */
.status { position: relative; overflow: hidden; isolation: isolate; animation-delay: var(--delay, 0s); }
.status-icon { animation-delay: var(--delay, 0s); }
.card:nth-child(4n+2) { --delay: -0.9s; }
.card:nth-child(4n+3) { --delay: -1.7s; }
.card:nth-child(4n+4) { --delay: -2.6s; }

/* Active: a slow breathing glow, like a power light. */
.status.status-active { animation: status-breathe 3.2s ease-in-out infinite; }
@keyframes status-breathe {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c) 0%, transparent); }
    50% { box-shadow: 0 0 14px 1px color-mix(in srgb, var(--c) 45%, transparent); }
}

/* In development: a shimmer sweeps across, like a build in progress. */
.status.status-development::after {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: linear-gradient(100deg, transparent 20%, color-mix(in srgb, var(--c) 30%, transparent) 40%, color-mix(in srgb, var(--c) 60%, transparent) 50%, color-mix(in srgb, var(--c) 30%, transparent) 60%, transparent 80%);
    transform: translateX(-110%);
    animation: status-shimmer 2.6s ease-in-out infinite; animation-delay: var(--delay, 0s);
}
@keyframes status-shimmer { 55%, 100% { transform: translateX(110%); } }

/* Archived: the box lifts and settles now and then, like it's being put away. */
.status.status-archived .status-icon { animation: status-settle 4.5s ease-in-out infinite; }
@keyframes status-settle {
    0%, 78%, 100% { transform: translateY(0); }
    84% { transform: translateY(-3px); }
    90% { transform: translateY(1px); }
    95% { transform: translateY(0); }
}

/* Replaced: the arrows swap over. */
.status.status-replaced .status-icon { animation: status-swap 4s ease-in-out infinite; }
@keyframes status-swap {
    0%, 40% { transform: rotateY(0); }
    50%, 90% { transform: rotateY(180deg); }
    100% { transform: rotateY(360deg); }
}

/* Defunct: flickers like a dying neon sign, with a little shake of the X. */
.status.status-defunct { animation: status-flicker 5s linear infinite; }
.status.status-defunct .status-icon { animation: status-jolt 5s linear infinite; }
@keyframes status-flicker {
    0%, 86%, 89%, 93%, 100% { opacity: 1; }
    87% { opacity: 0.35; }
    91% { opacity: 0.55; }
}
@keyframes status-jolt {
    0%, 86%, 92%, 100% { transform: translateX(0); }
    87% { transform: translateX(-1.5px); }
    89% { transform: translateX(1.5px); }
}

.tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.tags li, .tags a { font-size: 12px; font-weight: 600; color: var(--muted); }
.tags li { padding: 3px 9px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--border); }
.tags a { text-decoration: none; }
.tags a:hover { color: var(--text); }

/* Portfolio filters */
.filters { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px; margin-bottom: 14px; }
.status-filters { display: flex; flex-wrap: wrap; gap: 8px; }
.status-filters a {
    display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 999px;
    font-size: 14px; font-weight: 650; color: var(--muted); text-decoration: none;
    background: var(--surface); border: 1px solid var(--border); transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.status-filters a:hover { color: var(--text); border-color: var(--border-strong); }
.status-filters a[aria-current="true"] { color: var(--text); background: var(--surface-2); border-color: var(--accent); }
.status-filters .count { font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
.filter-form { display: flex; flex-wrap: wrap; gap: 8px; }
.filter-form input, .filter-form select {
    font: inherit; font-size: 14px; color: var(--text); background: var(--surface);
    border: 1px solid var(--border); border-radius: 999px; padding: 8px 14px; min-height: 40px;
}
.filter-form select { padding-right: 30px; appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%); background-position: calc(100% - 17px) 52%, calc(100% - 12px) 52%; background-size: 5px 5px; background-repeat: no-repeat; }
.filter-form input:focus, .filter-form select:focus { outline: none; border-color: var(--accent); }
.search { position: relative; display: flex; align-items: center; }
.search .icon { position: absolute; left: 12px; width: 16px; height: 16px; color: var(--faint); pointer-events: none; }
.search input { padding-left: 36px; width: 230px; }
.js .no-js-only { display: none; }
.result-count { font-size: 14px; color: var(--faint); margin-bottom: 22px; }
.empty { padding: 48px 0; text-align: center; color: var(--muted); }
.legend { display: flex; flex-wrap: wrap; gap: 10px 28px; margin: 48px 0 0; padding-top: 24px; border-top: 1px solid var(--border); }
.legend div { display: flex; align-items: center; gap: 10px; }
.legend dd { margin: 0; font-size: 14px; color: var(--muted); }
@media (max-width: 640px) {
    .filter-form, .search, .search input { width: 100%; }
    .filter-form label:not(.search) { flex: 1; }
    .filter-form select { width: 100%; }
}

/* About, organisations, contact */
/* The intro beside its four traits, then the toolbox across the full width with its groups in a grid. */
.about { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); gap: 32px 48px; align-items: center; }
.about h2 { margin-bottom: 18px; }
.about p { color: var(--muted); max-width: 62ch; }
.traits { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 0; padding: 0; list-style: none; }
.traits li { position: relative; display: flex; align-items: center; min-height: 76px; padding: 16px 18px 16px 22px; overflow: hidden;
    border-radius: var(--radius-sm); background: var(--surface); border: 1px solid var(--border); color: var(--text); font-weight: 600; font-size: 15px; line-height: 1.35; }
.traits li::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 4px; background: var(--bi); }
.toolbox { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 28px 40px; margin-top: 40px; padding: 28px;
    border-radius: var(--radius); background: var(--surface); border: 1px solid var(--border); }
.toolbox h3 { font-size: 16px; margin-bottom: 14px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.chips li { display: inline-flex; align-items: center; gap: 7px; padding: 6px 12px; border-radius: 999px; font-size: 14px; font-weight: 600; background: var(--surface-2); border: 1px solid var(--border); }
/* Each language's logo in its brand colour, lifted on the dark theme and deepened on the light one so
   every logo (even JavaScript's yellow or Java's red) stays readable on its chip. */
.tech-icon { width: 16px; height: 16px; flex: none; color: color-mix(in srgb, var(--brand) 72%, #ffffff); }
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .tech-icon { color: color-mix(in srgb, var(--brand) 80%, #000000); } }
:root[data-theme="light"] .tech-icon { color: color-mix(in srgb, var(--brand) 80%, #000000); }
.tech-icon.tech-icon-mono, :root[data-theme="light"] .tech-icon.tech-icon-mono { color: var(--text); }
@media (prefers-color-scheme: light) { :root:not([data-theme="dark"]) .tech-icon.tech-icon-mono { color: var(--text); } }
@media (max-width: 860px) { .about { grid-template-columns: 1fr; } .toolbox { grid-template-columns: 1fr; } }
@media (max-width: 560px) { .toolbox { margin-top: 28px; padding: 22px 18px; gap: 24px; } .traits li { min-height: 0; padding: 14px 14px 14px 18px; font-size: 14px; } }

.orgs { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: 12px; margin: 0; padding: 0; list-style: none; }
.orgs a { display: flex; align-items: center; gap: 14px; height: 100%; padding: 16px; border-radius: var(--radius); color: var(--text); text-decoration: none; background: var(--surface); border: 1px solid var(--border); transition: border-color 0.15s, transform 0.15s; }
.orgs a:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.orgs img { width: 44px; height: 44px; object-fit: contain; flex: none; }
/* Two-tone logos (the organisations, and portfolio icons with "iconThemed"): the light version on the dark theme,
   the dark version on the light theme. Portfolio screenshots use the same classes the other way round: on-dark is the
   dark-mode capture, on-light the light-mode one. */
img.on-light { display: none; }
@media (prefers-color-scheme: light) {
    :root:not([data-theme="dark"]) img.on-dark { display: none; }
    :root:not([data-theme="dark"]) img.on-light { display: block; }
}
:root[data-theme="light"] img.on-dark { display: none; }
:root[data-theme="light"] img.on-light { display: block; }
.orgs span { display: flex; flex-direction: column; line-height: 1.35; }
.orgs small { color: var(--muted); font-size: 13px; }

.contact { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center; padding: clamp(28px, 5vw, 48px); border-radius: calc(var(--radius) + 6px); background: radial-gradient(80% 120% at 0% 0%, rgba(214, 2, 112, 0.16), transparent 60%), radial-gradient(80% 120% at 100% 100%, rgba(0, 56, 168, 0.2), transparent 60%), var(--surface); border: 1px solid var(--border); }
.contact h2 { margin-bottom: 14px; }
.contact p { color: var(--muted); margin: 0; }
.contact-links { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.contact-link { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: var(--radius-sm); color: var(--text); text-decoration: none; font-weight: 600; font-size: 15px; background: var(--surface-2); border: 1px solid var(--border); transition: border-color 0.15s; }
.contact-link:hover { border-color: var(--accent); }
.contact-link span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 860px) { .contact { grid-template-columns: 1fr; } }

/* Project page */
.project-title { display: flex; align-items: center; gap: 18px; }
.project-title img { width: 64px; height: 64px; border-radius: 16px; flex: none; }
.project-title h1 { margin-bottom: 6px; }
.project-title .lead { margin: 0; }
.project-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 32px 40px; padding-top: 32px; padding-bottom: 96px; }
.project-shot { margin: 0; border-radius: var(--radius); overflow: hidden; background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow); }
.browser { display: flex; align-items: center; gap: 6px; padding: 10px 14px; border-bottom: 1px solid var(--border); background: var(--surface-2); }
.browser span { width: 10px; height: 10px; border-radius: 50%; background: var(--border-strong); }
.browser em { margin-left: 10px; font-style: normal; font-size: 12px; color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-shot .shot { width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: cover; object-position: top; }
.project-shot figcaption { display: flex; align-items: center; gap: 8px; padding: 10px 14px; font-size: 13px; color: var(--faint); border-top: 1px solid var(--border); }
.project-shot figcaption .icon { width: 15px; height: 15px; }
.project-side { display: flex; flex-direction: column; gap: 20px; }
.details { margin: 0; padding: 6px 20px; border-radius: var(--radius); background: var(--surface); border: 1px solid var(--border); }
.details div { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.details div:last-child { border-bottom: 0; }
.details dt { font-size: 14px; color: var(--muted); }
.details dd { margin: 0; font-weight: 600; font-size: 15px; text-align: right; }
.project-links { display: flex; flex-direction: column; gap: 10px; }
.project-links .button { justify-content: center; }
.project-body { grid-column: 1; max-width: 68ch; }
.project-body p { color: var(--muted); font-size: 18px; }
.note { padding: 14px 18px; border-radius: var(--radius-sm); background: var(--surface); border: 1px solid var(--border); font-size: 15px !important; }
@media (max-width: 900px) {
    .project-layout { grid-template-columns: 1fr; }
    .project-body { grid-column: auto; }
}

/* Prose pages: legal, changelog, sitemap */
.prose-section { padding-top: 24px; }
.prose { color: var(--muted); }
.prose h2 { color: var(--text); font-size: 22px; margin: 36px 0 10px; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { margin: 18px 0 8px; }
.prose ul { padding-left: 20px; }
.prose li { margin-bottom: 6px; }
.prose code { background: var(--surface-2); padding: 1px 6px; border-radius: 4px; color: var(--text); }
.prose strong { color: var(--text); }
.updated { margin-top: 36px; font-size: 14px; color: var(--faint); }
.legal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 320px), 1fr)); gap: 12px; margin-bottom: 32px; }
.legal-grid a { display: flex; flex-direction: column; gap: 4px; padding: 18px 20px; border-radius: var(--radius); text-decoration: none; background: var(--surface); border: 1px solid var(--border); transition: border-color 0.15s; }
.legal-grid a:hover { border-color: var(--accent); }
.legal-grid strong { color: var(--text); }
.legal-grid span { color: var(--muted); font-size: 14px; }
/* Changelog type badges - a fixed palette shared across every Stux project. */
.cl-badge { --cl: #8a8a94; display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 11px; font-weight: 700; letter-spacing: 0.08em; line-height: 1.4; color: var(--cl); background: color-mix(in srgb, var(--cl) 14%, transparent); border: 1px solid color-mix(in srgb, var(--cl) 45%, transparent); }
.cl-badge.cl-added { --cl: #2ecc71; }
.cl-badge.cl-changed { --cl: #3ba7ff; }
.cl-badge.cl-fixed { --cl: #ffa64d; }
.cl-badge.cl-removed { --cl: #ff4d4d; }
.cl-badge.cl-security { --cl: #b06bff; }
.cl-badge.cl-deprecated { --cl: #8a8a94; }
.error-page { padding-bottom: 120px; }

/* Footer */
.site-footer { margin-top: 40px; padding: 48px 0 32px; border-top: 1px solid var(--border); background: var(--bg-raised); font-size: 15px; }
.footer-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 32px; }
.footer-brand p { margin: 10px 0 14px; color: var(--muted); }
.footer-social { display: flex; flex-wrap: wrap; gap: 8px; }
.footer-social a { display: grid; place-items: center; width: 38px; height: 38px; border-radius: 50%; color: var(--muted); background: var(--surface); border: 1px solid var(--border); transition: color 0.15s, border-color 0.15s; }
.footer-social a:hover { color: var(--text); border-color: var(--accent); }
.footer-social .icon { width: 18px; height: 18px; }
.footer-links { display: flex; flex-wrap: wrap; gap: 48px; }
.footer-links div { display: flex; flex-direction: column; gap: 8px; }
.footer-links h2 { font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--faint); margin-bottom: 4px; }
.footer-links a, .footer-bottom a { color: var(--muted); text-decoration: none; }
.footer-links a:hover, .footer-bottom a:hover { color: var(--text); }
.footer-bottom { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px 24px; margin-top: 36px; padding-top: 20px; border-top: 1px solid var(--border); font-size: 13px; color: var(--faint); }
.footer-bottom p { margin: 0; }
/* The brand mark, "logo | A StuxieDev Project": the logo is grey until hovered, as on the other StuxieDev sites. */
.footer-mark { display: inline-flex; align-items: center; gap: 10px; }
.footer-mark-logo { display: inline-flex; }
.footer-mark img { display: block; border-radius: 50%; filter: grayscale(1); opacity: 0.7; transition: filter 0.2s, opacity 0.2s; }
.footer-mark-logo:hover img, .footer-mark-logo:focus-visible img { filter: grayscale(0); opacity: 1; }
.footer-mark-sep { opacity: 0.5; }
@media (prefers-reduced-motion: reduce) { .footer-mark img { transition: none; } }
/* The kat picker (public/static/js/kat.js shows it). */
.kat-picker { display: inline-flex; align-items: center; gap: 8px; }
.kat-picker select {
    font: inherit; font-size: 13px; color: var(--text); background: var(--surface);
    border: 1px solid var(--border); border-radius: 999px; padding: 4px 26px 4px 12px; appearance: none; cursor: pointer;
    background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
    background-position: calc(100% - 14px) 55%, calc(100% - 9px) 55%; background-size: 5px 5px; background-repeat: no-repeat;
}
.kat-picker select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.made-with { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0 5px; }
.made-with svg { display: inline-block; flex: none; }
.made-with-love { color: var(--pink); }
.made-with-code { color: var(--accent); }
.made-with-coffee { color: #c08552; }

/* Holding page: maintenance and coming soon mode (config.php). */
.holding-main { position: relative; display: grid; place-items: center; min-height: 100vh; min-height: 100dvh; overflow: hidden; padding: 48px max(16px, env(safe-area-inset-right, 0px)) 48px max(16px, env(safe-area-inset-left, 0px)); }
/* min-width: 0 lets the card shrink to the screen; without it the social row's width sets the page width on phones. */
.holding-card { display: flex; flex-direction: column; align-items: center; text-align: center; width: 100%; max-width: 560px; min-width: 0; }
.holding-avatar { width: 120px; height: 120px; border-radius: 50%; margin-bottom: 24px; animation: float 6s ease-in-out infinite; filter: drop-shadow(0 20px 40px rgba(214, 2, 112, 0.35)); }
.holding h1 { font-size: clamp(30px, 6vw, 48px); margin-bottom: 14px; }
.holding .lead { margin: 0 auto 18px; }
.holding-status { color: var(--muted); font-size: 15px; }
.holding-social { justify-content: center; margin: 10px 0 28px; }
.holding-foot { margin: 0; font-family: var(--mono); font-size: 13px; color: var(--faint); }

/* kat.stuxie.dev (public/kat/): the ways to have the kat on any site, as cards under the holding page's heading. */
.kat-page .holding-card { max-width: 640px; }
.kat-choice { margin: 0 0 8px; color: var(--muted); font-size: 14px; }
.kat-way { width: 100%; margin: 16px 0 0; padding: 18px 20px; text-align: left; background: color-mix(in srgb, var(--surface) 82%, transparent);
    border: 1px solid var(--border); border-radius: var(--radius); }
.kat-way h2 { margin: 0 0 6px; font-size: 18px; }
.kat-way p { margin: 0 0 12px; color: var(--muted); font-size: 15px; }
.kat-way .kat-note { margin: 12px 0 0; font-size: 13px; }
.kat-code { display: flex; align-items: center; gap: 10px; }
.kat-code code { flex: 1; min-width: 0; padding: 10px 12px; overflow-x: auto; white-space: nowrap; background: var(--surface-2);
    border: 1px solid var(--border); border-radius: var(--radius-sm); font-size: 13px; }
.kat-page .holding-foot { margin-top: 28px; }
.kat-way { scroll-margin-top: 16px; }
/* A page to read, so no bouncing logo drifting behind the text (the kat is the star here). */
.holding.kat-page::after { display: none; }
.kat-table td:first-child { white-space: nowrap; }
.kat-way h3 { margin: 18px 0 6px; font-size: 15px; }
.kat-way code { overflow-wrap: anywhere; }
.kat-toc { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 16px; margin: 0 0 8px; font-size: 14px; }
.kat-toc a { color: var(--muted); }
.kat-toc a:hover { color: var(--text); }
.kat-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.kat-card { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 14px 10px 12px; font: inherit; text-align: center;
    color: var(--text); background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); cursor: pointer;
    transition: border-color 0.15s, transform 0.15s; }
.kat-card:hover { transform: translateY(-1px); border-color: var(--border-strong); }
.kat-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.kat-card[aria-pressed="true"] { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.kat-card canvas { width: 64px; height: 64px; image-rendering: pixelated; }
.kat-card strong { font-size: 15px; }
.kat-card span { color: var(--muted); font-size: 12.5px; line-height: 1.4; }
.kat-list, .kat-steps { margin: 0; padding-left: 20px; color: var(--muted); font-size: 15px; }
.kat-list li, .kat-steps li { margin: 0 0 8px; }
.kat-list strong, .kat-steps strong { color: var(--text); }
.kat-steps .kat-code, .kat-steps p { margin: 10px 0 4px; }
.kat-table-wrap { overflow-x: auto; }
.kat-sheets { display: grid; gap: 10px; margin: 6px 0 0; }
.kat-sheet { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; padding: 10px 12px; background: var(--surface-2);
    border: 1px solid var(--border); border-radius: var(--radius-sm); }
.kat-sheet canvas { width: 128px; height: 64px; image-rendering: pixelated; background: rgba(255, 255, 255, 0.04); border-radius: 6px; }
.kat-sheet strong { flex: 1; min-width: 80px; font-size: 15px; }
.kat-sheet .button { padding: 6px 14px; font-size: 13px; }
.kat-table { width: 100%; border-collapse: collapse; font-size: 14px; color: var(--muted); }
.kat-table th, .kat-table td { padding: 8px 10px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--border); }
.kat-table th { color: var(--text); font-weight: 600; }
.kat-way details { border-top: 1px solid var(--border); padding: 10px 0; }
.kat-way details:first-of-type { border-top: 0; }
.kat-way summary { cursor: pointer; color: var(--text); font-weight: 600; }
.kat-way details p { margin: 8px 0 0; }
@media (prefers-reduced-motion: reduce) { .kat-card { transition: none; } .kat-card:hover { transform: none; } }

/* Bouncing logo, like an old DVD player's screensaver, on the holding pages (coming soon, maintenance, and the
   folder pages like /fluxer that share their look). The kat and STUXIEDEV (static/img/bounce.svg, as a mask) drift
   across the background and change colour at every wall they hit. It's body::after, at z-index -1 after the glow,
   so it sits above the glow and under the card. Pure CSS: across and down are separate timers (13 s and 9 s a
   sweep), so it bounces the same on any screen size. Started part-way (-4 s, -2 s), it reaches its first corner
   61 s in, then one every 117 s (13 x 9), with a little pop when it does. The colour steps through the bi
   flag's pink, purple and blue (21 hits a cycle, 3 colours, so it loops seamlessly). Hidden on small screens and
   with reduced motion. */
.holding::after {
    --dvd-w: clamp(120px, 16vw, 240px);
    --dvd-h: calc(var(--dvd-w) / 2);
    content: "";
    position: fixed; z-index: -1; top: 0; left: 0;
    width: var(--dvd-w); height: var(--dvd-h);
    pointer-events: none;
    background-color: #ff4fa3;
    opacity: 0.85;
    -webkit-mask: url("../img/bounce.svg") center / contain no-repeat;
    mask: url("../img/bounce.svg") center / contain no-repeat;
    animation:
        dvd-x 13s linear -4s infinite alternate,
        dvd-y 9s linear -2s infinite alternate,
        dvd-colour 117s step-end -56s infinite,
        dvd-corner 117s linear -56s infinite;
}
@keyframes dvd-x { from { left: 0; } to { left: calc(100vw - var(--dvd-w)); } }
@keyframes dvd-y { from { top: 0; } to { top: calc(100vh - var(--dvd-h)); } }
/* one colour per wall hit: in the colour's own 117 s cycle, starting at a corner, the side walls come every 13 s
   and the top and bottom every 9 s */
@keyframes dvd-colour {
    0% { background-color: #ff4fa3; }
    7.692% { background-color: #b06bff; }
    11.111% { background-color: #3ba7ff; }
    15.385% { background-color: #ff4fa3; }
    22.222% { background-color: #b06bff; }
    23.077% { background-color: #3ba7ff; }
    30.769% { background-color: #ff4fa3; }
    33.333% { background-color: #b06bff; }
    38.462% { background-color: #3ba7ff; }
    44.444% { background-color: #ff4fa3; }
    46.154% { background-color: #b06bff; }
    53.846% { background-color: #3ba7ff; }
    55.556% { background-color: #ff4fa3; }
    61.538% { background-color: #b06bff; }
    66.667% { background-color: #3ba7ff; }
    69.231% { background-color: #ff4fa3; }
    76.923% { background-color: #b06bff; }
    77.778% { background-color: #3ba7ff; }
    84.615% { background-color: #ff4fa3; }
    88.889% { background-color: #b06bff; }
    92.308% { background-color: #3ba7ff; }
}
@keyframes dvd-corner { 0% { scale: 1.12; opacity: 1; } 2%, 100% { scale: 1; opacity: 0.85; } }
@media (max-width: 35rem), (max-height: 17.5rem), (prefers-reduced-motion: reduce) { .holding::after { display: none; } }
