* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

:root {
    --bg: #0a0a0a;
    --bg-secondary: #101010;
    --bg-card: #131313;
    --bg-hero: #08060a;
    --bg-fade: rgba(10, 10, 10, 0.85);
    --text: #d4d4d4;
    --text-dim: #6b6b6b;
    --red: #ff3b3b;
    --red-bright: #ff5c5c;
    --red-dim: #7a1f1f;
    --red-soft: rgba(255, 59, 59, 0.22);
    --border: #1f1f1f;
    --selection: #0a0a0a;
    --font-mono: 'Victor Mono Variable', ui-monospace, monospace;
    --radius: 10px;
    --glow: 0 0 12px rgba(255, 59, 59, 0.45);
}

/* Light theme: set on <body class="light"> via the theme toggle */
body.light {
    --bg: #f4f4f0;
    --bg-secondary: #ececea;
    --bg-card: #ffffff;
    --bg-hero: #e9e7e2;
    --bg-fade: rgba(240, 240, 238, 0.9);
    --text: #16161a;
    --text-dim: #5b5b66;
    --red: #d92b2b;
    --red-bright: #ff3b3b;
    --red-dim: #ffc2c2;
    --red-soft: rgba(217, 43, 43, 0.22);
    --border: #dbdbd4;
    --selection: #ffffff;
    --glow: 0 0 12px rgba(217, 43, 43, 0.35);
}

/* ---- Control panel ----
   The bar is fixed, so every page that is not the home page has to clear it.
   The home page deliberately does not: each of its sections is a full 100vh
   scroll-snap target that already carries 4.5rem of padding, so the bar sits
   inside that padding. Adding body padding on the home page too would push
   every section down and break the snapping. */
body:not(.home) {
    /* Matches .cp-bar's height. Both are load-bearing together: the bar is
       position:fixed, so this padding is the only thing keeping page content
       from starting underneath it. */
    padding-top: 3.1rem;
}

.cp-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100060;
    /* 3.1rem, and load-bearing in four places: this, body:not(.home)'s
       padding-top, .cp-panel's and .cp-navmenu's top, and the phone rule's
       values. The height is only as tall as the triggers need it to be. */
    height: 3.1rem;
    /* 1fr auto 1fr, not space-between. Three children in three columns: the
       brand takes column 1, the nav dropdown column 2 and the control panel
       column 3. The nav trigger has to sit in the optical centre of the bar, and
       the two equal 1fr columns are what put it there — with space-between both
       triggers would be pinned to the two ends and nothing would be centred. */
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    column-gap: 1rem;
    padding: 0 0.9rem;
    background: var(--bg-fade);
    border-bottom: 1px solid var(--border);
    font-family: var(--font-mono);
    user-select: none;
}

.cp-brand {
    grid-column: 1;
    justify-self: start;
    font-size: 0.8rem;
    color: var(--text-dim);
    letter-spacing: 0.5px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

.cp-brand-tilde {
    color: var(--red);
}

.cp-caret {
    display: inline-block;
    width: 0.45rem;
    height: 0.85rem;
    margin-left: 2px;
    vertical-align: -1px;
    background: var(--red);
    animation: cp-blink 1.15s steps(1) infinite;
}

@keyframes cp-blink {
    0%, 55% { opacity: 1; }
    56%, 100% { opacity: 0; }
}

/* Shared text blink: the status dot, the typewriter cursor, the terminal
   cursor and the scroll hint all use it. It is named separately from cp-blink
   because it is a plain 50% fade with no off-by-one step boundary. */
@keyframes blink {
    50% { opacity: 0.25; }
}

/* The bar's nav trigger: the centre column. Deliberately quieter than .cp-btn —
   the control panel is the site's one settings surface and this is a shortcut to
   links the panel also lists, so two things pulsing in the bar would be noise
   rather than emphasis. No idle animation at all: the red chevron and the
   glow-on-hover are what mark it as live, because the site hides the real cursor
   and a steady border is the only thing that would ever say "press me". */
.cp-navbtn {
    grid-column: 2;
    justify-self: center;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    background: none;
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text);
    font-family: inherit;
    font-size: 0.8rem;
    letter-spacing: 1.1px;
    padding: 0.4rem 0.85rem;
    cursor: none;
    transition: color 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}

.cp-navbtn:hover,
.cp-navbtn:focus-visible,
.cp-navbtn[aria-expanded="true"] {
    color: var(--red-bright);
    border-color: var(--red-dim);
    box-shadow: var(--glow);
    outline: none;
}

.cp-navbtn-chev {
    color: var(--red);
    font-size: 0.6rem;
    transition: transform 0.2s ease;
}

.cp-navbtn[aria-expanded="true"] .cp-navbtn-chev {
    transform: rotate(180deg);
}

/* The nav dropdown: a compact card hanging off the bar's centre trigger. It
   shares the control panel's open/close mechanics (an .is-open class, so
   visibility can be transitioned) but not its scrim — four links are not a modal,
   and a full-screen scrim behind a menu that short would be heavier than the
   menu. Closed by an outside press or Escape in main.js.

   Centred with left:0/right:0 + margin:auto + a definite width rather than
   left:50% + translateX(-50%), because transform is already load-bearing here —
   it is the open/close animation, so a centring transform would have to be folded
   into both of its states. The phone rule below only has to drop the width. */
.cp-navmenu {
    position: fixed;
    top: 3.6rem;            /* the 3.1rem bar + a 0.5rem gutter */
    left: 0;
    right: 0;
    margin: auto;
    z-index: 100065;         /* above the scrim, below the panel — see the ladder */
    width: min(16rem, calc(100vw - 1.8rem));
    padding: 0.3rem;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-top: 1px solid var(--red-dim);
    border-radius: 5px;
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55), 0 0 20px rgba(255, 59, 59, 0.07);
    font-family: var(--font-mono);
    user-select: none;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-0.4rem);
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
}

.cp-navmenu.is-open {
    opacity: 1;
    visibility: visible;
    transform: none;
}

.cp-btn {
    /* Column 3 of the 1fr auto 1fr bar grid, pinned to the far right. */
    grid-column: 3;
    justify-self: end;
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex: 0 0 auto;
    background: linear-gradient(180deg, rgba(255, 59, 59, 0.09), rgba(255, 59, 59, 0.02));
    border: 1px solid var(--red-dim);
    border-radius: 4px;
    color: var(--red);
    font-family: inherit;
    font-size: 0.8rem;
    letter-spacing: 1.1px;
    padding: 0.4rem 0.85rem;
    cursor: none;
    /* The idle glow is the whole point of this control. The site hides the real
       cursor, so a steady border is the only thing that would ever say "press
       me" — and the first version of this button was a dim grey label in the
       corner that nobody found. Cancelled (not paused) on hover: a paused
       animation still applies its frozen keyframe value and animation values
       outrank ordinary declarations, so a pause would leave the hover fighting
       the freeze point instead of showing the emphasis. Same trap as the nav
       links.

       The pulse is a box-shadow breathing in and out, and that is the entire
       animation vocabulary of this bar. An earlier version put twinkling star
       glyphs on ::before/::after; they were cut because a sparkle is a
       decoration, not a terminal — a bar that twinkles reads as a toy rather than
       as a machine. Nothing here animates anything but colour, shadow, transform
       and opacity. */
    animation: cp-btn-glow 2.4s ease-in-out infinite;
    transition: color 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease,
                transform 0.18s ease;
}

@keyframes cp-btn-glow {
    0%, 100% { box-shadow: 0 0 6px rgba(255, 59, 59, 0.18), 0 0 0 1px rgba(255, 59, 59, 0.05); }
    50%      { box-shadow: 0 0 16px rgba(255, 59, 59, 0.5), 0 0 0 1px rgba(255, 59, 59, 0.16); }
}

