/* ==========================================================================
   stubot5000 — "Neon Sprawl"
   Neo-Tokyo street level. The site is a grid; every place I publish is a
   node on it, and the latest writing arrives as signal.

   Three type roles. A pixel face (DotGothic16) carries both the largest
   type and the smallest — hero, section titles, tags, readouts — because
   that is where signage energy lives. A signage grotesk (Zen Kaku Gothic
   New) does the mid-size legible work: article titles, card names,
   buttons. The system stack carries long-form prose, which no pixel face
   should ever be asked to do.

   Every colour in the file resolves from the :root block below. Nothing
   past it hardcodes a value, including the translucent washes, which use
   color-mix() against a token. Swap the tokens and the site re-themes.
   ========================================================================== */

@font-face {
    font-family: 'Zen Kaku Gothic New';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('/fonts/zenkaku-700.woff2') format('woff2');
}
@font-face {
    font-family: 'Zen Kaku Gothic New';
    font-style: normal;
    font-weight: 900;
    font-display: swap;
    src: url('/fonts/zenkaku-900.woff2') format('woff2');
}
/* Latin and kana ship as separate subsets so the JP glyphs never block Latin
   text. The kana file carries the full katakana and hiragana blocks, so new
   furniture can use any kana without re-subsetting. It carries no kanji, so
   new furniture must not use any. */
@font-face {
    font-family: 'DotGothic16';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/fonts/dotgothic-latin.woff2') format('woff2');
    unicode-range: U+0020-007E, U+00A0-00FF, U+2013-2026, U+2190-2199, U+25B2-25CF;
}
@font-face {
    font-family: 'DotGothic16';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/fonts/dotgothic-kana.woff2') format('woff2');
    unicode-range: U+3000-30FF, U+4E00-9FFF, U+FF00-FFEF;
}
:root {
    /* Palette — wet asphalt and neon tube.
       Every pairing here clears WCAG AA against --void or --panel. */
    --void:     #060309;
    --panel:    #140A1E;
    --panel-2:  #1D1030;
    --edge:     #322046;
    --sign:     #F4EEFF;
    --muted:    #A897C7;

    /* The three tubes. --accent is the site's own; nodes override
       --node-color per element from hugo.toml. */
    --magenta:  #FF2E88;
    --cyan:     #00F0FF;
    --lime:     #C6FF00;
    --accent:   var(--magenta);

    /* Type roles */
    --font-pixel: 'DotGothic16', 'Hiragino Kaku Gothic ProN', 'Yu Gothic', Meiryo, 'Noto Sans CJK JP', monospace;
    --font-sign: 'Zen Kaku Gothic New', 'Hiragino Kaku Gothic ProN', 'Yu Gothic', Meiryo, 'Noto Sans CJK JP', sans-serif;
    --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

    --container-w: 1080px;
    --container-narrow-w: 700px;
    --wide-w: 1800px;

    --radius: 3px;
    --radius-panel: 8px;

    /* Depth shadow behind panels that sit above the page (hero board, the
       consent notice) — separate from --void so it stays dark in both themes
       instead of vanishing when --void turns pale in light mode. */
    --shadow-ink: rgba(0, 0, 0, 0.6);

    color-scheme: dark;
}

/* --------------------------------------------------------------------------
   Light theme — same signage, daylight concrete instead of wet asphalt.
   The neon triad darkens here so it still reads as text and glow against a
   pale ground; decorative uses (borders, rings, trace lines) stay on the
   dark-tuned hex values below since those never carry text.
   -------------------------------------------------------------------------- */

[data-theme="light"] {
    color-scheme: light;
    --void:     #F3EFE7;
    --panel:    #FFFFFF;
    --panel-2:  #EEE7DB;
    --edge:     #DBD1C0;
    --sign:     #1C1420;
    --muted:    #6B6078;

    --magenta:  #C81760;
    --cyan:     #0089A6;
    --lime:     #5C8A00;

    --shadow-ink: rgba(40, 28, 15, 0.16);
}

/* Raw node colours are set inline per node from hugo.toml and tuned for glow
   on dark asphalt — darken them at the point they're used as text (not as a
   border or trace) so a bright node like DV's cyan (#00F0FF) still clears
   contrast on a white panel. */
[data-theme="light"] .node-ext,
[data-theme="light"] .sig-title:hover,
[data-theme="light"] .sig-status {
    color: color-mix(in srgb, var(--node-color, var(--accent)) 55%, var(--sign) 45%);
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
@media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
}
body {
    margin: 0;
    background: var(--void);
    color: var(--sign);
    font-family: var(--font-body);
    font-size: 18px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    transition: background-color 0.2s ease, color 0.2s ease;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
ul, ol { padding: 0; margin: 0; list-style: none; }
h1, h2, h3, h4, p, figure { margin: 0; }
button { font: inherit; cursor: pointer; }
::selection { background: var(--accent); color: var(--void); }

:focus-visible {
    outline: 2px solid var(--cyan);
    outline-offset: 2px;
    border-radius: 2px;
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--accent);
    color: var(--void);
    padding: 0.75rem 1.25rem;
    z-index: 1000;
    font-weight: 700;
    border-radius: var(--radius);
}
.skip-link:focus { left: 1rem; top: 1rem; }