.cp-btn:hover,
.cp-btn:focus-visible {
    color: var(--red-bright);
    border-color: var(--red);
    background: linear-gradient(180deg, rgba(255, 59, 59, 0.18), rgba(255, 59, 59, 0.05));
    animation: none;
    box-shadow: var(--glow), 0 0 0 1px rgba(255, 59, 59, 0.2);
    transform: translateY(-1px);
    outline: none;
}

.cp-btn[aria-expanded="true"] {
    color: var(--red-bright);
    border-color: var(--red);
    background: linear-gradient(180deg, rgba(255, 59, 59, 0.2), rgba(255, 59, 59, 0.06));
    animation: none;
    box-shadow: var(--glow), 0 0 0 1px rgba(255, 59, 59, 0.2);
}

.cp-btn-chev {
    font-size: 0.6rem;
    transition: transform 0.2s ease;
}

.cp-btn[aria-expanded="true"] .cp-btn-chev {
    transform: rotate(180deg);
}

.cp-scrim {
    position: fixed;
    inset: 0;
    z-index: 100050;
    /* The panel is an opaque card again, so the scrim can afford to be properly
       dark: it is there to stop the page reading through as clickable while a
       modal-ish panel is open, not to be seen. */
    background: rgba(0, 0, 0, 0.55);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.2s ease, visibility 0.2s;
}

.cp-scrim.is-open {
    opacity: 1;
    visibility: visible;
}

.cp-panel {
    position: fixed;
    /* A compact card hanging off the bar's right-hand trigger — a dropdown, not a
       window. It was a centred 44rem glass window for a while, and the blur cost
       real frames on every repaint behind it; an opaque card anchored to the
       thing you clicked is both cheaper and easier to aim at.

       `right` matches the bar's own side padding so the card's right edge lines up
       with the trigger's, and the red top border is what ties the two together.
       Centring is not wanted here: the panel belongs to the button. */
    top: 3.6rem;            /* the 3.1rem bar + a 0.5rem gutter */
    right: 0.9rem;
    z-index: 100070;
    /* Compact: 24rem is wide enough for a font name and for the music row's fixed
       controls, and no wider. */
    width: min(24rem, calc(100vw - 1.8rem));
    /* Capped, because the card is anchored to the *top*: a twelve-row font list
       plus four sections would otherwise run off the bottom of a short window.
       This is a max-height rather than a top+bottom band (which is what the
       centred window used) precisely because there is no bottom offset to cap it
       now. */
    max-height: calc(100vh - 4.4rem);
    /* The panel is the one scrollable region on the home page, and the page snaps
       one section per wheel notch from a document-level listener that
       preventDefaults first. main.js's panelOwnsScroll() is what actually stops
       that; these two declarations are the belt to its braces — contain stops the
       scroll chaining once the panel hits its limit, and touch-action stops touch
       drags being read as a page scroll on browsers without contain. */
    overflow-y: auto;
    overscroll-behavior: contain;
    touch-action: pan-y;
    /* Deliberately an opaque card. It was `backdrop-filter: blur(16px)
       saturate(1.7)` over a translucent tint, which is what a compositor does for
       a window — and it is expensive: the backdrop has to be re-blurred on every
       frame anything under the panel changes, which on the home page is the grid
       drift, the scan sweep and the glitch all at once. Do not put a
       backdrop-filter back on this without measuring it. */
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-top: 1px solid var(--red-dim);
    border-radius: 6px;
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.6), 0 0 22px rgba(255, 59, 59, 0.08);
    font-family: var(--font-mono);
    user-select: none;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-0.4rem);
    transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
}

.cp-panel.is-open {
    opacity: 1;
    visibility: visible;
    transform: none;
}

/* ---- Home page inline nav -------------------------------------------------
   The home page's navigation, laid out across the hero instead of stacked in a
   dropdown: a landing page should show where you can go rather than make you
   click to find out. Layout is the only thing defined here — the links
   themselves are the shared .cp-nav-link rows, so a nav link cannot look
   different in the hero than it does in the bar's dropdown or the panel. */
.hero-nav {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.1rem 1.1rem;
    margin: 1.1rem 0 0;
}


.cp-head {
    position: sticky;
    top: 0;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.45rem 0.6rem;
    /* Opaque, and a shade off the body colour so the title bar reads as a bar.
       It was a second translucent tint so content scrolling underneath would not
       show through it — which an opaque background does just as well, and without
       a backdrop-filter to keep in sync. */
    background: var(--bg-secondary);
    /* Scanlines on the head only. An overlay spanning the whole panel would be
       positioned against the padding box, so it would scroll away with the
       content instead of staying put. */
    background-image: repeating-linear-gradient(
        to bottom, rgba(255, 59, 59, 0.05) 0 1px, transparent 1px 3px);
    border-bottom: 1px solid var(--border);
}

.cp-title {
    color: var(--red);
    font-size: 0.72rem;
    letter-spacing: 0.8px;
}

.cp-close {
    background: none;
    border: 1px solid transparent;
    color: var(--text-dim);
    font-family: inherit;
    font-size: 0.7rem;
    line-height: 1;
    padding: 0.2rem 0.35rem;
    border-radius: 3px;
    cursor: none;
    transition: color 0.15s ease, border-color 0.15s ease;
}

.cp-close:hover,
.cp-close:focus-visible {
    color: var(--red-bright);
    border-color: var(--red-dim);
    outline: none;
}

/* One column, always. The panel used to be a wide window whose sections laid
   themselves out side by side once it was wide enough, via a query on its own
   width; it is a compact dropdown now, so there is nothing to switch and no
   container to measure. Do not reintroduce a two-column step without the width
   to justify it. */
.cp-body {
    padding: 0.1rem 0.6rem 0.7rem;
}

.cp-sec {
    padding: 0.6rem 0 0.2rem;
    border-bottom: 1px dashed var(--border);
}

.cp-sec:last-child {
    border-bottom: 0;
}

.cp-sec-title {
    margin: 0 0 0.4rem;
    color: var(--text-dim);
    font-size: 0.6rem;
    font-weight: 400;
    letter-spacing: 1.4px;
    text-transform: uppercase;
}

.cp-nav {
    display: flex;
    flex-direction: column;
}

.cp-nav-link {
    display: block;
    padding: 0.28rem 0.45rem;
    font-size: 0.8rem;
    color: var(--text);
    border-radius: 3px;
    transform: scale(1);
    transition: color 0.25s ease, text-shadow 0.25s ease,
                transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.cp-nav-link::before {
    content: ">";
    color: var(--red);
    opacity: 0;
    margin-right: 0.35rem;
    transition: opacity 0.2s ease;
}

/* The page you are on: flatly red, no background box, no lift. Declared
   *before* the hover rules on purpose — same specificity, so the later rule has
   to win, otherwise hovering the page you are already on would shrink the
   emphasis instead of popping it. */
.cp-nav-link.active {
    color: var(--red);
    text-shadow: var(--glow);
}

.cp-nav-link.active::before {
    opacity: 1;
}

.cp-nav-link:hover,
.cp-nav-link:focus-visible {
    color: var(--red-bright);
    text-shadow: var(--glow), 0 0 22px rgba(255, 59, 59, 0.25);
    transform: scale(1.06);
    outline: none;
}

.cp-nav-link:hover::before,
.cp-nav-link:focus-visible::before {
    opacity: 1;
}

/* Keyboard focus still needs something unmistakable, and it must not be a box.
   An underline costs no layout and cannot be mistaken for a button. Declared
   after the hover block on purpose: a mouse hover never matches :focus-visible,
   so this cannot turn a hover into an underline. */
.cp-nav-link:focus-visible {
    text-decoration: underline;
    text-underline-offset: 3px;
}

/* Links that are *not* the current page keep a slow pulse: that is what says
   they are still clickable. Hover drops the pulse rather than pausing it — a
   paused animation still applies its frozen keyframe value, and animation
   values outrank ordinary declarations, so pausing left the hover glow fighting
   whatever frame it froze on. Cancelling hands colour back to the cascade. */
.cp-nav-link:not(.active) {
    animation: cp-nudge-glow 2.8s ease-in-out infinite;
}

.cp-nav-link:not(.active):nth-child(even) {
    animation-delay: 0.7s;
}

.cp-nav-link:not(.active):hover,
.cp-nav-link:not(.active):focus-visible {
    animation: none;
}

@keyframes cp-nudge-glow {
    0%, 100% {
        color: var(--text);
        text-shadow: none;
    }
    50% {
        color: var(--red-bright);
        text-shadow: var(--glow);
    }
}

.cp-fonts {
    max-height: 10.5rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 0.15rem;
}

/* Each row previews its own typeface, so the list is a live specimen sheet */
.cp-font-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    text-align: left;
    background: none;
    border: 0;
    color: var(--text);
    font-size: 0.8rem;
    line-height: 1.5;
    padding: 0.25rem 0.45rem;
    border-radius: 2px;
    cursor: none;
    transition: background 0.1s ease, color 0.1s ease;
}

.cp-font-item:hover,
.cp-font-item:focus-visible {
    background: var(--red-soft);
    color: var(--red);
    outline: none;
}

.cp-font-mark {
    margin-left: auto;
    color: var(--red);
    font-weight: 700;
    opacity: 0;
}

.cp-font-item[aria-selected="true"] {
    color: var(--red);
}

.cp-font-item[aria-selected="true"] .cp-font-mark {
    opacity: 1;
}

.cp-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    padding: 0.22rem 0.1rem;
}

.cp-label {
    color: var(--text-dim);
    font-size: 0.72rem;
}

.cp-seg {
    display: flex;
    border: 1px solid var(--border);
    border-radius: 3px;
    overflow: hidden;
}

.cp-seg-btn {
    background: none;
    border: 0;
    color: var(--text-dim);
    font-family: inherit;
    font-size: 0.68rem;
    letter-spacing: 0.4px;
    padding: 0.2rem 0.55rem;
    cursor: none;
    transition: background 0.15s ease, color 0.15s ease;
}

.cp-seg-btn + .cp-seg-btn {
    border-left: 1px solid var(--border);
}

.cp-seg-btn:hover,
.cp-seg-btn:focus-visible {
    color: var(--red-bright);
    outline: none;
}

.cp-seg-btn.is-on {
    background: var(--red-soft);
    color: var(--red);
}

.cp-step {
    display: flex;
    align-items: center;
    border: 1px solid var(--border);
    border-radius: 3px;
}

.cp-step-btn {
    background: none;
    border: 0;
    color: var(--text);
    font-family: inherit;
    font-size: 0.7rem;
    font-weight: 700;
    padding: 0.2rem 0.5rem;
    cursor: none;
    transition: color 0.15s ease, background 0.15s ease;
}

.cp-step-btn:hover,
.cp-step-btn:focus-visible {
    color: var(--red-bright);
    background: var(--red-soft);
    outline: none;
}

/* A step that would leave the allowed range is dimmed and inert, so the range
   is visible without a "you cannot go further" message. */
.cp-step-btn.is-off {
    color: var(--text-dim);
    opacity: 0.3;
    pointer-events: none;
}

.cp-step-val {
    min-width: 3.1rem;
    text-align: center;
    color: var(--red);
    font-size: 0.68rem;
    padding: 0.2rem 0;
    border-left: 1px solid var(--border);
    border-right: 1px solid var(--border);
}

.cp-switch {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    background: none;
    border: 0;
    color: var(--text-dim);
    font-family: inherit;
    font-size: 0.68rem;
    padding: 0.1rem;
    cursor: none;
    transition: color 0.15s ease;
}

.cp-switch-track {
    position: relative;
    width: 1.9rem;
    height: 0.9rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    transition: border-color 0.18s ease, background 0.18s ease;
}

.cp-switch-dot {
    position: absolute;
    top: 50%;
    left: 0.15rem;
    width: 0.5rem;
    height: 0.5rem;
    margin-top: -0.25rem;
    border-radius: 50%;
    background: var(--text-dim);
    transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1),
                background 0.18s ease;
}

.cp-switch.is-on {
    color: var(--red);
}

.cp-switch.is-on .cp-switch-track {
    border-color: var(--red);
    background: var(--red-soft);
}

.cp-switch.is-on .cp-switch-dot {
    transform: translateX(1.25rem);
    background: var(--red);
}

/* Hacker glitch flash overlay for theme switches */
.theme-glitch {
    position: fixed;
    inset: 0;
    z-index: 99999;
    pointer-events: none;
    background: linear-gradient(90deg,
        rgba(255, 59, 59, 0.18) 0%,
        transparent 18%,
        rgba(10, 10, 10, 0.35) 38%,
        transparent 55%,
        rgba(255, 59, 59, 0.15) 80%,
        transparent 100%);
    background-size: 300% 100%;
    mix-blend-mode: screen;
    animation: theme-glitch-shift 0.4s steps(3, end) forwards;
}

.theme-glitch.light-flash {
    mix-blend-mode: difference;
    background: rgba(255, 255, 255, 0.9);
    animation: theme-glitch-flicker 0.25s steps(2, end) forwards;
}

@keyframes theme-glitch-shift {
    0%   { background-position: 0% 0;   opacity: 1; filter: none; }
    40%  { background-position: 60% 0;  opacity: 0.9; filter: hue-rotate(90deg); }
    70%  { background-position: 30% 0;  opacity: 0.7; filter: hue-rotate(0deg); }
    100% { background-position: 100% 0; opacity: 0;   filter: none; }
}

@keyframes theme-glitch-flicker {
    0%   { opacity: 1; transform: translateX(0); }
    50%  { opacity: 0.6; transform: translateX(3px); }
    100% { opacity: 0; transform: translateX(0); }
}

html {
    font-size: 17.5px;
}

body {
    background:
        radial-gradient(ellipse at 50% -20%, var(--bg-card) 0%, var(--bg) 60%),
        var(--bg);
    color: var(--text);
    font-family: var(--font-mono);
    line-height: 1.65;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    padding: 0 1.25rem;
}

/* Grid background */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background-image:
        linear-gradient(rgba(255, 59, 59, 0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 59, 59, 0.035) 1px, transparent 1px);
    background-size: 38px 38px;
    mask-image: radial-gradient(ellipse at 50% 0%, black 40%, transparent 100%);
    -webkit-mask-image: radial-gradient(ellipse at 50% 0%, black 40%, transparent 100%);
}

/* ==================== HOME BACKGROUND FX ====================
   The grid above is static, which reads as a dead background. On the home page
   it drifts and breathes, a scan band sweeps down, and the whole thing snaps
   sideways every so often.

   Every effect here is `transform` or `opacity` on a layer that is deliberately
   LARGER than the viewport, and that is the whole design constraint. Animating
   `background-position` would be the obvious way to move a grid and it repaints
   a full-viewport element on every single frame; a translate on an oversized
   layer is promoted and composited instead. For the same reason there is no
   `will-change` here: these animations never stop, so the compositor promotes
   the layers by itself, and a permanent `will-change` on a full-viewport
   texture just pins that memory forever. */
body.home::before {
    /* One grid cell of bleed on every side, because the grid travels exactly
       one cell. inset: 0 would let the drift expose an empty edge. */
    inset: -38px;
    animation:
        bg-grid-drift 26s linear infinite,
        bg-grid-breathe 7s ease-in-out infinite;
}

/* Exactly one cell (38px) on each axis, so the pattern lands back on itself and
   the loop has no seam. Linear for the same reason: an eased drift visibly
   hitches once per cycle when it wraps. */