.sr-only {
    position: absolute; width: 1px; height: 1px;
    padding: 0; margin: -1px; overflow: hidden;
    clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

.container { max-width: var(--container-w); margin: 0 auto; padding: 0 1.5rem; }
.container-narrow { max-width: var(--container-narrow-w); margin: 0 auto; padding: 0 1.5rem; }

/* Scroll-reveal — see scripts.js. baseof.html ships a <noscript> override
   so this never leaves content invisible when JS is disabled. */
[data-observe] { opacity: 0; transform: translateY(16px); transition: opacity 0.5s ease, transform 0.5s ease; }
[data-observe].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
    [data-observe] { opacity: 1; transform: none; transition: none; }
}

/* --------------------------------------------------------------------------
   Screens

   CRT texture is reserved for the two elements that are diegetically screens:
   the hero board and the signal feed. Applying it site-wide would lay
   scanlines over the photography, which is the one place on the site that
   must stay clean.
   -------------------------------------------------------------------------- */

.screen { position: relative; }
.screen::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 2;
    border-radius: inherit;
    background: repeating-linear-gradient(
        180deg,
        color-mix(in srgb, var(--sign) 4%, transparent) 0 1px,
        transparent 1px 3px);
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.7rem 1.4rem;
    font-family: var(--font-pixel);
    font-size: 0.95rem;
    letter-spacing: 0.05em;
    border-radius: var(--radius);
    border: 1px solid transparent;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.btn-primary {
    background: var(--accent);
    color: var(--void);
    box-shadow: 0 0 16px -2px color-mix(in srgb, var(--accent) 60%, transparent);
}
.btn-primary:hover {
    background: var(--cyan);
    box-shadow: 0 0 20px -2px color-mix(in srgb, var(--cyan) 65%, transparent);
}
.btn-secondary { background: transparent; color: var(--sign); border-color: var(--edge); }
.btn-secondary:hover {
    border-color: var(--cyan);
    color: var(--cyan);
    box-shadow: 0 0 14px -4px color-mix(in srgb, var(--cyan) 55%, transparent);
}

/* --------------------------------------------------------------------------
   Node tag — the grid's route mark. The ring takes the node colour via
   --node-color; the code stays sign-white. Used in the nav, the directory
   and the signal feed.
   -------------------------------------------------------------------------- */

.node-tag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    border: 2px solid var(--node-color, var(--accent));
    border-radius: var(--radius);
    font-family: var(--font-pixel);
    font-size: 0.8rem;
    letter-spacing: 0.03em;
    color: var(--sign);
    background: var(--void);
    box-shadow:
        0 0 10px -2px color-mix(in srgb, var(--node-color, var(--accent)) 70%, transparent),
        inset 0 0 10px -4px color-mix(in srgb, var(--node-color, var(--accent)) 60%, transparent);
}
.node-tag--sm { width: 28px; height: 28px; font-size: 0.65rem; }
.node-tag--nav { width: 30px; height: 30px; font-size: 0.7rem; }

/* --------------------------------------------------------------------------
   Navigation
   -------------------------------------------------------------------------- */

.nav {
    position: sticky;
    top: 0;
    z-index: 100;
    background: color-mix(in srgb, var(--void) 88%, transparent);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--edge);
}
.nav-container {
    max-width: var(--container-w);
    margin: 0 auto;
    padding: 0.8rem 1.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}
.nav-logo {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-family: var(--font-sign);
    font-weight: 700;
    font-size: 1.05rem;
}
.nav-links { display: flex; align-items: center; gap: 1.6rem; }
.nav-links a {
    font-family: var(--font-pixel);
    font-size: 0.95rem;
    letter-spacing: 0.06em;
    color: var(--muted);
    padding: 0.2rem 0;
    border-bottom: 2px solid transparent;
    transition: color 0.15s ease, border-color 0.15s ease, text-shadow 0.15s ease;
}
.nav-links a:hover {
    color: var(--cyan);
    border-color: var(--cyan);
    text-shadow: 0 0 12px color-mix(in srgb, var(--cyan) 70%, transparent);
}
.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    color: var(--muted);
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    transition: color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.theme-toggle:hover {
    color: var(--cyan);
    border-color: var(--cyan);
    box-shadow: 0 0 14px -4px color-mix(in srgb, var(--cyan) 70%, transparent);
}
/* Default (dark): show the sun as the affordance to switch to light. */
.theme-toggle .icon-moon { display: none; }
.theme-toggle .icon-sun  { display: block; }
[data-theme="light"] .theme-toggle .icon-moon { display: block; }
[data-theme="light"] .theme-toggle .icon-sun  { display: none; }

.nav-mobile-toggle {
    display: none;
    background: none;
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    color: var(--sign);
    padding: 0.45rem 0.55rem;
    line-height: 0;
}
.nav-close-icon { display: none; }
.nav-links.nav--open ~ .nav-mobile-toggle .nav-hamburger-icon { display: none; }
.nav-links.nav--open ~ .nav-mobile-toggle .nav-close-icon { display: block; }

@media (max-width: 768px) {
    .nav-mobile-toggle { display: inline-flex; }
    .nav-links {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        background: var(--panel);
        border-bottom: 1px solid var(--edge);
        padding: 0.5rem 0;
    }
    .nav-links.nav--open { display: flex; }
    .nav-links a { padding: 0.85rem 1.5rem; border-bottom: none; }
    .nav-links a:hover { background: var(--panel-2); }
}

/* --------------------------------------------------------------------------
   Hero — the neon board
   -------------------------------------------------------------------------- */

.hero {
    position: relative;
    padding: clamp(4rem, 10vh, 7rem) 0 3.5rem;
    overflow: hidden;
    text-align: center;
}
/* Wet asphalt: two neon pools bleeding into the road, over a faint grid.
   No imagery, so it costs nothing to load. */
.hero::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        radial-gradient(680px 340px at 8% -10%, color-mix(in srgb, var(--magenta) 16%, transparent), transparent 70%),
        radial-gradient(680px 340px at 92% 110%, color-mix(in srgb, var(--cyan) 13%, transparent), transparent 70%),
        repeating-linear-gradient(90deg, color-mix(in srgb, var(--edge) 40%, transparent) 0 1px, transparent 1px 64px),
        repeating-linear-gradient(180deg, color-mix(in srgb, var(--edge) 40%, transparent) 0 1px, transparent 1px 64px);
}
.hero .container { position: relative; z-index: 1; }

.hero-board {
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius-panel);
    padding: clamp(2rem, 5vw, 3.5rem) clamp(1.25rem, 4vw, 3rem) 0;
    max-width: 820px;
    margin: 0 auto;
    box-shadow:
        0 24px 70px -30px var(--shadow-ink),
        0 0 40px -20px color-mix(in srgb, var(--magenta) 50%, transparent);
}
/* The tube. Layered text-shadow is what separates lit neon from coloured
   text: a tight core, a mid bloom, and a wide haze. */
.hero-title {
    font-family: var(--font-pixel);
    /* DotGothic16 sets katakana full-width, so this string is a fixed ~11.7em
       wide. The ceiling is what keeps it on one line inside the 820px board;
       past 3.8rem it wraps. */
    font-size: clamp(2rem, 6.2vw, 3.8rem);
    line-height: 1.2;
    letter-spacing: 0.06em;
    margin: 0 0 1.4rem;
    color: var(--sign);
    text-shadow:
        0 0 5px color-mix(in srgb, var(--magenta) 80%, transparent),
        0 0 20px color-mix(in srgb, var(--magenta) 50%, transparent),
        0 0 52px color-mix(in srgb, var(--magenta) 28%, transparent);
}
/* Flex, so the two name parts wrap as whole units and never mid-word.
   An inline-block pair plus <wbr> looks equivalent but is not: Chromium
   gives no break opportunity between two atomic inline boxes, so the name
   overflowed the board on a phone. Flex items wrap by definition.
   .sr-only is position:absolute, so it stays out of this flow. */
.hero-title {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
}

/* The spectrum bar: every live node's neon, side by side. */
.hero-spectrum {
    display: flex;
    gap: 4px;
    height: 5px;
}
.hero-spectrum span {
    flex: 1;
    background: var(--node-color, var(--edge));
    box-shadow: 0 0 10px -1px color-mix(in srgb, var(--node-color, var(--edge)) 80%, transparent);
}
.hero-adjacent {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    border-top: 1px solid var(--edge);
    margin-top: 1.4rem;
    padding: 0.9rem 0 1rem;
}
.hero-adj {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    color: var(--muted);
    transition: color 0.15s ease;
}
.hero-adj:hover { color: var(--cyan); }
.hero-adj-arrow { color: var(--accent); font-size: 0.8rem; }
.hero-adj:hover .hero-adj-arrow { color: var(--cyan); }
.hero-adj-body { display: flex; flex-direction: column; align-items: flex-start; text-align: left; }
.hero-adj--next .hero-adj-body { align-items: flex-end; text-align: right; }
.hero-adj-caption { font-family: var(--font-pixel); font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; }
.hero-adj-name { font-family: var(--font-sign); font-weight: 700; font-size: 1rem; line-height: 1.2; }
.hero-roles {
    font-family: var(--font-pixel);
    font-size: 0.9rem;
    letter-spacing: 0.08em;
    color: var(--muted);
}
@media (max-width: 640px) {
    .hero-adjacent { flex-wrap: wrap; }
    .hero-roles {
        order: 3;
        flex-basis: 100%;
        text-align: center;
        border-top: 1px solid var(--edge);
        margin-top: 0.35rem;
        padding-top: 0.9rem;
    }
}
.hero-description {
    max-width: 520px;
    margin: 2rem auto 0;
    color: var(--muted);
    font-size: 1.15rem;
    line-height: 1.6;
}
.hero-down {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 2rem;
    font-family: var(--font-pixel);
    font-size: 0.8rem;
    letter-spacing: 0.1em;
    color: var(--cyan);
    text-shadow: 0 0 14px color-mix(in srgb, var(--cyan) 55%, transparent);
}
.hero-down:hover { color: var(--sign); }