@keyframes bg-grid-drift {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(-38px, -38px, 0); }
}

/* Opacity only, so it composites. Shallow on purpose: the base grid is already
   faint at 0.035, and this is meant to read as "alive", not as a strobe. */
@keyframes bg-grid-breathe {
    0%, 100% { opacity: 0.7; }
    50%      { opacity: 1; }
}

/* Sits below the pages by tree order rather than by a z-index fight: it is
   markup ahead of <main>, and both it and the position:relative .page sections
   land in the same "positioned, z-index: auto/0" paint step, where document
   order decides. Non-interactive and decorative, hence aria-hidden. */
.bg-fx {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
}

/* A soft bright band falling down the page, like a CRT refresh sweep. It is a
   gradient on a `top: 0` box that translates, clipped by the parent's
   overflow: hidden -- never a moving background-position. */
.bg-sweep {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 34vh;
    background: linear-gradient(
        to bottom,
        transparent 0%,
        rgba(255, 59, 59, 0.045) 45%,
        rgba(255, 59, 59, 0.085) 50%,
        rgba(255, 59, 59, 0.045) 55%,
        transparent 100%
    );
    animation: bg-sweep-fall 9s linear infinite;
}

@keyframes bg-sweep-fall {
    0%   { transform: translate3d(0, -40vh, 0); opacity: 0; }
    10%  { opacity: 1; }
    88%  { opacity: 1; }
    100% { transform: translate3d(0, 105vh, 0); opacity: 0; }
}

/* Occasional horizontal displacement, the cyberpunk glitch. steps(1, end) is
   the whole trick: without it the offsets ease into each other and the bars
   *slide* instead of snapping, which reads as a wobble rather than a glitch.
   The long idle stretch matters just as much -- a glitch that runs continuously
   stops reading as an event and starts reading as noise. */
.bg-glitch {
    position: absolute;
    inset: 0;
    background: repeating-linear-gradient(
        to bottom,
        transparent 0 38px,
        rgba(255, 59, 59, 0.055) 38px 39px,
        transparent 39px 76px
    );
    opacity: 0;
    animation: bg-glitch-snap 9s steps(1, end) infinite;
}

@keyframes bg-glitch-snap {
    0%, 87%  { transform: translate3d(0, 0, 0); opacity: 0; }
    88%      { transform: translate3d(-14px, 0, 0); opacity: 0.95; }
    89%      { transform: translate3d(9px, 0, 0); opacity: 0.7; }
    90%      { transform: translate3d(-6px, 0, 0); opacity: 0.9; }
    91%      { transform: translate3d(0, 0, 0); opacity: 0; }
    100%     { transform: translate3d(0, 0, 0); opacity: 0; }
}

/* Anyone who asked their OS to stop moving things gets a static grid back. */
@media (prefers-reduced-motion: reduce) {
    body.home::before,
    .bg-sweep,
    .bg-glitch {
        animation: none;
    }
    .bg-glitch { opacity: 0; }
}

/* CRT scanlines */
body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 9999;
    pointer-events: none;
    background: repeating-linear-gradient(
        0deg,
        rgba(0, 0, 0, 0.18) 0px,
        rgba(0, 0, 0, 0.18) 1px,
        transparent 1px,
        transparent 3px
    );
    animation: flicker 4s infinite;
}

@keyframes flicker {
    0%, 100% { opacity: 1; }
    92% { opacity: 1; }
    93% { opacity: 0.6; }
    94% { opacity: 1; }
    97% { opacity: 0.8; }
    98% { opacity: 1; }
}

a {
    color: var(--red);
    text-decoration: none;
    transition: color 0.15s ease, text-shadow 0.15s ease;
}

a:hover {
    color: var(--red-bright);
    text-shadow: var(--glow);
    text-decoration: none;
}

.red {
    color: var(--red);
}

::selection {
    background: var(--red);
    color: var(--selection);
}

/* Layout - centered column for desktop */
nav,
main,
footer {
    width: 100%;
    max-width: 1080px;
    margin: 0 auto;
    position: relative;
    z-index: 1;
}

/* Main */
main {
    flex: 1;
    padding: 2.5rem 0;
}

/* Hero */
.hero {
    margin-bottom: 2.5rem;
}

/* Matrix intro - hacker terminal */
.matrix-stage {
    position: relative;
    width: 100%;
    height: 60vh;
    min-height: 340px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    background: var(--bg-hero);
    margin-bottom: 2.5rem;
}

.matrix {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
}

.matrix-overlay {
    position: relative;
    z-index: 2;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.1rem;
    text-align: center;
    padding: 0 1rem;
}

.matrix-quotes {
    max-width: 760px;
}

.matrix-quote-inner {
    font-size: 1.15rem;
    color: #ffb3c1;
    text-shadow: 0 0 14px rgba(255, 59, 91, 0.7);
    line-height: 1.5;
    white-space: pre-wrap;
    font-weight: 600;
    letter-spacing: 0.5px;
}

.matrix-quote-inner.mq-enter {
    animation: mq-in 0.25s steps(3) both;
}

@keyframes mq-in {
    0%   { transform: translateX(-6px); opacity: 0; clip-path: inset(0 100% 0 0); }
    50%  { transform: translateX(3px); }
    100% { transform: translateX(0); opacity: 1; clip-path: inset(0 0 0 0); }
}

.mq-text.mq-done::after {
    content: "▌";
    color: #ff3b6b;
    animation: blink 0.9s steps(1) infinite;
}

/* quote navigation - subtle, integrated */
.matrix-nav {
    display: flex;
    align-items: center;
    gap: 0.8rem;
}

.mat-btn {
    background: transparent;
    border: none;
    color: #ff6b86;
    padding: 0.25rem 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.72rem;
    letter-spacing: 1px;
    text-transform: uppercase;
    cursor: pointer;
    transition: color 0.2s ease, text-shadow 0.2s ease;
}

.mat-btn:hover {
    color: #ffb3c1;
    text-shadow: 0 0 10px rgba(255, 59, 91, 0.8);
}

.matrix-count {
    font-size: 0.72rem;
    color: var(--text-dim);
    letter-spacing: 1px;
}

.content-after-matrix {
    opacity: 1;
    transform: translateY(0);
}

.hero h1 {
    position: relative;
    display: inline-block;
    font-size: 1.75rem;
    font-weight: bold;
    margin-bottom: 0.35rem;
    letter-spacing: 0.5px;
    text-shadow: 0 0 20px rgba(255, 59, 59, 0.3);
}

/* Glitch layers (invisible until hover) */
.hero h1::before,
.hero h1::after {
    content: attr(data-text);
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    pointer-events: none;
    opacity: 0;
}

.hero h1:hover::before {
    opacity: 0.75;
    color: var(--red-bright);
    clip-path: inset(0 0 55% 0);
    animation: glitch-a 0.35s steps(2) infinite;
}

.hero h1:hover::after {
    opacity: 0.75;
    color: #ff8787;
    clip-path: inset(55% 0 0 0);
    animation: glitch-b 0.35s steps(2) infinite;
}

@keyframes glitch-a {
    0%   { transform: translateX(-2px); }
    50%  { transform: translateX(2px); }
    100% { transform: translateX(-2px); }
}

@keyframes glitch-b {
    0%   { transform: translateX(2px); }
    50%  { transform: translateX(-3px); }
    100% { transform: translateX(2px); }
}

.tagline {
    color: var(--text-dim);
    font-size: 0.85rem;
}

/* Typing cursor */
[data-typing]::after {
    content: "▌";
    margin-left: 2px;
    color: var(--red);
    animation: blink 0.9s steps(1) infinite;
}

h1 {
    font-size: 1.3rem;
    margin-bottom: 1rem;
}

/* Page intro (from _index.md) */
.page-intro {
    margin-bottom: 2rem;
}

.page-intro p {
    font-size: 0.85rem;
    color: var(--text-dim);
    margin-bottom: 0.85rem;
}

.page-intro ul,
.page-intro ol {
    margin-left: 1.2rem;
    margin-bottom: 0.9rem;
    font-size: 0.85rem;
    color: var(--text-dim);
    list-style: none;
}

.page-intro ul li,
.page-intro ol li {
    margin-bottom: 0.15rem;
    padding-left: 0.3rem;
}

.page-intro ul li::before {
    content: ">";
    color: var(--red);
    margin-right: 0.4rem;
}

.page-intro li a {
    color: var(--red);
}

.page-intro li a:hover {
    color: var(--red-bright);
}

/* Section */
section h2 {
    font-size: 0.9rem;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 1.5px;
    font-weight: 600;
}

section h2::before {
    content: "# ";
    color: var(--red);
}

/* Section header + slider controls */
.section-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.2rem;
}

.section-head h2 {
    margin-bottom: 0;
}

.scroll-controls {
    display: flex;
    gap: 0.4rem;
}

.scroll-btn {
    background: var(--bg-card);
    color: var(--text-dim);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.2rem 0.6rem;
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 1rem;
    line-height: 1;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.scroll-btn:hover {
    border-color: var(--red-dim);
    color: var(--red);
}

/* Lazy-loaded comments */
.comments {
    margin-top: 2.5rem;
    padding-top: 1.5rem;
    border-top: 1px dashed var(--border);
}

.comments-actions {
    display: flex;
    gap: 0.7rem;
    flex-wrap: wrap;
}

.comments-toggle {
    background: none;
    border: none;
    color: var(--text);
    padding: 0.4rem 0.2rem;
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: 0.9rem;
    font-weight: bold;
    letter-spacing: 2px;
    transition: color 0.15s ease, text-shadow 0.15s ease;
}

.comments-toggle:hover {
    color: var(--red);
    text-shadow: 0 0 12px rgba(255, 59, 91, 0.5);
}

.comments-toggle .red {
    font-weight: bold;
}

/* Comments modal */
.comments-modal {
    position: fixed;
    inset: 0;
    z-index: 999;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.75);
    backdrop-filter: blur(3px);
    -webkit-backdrop-filter: blur(3px);
}

.comments-modal[hidden] {
    display: none;
}

.comments-modal-box {
    position: relative;
    width: min(680px, 95vw);
    max-height: 85vh;
    overflow-y: auto;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.6rem 2rem 2.5rem;
    box-shadow: 0 0 40px rgba(255, 59, 91, 0.18);
}

.comments-close {
    position: absolute;
    top: 0.3rem;
    right: 0.7rem;
    background: transparent;
    border: none;
    color: var(--text-dim);
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    transition: color 0.15s ease;
}

.comments-close:hover {
    color: var(--red);
}

/* giscus widget fits the modal */
.comments-modal-box .giscus {
    width: 100%;
}

.comments-modal-box iframe.giscus-frame {
    width: 100%;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 0 24px rgba(255, 59, 59, 0.12);
    background: var(--bg);
}

.comments-modal-box a {
    color: var(--red);
}

/* Horizontal scroll slider */
.recent-scroll {
    display: flex;
    gap: 0.7rem;
    overflow-x: auto;
    padding: 0.15rem 0.15rem 1rem;
    scroll-snap-type: x mandatory;
    scrollbar-width: thin;
    scrollbar-color: var(--red-dim) transparent;
}

.recent-scroll::-webkit-scrollbar {
    height: 5px;
}

.recent-scroll::-webkit-scrollbar-thumb {
    background: var(--red-dim);
    border-radius: 3px;
}

.recent-scroll::-webkit-scrollbar-track {
    background: transparent;
}

.recent-card {
    flex: 0 0 auto;
    scroll-snap-align: start;
    min-width: 210px;
    max-width: 300px;
    padding: 0.9rem 1.1rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

.recent-card:hover {
    border-color: var(--red-dim);
    transform: translateY(-2px);
    box-shadow: 0 4px 20px rgba(255, 59, 59, 0.1);
}

.recent-cat {
    font-size: 0.58rem;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--red);
    opacity: 0.8;
}

.recent-title {
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--text);
    line-height: 1.35;
}

.recent-date {
    font-size: 0.62rem;
    color: var(--text-dim);
}

.recent-desc {
    font-size: 0.72rem;
    color: var(--text-dim);
    opacity: 0.8;
    margin: 0;
    line-height: 1.4;
}

/* Items */
.item-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    margin-top: 1.4rem;
}

.item {
    padding: 0.85rem 1.1rem;
    border: 1px solid var(--border);
    background: var(--bg-card);
    border-radius: var(--radius);
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

.item:hover {
    border-color: var(--red-dim);
    transform: translateX(3px);
    box-shadow: 0 0 16px rgba(255, 59, 59, 0.08);
}

.item a {
    font-weight: 600;
    font-size: 0.9rem;
}

.item a::before {
    content: "> ";
    color: var(--red-dim);
    opacity: 0;
    transition: opacity 0.15s ease;
}

.item:hover a::before {
    opacity: 1;
}

.item .date {
    float: right;
    font-size: 0.7rem;
    color: var(--text-dim);
    padding-top: 0.25rem;
}

.item p {
    font-size: 0.78rem;
    margin-top: 0.25rem;
    color: var(--text-dim);
}

.item-desc {
    display: block;
    font-size: 0.78rem;
    color: var(--text-dim);
    opacity: 0.9;
    margin-top: 0.25rem;
    line-height: 1.45;
    max-width: 72%;
    padding-left: 1.1rem;
}

.item-snippet {
    display: none;
    font-size: 0.78rem;
    color: var(--text-dim);
    opacity: 0.85;
    margin-top: 0.3rem;
    line-height: 1.45;
}

/* List items with an auto-generated og cover thumbnail */
.item.has-thumb {
    display: flex;
    gap: 1.1rem;
    align-items: flex-start;
}

.item-thumb-link {
    flex: 0 0 150px;
}

.item-thumb {
    display: block;
    width: 150px;
    height: auto;
    aspect-ratio: 1200 / 630;
    border: 1px solid var(--border);
    border-radius: 4px;
    filter: saturate(0.85);
    transition: filter 0.2s ease, transform 0.2s ease;
}

.item-thumb-link:hover .item-thumb,
.item:hover .item-thumb {
    filter: saturate(1.2);
    transform: translateX(2px);
}

.item.has-thumb .item-body {
    flex: 1 1 auto;
    min-width: 0;
}

@media (max-width: 600px) {
    .item.has-thumb {
        gap: 0.8rem;
    }
    .item-thumb-link,
    .item-thumb {
        width: 96px;
        flex-basis: 96px;
    }
}

.empty {
    color: var(--text-dim);
    font-style: italic;
    font-size: 0.8rem;
}

/* Post */
.post-header {
    margin-bottom: 2rem;
    padding-bottom: 1.25rem;
    border-bottom: 1px solid var(--border);
}

.back {
    font-size: 0.75rem;
    color: var(--text-dim);
    display: inline-block;
    margin-bottom: 0.9rem;
}

.back:hover {
    color: var(--red);
}

.post-header h1 {
    font-size: 1.5rem;
    margin-bottom: 0.4rem;
}

.post-header .date {
    font-size: 0.7rem;
    color: var(--text-dim);
}

.post-header .date::before {
    content: "[ ";
    color: var(--red-dim);
}

.post-header .date::after {
    content: " ]";
    color: var(--red-dim);
}

/* Article content */
article h1,
article h2,
article h3 {
    margin-top: 1.4rem;
    margin-bottom: 0.5rem;
    color: var(--text);
}

article h1 { font-size: 1.7rem; font-weight: 800; margin-bottom: 0.7rem; }
article h2 { font-size: 1.3rem; font-weight: 700; }
article h3 { font-size: 1.1rem; font-weight: 700; }

article hr {
    border: none;
    border-top: 1px solid var(--red);
    margin: 2rem 0;
    opacity: 0.5;
}

article p {
    margin-bottom: 0.9rem;
    font-size: 0.85rem;
}

article ul, article ol {
    margin-left: 1.4rem;
    margin-bottom: 0.9rem;
    font-size: 0.85rem;
}

article li {
    margin-bottom: 0.25rem;
}

article code {
    background: var(--bg-card);
    padding: 0.15rem 0.4rem;
    border: 1px solid var(--border);
    border-radius: 5px;
    font-size: 0.8rem;
    color: var(--red);
}

/* Terminal window for code blocks */
article pre {
    position: relative;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 2.4rem 1rem 1rem;
    margin-bottom: 0.9rem;
    overflow-x: auto;
    font-size: 0.78rem;
    line-height: 1.6;
    box-shadow: inset 0 0 40px rgba(255, 59, 59, 0.04);
}

article pre::before {
    content: "/ sys $";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    padding: 0.45rem 1rem;
    border-bottom: 1px solid var(--border);
    background: var(--bg-secondary);
    color: var(--text-dim);
    font-size: 0.68rem;
    letter-spacing: 0.5px;
    border-radius: var(--radius) var(--radius) 0 0;
}

article pre code {
    background: none;
    border: none;
    border-radius: 0;
    padding: 0;
    color: var(--text);
}

article blockquote {
    border-left: 2px solid var(--red-dim);
    padding-left: 1rem;
    margin-bottom: 0.9rem;
    color: var(--text-dim);
    font-style: italic;
}

article strong {
    color: var(--text);
}

article a {
    border-bottom: 1px solid var(--red-dim);
}

/* Footer */
footer {
    text-align: center;
    padding: 1.5rem 0;
    border-top: 1px solid var(--border);
    font-size: 0.7rem;
    color: var(--text-dim);
}

footer .red {
    animation: blink 2.5s steps(1) infinite;
}



.feed-link {
    color: var(--text-dim);
    text-decoration: none;
    margin-left: 0.5rem;
    transition: color 0.2s;
}

.feed-link:hover {
    color: var(--red-bright);
}

/* ============ Haunt/guns.lol style bio-link home ============ */

/* Right-side dot navigation (one dot per section) */
.dot-nav {
    position: fixed;
    right: 1.2rem;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    padding: 0.4rem 0.25rem;
    width: fit-content;
    height: fit-content;
    z-index: 10000;
    pointer-events: none;
}

.dot {
    width: 10px;
    height: 10px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--text-dim);
    background: transparent;
    cursor: pointer;
    pointer-events: auto;
    transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}