/* Power-on sequence: the board settles, the tube strikes once with a hard
   RGB split, then holds steady. It fires once and never loops, so it reads
   as neon coming on instead of a fault. */
@media (prefers-reduced-motion: no-preference) {
    .hero-board { animation: board-in 0.6s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
    .hero-title { animation: tube-strike 1.1s steps(1, end) both; animation-delay: 0.3s; }
    .hero-spectrum span {
        transform-origin: left center;
        animation: trace-draw 0.45s cubic-bezier(0.2, 0.7, 0.3, 1) both;
    }
    .hero-spectrum span:nth-child(1) { animation-delay: 0.90s; }
    .hero-spectrum span:nth-child(2) { animation-delay: 0.96s; }
    .hero-spectrum span:nth-child(3) { animation-delay: 1.02s; }
    .hero-spectrum span:nth-child(4) { animation-delay: 1.08s; }
    .hero-spectrum span:nth-child(5) { animation-delay: 1.14s; }
    .hero-spectrum span:nth-child(6) { animation-delay: 1.20s; }
    .hero-spectrum span:nth-child(7) { animation-delay: 1.26s; }
    .hero-spectrum span:nth-child(8) { animation-delay: 1.32s; }
    .hero-adjacent, .hero-description, .hero-down { animation: sign-in 0.5s ease both 1.3s; }
}
@keyframes board-in {
    from { opacity: 0; transform: translateY(18px); }
    to   { opacity: 1; transform: none; }
}
@keyframes sign-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes trace-draw {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
}
@keyframes tube-strike {
    0%   { opacity: 0; text-shadow: none; }
    14%  { opacity: 1; text-shadow: -3px 0 var(--cyan), 3px 0 var(--magenta); }
    22%  { opacity: 0.25; text-shadow: none; }
    36%  { opacity: 1; text-shadow: 2px 0 var(--magenta), -2px 0 var(--cyan); }
    46%  { opacity: 0.5; text-shadow: none; }
    58%  { opacity: 1; text-shadow: -1px 0 var(--cyan), 1px 0 var(--magenta); }
    100% {
        opacity: 1;
        text-shadow:
            0 0 5px color-mix(in srgb, var(--magenta) 80%, transparent),
            0 0 20px color-mix(in srgb, var(--magenta) 50%, transparent),
            0 0 52px color-mix(in srgb, var(--magenta) 28%, transparent);
    }
}

/* --------------------------------------------------------------------------
   Section furniture
   -------------------------------------------------------------------------- */

.hero + section { padding-top: 1rem; }
.home-section { padding: 4.5rem 0; }

.section-header { margin-bottom: 2.2rem; max-width: 640px; }
.section-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 0.55em;
    font-family: var(--font-pixel);
    font-size: 0.9rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--cyan);
    text-shadow: 0 0 14px color-mix(in srgb, var(--cyan) 45%, transparent);
}
.section-eyebrow [lang="ja"] { color: var(--muted); letter-spacing: 0.2em; text-shadow: none; }
.section-eyebrow::before {
    content: "";
    width: 14px;
    height: 2px;
    background: var(--cyan);
    box-shadow: 0 0 8px var(--cyan);
}
.section-title {
    font-family: var(--font-pixel);
    font-size: clamp(1.6rem, 4vw, 2.2rem);
    line-height: 1.25;
    letter-spacing: 0.02em;
    margin-top: 0.6rem;
}
.section-description { color: var(--muted); margin-top: 0.7rem; }

.page-hero { padding: 4rem 0 1rem; }
.page-title {
    font-family: var(--font-pixel);
    font-size: clamp(2rem, 5.5vw, 3rem);
    line-height: 1.2;
    letter-spacing: 0.02em;
    margin-top: 0.6rem;
    text-shadow:
        0 0 6px color-mix(in srgb, var(--magenta) 55%, transparent),
        0 0 26px color-mix(in srgb, var(--magenta) 30%, transparent);
}
.page-description { color: var(--muted); margin-top: 0.7rem; max-width: 620px; }
.page-back { margin-top: 3rem; }

/* --------------------------------------------------------------------------
   Nodes directory
   -------------------------------------------------------------------------- */

.nodes-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 1rem;
}
.node-card {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: 1rem;
    height: 100%;
    padding: 1.2rem 1.2rem 1.5rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius-panel);
    overflow: hidden;
    transition: border-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
}
a.node-card:hover, a.node-card:focus-visible {
    border-color: var(--node-color);
    transform: translateY(-2px);
    box-shadow: 0 0 26px -8px color-mix(in srgb, var(--node-color) 75%, transparent);
}
.node-body { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
.node-name {
    font-family: var(--font-sign);
    font-weight: 700;
    font-size: 1.05rem;
    line-height: 1.3;
}
.node-ext { color: var(--node-color, var(--accent)); font-size: 0.9em; }
.node-desc { color: var(--muted); font-size: 0.92rem; line-height: 1.5; }

/* The trace: each card's line runs along its foot and lights up on hover. */
.node-trace {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 3px;
    background: var(--node-color, var(--edge));
    box-shadow: 0 0 12px color-mix(in srgb, var(--node-color, var(--edge)) 80%, transparent);
    transform: scaleX(0.12);
    transform-origin: left center;
    transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1);
}
a.node-card:hover .node-trace, a.node-card:focus-visible .node-trace { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
    .node-card, .node-trace { transition: none; }
}

.node-card--planned { border-style: dashed; background: transparent; }
.node-card--planned .node-tag { border-style: dashed; color: var(--muted); box-shadow: none; }
.node-card--planned .node-name { color: var(--muted); }
.node-trace--dashed {
    background: repeating-linear-gradient(90deg,
        var(--node-color) 0 10px, transparent 10px 18px);
    box-shadow: none;
    transform: scaleX(1);
    opacity: 0.45;
}
.node-chip {
    display: inline-block;
    vertical-align: 0.15em;
    margin-left: 0.4em;
    padding: 0.1em 0.5em;
    font-family: var(--font-pixel);
    font-size: 0.7rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--muted);
    border: 1px dashed var(--edge);
    border-radius: 99px;
}

/* --------------------------------------------------------------------------
   Signal feed
   -------------------------------------------------------------------------- */

.sig-board {
    display: flex;
    flex-direction: column;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius-panel);
    overflow: hidden;
    font-family: var(--font-pixel);
}
/* Each .sig-rows list keeps its own <ul data-feed-url> for independent
   client-side refresh, but display:contents lifts its <li> rows into the
   .sig-board flex flow so the inline "order" (set per-row in index.html
   from a merged, date-sorted list) can interleave rows across sources. */
.sig-rows { display: contents; }
.sig-head, .sig-row {
    display: grid;
    grid-template-columns: 72px minmax(0, 1fr) 44px 130px;
    gap: 1rem;
    align-items: center;
    padding: 0.8rem 1.25rem;
}
.sig-head {
    order: -1;
    font-size: 0.65rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--muted);
    background: var(--panel-2);
    border-bottom: 1px solid var(--edge);
}
.sig-row { border-top: 1px solid var(--edge); }
.sig-time { font-size: 0.8rem; color: var(--muted); letter-spacing: 0.06em; white-space: nowrap; }
.sig-title {
    font-size: 0.95rem;
    line-height: 1.45;
    color: var(--sign);
    overflow-wrap: anywhere;
    transition: color 0.15s ease, text-shadow 0.15s ease;
}
.sig-title:hover {
    color: var(--node-color, var(--accent));
    text-shadow: 0 0 14px color-mix(in srgb, var(--node-color, var(--accent)) 60%, transparent);
}
.sig-row .node-tag--sm { justify-self: center; }
.sig-status {
    font-size: 0.7rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--node-color, var(--accent));
}

/* "LIVE" marks the newest post, keyed to DOM position rather than the
   sorted order, so it survives client-side feed refresh re-rendering the
   list's rows. */
.sig-rows--wl .sig-row:first-child .sig-status::before { content: "\25CF Live"; }
@media (prefers-reduced-motion: no-preference) {
    .sig-rows--wl .sig-row:first-child .sig-status::before { animation: live-pulse 2s ease-in-out infinite; }
}
@keyframes live-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.4; }
}

/* Rows acquire top-to-bottom once the section scrolls into view. Rows are
   visible by default — no JS, no reveal, no hidden content. */
@media (prefers-reduced-motion: no-preference) {
    .signal-section.is-visible .sig-row {
        animation: sig-acquire 0.4s ease backwards;
        /* --sig-order is the row's rank in the merged, date-sorted list
           (set inline in index.html), so the board fills in the same
           newest-first order the rows are displayed in. */
        animation-delay: calc(var(--sig-order, 1) * 0.12s);
    }
}
@keyframes sig-acquire {
    from { opacity: 0; transform: translateX(-6px); }
    to   { opacity: 1; transform: none; }
}

.sig-sources {
    margin-top: 1.2rem;
    font-family: var(--font-pixel);
    font-size: 0.85rem;
    letter-spacing: 0.05em;
    color: var(--muted);
}
.sig-sources a { color: var(--cyan); }
.sig-sources a:hover { color: var(--sign); text-shadow: 0 0 12px color-mix(in srgb, var(--cyan) 60%, transparent); }

@media (max-width: 640px) {
    .sig-head, .sig-row { grid-template-columns: 56px minmax(0, 1fr) 34px; gap: 0.75rem; padding: 0.75rem 1rem; }
    .sig-h-status, .sig-status { display: none; }
}