.dot:hover {
    border-color: var(--red);
}

.dot.active {
    background: var(--red);
    border-color: var(--red);
    box-shadow: var(--glow);
    transform: scale(1.35);
}

/* One page per section, each filling a full viewport */
main.pages {
    display: block;
    padding: 0;
    max-width: none;
}

.page {
    min-height: 100vh;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4.5rem 1.25rem;
    scroll-margin-top: 0;
    scroll-snap-align: start;
    position: relative;
}

html {
    scroll-snap-type: y proximity;
}

.page-panel {
    width: 100%;
    max-width: 1080px;
}

/* Section titles */
.section-title {
    font-size: 1.05rem;
    color: var(--text);
    text-transform: uppercase;
    letter-spacing: 2px;
    font-weight: 600;
    margin-bottom: 1.4rem;
    text-align: left;
}

.section-intro {
    font-size: 0.82rem;
    color: var(--text-dim);
    margin: -0.6rem 0 1.2rem;
    text-align: left;
}

/* ---- Hero (no container, centered on open background) ---- */
.hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 0.6rem;
}

.hero-avatar {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    border: 2px solid var(--red-dim);
    box-shadow: var(--glow);
    margin-bottom: 0.4rem;
}

.hero-name {
    font-size: 2rem;
    color: var(--text);
    letter-spacing: 1px;
}

.hero-handle {
    font-size: 0.8rem;
    color: var(--text-dim);
}

.hero-status {
    color: var(--red);
}

.hero-quote {
    font-size: 0.85rem;
    color: var(--red);
    text-shadow: var(--glow);
}

/* Tiny "scroll below" hint at the bottom of the hero viewport */
.scroll-hint {
    position: absolute;
    bottom: 1.6rem;
    left: 50%;
    transform: translateX(-50%);
    font-size: 0.7rem;
    color: var(--text-dim);
    letter-spacing: 2px;
    text-transform: uppercase;
    animation: hint-bob 1.8s ease-in-out infinite;
}

@keyframes hint-bob {
    0%, 100% { transform: translate(-50%, 0); opacity: 0.6; }
    50%      { transform: translate(-50%, 6px); opacity: 1; }
}

/* Inline nav under the profile */
/* ---- Rich presence social cards (inside about) ---- */
.about-socials {
    display: flex;
    flex-wrap: wrap;
    gap: 0.8rem;
    margin-top: 1.2rem;
}