/* --------------------------------------------------------------------------
   Operator
   -------------------------------------------------------------------------- */

.about-lead {
    font-family: var(--font-sign);
    font-weight: 700;
    font-size: clamp(1.2rem, 2.6vw, 1.45rem);
    line-height: 1.6;
    max-width: 720px;
}
.about-chips {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
    gap: 0.9rem;
    margin-top: 2rem;
}
.about-chip {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 1rem 1.1rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius-panel);
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.about-chip:hover {
    border-color: var(--cyan);
    box-shadow: 0 0 22px -10px color-mix(in srgb, var(--cyan) 70%, transparent);
}
.about-chip svg {
    color: var(--cyan);
    filter: drop-shadow(0 0 6px color-mix(in srgb, var(--cyan) 55%, transparent));
}
.about-chip-name { font-family: var(--font-sign); font-weight: 700; font-size: 1.08rem; margin-top: 0.25rem; }
.about-chip-sub { font-family: var(--font-pixel); font-size: 0.75rem; letter-spacing: 0.06em; color: var(--muted); }
.about-more { margin-top: 2.2rem; }

/* --------------------------------------------------------------------------
   Photography gallery

   The one section with no neon on the artwork itself. Glow lives on the
   frame and the overlay, never over the photograph.
   -------------------------------------------------------------------------- */

.gallery-intro { color: var(--muted); max-width: 640px; margin-bottom: 2.2rem; }
.gallery-intro > * + * { margin-top: 1em; }
.gallery-empty { color: var(--muted); font-family: var(--font-pixel); font-size: 0.9rem; letter-spacing: 0.04em; }

/* The mosaic breaks out well past the site's normal 1080px column — the
   gallery is the one place on the site meant to fill the screen. The page
   title/intro/back-link stay in the standard .container so their left edge
   lines up with the nav logo above them; only the grid itself breaks out. */
.gallery-wide { max-width: var(--wide-w); margin: 2.2rem auto 0; padding: 0 1.5rem; }

/* Past 1800px the grid was capped and floating in a sea of margin on
   ultrawide monitors. Let it keep growing, and add two more columns so
   individual tiles don't stretch into odd proportions as it does. */
@media (min-width: 2100px) {
    :root { --wide-w: min(94vw, 2800px); }
    .gallery-grid { grid-template-columns: repeat(8, 1fr); }
}

.gallery-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    grid-auto-rows: clamp(90px, 11vw, 170px);
    grid-auto-flow: dense;
    gap: 0.6rem;
}
.gallery-item {
    grid-column: span 2;
    grid-row: span 1;
    min-height: 0;
}
.gallery-item:nth-child(6n+2) { transition-delay: 0.06s; }
.gallery-item:nth-child(6n+3) { transition-delay: 0.12s; }
.gallery-item:nth-child(6n+4) { transition-delay: 0.18s; }
.gallery-item:nth-child(6n+5) { transition-delay: 0.24s; }
.gallery-item.gi-big { grid-column: span 4; grid-row: span 2; }
.gallery-item.gi-tall { grid-column: span 2; grid-row: span 2; }
.gallery-item.gi-small { grid-column: span 2; grid-row: span 1; }
.gallery-item.gi-portrait { grid-column: span 2; grid-row: span 4; }

.gallery-thumb {
    position: relative;
    display: block;
    width: 100%;
    height: 100%;
    padding: 0;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius-panel);
    overflow: hidden;
    cursor: zoom-in;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.gallery-thumb img {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    transition: transform 0.4s ease;
}
.gallery-thumb:hover, .gallery-thumb:focus-visible {
    border-color: var(--cyan);
    box-shadow: 0 0 24px -8px color-mix(in srgb, var(--cyan) 75%, transparent);
}
.gallery-thumb:hover img, .gallery-thumb:focus-visible img { transform: scale(1.06); }

.gallery-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: flex-end;
    padding: 1rem;
    background: linear-gradient(180deg,
        transparent 55%,
        color-mix(in srgb, var(--void) 88%, transparent) 100%);
    opacity: 0;
    transition: opacity 0.25s ease;
}
.gallery-thumb:hover .gallery-overlay, .gallery-thumb:focus-visible .gallery-overlay { opacity: 1; }
.gallery-overlay-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    margin-right: 0.6rem;
    flex-shrink: 0;
    border: 1px solid var(--cyan);
    border-radius: 50%;
    color: var(--cyan);
    font-size: 1rem;
    line-height: 1;
    box-shadow: 0 0 12px -3px var(--cyan);
}
.gallery-overlay-text {
    font-family: var(--font-pixel);
    font-size: 0.8rem;
    letter-spacing: 0.03em;
    color: var(--sign);
    text-align: left;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

@media (prefers-reduced-motion: reduce) {
    .gallery-thumb, .gallery-thumb img, .gallery-overlay { transition: none; }
}

/* Lightbox — a native <dialog>, centred and sized by hand rather than relying
   on the browser's default UA centring, which varies across engines. */
dialog.lightbox {
    position: fixed;
    inset: 0;
    margin: auto;
    max-width: 100vw;
    max-height: 100vh;
    width: 100%;
    height: 100%;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--sign);
}
dialog.lightbox[open] { display: flex; align-items: center; justify-content: center; }
dialog.lightbox::backdrop { background: color-mix(in srgb, #060309 95%, transparent); }
.lightbox-figure {
    margin: 0;
    max-width: 92vw;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.7rem;
}
.lightbox-img { max-width: 92vw; max-height: 78vh; width: auto; height: auto; border-radius: var(--radius); }
.lightbox-caption { font-family: var(--font-pixel); font-size: 0.85rem; color: var(--muted); text-align: center; }
.lightbox-caption:empty { display: none; }
.lightbox-count { font-family: var(--font-pixel); font-size: 0.75rem; letter-spacing: 0.08em; color: var(--muted); text-align: center; margin: 0; }
.lightbox-close, .lightbox-prev, .lightbox-next {
    position: fixed;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    color: var(--sign);
    line-height: 1;
    transition: color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.lightbox-close:hover, .lightbox-prev:hover, .lightbox-next:hover {
    color: var(--cyan);
    border-color: var(--cyan);
    box-shadow: 0 0 16px -4px color-mix(in srgb, var(--cyan) 70%, transparent);
}
.lightbox-close { top: 1.2rem; right: 1.2rem; width: 44px; height: 44px; font-size: 1.6rem; }
.lightbox-prev, .lightbox-next { top: 50%; transform: translateY(-50%); width: 48px; height: 48px; font-size: 1.7rem; }
.lightbox-prev { left: 1.2rem; }
.lightbox-next { right: 1.2rem; }
@media (max-width: 900px) {
    .gallery-grid { grid-template-columns: repeat(4, 1fr); }
    .gallery-item.gi-big { grid-column: span 4; grid-row: span 2; }
    .gallery-item.gi-tall, .gallery-item.gi-small { grid-column: span 2; grid-row: span 1; }
    .gallery-item.gi-portrait { grid-column: span 1; grid-row: span 3; }
}
@media (max-width: 640px) {
    .gallery-wide { padding: 0 1rem; }
    .gallery-grid { grid-template-columns: repeat(2, 1fr); grid-auto-rows: clamp(150px, 42vw, 220px); gap: 0.5rem; }
    .gallery-item, .gallery-item.gi-big, .gallery-item.gi-tall, .gallery-item.gi-small { grid-column: span 1; grid-row: span 1; }
    .gallery-item.gi-portrait { grid-column: span 1; grid-row: span 2; }
    .gallery-overlay {
        opacity: 1;
        padding: 0.7rem;
        background: linear-gradient(180deg,
            transparent 65%,
            color-mix(in srgb, var(--void) 88%, transparent) 100%);
    }
    .gallery-overlay-icon { display: none; }
    .lightbox-close { top: 0.7rem; right: 0.7rem; width: 38px; height: 38px; }
    .lightbox-prev, .lightbox-next { width: 40px; height: 40px; }
    .lightbox-prev { left: 0.7rem; }
    .lightbox-next { right: 0.7rem; }
}

/* --------------------------------------------------------------------------
   Breadcrumb, static pages
   -------------------------------------------------------------------------- */

.breadcrumb { display: flex; align-items: center; gap: 0.5rem; font-family: var(--font-pixel); font-size: 0.8rem; color: var(--muted); flex-wrap: wrap; }
.breadcrumb a:hover { color: var(--cyan); }
.breadcrumb-sep { color: var(--edge); }

.content-page { padding-bottom: 4.5rem; }

/* Generic long-form prose (currently: the About page body). Every child
   (p, li, blockquote, strong, em) inherits the family from here; only the
   headings below need their own rule, for weight and size. */
.prose { font-family: var(--font-body); font-size: 1.05rem; line-height: 1.7; }
.prose > * + * { margin-top: 1.1em; }
.prose h2, .prose h3 {
    font-family: var(--font-sign);
    font-weight: 700;
    line-height: 1.25;
    margin-top: 1.8em;
}
.prose h2 { font-size: 1.4rem; }
.prose h3 { font-size: 1.15rem; }
.prose a { color: var(--cyan); text-decoration: underline; text-underline-offset: 3px; }
.prose a:hover { color: var(--sign); text-shadow: 0 0 12px color-mix(in srgb, var(--cyan) 60%, transparent); }
.prose strong { color: var(--sign); }
.prose blockquote {
    margin: 1.4em 0;
    padding: 0.2em 0 0.2em 1.2em;
    border-left: 2px solid var(--accent);
    box-shadow: -2px 0 14px -6px var(--accent);
    color: var(--muted);
}
.prose ul, .prose ol { padding-left: 1.4em; }
.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }
.prose li + li { margin-top: 0.4em; }
.prose img, .prose figure { border-radius: var(--radius-panel); margin: 1.6em auto; }
.prose figcaption { font-size: 0.85rem; color: var(--muted); text-align: center; margin-top: 0.6em; }
.prose code {
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 0.88em;
    background: var(--panel-2);
    border: 1px solid var(--edge);
    border-radius: 4px;
    padding: 0.1em 0.35em;
}
.prose pre {
    background: var(--panel-2);
    border: 1px solid var(--edge);
    border-radius: var(--radius-panel);
    padding: 1.1rem 1.3rem;
    overflow-x: auto;
}
.prose pre code { background: none; border: none; padding: 0; }

.not-found { padding: 6rem 0; text-align: center; }
.not-found-code {
    font-family: var(--font-pixel);
    font-size: clamp(4rem, 14vw, 7rem);
    line-height: 1;
    color: var(--sign);
    text-shadow:
        0 0 6px color-mix(in srgb, var(--magenta) 80%, transparent),
        0 0 24px color-mix(in srgb, var(--magenta) 50%, transparent),
        0 0 60px color-mix(in srgb, var(--magenta) 25%, transparent);
}
.not-found-kana { font-family: var(--font-pixel); letter-spacing: 0.3em; color: var(--muted); margin-top: 1rem; }
.not-found-title { font-family: var(--font-pixel); font-size: clamp(1.5rem, 4.5vw, 2.1rem); letter-spacing: 0.02em; margin-top: 0.8rem; }
.not-found-text { color: var(--muted); max-width: 420px; margin: 0.8rem auto 2rem; }

.view-all { margin-top: 2.5rem; }

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

.footer { border-top: 1px solid var(--edge); background: var(--panel); margin-top: 3rem; }
.footer-inner { padding-top: 2.8rem; padding-bottom: 2rem; }
.footer-top { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap; }
.footer-tagline { font-family: var(--font-pixel); font-size: 0.95rem; letter-spacing: 0.04em; }
.footer-links { display: flex; gap: 1.3rem; flex-wrap: wrap; }
.footer-links a { font-family: var(--font-pixel); font-size: 0.8rem; letter-spacing: 0.06em; color: var(--muted); }
.footer-links a:hover { color: var(--cyan); }
.footer-social { display: flex; gap: 0.6rem; }
.footer-social-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    color: var(--muted);
    transition: color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.footer-social-link:hover {
    color: var(--cyan);
    border-color: var(--cyan);
    box-shadow: 0 0 14px -4px color-mix(in srgb, var(--cyan) 70%, transparent);
}
.footer-bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    border-top: 1px solid var(--edge);
    margin-top: 2rem;
    padding-top: 1.4rem;
}
.footer-text { color: var(--muted); font-size: 0.85rem; }
.footer-status {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-pixel);
    font-size: 0.78rem;
    letter-spacing: 0.1em;
    color: var(--muted);
}
.footer-status-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--lime);
    box-shadow: 0 0 8px var(--lime);
}
@media (prefers-reduced-motion: no-preference) {
    .footer-status-dot { animation: live-pulse 2.4s ease-in-out infinite; }
}