.presence-card {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    flex: 1 1 calc(50% - 0.4rem);
    padding: 0.9rem 1.1rem;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 12px;
    text-decoration: none;
    color: var(--text);
    transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

.presence-card:hover {
    color: var(--text);
    text-shadow: none;
    border-color: var(--red-dim);
    transform: translateY(-2px);
    box-shadow: var(--glow);
}

.presence-icon {
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    color: var(--red);
}

.presence-icon svg {
    width: 24px;
    height: 24px;
}

.presence-info {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
}

.presence-handle {
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.presence-status {
    font-size: 0.72rem;
    color: var(--text-dim);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.presence-arrow {
    color: var(--red-dim);
    font-size: 1rem;
    opacity: 0;
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.presence-card:hover .presence-arrow {
    opacity: 1;
    transform: translateX(3px);
}

/* ---- About me ---- */
.about-panel {
    width: 100%;
    max-width: 1080px;
    margin: 0 auto;
}

.about-desc {
    font-size: 0.85rem;
    color: var(--text);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.4rem;
}

.about-desc p {
    margin-bottom: 0.6rem;
}

.about-desc p:last-child {
    margin-bottom: 0;
}

.about-sysinfo {
    margin-top: 1rem;
}

/* Sysinfo (neofetch block) */
.sysinfo {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.2rem;
    font-size: 0.8rem;
    line-height: 1.8;
    color: var(--text-dim);
    overflow-x: auto;
}

.sysinfo-inner {
    margin-top: 0.5rem;
}

.sys-key {
    color: var(--red);
    font-weight: 600;
}

.sys-val {
    color: var(--text);
}

/* Skills (chips, no container) below socials */
.about-skills {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    margin-top: 1.2rem;
}

.skill-chip {
    font-size: 0.72rem;
    color: var(--text);
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.35rem 0.85rem;
    transition: border-color 0.15s ease, color 0.15s ease;
}

.skill-chip:hover {
    color: var(--red);
    border-color: var(--red-dim);
}

.skill-chip::before {
    content: ">";
    color: var(--red-dim);
    margin-right: 0.35rem;
}

/* ---- Projects / Games image cards ---- */
.bio-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1.1rem;
}

.bio-card-link {
    display: block;
    color: var(--text);
    text-decoration: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.bio-card-link:hover {
    color: var(--text);
    text-shadow: none;
    transform: translateY(-4px);
    box-shadow: 0 8px 24px rgba(255, 59, 59, 0.12);
}

.bio-card {
    display: flex;
    flex-direction: column;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    height: 100%;
}

.bio-card-img {
    width: 100%;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    display: block;
    border-bottom: 1px solid var(--border);
    background: var(--bg-secondary);
}

.bio-card-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.2rem;
    padding: 1rem 1.1rem 1.1rem;
    text-align: center;
}

.bio-card-title {
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--text);
}

.bio-card-title::before {
    content: ">";
    color: var(--red-dim);
    margin-right: 0.35rem;
}

.bio-card-desc {
    font-size: 0.75rem;
    color: var(--text-dim);
}

/* Games + projects: single floating horizontal row each */
.card-scroll {
    display: flex;
    align-items: stretch;
    gap: 1.1rem;
    overflow-x: auto;
    padding: 0.5rem 0.2rem 0.9rem;
    scroll-snap-type: x mandatory;
    scrollbar-width: thin;
    scrollbar-color: var(--red-dim) transparent;
}

.card-scroll::-webkit-scrollbar {
    height: 5px;
}

.card-scroll::-webkit-scrollbar-thumb {
    background: var(--red-dim);
    border-radius: 3px;
}

.card-scroll::-webkit-scrollbar-track {
    background: transparent;
}

.card-scroll .bio-card-link {
    flex: 0 0 230px;
    scroll-snap-align: start;
}

.card-scroll.project-scroll .bio-card-link {
    flex: 0 0 300px;
}

.card-scroll .bio-card {
    box-shadow: 0 0 14px rgba(255, 59, 59, 0.06);
}

@media (prefers-reduced-motion: reduce) {
    .card-scroll .bio-card {
        animation: none;
    }
}

/* Recent keeps the horizontal slider */
.section-head {
    justify-content: space-between;
    align-items: center;
    margin-bottom: 1.2rem;
}

.section-head .section-title {
    margin-bottom: 0;
}

/* Wiki tree (simple hierarchical view) */
.wiki-tree {
    margin-top: 1.5rem;
    font-size: 0.92rem;
}

.wiki-folder {
    margin: 0;
}

.wiki-folder-title {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.35rem 0.5rem;
    border-radius: 6px;
    cursor: pointer;
    color: var(--text);
    font-weight: 600;
    letter-spacing: 0.5px;
    user-select: none;
    transition: color 0.15s ease, background 0.15s ease;
}

.wiki-folder-title:hover {
    background: rgba(255, 59, 59, 0.08);
    color: var(--red-bright);
}

.wiki-folder-title .wiki-chevron {
    color: var(--red);
    font-size: 0.7rem;
    display: inline-block;
    transition: transform 0.2s ease;
    flex-shrink: 0;
}

.wiki-folder.open > .wiki-folder-title .wiki-chevron {
    transform: rotate(90deg);
}

/* Children container — CSS max-height accordion */
.wiki-children {
    margin-left: 1.15rem;
    padding-left: 0.9rem;
    border-left: 1px solid var(--border);
    display: block;
    max-height: 0;
    opacity: 0;
    overflow: hidden;
    transition: max-height 0.3s ease, opacity 0.25s ease;
}

.wiki-folder.open > .wiki-children {
    max-height: 500px;
    opacity: 1;
}

.wiki-note,
.wiki-dirfile {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.35rem 0.5rem;
    border-radius: 6px;
    flex-wrap: wrap;
}

.wiki-snippet {
    display: none;
    flex-basis: 100%;
    font-size: 0.78rem;
    color: var(--text-dim);
    opacity: 0.85;
    padding-left: 1.2rem;
    line-height: 1.45;
}

.wiki-note a,
.wiki-dirfile a {
    color: var(--text-dim);
    text-decoration: none;
    transition: color 0.15s ease, text-shadow 0.15s ease;
}

.wiki-note:hover a,
.wiki-dirfile:hover a {
    color: var(--text);
    text-shadow: 0 0 8px rgba(255, 59, 59, 0.35);
}

.wiki-note .wiki-chevron,
.wiki-dirfile .wiki-chevron {
    color: var(--red-dim);
    font-size: 0.7rem;
    flex-shrink: 0;
}

/* search highlight */
mark.search-hl {
    background: rgba(255, 59, 59, 0.2);
    color: var(--red-bright);
    border-radius: 2px;
    padding: 0 2px;
}

.wiki-note, .wiki-dirfile, .wiki-folder {
    transition: opacity 0.15s ease;
}

.wiki-note.search-match,
.wiki-dirfile.search-match {
    background: rgba(255, 59, 59, 0.06);
}

.wiki-note.search-match a,
.wiki-dirfile.search-match a {
    color: var(--red-bright);
    text-shadow: 0 0 8px rgba(255, 59, 59, 0.45);
}

/* Search box */
.search-box {
    margin: 1.2rem 0 0.4rem;
    max-width: 480px;
}

.search-box input {
    width: 100%;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.6rem 0.9rem;
    color: var(--text);
    font-family: var(--font-mono);
    font-size: 0.85rem;
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.search-box input:focus {
    border-color: var(--red);
    box-shadow: 0 0 0 1px rgba(255, 59, 59, 0.3), 0 0 14px rgba(255, 59, 59, 0.2);
}

.search-box input::placeholder {
    color: var(--text-dim);
}

.item-list-empty {
    margin-top: 1.2rem;
    color: var(--text-dim);
}

/* Wiki breadcrumb on note/folder pages */
.wiki-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    margin: 0.25rem 0 0.9rem;
    font-size: 0.68rem;
    color: var(--text-dim);
    opacity: 0.85;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--border);
}

.wiki-breadcrumb a {
    color: var(--text-dim);
    text-decoration: none;
    transition: color 0.15s ease, text-shadow 0.15s ease;
}

.wiki-breadcrumb a:hover {
    color: var(--red-bright);
    text-shadow: 0 0 8px rgba(255, 59, 59, 0.35);
}

.wiki-breadcrumb .wiki-crumb-current {
    color: var(--red-dim);
}

.wiki-breadcrumb .wiki-crumb-sep {
    color: var(--red-dim);
    opacity: 0.6;
}

/* Custom right-click context menu */
.context-menu {
    position: fixed;
    z-index: 100000;
    min-width: 180px;
    background: var(--bg-card);
    border: 1px solid var(--red-dim);
    box-shadow: 6px 6px 0 rgba(255, 59, 59, 0.1), 0 0 24px rgba(0, 0, 0, 0.6);
    padding: 0.35rem;
    user-select: none;
    cursor: default;
}
.context-menu .ctx-title {
    color: var(--text-dim);
    font-size: 0.65rem;
    letter-spacing: 1px;
    text-transform: uppercase;
    padding: 0.3rem 0.6rem 0.4rem;
}
.context-menu .ctx-item {
    display: block;
    color: var(--text);
    font-size: 0.8rem;
    padding: 0.35rem 0.6rem;
    text-decoration: none;
    white-space: nowrap;
    cursor: none;
    transition: background 0.1s ease, color 0.1s ease;
}
.context-menu .ctx-item:hover {
    background: var(--red-soft);
    color: var(--red);
}
.context-menu .ctx-sep {
    border-top: 1px solid var(--red-dim);
    margin: 0.3rem 0;
}

/* Custom glowing red dot cursor with sparkles */
body, a, button, input, textarea, select, .dot, .wiki-folder-title, [role="button"] {
    cursor: none;
}

.cursor-dot {
    position: fixed;
    left: 0;
    top: 0;
    width: 8px;
    height: 8px;
    margin: -4px 0 0 -4px;
    border-radius: 50%;
    background: var(--red-bright);
    box-shadow:
        0 0 8px var(--red-bright),
        0 0 16px var(--red),
        0 0 28px rgba(255, 59, 59, 0.6);
    pointer-events: none;
    z-index: 999999;
    transition: box-shadow 0.2s ease, background 0.2s ease;
}

.cursor-dot.hover {
    background: #ff4040;
    box-shadow:
        0 0 12px var(--red-bright),
        0 0 24px var(--red),
        0 0 40px rgba(255, 59, 59, 0.7),
        0 0 60px rgba(255, 59, 59, 0.3);
}

.cursor-spark {
    position: fixed;
    left: 0;
    top: 0;
    width: 4px;
    height: 4px;
    margin: -2px 0 0 -2px;
    border-radius: 50%;
    background: var(--red);
    box-shadow: 0 0 6px var(--red);
    pointer-events: none;
    z-index: 999998;
    animation: cursor-sparkle 0.55s ease-out forwards;
}

@keyframes cursor-sparkle {
    0% { opacity: 1; transform: translate(0, 0) scale(1); }
    100% {
        opacity: 0;
        transform: translate(var(--dx), var(--dy)) scale(0);
    }
}

@media (hover: none), (pointer: coarse) {
    body, a, button, input, textarea, select, .dot, .wiki-folder-title, [role="button"] {
        cursor: auto;
    }
    /* the control panel and the context menu keep the native cursor */
    .cursor-dot, .cursor-spark {
        display: none;
    }
    .cp-bar, .cp-btn, .cp-navbtn, .cp-panel, .cp-panel button, .cp-panel a,
    .cp-navmenu, .cp-navmenu a,
    .context-menu, .context-menu .ctx-item {
        cursor: auto;
    }
    /* sections are often taller than the viewport on touch devices —
       free-scroll instead of snapping away mid-section */
    html {
        scroll-snap-type: none;
    }
}

/* Responsive */
@media (max-width: 600px) {
    main,
    footer {
        padding-left: 1.1rem;
        padding-right: 1.1rem;
    }

    /* Both bar dropdowns span the viewport on a phone instead of leaving a
       sliver. Only the horizontal box changes: the base rules anchor the top
       already, and with width:auto there is no free space left for margin:auto
       to distribute (the nav menu's centring) or for right:0.9rem to hang off,
       so nothing needs a transform reset. max-height is not restated — the
       panel's own cap is the right one at any width.

       They stay cards on a phone: the border, the red top edge and the radius
       all survive, only the gutters tighten and the drop shadow is softened (a
       shadow on a full-width card just clips).

       The bar keeps the words "nav" and "control_panel" on a phone too: the
       1fr auto 1fr grid gives the brand whatever is left over, and it ellipsises
       on its own. Dropping the labels used to reduce the triggers to a bare "▾",
       which is exactly the discoverability problem the bar was rebuilt to fix. */
    .cp-panel {
        left: 0.6rem;
        right: 0.6rem;
        width: auto;
        top: 3.6rem;   /* unchanged: the bar is still 3.1rem */
        box-shadow: 0 14px 40px rgba(0, 0, 0, 0.6);
    }

    .cp-navmenu {
        left: 0.6rem;
        right: 0.6rem;
        width: auto;
    }

    .cp-btn,
    .cp-navbtn {
        padding: 0.25rem 0.5rem;
    }

    .item .date {
        float: none;
        display: block;
    }

    .page {
        padding: 3.5rem 1.1rem;
    }

    .dot-nav {
        display: none;
    }
}

/* ---- Terminal mode ---- */
.terminal-page {
    display: flex;
    justify-content: center;
    padding-top: 1.5rem;
}

.terminal {
    width: 100%;
    max-width: 1080px;
    background: transparent;
}

.terminal-head {
    padding-bottom: 1.25rem;
    border-bottom: 1px dashed var(--border);
    margin-bottom: 1.25rem;
}

.terminal-body {
    padding: 0 0.25rem 4rem;
    font-size: 0.9rem;
    line-height: 1.7;
    min-height: 40vh;
}

.term-line {
    white-space: pre-wrap;
    word-break: break-word;
}

.term-out {
    color: var(--text);
}

.term-dim,
.term-greeting,
.term-intro {
    color: var(--text-dim);
}

.term-intro {
    margin-top: 0.5rem;
}

.term-cmd {
    color: var(--red-bright);
    text-shadow: 0 0 8px rgba(255, 59, 59, 0.3);
}

.term-link {
    color: var(--accent, #4fd6ff);
    text-decoration: underline;
    word-break: break-all;
    cursor: pointer;
}

.term-link.term-copied {
    color: var(--red-bright);
}

.term-banner {
    color: var(--red);
    font-weight: 700;
    font-size: 1.15rem;
    letter-spacing: 1px;
    text-shadow: 0 0 18px rgba(255, 59, 59, 0.45);
}

.term-prompt {
    color: var(--red);
}

.term-in {
    color: var(--text);
}

.term-prompt-line {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    position: relative;
}

.terminal-input {
    width: 1ch;
    min-width: 1ch;
    background: transparent;
    border: none;
    outline: none;
    color: var(--text);
    font-family: var(--font-mono);
    font-size: 0.85rem;
    padding: 0;
    caret-color: var(--red);
}

.terminal-input:focus {
    outline: none;
}

/* ---- Copy button on code blocks ---- */
article pre .code-copybtn {
    position: absolute;
    top: 0.3rem;
    right: 0.6rem;
    z-index: 1;
    font-family: inherit;
    font-size: 0.62rem;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: var(--text-dim);
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: 5px;
    padding: 0.12rem 0.5rem;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s, box-shadow 0.15s;
}

article pre .code-copybtn:hover {
    color: var(--red-bright);
    border-color: var(--red-dim);
    box-shadow: var(--glow);
}

article pre .code-copybtn.copied {
    color: var(--red-bright);
    border-color: var(--red);
}

/* ---- 404 error page ---- */
.error-page {
    min-height: 60vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
    max-width: 900px;
    width: 100%;
    margin: 0 auto;
    padding: 3rem 0;
}

.error-code {
    font-size: clamp(3.5rem, 10vw, 7rem);
    line-height: 1;
    margin: 0;
    color: var(--red);
    text-shadow: 0 0 30px rgba(255, 59, 59, 0.5), 0 0 80px rgba(255, 59, 59, 0.3);
}

.error-code::after {
    content: "▊";
    margin-left: 1rem;
    animation: error-blink 1.1s steps(2, start) infinite;
}

@keyframes error-blink {
    to { visibility: hidden; }
}

.error-msg {
    font-size: 1.05rem;
    margin: 1rem 0 0;
    word-break: break-all;
}

.error-hint {
    color: var(--text-dim);
    font-size: 0.85rem;
    margin: 0.4rem 0 0;
}

.error-actions {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 1.6rem;
}

.error-link {
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 0.35rem 0.9rem;
    text-decoration: none;
    transition: border-color 0.15s, color 0.15s, box-shadow 0.15s;
}

.error-link:hover {
    color: var(--red-bright);
    border-color: var(--red-dim);
    box-shadow: var(--glow);
}

/* ---- 404 page: void_snake game window ---- */
.snake-window {
    max-width: 720px;
    width: 100%;
    margin-top: 1.6rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: #0a0a0a;
    box-shadow: inset 0 0 40px rgba(255, 59, 59, 0.05);
    overflow: hidden;
}

.snake-titlebar {
    display: flex;
    justify-content: space-between;
    background: #101010;
    border-bottom: 1px solid var(--border);
    padding: 0.4rem 0.9rem;
    font-size: 0.72rem;
    letter-spacing: 0.5px;
    color: var(--text-dim);
}

.snake-canvas-wrap {
    position: relative;
}

#snake {
    display: block;
    width: 100%;
    height: auto;
}

.snake-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    background: rgba(10, 10, 10, 0.55);
    text-align: center;
    padding: 1rem;
}

.snake-overlay-title {
    color: var(--red);
    font-size: 0.95rem;
    text-shadow: 0 0 12px rgba(255, 59, 59, 0.6);
}

.snake-keys {
    color: var(--text-dim);
    font-size: 0.72rem;
    letter-spacing: 1px;
}