/* ---------------------------------------------------------------------------
   Analytics consent notice
   Only rendered when params.googleAnalytics is set. Sits bottom-right as a
   panel rather than a full-width bar, so it never covers the page content.
--------------------------------------------------------------------------- */

#sd-notice {
    position: fixed;
    bottom: 1.5rem;
    right: 1.5rem;
    z-index: 9999;
    max-width: 340px;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding: 1rem 1.125rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-top: 1px solid var(--cyan);
    border-radius: var(--radius-panel);
    box-shadow: 0 8px 32px var(--shadow-ink), 0 0 18px -8px var(--cyan);
}

.sd-notice-text {
    margin: 0;
    font-family: var(--font-body);
    font-size: 0.85rem;
    line-height: 1.55;
    color: var(--muted);
}

.sd-notice-actions { display: flex; gap: 0.5rem; }

.sd-notice-btn-accept,
.sd-notice-btn-reject {
    padding: 0.45rem 1rem;
    font-family: var(--font-pixel);
    font-size: 0.8rem;
    letter-spacing: 0.05em;
    border-radius: var(--radius);
    border: 1px solid transparent;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.sd-notice-btn-accept {
    background: var(--accent);
    color: var(--void);
    box-shadow: 0 0 16px -2px color-mix(in srgb, var(--accent) 60%, transparent);
}

.sd-notice-btn-accept:hover {
    background: var(--cyan);
    box-shadow: 0 0 20px -2px color-mix(in srgb, var(--cyan) 65%, transparent);
}

.sd-notice-btn-reject {
    background: transparent;
    color: var(--sign);
    border-color: var(--edge);
}

.sd-notice-btn-reject:hover {
    border-color: var(--cyan);
    color: var(--cyan);
}

/* Phones: span the width so the buttons stay comfortably tappable. */
@media (max-width: 560px) {
    #sd-notice {
        left: 1rem;
        right: 1rem;
        bottom: 1rem;
        max-width: none;
    }
}
