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

:root {
    --desktop-bg: #E8E7E3;
    --canvas-bg: #FFFFFF;
    --canvas-dot: #D4D4D4;
    --canvas-border: rgba(0,0,0,0.08);
    --canvas-radius: 14px;
    --sidebar-bg: #FAFAFA;
    --sidebar-border: rgba(0,0,0,0.06);
    --sidebar-active: rgba(0,0,0,0.05);
    --window-bg: #FFFFFF;
    --window-border: rgba(0,0,0,0.07);
    /* Layered shadow: hairline ring + contact + key + ambient.
       Hairline ring replaces 1px border on .window for sub-pixel fidelity on retina. */
    --window-shadow:
        0 0 0 0.5px rgba(0,0,0,0.06),
        0 1px 1px rgba(0,0,0,0.03),
        0 4px 12px -2px rgba(0,0,0,0.04),
        0 12px 28px -6px rgba(0,0,0,0.05);
    --window-shadow-active:
        0 0 0 0.5px rgba(0,0,0,0.08),
        0 2px 3px rgba(0,0,0,0.05),
        0 8px 20px -4px rgba(0,0,0,0.06),
        0 24px 48px -12px rgba(0,0,0,0.08);
    --title-bar: #FAFAFA;
    --title-text: #808080;
    --titlebar-highlight: rgba(255,255,255,0.6);
    --tl-inactive: #dcdcdc;
    --glass-window-fill: rgba(255,255,255,0.70);
    --glass-sidebar-fill: rgba(250,250,250,0.88);
    --social-fill: rgba(0,0,0,0.045);          /* glassy resting fill for social deck */
    --social-fill-hover: rgba(0,0,0,0.10);      /* more solid on hover */
    --win-radius: 28px;
    --shell-radius: 12px;
    --shell-width: 6px;
    --text-1: #1a1a1a;
    --text-2: #555;
    --text-3: #808080;
    --accent: #1a1a1a;
    --accent-soft: rgba(0,0,0,0.05);
    /* Type system (locked 2026-05-28). sans = Hanken everywhere; serif = Source
       Serif 4 for reading headlines; mono = Commit Mono TERMINAL-ONLY (+ ASCII art
       / tree connectors, where fixed-width is functional); display = Instrument
       Serif for the hero wordmark. */
    --font-sans: 'Satoshi', 'Hanken Grotesk', system-ui, -apple-system, sans-serif;
    --font-serif: 'Source Serif 4', Georgia, 'Times New Roman', serif;
    --font-mono: 'Commit Mono', ui-monospace, 'SF Mono', Menlo, monospace;
    --font-display: 'Instrument Serif', Georgia, serif;
    --overlay-bg: rgba(0,0,0,0.3);
    --cmd-bg: #FFFFFF;
    --file-hover: rgba(0,0,0,0.03);
    --terminal-bg: #1C1C1E;
    --terminal-text: #E5E5E5;
    --terminal-dim: #777;
    --terminal-accent: #4CAF50;
    --figma-red: #F24E1E;
    --figma-orange: #FF7262;
    --figma-violet: #A259FF;
    --figma-green: #0ACF83;
    --figma-blue: #1ABCFE;
    /* Debug: multiply workspace transition durations. Overridden via ?slow=N. */
    --ws-scale: 1;

    /* Motion vocabulary.
       entry: incoming things settle in (slide-in, fade-in, expand, focus).
       exit: outgoing things accelerate away (slide-out, fade-out, dismiss).
       spring: delight-only overshoot — use sparingly, never as a default.
       For everyday hover/state changes the generic `ease` keyword is the
       house default — don't tokenize it. */
    --ease-entry: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-exit: cubic-bezier(0.5, 0, 0.75, 0);
    --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

    --dur-fast: 120ms;
    --dur-base: 200ms;
    --dur-medium: 350ms;
    --dur-slow: 500ms;
    /* Mode-switch crossfade duration (light/dark/tim). Faster than --dur-slow
       so theme changes feel crisp rather than draggy. */
    --dur-mode: 260ms;
}

[data-mode="dark"] {
    --desktop-bg: #050505;
    --canvas-bg: #0E0E0E;
    --canvas-dot: #2A2A2A;
    --canvas-border: rgba(255,255,255,0.06);
    --sidebar-bg: #111;
    --sidebar-border: rgba(255,255,255,0.05);
    --sidebar-active: rgba(255,255,255,0.05);
    --window-bg: #181818;
    --window-border: rgba(255,255,255,0.06);
    --window-shadow:
        0 0 0 0.5px rgba(255,255,255,0.05),
        0 2px 4px rgba(0,0,0,0.3),
        0 8px 20px -4px rgba(0,0,0,0.35),
        0 20px 40px -8px rgba(0,0,0,0.3);
    --window-shadow-active:
        0 0 0 0.5px rgba(255,255,255,0.07),
        0 2px 4px rgba(0,0,0,0.4),
        0 12px 28px -4px rgba(0,0,0,0.45),
        0 32px 56px -12px rgba(0,0,0,0.4);
    --title-bar: #1A1A1A;
    --title-text: #808080;
    --titlebar-highlight: rgba(255,255,255,0.05);
    --tl-inactive: #565658;
    --glass-window-fill: rgba(24,24,24,0.68);
    --glass-sidebar-fill: rgba(17,17,17,0.72);
    --social-fill: rgba(255,255,255,0.06);
    --social-fill-hover: rgba(255,255,255,0.15);
    --text-1: #E8E8E8;
    --text-2: #AAA;
    --text-3: #808080;
    --accent: #E8E8E8;
    --accent-soft: rgba(255,255,255,0.06);
    --overlay-bg: rgba(0,0,0,0.55);
    --cmd-bg: #1C1C1C;
    --file-hover: rgba(255,255,255,0.04);
    --terminal-bg: #0C0C0C;
    --terminal-text: #E5E5E5;
}

html, body {
    height: 100%;
    overflow: hidden;
    font-family: var(--font-sans);
    background: var(--desktop-bg);
    color: var(--text-1);
    cursor: default;
    user-select: none;
    transition: background var(--dur-mode) ease, color var(--dur-mode) ease;
}

/* ============ DESKTOP VIDEO BG ============ */
.desktop-video {
    position: fixed;
    inset: 0;
    z-index: 0;
    overflow: hidden;
}
.desktop-video video {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ============ CANVAS FRAME ============ */
/* The canvas is an inset panel floating on the desktop */
.canvas-frame {
    position: fixed;
    inset: 24px;
    border-radius: var(--canvas-radius);
    overflow: hidden;
    display: flex;
    box-shadow:
        0 0 0 0.5px var(--canvas-border),
        0 2px 20px rgba(0,0,0,0.04);
    /* No box-shadow transition: the frame spans the full viewport, so animating
       its shadow on mode switch repaints a huge area and stutters. Hairline snaps
       under the bg crossfade. */
}

/* ============ SIDEBAR ============ */
.sidebar {
    width: 200px;
    flex-shrink: 0;
    background: var(--sidebar-bg);
    border-right: 1px solid var(--sidebar-border);
    display: flex;
    flex-direction: column;
    padding: 16px 0;
    z-index: 100;
    transition: background var(--dur-mode) ease, border-color var(--dur-mode) ease;
}
/* Sidebar content fades in, but the sidebar box is always visible */
.sidebar > * {
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.4s var(--ease-entry), transform 0.4s var(--ease-entry);
}
.sidebar.visible > * {
    opacity: 1;
    transform: none;
    transition: opacity 0.4s var(--ease-entry), transform 0.4s var(--ease-entry), background var(--dur-mode) ease;
}
.sidebar-section-label {
    font-family: var(--font-sans);
    font-size: 12px;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    padding: 12px 16px 6px;
}
.sidebar-nav { padding: 0 8px; flex: 1; overflow-y: auto; }
.tree { font-family: var(--font-sans); font-size: 15px; }
.tree-item {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 5px 8px;
    border-radius: 6px;
    color: var(--text-3);
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
    white-space: nowrap;
}
.tree-item:hover { color: var(--text-1); background: var(--file-hover); }
.tree-item.active { color: var(--text-1); background: var(--sidebar-active); }
/* Inline Heroicons — outline by default, solid on hover/active. The .ico wrapper
   stacks the two (line + fill) and crossfades. Bodies carry their own
   stroke/fill (currentColor), so color is driven by `color` here. */
.tree-item .ico {
    position: relative;
    width: 15px; height: 15px;
    flex-shrink: 0;
    display: inline-block;
    color: currentColor;
}
.tree-item .ico svg {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    transition: opacity 0.15s ease;
}
.tree-item .ico .ico-fill { opacity: 0; }
.tree-item:hover .ico .ico-line,
.tree-item.active .ico .ico-line { opacity: 0; }
.tree-item:hover .ico .ico-fill,
.tree-item.active .ico .ico-fill { opacity: 1; }
/* File leaves keep the green tint (both weights) */
.tree-item[data-target] .ico,
.tree-item[data-action="resume"] .ico { color: #4CAF50; }
.tree-branch {
    color: var(--text-3);
    font-family: var(--font-mono);   /* keep box-drawing connectors aligned */
    flex-shrink: 0;
    font-size: 14px;
    line-height: 1;
    width: 12px;
    text-align: center;
    opacity: 0.3;
}

/* Folder toggle */
.tree-folder {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 5px 8px;
    border-radius: 6px;
    color: var(--text-2);
    cursor: pointer;
    font-family: var(--font-sans);
    font-size: 15px;
    font-weight: 500;
    transition: color 0.15s, background 0.15s;
    position: relative;
}
.tree-folder:hover { color: var(--text-1); background: var(--file-hover); }

/* Folder icon — two stacked Heroicons (solid) that crossfade closed↔open, with
   a subtle lift on the open state to echo the old lid-lift animation. */
.folder-icon {
    width: 16px; height: 16px;
    position: relative;
    flex-shrink: 0;
    font-size: 16px;
}
.folder-icon svg {
    position: absolute;
    inset: 0;
    width: 100%; height: 100%;
    color: currentColor;
    transition: opacity 0.22s var(--ease-entry), transform 0.22s var(--ease-entry);
}
.folder-icon .fi-open-line,
.folder-icon .fi-open-fill { opacity: 0; transform: translateY(1px) scale(0.92); }
/* Hover (when not the open/current folder): animated OUTLINE open — not filled. */
.tree-folder:hover:not(.open):not(.active) .folder-icon .fi-closed { opacity: 0; }
.tree-folder:hover:not(.open):not(.active) .folder-icon .fi-open-line { opacity: 1; transform: none; }
/* Open / current workspace (clicked): SOLID open. */
.tree-folder.open .folder-icon .fi-closed,
.tree-folder.active .folder-icon .fi-closed { opacity: 0; }
.tree-folder.open .folder-icon .fi-open-fill,
.tree-folder.active .folder-icon .fi-open-fill { opacity: 1; transform: none; }

/* Children container — animated slide */
.tree-children {
    margin-left: 10px;
    overflow: hidden;
    max-height: 0;
    opacity: 0;
    transition: max-height 0.35s var(--ease-entry),
                opacity 0.25s ease,
                margin 0.25s ease;
    margin-top: 0;
    margin-bottom: 0;
}
.tree-children.expanded {
    max-height: 300px;
    opacity: 1;
    margin-top: 2px;
    margin-bottom: 4px;
}
.sidebar-footer {
    padding: 12px 16px 4px;
    display: flex; flex-direction: column; gap: 10px;
    margin-top: 8px;
    /* hairline dropped — it didn't span the pane and read as an artifact; the
       spacing separates the footer instead. */
}
/* Segmented control — "flat fill" (spike V3). A deeper neutral track with a
   solid, shadowless thumb: the selection reads by fill contrast, not elevation,
   which keeps it calm and avoids the washed-out white-on-near-white look. */
.mode-pills {
    position: relative;
    display: flex; gap: 0;
    background: rgba(0,0,0,0.07);
    border-radius: 999px; padding: 2px;
}
[data-mode="dark"] .mode-pills { background: rgba(255,255,255,0.08); }
[data-mode="tim"]  .mode-pills { background: rgba(255,255,255,0.12); }
/* The active background is a single sliding thumb. JS positions it under the
   active pill; it slides between segments with a touch of spring. */
.mode-pill-thumb {
    position: absolute; left: 0; top: 2px;
    height: calc(100% - 4px); width: 0;
    border-radius: 999px;
    background: var(--window-bg);
    box-shadow: none;             /* flat fill — no elevation */
    z-index: 0; pointer-events: none;
}
.mode-pills.thumb-ready .mode-pill-thumb {
    transition: transform 0.32s cubic-bezier(.34,1.25,.5,1), width 0.32s cubic-bezier(.34,1.25,.5,1);
}
[data-mode="dark"] .mode-pill-thumb { background: #2e2e30; }
.mode-pill {
    position: relative; z-index: 1;
    font-family: var(--font-sans);
    font-size: 12.5px; font-weight: 500;
    padding: 6px 0; flex: 1; text-align: center;
    border-radius: 999px; border: none;
    background: transparent; color: var(--text-2);
    cursor: pointer;
    transition: color 0.18s ease;
}
/* Sun / Moon / Mountain glyphs replace the Light/Dark/Tim labels. currentColor
   inherits the pill's active/resting color; fill variants read crisp at this size. */
.mode-pill svg, .mobile-mode-pill svg { display: block; width: 15px; height: 15px; margin: 0 auto; }
.mode-pill.active { color: var(--text-1); font-weight: 600; }
/* Active segment gets a touch more presence than the resting glyphs. */
.mode-pill.active svg { transform: scale(1.06); }
.mode-pill:hover:not(.active) { color: var(--text-1); }
/* Dark mode: the default --text-2 (#aaa) reads too light at rest — mute it. */
[data-mode="dark"] .mode-pill:not(.active) { color: #7c7c7c; }
[data-mode="dark"] .mode-pill:hover:not(.active) { color: var(--text-1); }
/* The "Tim" segment hints its identity on hover in dark mode → light green. */
[data-mode="dark"] .mode-pill[data-mode="tim"]:hover:not(.active) { color: #6fcf7a; }
.sidebar-hint {
    font-family: var(--font-sans);
    font-size: 10px;
    color: var(--text-2);
    padding: 0 16px 16px;
}

/* ============ CANVAS (inside frame) ============ */
.canvas {
    flex: 1;
    position: relative;
    background-color: var(--canvas-bg);
    background-image: radial-gradient(circle, var(--canvas-dot) 1.2px, transparent 1.2px);
    background-size: 24px 24px;
    overflow: hidden;
    transition: background-color var(--dur-mode) ease;
}
.canvas-inner {
    position: absolute;
    inset: 0;
    transform: translate(0px, 0px);
}
.canvas-inner.animating {
    transition: transform 0.5s var(--ease-entry);
}

/* ============ WINDOWS ============ */
.window {
    position: absolute;
    background: var(--window-bg);
    border-radius: var(--win-radius);
    /* Tahoe-style continuous corners (Chromium 139+; degrades to circular
       border-radius elsewhere). superellipse(1.7) ≈ Apple's continuous curve. */
    corner-shape: superellipse(1.7);
    box-shadow: var(--window-shadow);
    overflow: visible;
    opacity: 0;
    transform: scale(0.92) translateY(20px);
}
.window.visible {
    opacity: 1;
    transform: none;
    /* box-shadow intentionally NOT transitioned here: theme switches swap
       --window-shadow across every window at once, and animating a 4-layer
       shadow on ~8 windows simultaneously caused mode-switch stutter. Shadow
       snaps under the bg crossfade (imperceptible). Drag-lift keeps its own
       transition below. */
    transition: opacity 0.35s var(--ease-entry),
                transform 0.35s var(--ease-entry),
                background var(--dur-mode) ease;
}
.window.dragging {
    box-shadow: var(--window-shadow-active);
    transition: box-shadow var(--dur-fast) ease;
}

.window-titlebar {
    height: 40px;
    /* Unified chrome: titlebar shares the content surface — no separate bar
       color, no divider line. The inset top highlight stays (it's the window's
       lit top edge — the "white line" worth keeping, esp. in Tim mode). */
    background: var(--window-bg);
    display: flex;
    align-items: center;
    padding: 0 14px;
    cursor: grab;
    gap: 10px;
    border-radius: var(--win-radius) var(--win-radius) 0 0;
    corner-shape: inherit;
    box-shadow: inset 0 1px 0 var(--titlebar-highlight);
    transition: background var(--dur-mode) ease;
}
.window-titlebar:active { cursor: grabbing; }
.traffic-lights { display: flex; gap: 0; }
.traffic-light {
    width: 20px; height: 24px;
    border-radius: 50%;
    cursor: pointer;
    transition: opacity 0.15s, transform 0.15s;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Visual dot is the ::before, hit area is the full 24px element */
    background: transparent;
}
.traffic-light::before {
    content: '';
    width: 12px; height: 12px;
    border-radius: 50%;
    opacity: 1;
    /* macOS inactive pattern: gray by default, colorized on window hover. */
    background: var(--tl-inactive);
    transition: background 0.15s, transform 0.15s;
}
.traffic-light:hover::before { transform: scale(1.15); }
/* Colorize this window's lights when the cursor is anywhere over the window. */
.window:hover .tl-red::before    { background: #ec6765; }
.window:hover .tl-yellow::before { background: #f2ca44; }
.window:hover .tl-green::before  { background: #35c759; }
/* Non-expandable cards: the green (expand) light stays the inactive gray and
   does nothing — reads disabled instead of colorizing on hover. */
.window.no-expand:hover .tl-green::before { background: var(--tl-inactive); }
.window.no-expand .tl-green { cursor: default; }
/* Disabled green = truly inert: never show the "+" glyph, never scale on hover. */
.window.no-expand .tl-green svg { opacity: 0 !important; }
.window.no-expand .tl-green:hover::before { transform: none; }
/* The case-study overlay is the focused view — its lights stay colored. */
.cs-overlay .tl-red::before    { background: #ec6765; }
.cs-overlay .tl-yellow::before { background: #f2ca44; }
.cs-overlay .tl-green::before  { background: #35c759; }
/* Show icons on hover */
.traffic-light svg {
    position: absolute;
    width: 6px; height: 6px;
    stroke: rgba(0,0,0,0.5);
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
    opacity: 0;
    transition: opacity 0.1s;
    z-index: 1;
}
/* Glyphs (×, −, expand) reveal only when hovering the light cluster itself. */
.traffic-lights:hover .traffic-light svg { opacity: 1; }
/* Minimized window */
.window.collapsed .window-content {
    display: none;
}
.window.collapsed {
    height: auto !important;
}
.window-title {
    font-family: var(--font-sans);
    font-size: 13.5px;
    color: var(--title-text);
    flex: 1;
    min-width: 0;
    text-align: left;
    margin-left: 4px;
    margin-right: 50px;
    opacity: 0.7;
    overflow: hidden;
    white-space: nowrap;
    /* Right-only soft edge: solid from the left, fades where a long title
       overflows on the right — so short titles never clip and long ones trail
       off cleanly instead of hard-cutting. */
    -webkit-mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 16px), transparent 100%);
    mask-image: linear-gradient(90deg, #000 0, #000 calc(100% - 16px), transparent 100%);
}
.window-content {
    padding: 20px;
    overflow-y: auto;
    border-radius: 0 0 var(--win-radius) var(--win-radius);
    corner-shape: inherit;
}

/* Hero Window */
.hero-window { min-width: 0; }
.hero-greeting {
    font-family: var(--font-sans);
    font-size: 14px;
    color: var(--text-3);
    margin-bottom: 12px;
    letter-spacing: 0.04em;
}
.hero-name {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 84px;
    font-weight: 400;
    letter-spacing: -0.01em;
    line-height: 1.1;
    margin-bottom: 6px;
}
.hero-title {
    font-size: 17px;
    color: var(--text-2);
    font-weight: 500;
    margin-bottom: 20px;
}
.hero-bio {
    font-size: 18px;
    line-height: 1.6;
    color: var(--text-1);
    font-weight: 500;
    letter-spacing: -0.01em;
    margin-bottom: 20px;
}
.hero-meta {
    font-size: 15px;
    color: var(--text-3);
    line-height: 1.6;
}
.hero-meta a {
    color: var(--text-1);
    text-decoration: underline;
    text-decoration-color: var(--text-3);
    text-underline-offset: 2px;
}
.hero-cta-row { display: flex; gap: 10px; margin-top: 20px; }
.cta-btn {
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 600;
    padding: 9px 20px;
    border-radius: 9px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform var(--dur-fast) ease-out, box-shadow var(--dur-fast) ease;
    position: relative;
}
.cta-btn:hover { transform: translateY(-2px); }
.cta-primary:hover { box-shadow: 0 8px 20px rgba(0,0,0,0.28); }
.cta-secondary:hover { background: var(--accent-soft); box-shadow: 0 6px 16px rgba(0,0,0,0.10); }
.cta-btn:active {
    transform: scale(0.97);
}
.cta-primary {
    background: var(--accent);
    color: var(--canvas-bg);
    border-color: var(--accent);
}
.cta-secondary {
    background: transparent;
    color: var(--accent);
    border-color: var(--window-border);
}

/* Projects Window */
.projects-window { min-width: 0; }
.file-list { display: flex; flex-direction: column; gap: 6px; }
.file-row {
    display: flex;
    gap: 16px;
    padding: 16px 14px;
    border-radius: 8px;
    cursor: pointer;
    transition: background var(--dur-fast) ease;
    position: relative;
}
.file-row:hover { background: var(--file-hover); }
.file-row-header {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    width: 100%;
}
.file-icon {
    width: 16px; height: 16px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 2px;
}
.file-icon .ico { position: relative; width: 16px; height: 16px; display: inline-block; color: var(--text-3); }
.file-icon .ico svg { position: absolute; inset: 0; width: 100%; height: 100%; transition: opacity 0.15s ease; }
.file-icon .ico .ico-fill { opacity: 0; }
.file-row:hover .file-icon .ico .ico-line { opacity: 0; }
.file-row:hover .file-icon .ico .ico-fill { opacity: 1; }
/* Project favicon — hidden by default; the full projects viewer keeps the glyph. */
.file-fav { display: none; }
.file-fav img, .file-fav svg { width: 100%; height: 100%; object-fit: contain; display: block; }
/* Card/thumb mode (home preview, life rail): favicon replaces the glyph. */
.projects-window.ws-thumb .file-icon .ico { display: none; }
.projects-window.ws-thumb .file-icon { width: 20px; height: 20px; }
.projects-window.ws-thumb .file-icon .file-fav {
    display: flex; align-items: center; justify-content: center;
    width: 20px; height: 20px; flex: 0 0 20px;
    border-radius: 5px; corner-shape: superellipse(1.7);
    overflow: hidden; background: #fff; padding: 1.5px;
}
.file-name {
    font-size: 17px;
    font-weight: 600;
    color: var(--text-1);
    flex: 1;
    min-width: 0;
}
.file-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.file-hero {
    flex-shrink: 0;
    aspect-ratio: 22/9;
    height: 117px;
    border-radius: 2px;
    overflow: hidden;
    background: #3e3e3e;
}
.file-hero-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
}
.file-hero-placeholder span {
    font-family: var(--font-sans);
    font-size: 10px;
    letter-spacing: 0.08em;
    color: #808080;
}
.file-hero img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top;
    display: block;
}
.file-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
}
.file-tag {
    font-family: var(--font-sans);
    font-size: 11.5px;
    padding: 2px 7px;
    border-radius: 5px;
    background: rgba(0,0,0,0.05);
    color: #636363;
    font-weight: 500;
}
.file-summary {
    font-size: 15.5px;
    line-height: 1.6;
    color: var(--text-3);
    flex: 1;
    min-height: 0;
}
.pw-overlay {
    position: fixed; inset: 0; z-index: 99998;
    background: rgba(0,0,0,0.5); backdrop-filter: blur(8px);
    display: flex; align-items: center; justify-content: center;
    opacity: 0; transition: opacity 0.2s; pointer-events: none;
}
.pw-overlay.open { opacity: 1; pointer-events: auto; }
.pw-box {
    background: var(--window-bg); border: 1px solid var(--window-border);
    border-radius: 12px; padding: 28px 32px; width: 340px;
    box-shadow: 0 16px 48px rgba(0,0,0,0.2);
    transform: scale(0.95); transition: transform 0.2s;
}
.pw-overlay.open .pw-box { transform: scale(1); }
.pw-title { font-size: 15px; font-weight: 600; color: var(--text-1); margin-bottom: 4px; }
.pw-subtitle { font-size: 12px; color: var(--text-3); margin-bottom: 16px; }
.pw-input {
    width: 100%; padding: 10px 12px; border-radius: 8px;
    border: 1px solid var(--window-border); background: var(--canvas-bg);
    font-family: var(--font-sans); font-size: 13px; color: var(--text-1);
    outline: none; box-sizing: border-box;
}
.pw-input:focus { border-color: var(--accent); }
.pw-input.error { border-color: #e74c3c; animation: pw-shake 0.3s; }
@keyframes pw-shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-6px)} 75%{transform:translateX(6px)} }
.pw-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }
.pw-btn {
    padding: 7px 16px; border-radius: 8px; font-size: 13px; font-weight: 500;
    cursor: pointer; border: 1px solid var(--window-border); background: var(--file-hover);
    color: var(--text-1); font-family: var(--font-sans);
}
.pw-btn-primary { background: var(--text-1); color: var(--canvas-bg); border-color: var(--text-1); }

/* Personal Window */
.personal-window { min-width: 0; }
.personal-window .window-content { padding: 6px 14px 10px; }
/* List windows: rows carry their own top padding, so the default 20px content
   top stacks into a big gap under the titlebar. Trim it. */
.projects-window .window-content,
.reviews-window .window-content { padding-top: 8px; }
.personal-item {
    display: flex;
    align-items: stretch;
    gap: 10px;
    padding: 8px 0;
    border-radius: 6px;
    transition: background var(--dur-fast) ease;
}
.personal-item:hover { background: var(--file-hover); margin: 0 -8px; padding: 8px 8px; }
.personal-item + .personal-item { border-top: 1px solid var(--window-border); }
.personal-item:hover + .personal-item,
.personal-item + .personal-item:hover { border-top-color: transparent; }
.personal-accent {
    width: 3px;
    align-self: stretch;
    border-radius: 2px;
    flex-shrink: 0;
    transition: width 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), align-self 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), border-radius 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.personal-item:hover .personal-accent {
    width: 48px;
    align-self: center;
    aspect-ratio: 16/9;
    border-radius: 0;
}
.personal-body { flex: 1; min-width: 0; }
.personal-label {
    font-size: 17px;
    font-weight: 600;
    color: var(--text-1);
    display: flex;
    align-items: center;
    gap: 6px;
}
.personal-label .external-arrow {
    opacity: 0;
    font-size: 10px;
    color: var(--text-3);
    transition: opacity 0.15s, transform 0.15s;
}
.personal-item:hover .external-arrow { opacity: 0.6; transform: translate(1px, -1px); }
.personal-sub {
    font-size: 15px;
    color: var(--text-3);
    margin-top: 2px;
    line-height: 1.45;
}

/* Terminal Window — a normal canvas card. It uses the default card surface
   (--window-bg) and the default --window-shadow, so it sits identically to
   every other card; only its content is a monospace prompt. */
.terminal-fixture .window-title {
    color: #4CAF50;
    font-size: 13px;
    font-weight: 500;
}
.terminal-fixture .window-content {
    max-height: 300px;
}
.terminal-window .window-titlebar {
    background: transparent;                    /* share the card's frosted glass */
    border-color: transparent;                 /* no divider between bar and body */
}
.terminal-window .traffic-light { opacity: 1; }
.terminal-window .window-title { display: none; }   /* drop the "terminal" label */
/* Terminal reads as a normal card (light surface), not a dark hacker panel —
   just a card whose content happens to be a monospace prompt. Text is
   theme-aware so it stays legible in light / dark / Tim. */
.terminal-window .window-content {
    background: transparent;                    /* share the card's frosted glass */
    font-family: var(--font-mono);
    font-size: 13px;
    line-height: 1.7;
    color: var(--text-1);
    padding: 18px 20px;
    max-height: 460px;
    border-radius: 0 0 var(--win-radius) var(--win-radius);
    cursor: text;          /* whole body reads as "click anywhere to type" */
}
.term-prompt { color: var(--terminal-accent); }   /* keep the green $ accent */
.term-cmd { color: var(--text-1); }
.term-dim { color: var(--text-2); }
.term-key {
    display: inline-block;
    background: var(--accent-soft);
    border: 1px solid var(--window-border);
    border-radius: 4px;
    padding: 0 5px;
    font-size: 11px;
    min-width: 20px;
    text-align: center;
    color: var(--text-2);
}
.term-label { color: var(--text-2); }
.term-section { margin-bottom: 12px; }
/* Commands shown as an aligned grid (not a ragged comma blob) for a balanced card. */
.term-cmd-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 5px 14px;
    margin-top: 6px;
}
.term-cmd-item { color: var(--text-2); }
.term-shortcut-row {
    display: flex;
    gap: 8px;
    align-items: center;
    margin: 3px 0;
}
/* Terminal fills its window height; the prompt sits at the bottom (output above,
   room between) like a real terminal — and keeps it as tall as the facsimile card. */
.terminal-window { display: flex; flex-direction: column; }
.terminal-window .window-content { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.term-input-line {
    display: flex;
    align-items: center;
    gap: 0;
    margin-top: auto;   /* push the prompt to the bottom of the terminal */
}
.term-input-field {
    background: transparent;
    border: none;
    outline: none;
    color: var(--text-1);
    font-family: var(--font-mono);
    font-size: 13px;
    flex: 1;
    margin-left: 8px;
    caret-color: var(--terminal-accent);
    line-height: 1.7;
}
.term-input-field::placeholder { color: var(--text-2); }


/* ============ COMMAND PALETTE ============ */
.cmd-overlay {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 2000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 20vh;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease-entry);
}
.cmd-overlay.open { opacity: 1; pointer-events: auto; }
.cmd-box {
    width: 520px;
    background: var(--cmd-bg);
    border: 1px solid var(--window-border);
    border-radius: 14px;
    box-shadow: 0 24px 80px rgba(0,0,0,0.15);
    overflow: hidden;
    transform: scale(0.96) translateY(-10px);
    transition: transform 0.2s var(--ease-entry);
}
.cmd-overlay.open .cmd-box { transform: scale(1) translateY(0); }
.cmd-input-row {
    display: flex;
    align-items: center;
    padding: 14px 18px;
    gap: 10px;
    border-bottom: 1px solid var(--window-border);
}
.cmd-slash {
    font-family: var(--font-sans);
    font-size: 16px;
    color: var(--text-3);
    font-weight: 500;
}
.cmd-input {
    flex: 1;
    border: none;
    outline: none;
    font-family: var(--font-sans);
    font-size: 15px;
    font-weight: 500;
    background: transparent;
    color: var(--text-1);
}
.cmd-input::placeholder { color: var(--text-3); }
.cmd-hint {
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--text-3);
    background: var(--accent-soft);
    padding: 3px 8px;
    border-radius: 5px;
}
.cmd-results { padding: 8px; max-height: 280px; overflow-y: auto; }
.cmd-result {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.1s;
}
.cmd-result:hover, .cmd-result.active { background: var(--accent-soft); }
.cmd-result-icon {
    width: 20px; height: 20px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-3);
}
/* Inline Heroicons — outline default, solid on hover/active row. */
.cmd-result-icon .ico { position: relative; width: 17px; height: 17px; display: inline-block; color: currentColor; }
.cmd-result-icon .ico svg { position: absolute; inset: 0; width: 100%; height: 100%; transition: opacity 0.12s ease; }
.cmd-result-icon .ico .ico-fill { opacity: 0; }
.cmd-result:hover .cmd-result-icon .ico .ico-line,
.cmd-result.active .cmd-result-icon .ico .ico-line { opacity: 0; }
.cmd-result:hover .cmd-result-icon .ico .ico-fill,
.cmd-result.active .cmd-result-icon .ico .ico-fill { opacity: 1; }
.cmd-result-text { flex: 1; }
.cmd-result-label { font-size: 14px; font-weight: 500; color: var(--text-1); }
.cmd-result-desc { font-size: 12px; color: var(--text-3); }
.cmd-result-key {
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--text-3);
    background: var(--file-hover);
    border: 1px solid var(--window-border);
    padding: 2px 6px;
    border-radius: 4px;
}
.toast {
    position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%) translateY(20px);
    background: var(--window-bg); color: var(--text-1); border: 1px solid var(--window-border);
    padding: 10px 20px; border-radius: 10px; font-size: 14px; font-family: var(--font-sans);
    z-index: 99999; opacity: 0; transition: opacity 0.3s, transform 0.3s;
    box-shadow: 0 8px 32px rgba(0,0,0,0.2); pointer-events: none;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ============ SHORTCUTS OVERLAY ============ */
.shortcuts-overlay {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease-entry);
}
.shortcuts-overlay.open { opacity: 1; pointer-events: auto; }
.shortcuts-box {
    background: var(--cmd-bg);
    border: 1px solid var(--window-border);
    border-radius: 14px;
    padding: 28px 36px;
    box-shadow: 0 24px 80px rgba(0,0,0,0.15);
    min-width: 340px;
    transform: scale(0.96);
    transition: transform 0.2s var(--ease-entry);
}
.shortcuts-overlay.open .shortcuts-box { transform: scale(1); }
.shortcuts-title {
    font-size: 16px;
    font-weight: 700;
    margin-bottom: 20px;
    color: var(--text-1);
}
.shortcut-group-label {
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-top: 16px;
    margin-bottom: 8px;
}
.shortcut-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 5px 0;
}
.shortcut-label { font-size: 13px; color: var(--text-2); }
.shortcut-keys { display: flex; gap: 4px; }
.sk {
    font-family: var(--font-sans);
    font-size: 11px;
    min-width: 24px;
    text-align: center;
    padding: 3px 7px;
    background: var(--file-hover);
    border: 1px solid var(--window-border);
    border-radius: 5px;
    color: var(--text-2);
}

/* ============ TIM MODE (light, hand-drawn) ============ */
[data-mode="tim"] {
    --desktop-bg: #E8EDE9;
    --canvas-bg: #F5F8F5;
    --canvas-dot: #C8D4CA;
    --canvas-border: rgba(76,130,80,0.12);
    --sidebar-bg: #1b4017;
    --sidebar-border: rgba(255,255,255,0.1);
    --sidebar-active: rgba(255,255,255,0.1);
    --accent: #2D5E30;
    --accent-soft: rgba(76,130,80,0.06);
    --window-bg: #FAFCFA;
    --window-border: rgba(76,130,80,0.1);
    --window-shadow:
        0 0 0 0.5px rgba(76,130,80,0.12),
        0 1px 1px rgba(0,40,0,0.04),
        0 4px 12px -2px rgba(0,40,0,0.05),
        0 12px 28px -6px rgba(0,40,0,0.06);
    --window-shadow-active:
        0 0 0 0.5px rgba(76,130,80,0.16),
        0 2px 3px rgba(0,40,0,0.06),
        0 8px 20px -4px rgba(0,40,0,0.08),
        0 24px 48px -12px rgba(0,40,0,0.1);
    --title-bar: #F0F4F0;
    --title-text: #6A9A6E;
    --titlebar-highlight: rgba(255,255,255,0.7);
    --tl-inactive: #cdd8cf;
    --glass-window-fill: rgba(250,252,250,0.68);
    --glass-sidebar-fill: rgba(27,64,23,0.78);
    --social-fill: rgba(255,255,255,0.10);
    --social-fill-hover: rgba(255,255,255,0.22);
    --text-1: #1A3A1C;
    --text-2: #3E6840;
    --text-3: #7AAA7E;
    --cmd-bg: #FAFCFA;
    --file-hover: rgba(76,130,80,0.05);
    --terminal-bg: #1A2E1C;
    --terminal-accent: #4CAF50;
}
[data-mode="tim"] .sidebar .sidebar-section-label { color: rgba(255,255,255,0.4); }
[data-mode="tim"] .sidebar .tree-item { color: rgba(255,255,255,0.55); }
[data-mode="tim"] .sidebar .tree-item:hover { color: #E8F0E8; background: rgba(255,255,255,0.08); }
[data-mode="tim"] .sidebar .tree-item.active { color: #FFFFFF; background: rgba(255,255,255,0.12); }
[data-mode="tim"] .sidebar .tree-folder { color: rgba(255,255,255,0.65); }
[data-mode="tim"] .sidebar .tree-folder:hover { color: #E8F0E8; background: rgba(255,255,255,0.08); }
[data-mode="tim"] .sidebar .tree-branch { color: rgba(255,255,255,0.2); }
[data-mode="tim"] .sidebar .sidebar-hint { color: rgba(255,255,255,0.35); }
[data-mode="tim"] .sidebar .sidebar-social { color: rgba(255,255,255,0.45); }
[data-mode="tim"] .sidebar .sidebar-social:hover { color: #E8F0E8; background: rgba(255,255,255,0.08); }
/* Deck cards are glassy/translucent over the dark-green sidebar in Tim mode →
   light glyph, brightening to white on hover. (Same specificity, later wins.) */
[data-mode="tim"] .social-deck .sidebar-social { color: rgba(255,255,255,0.62); }
[data-mode="tim"] .social-deck .sidebar-social:hover { color: #fff; background: var(--social-fill-hover); }
[data-mode="tim"] .sidebar .mode-pills { background: rgba(255,255,255,0.08); }
[data-mode="tim"] .sidebar .mode-pill { color: rgba(255,255,255,0.55); border: none; background: transparent; }
[data-mode="tim"] .sidebar .mode-pill.active { background: transparent; color: #FFFFFF; }
[data-mode="tim"] .sidebar .mode-pill:hover:not(.active) { color: #fff; }   /* beat the tim base color on hover */
[data-mode="tim"] .sidebar .mode-pill-thumb {
    background: rgba(255,255,255,0.22);
    box-shadow: none;
}
[data-mode="tim"] .sidebar .sidebar-cs-back { color: rgba(255,255,255,0.55); }
[data-mode="tim"] .sidebar .sidebar-cs-back:hover { color: #E8F0E8; background: rgba(255,255,255,0.08); }
[data-mode="tim"] .sidebar .sidebar-cs-title { color: #FFFFFF; }
[data-mode="tim"] .sidebar .sidebar-toc-item { color: rgba(255,255,255,0.55); }
[data-mode="tim"] .sidebar .sidebar-toc-item:hover { color: #E8F0E8; background: rgba(255,255,255,0.08); }
[data-mode="tim"] .sidebar .sidebar-toc-item.active { color: #FFFFFF; background: rgba(255,255,255,0.12); }
[data-mode="tim"] .file-summary { color: #808080; }
[data-mode="tim"] .file-icon .ico { color: #808080; }
[data-mode="tim"] .personal-sub { color: #808080; }
/* Tim sidebar: lift the flat dark-green with a soft diagonal sheen + a faint film
   grain so it reads as a textured surface, not a flat fill. Translucent so the
   frosted frame still contributes underneath. Static (no animation) = cheap. */
[data-mode="tim"] .sidebar {
    background-color: rgba(22,52,20,0.45);
    background-image:
        radial-gradient(135% 75% at 22% 6%, rgba(98,154,86,0.22), transparent 58%),
        linear-gradient(180deg, rgba(44,86,38,0.10) 0%, rgba(10,30,10,0.34) 100%),
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%3E%3C/svg%3E");
    background-size: cover, cover, 160px 160px;
    background-repeat: no-repeat, no-repeat, repeat;
}
[data-mode="tim"] .canvas {
    background-image: none;
    background-color: var(--canvas-bg);
}
/* ASCII landscape art layer — replaces dot grid in Tim mode */
.tim-ascii {
    display: none;
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 0;
    overflow: hidden;
    font-family: var(--font-mono);
    color: rgba(76,130,80,0.18);
    white-space: pre;
}
[data-mode="tim"] .tim-ascii {
    display: block;
    overflow: visible;
    /* Atmospheric depth: glyphs fade cool/faint at the top to denser/warmer at the
       bottom (gradient clipped to the text). Kept gentle so the small/distant art
       reads as background, not foreground. */
    color: transparent;
    background-image: linear-gradient(180deg,
        rgba(122,168,120,0.20) 0%,
        rgba(84,140,86,0.29) 45%,
        rgba(100,152,92,0.40) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    /* The world is large + lives inside #canvasInner; promote it so panning
       composites the layer instead of repainting the whole text block. */
    will-change: transform;
}
.tim-watermark {
    display: none;
}
/* Tim watermark disabled */

.magnetic { position: relative; }

/* ============ WORKSPACE TRANSITIONS ============ */
/* Durations wrapped in calc() so ?slow=N can multiply them for visual debugging */
.window.ws-transitioning {
    transition: left calc(0.5s * var(--ws-scale)) var(--ease-entry),
                top calc(0.5s * var(--ws-scale)) var(--ease-entry),
                width calc(0.5s * var(--ws-scale)) var(--ease-entry),
                height calc(0.5s * var(--ws-scale)) var(--ease-entry),
                border-radius calc(0.5s * var(--ws-scale)) var(--ease-entry),
                opacity calc(0.35s * var(--ws-scale)) ease,
                box-shadow calc(0.25s * var(--ws-scale)) ease !important;
}
/* Accessibility: skip movement for reduced motion */
@media (prefers-reduced-motion: reduce) {
    .window.ws-transitioning {
        transition: opacity var(--dur-fast) var(--ease-entry) !important;
    }
}
/* ws-thumb base = the Home Projects/Life preview cards (clipped, click-to-open). */
.window.ws-thumb {
    overflow: hidden;
    cursor: pointer;
    transition: opacity var(--dur-medium) var(--ease-entry), box-shadow var(--dur-base) ease;
}
.window.visible.ws-thumb { opacity: 0.85; }
.window.visible.ws-thumb:hover {
    opacity: 1;
    box-shadow: 0 6px 24px rgba(0,0,0,0.06) !important;
}
.window.ws-thumb .window-content { pointer-events: none; }
.window.ws-thumb .file-hero { display: none; }
.window.ws-thumb .file-row { flex-direction: column; }

/* ============ WORKSPACE PEEK ICONS ============ */
/* In a NON-home workspace, each non-prominent window collapses to a round icon
   button at its old slot — same motion path as the full windows, so the eye
   tracks each one to the same place; only the form changes. Scoped away from
   home, where ws-thumb is the Projects/Life preview cards above. */
/* Rest: a squarish chip (soft superellipse corners — reads more square than round). */
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.ws-thumb {
    width: 56px !important;
    height: 56px !important;
    border-radius: 12px !important;
    corner-shape: superellipse(1.7);
    transition: width 0.26s cubic-bezier(.34,1.1,.5,1),
                border-radius 0.26s ease,
                transform 0.2s cubic-bezier(.34,1.3,.5,1),
                box-shadow var(--dur-base) ease,
                opacity var(--dur-medium) var(--ease-entry),
                background var(--dur-mode) ease;
}
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.visible.ws-thumb { opacity: 1; }
/* Hover: corners round fully (perfect-circle caps), the chip lifts a touch and
   grows rightward into a pill to reveal the label. */
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.visible.ws-thumb:hover {
    width: var(--pill-w, 150px) !important;
    border-radius: 999px !important;
    corner-shape: round;
    transform: translateY(-3px);
    box-shadow: 0 10px 24px rgba(0,0,0,0.16) !important;
    z-index: 60 !important;
}
/* Window chrome fades out as the chip forms; the identity glyph fades in. */
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.ws-thumb .window-titlebar,
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.ws-thumb .window-content {
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.18s var(--ease-entry);
}
/* Badge = glyph pinned left (centered in the 56px chip at rest) + label. */
.ws-icon-badge {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 10px;
    padding-left: 16px;   /* (56 - 24 glyph) / 2 → glyph reads centered at rest */
    opacity: 0;
    pointer-events: none;
    color: var(--text-2);
    transition: opacity 0.28s var(--ease-entry), color 0.18s ease;
}
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.ws-thumb .ws-icon-badge { opacity: 1; }
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.ws-thumb:hover .ws-icon-badge { color: var(--accent); }
.ws-icon-badge .ico { position: relative; flex: 0 0 24px; width: 24px; height: 24px; display: inline-block; }
.ws-icon-badge .ico svg { position: absolute; inset: 0; width: 100%; height: 100%; transition: opacity 0.15s ease; }
.ws-icon-badge .ico .ico-fill { opacity: 0; }
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.ws-thumb:hover .ws-icon-badge .ico .ico-line { opacity: 0; }
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.ws-thumb:hover .ws-icon-badge .ico .ico-fill { opacity: 1; }
.ws-icon-name {
    display: inline-block;
    white-space: nowrap;
    max-width: 0;
    opacity: 0;
    overflow: hidden;
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--text-1);
    transition: max-width 0.26s var(--ease-entry), opacity 0.2s ease;
}
#canvas[data-peek="icons"]:not([data-ws="home"]) .window.ws-thumb:hover .ws-icon-name { max-width: 160px; opacity: 1; }

/* ---- PEEK MODE: MINIS (spike alt) ----
   Each peek window stays a tiny window: real titlebar (dots + title, inert) on
   top, identity glyph in the body. Reads as a labeled miniature, vs the icon
   dock. Toggle with the floating Peek control. */
#canvas[data-peek="minis"]:not([data-ws="home"]) .window.ws-thumb {
    width: 172px !important;
    height: 76px !important;
    border-radius: 16px !important;
    corner-shape: superellipse(1.7);
    transition: transform 0.2s var(--ease-entry),
                box-shadow var(--dur-base) ease,
                opacity var(--dur-medium) var(--ease-entry);
}
#canvas[data-peek="minis"]:not([data-ws="home"]) .window.visible.ws-thumb { opacity: 1; }
#canvas[data-peek="minis"]:not([data-ws="home"]) .window.visible.ws-thumb:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 24px rgba(0,0,0,0.14) !important;
}
/* Keep the titlebar (window chrome look) but make it inert; hide the messy body. */
#canvas[data-peek="minis"]:not([data-ws="home"]) .window.ws-thumb .window-titlebar {
    opacity: 1;
    pointer-events: none;
}
#canvas[data-peek="minis"]:not([data-ws="home"]) .window.ws-thumb .window-content { opacity: 0; }
/* Glyph sits in the body, below the titlebar; name stays hidden (titlebar has it). */
#canvas[data-peek="minis"]:not([data-ws="home"]) .window.ws-thumb .ws-icon-badge {
    opacity: 1;
    inset: 30px 0 0 0;
    justify-content: center;
    padding-left: 0;
    color: var(--text-3);
}
#canvas[data-peek="minis"]:not([data-ws="home"]) .window.ws-thumb:hover .ws-icon-badge { color: var(--accent); }
#canvas[data-peek="minis"]:not([data-ws="home"]) .window.ws-thumb .ws-icon-name { max-width: 0; opacity: 0; }

/* ---- PEEK MODE: THUMBS (spike alt) ----
   Each peek window is its REAL content, shrunk to a crisp miniature via
   transform: scale (Exposé-style). It keeps its real layout, so text stays
   vector-sharp; we just draw it small. */
#canvas[data-peek="thumbs"]:not([data-ws="home"]) .window.ws-thumb {
    width: 340px !important;
    height: 238px !important;   /* = a 340-wide card's titlebar + 16:9 frame, so every
                                   thumb is the same height → uniform rail spacing,
                                   and video cards fit exactly (no dead space). */
    border-radius: 28px !important;
    transform: scale(0.28) !important;
    transform-origin: top left;
    opacity: 1;
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.2s var(--ease-entry), box-shadow var(--dur-base) ease;
}
#canvas[data-peek="thumbs"]:not([data-ws="home"]) .window.visible.ws-thumb:hover {
    transform: scale(0.3) !important;
    box-shadow: 0 12px 28px rgba(0,0,0,0.18) !important;
}
/* real content stays; inner bits inert (whole thumb is one click target) */
#canvas[data-peek="thumbs"]:not([data-ws="home"]) .window.ws-thumb .window-titlebar,
#canvas[data-peek="thumbs"]:not([data-ws="home"]) .window.ws-thumb .window-content { pointer-events: none; }
#canvas[data-peek="thumbs"]:not([data-ws="home"]) .window.ws-thumb .ws-icon-badge { display: none; }

/* The prominent window slides right in minis + thumbs modes to clear the wider
   rail. Scoped to non-home so the home layout's prominent windows are untouched. */
#canvas:not([data-peek="icons"]):not([data-ws="home"]) .window.ws-prominent {
    left: 212px !important;
    width: calc(100% - 232px) !important;
}
/* Life view has TWO content cards (Community + Facsimile). Full-width makes the
   Facsimile screenshot enormous and both cards stack on the same spot. Give life's
   prominent cards a moderate centered width so they read as a calm vertical pair;
   their vertical stacking (top + gap) is set in workspaces.life. (Same specificity
   as the rule above + later in source, so it wins.) */
#canvas[data-ws="life"]:not([data-peek="icons"]) .window.ws-prominent {
    left: 50% !important;
    width: 540px !important;
    margin-left: -270px !important;
}
.window.ws-prominent { transition: left 0.3s var(--ease-entry), width 0.3s var(--ease-entry), opacity 0.35s var(--ease-entry), transform 0.35s var(--ease-entry), background var(--dur-mode) ease; }

/* Focus emphasis: a brief accent ring when a peek icon pulls its window up.
   Uses outline (follows the window's rounded corners in Chromium) so the
   window's own box-shadow is preserved. */
@keyframes winFocusPulse {
    0%   { outline-color: rgba(76,175,80,0); }
    18%  { outline-color: rgba(76,175,80,0.75); }
    100% { outline-color: rgba(76,175,80,0); }
}
.window.win-focus-pulse {
    outline: 2.5px solid transparent;
    outline-offset: 3px;
    animation: winFocusPulse 1.05s var(--ease-entry);
}

/* ============ VIDEO CARD (stacked lite-youtube facades) ============ */
/* Reusable: any .yt-facade[data-yt] becomes a click-to-load YouTube embed
   (thumbnail until clicked, then a lazy iframe). See initYTFacades() in app.js.
   Cards auto-size to their tiles; each tile is a true 16:9 frame so the
   thumbnail/player keeps the right aspect ratio (no squish). */
.video-stack {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 8px;
}
.video-tile {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: 14px;
    corner-shape: superellipse(1.7);
    overflow: hidden;
    background: #000;
    cursor: pointer;
    display: block;
}
/* Collage piles (reviews/community/facsimile/terminal): hover only runs the
   in-place tilt+lift (see app.js HOVER 3D TILT) — it does NOT reorder z.
   Bringing a card to the front is a deliberate click (pointerdown → topZ).
   This keeps a single, monotonic z source so hover and click never fight. */
.video-thumb {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0.92;
    transition: opacity 0.2s ease, transform 0.4s var(--ease-entry);
}
.video-tile:hover .video-thumb { opacity: 1; transform: scale(1.03); }
.video-tile-grad {
    position: absolute; inset: 0;
    background: linear-gradient(to top, rgba(0,0,0,0.74) 0%, rgba(0,0,0,0.18) 46%, transparent 72%);
    pointer-events: none;
}
.video-tile-meta {
    position: absolute; left: 13px; right: 13px; bottom: 11px;
    display: flex; flex-direction: column; gap: 1px;
    pointer-events: none;
}
.video-tile-title {
    color: #fff;
    font-family: var(--font-sans);
    font-size: 14px; font-weight: 600; line-height: 1.2;
    letter-spacing: -0.01em;
}
.video-tile-sub {
    color: rgba(255,255,255,0.78);
    font-family: var(--font-sans);
    font-size: 12px;
}
.video-play {
    position: absolute; top: 11px; right: 11px;
    width: 30px; height: 30px; border-radius: 50%;
    background: rgba(0,0,0,0.5);
    backdrop-filter: blur(4px);
    display: flex; align-items: center; justify-content: center;
    transition: background 0.2s ease, transform 0.2s var(--ease-entry);
}
.video-tile:hover .video-play { background: #f00; transform: scale(1.1); }
.video-play svg { width: 12px; height: 12px; fill: #fff; margin-left: 1px; }
.video-tile.yt-playing { cursor: default; }
.video-tile.yt-playing .video-tile-grad,
.video-tile.yt-playing .video-tile-meta,
.video-tile.yt-playing .video-play { display: none; }
.video-tile iframe { width: 100%; height: 100%; border: 0; display: block; }

/* ============ FACSIMILE CARD ============ */
.facsimile-window .window-content { display: flex; flex-direction: column; }
.fac-shot {
    position: relative;
    aspect-ratio: 16 / 10;
    background: linear-gradient(135deg, #2b2b30, #161619);
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
}
.fac-ghost { font-family: var(--font-serif); font-size: 15px; color: rgba(255,255,255,.45); }
.fac-screenshot { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.fac-chip {
    position: absolute; top: 12px; left: 12px;
    width: 50px; height: 50px; border-radius: 13px;
    background: #fff; display: flex; align-items: center; justify-content: center;
    box-shadow: 0 4px 14px rgba(0,0,0,.3);
}
.fac-chip img { width: 32px; height: 32px; }
.fac-body { padding: 15px 17px 17px; }
.fac-name { font-family: var(--font-sans); font-size: 17px; font-weight: 700; }
.fac-desc { font-family: var(--font-sans); font-size: 13.5px; color: var(--text-2); margin-top: 5px; line-height: 1.45; }
.fac-cta {
    margin-top: 13px; display: inline-flex; align-items: center; gap: 5px;
    background: var(--text-1); color: var(--canvas-bg);
    font-family: var(--font-sans); font-size: 13px; font-weight: 600;
    padding: 8px 14px; border-radius: 9px; text-decoration: none;
    transition: transform .18s var(--ease-entry), box-shadow .18s ease;
}
.fac-cta:hover { transform: translateY(-2px); box-shadow: 0 8px 18px rgba(0,0,0,.18); }
.fac-cta .external-arrow { font-style: normal; }

/* ============ COMMUNITY CARD (videos + community, unified list) ============ */
.community-window .comm-item {
    display: flex; gap: 12px; align-items: center;
    padding: 10px 16px; text-decoration: none; color: inherit;
    transition: background .16s ease;
}
.community-window .comm-item + .comm-item { border-top: 1px solid var(--window-border); }
.community-window .comm-item:hover { background: var(--file-hover); }
.comm-logo {
    width: 40px; height: 40px; border-radius: 11px; flex: 0 0 40px;
    overflow: hidden; background: var(--accent-soft);
    display: flex; align-items: center; justify-content: center;
}
.comm-logo img { width: 100%; height: 100%; object-fit: cover; }
/* video rows: a 16:9 thumbnail with a play badge */
.comm-thumb {
    position: relative; width: 66px; height: 40px; flex: 0 0 66px;
    border-radius: 8px; overflow: hidden; background: #000;
}
.comm-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .3s var(--ease-entry); }
.comm-item.comm-video:hover .comm-thumb img { transform: scale(1.06); }
.comm-play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.comm-play svg { width: 11px; height: 11px; fill: #fff; filter: drop-shadow(0 1px 2px rgba(0,0,0,.55)); margin-left: 1px; }
.comm-txt { display: flex; flex-direction: column; min-width: 0; }
.comm-name { font-family: var(--font-sans); font-size: 14.5px; font-weight: 600; display: flex; align-items: center; gap: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.comm-sub { font-family: var(--font-sans); font-size: 12.5px; color: var(--text-2); margin-top: 1px; line-height: 1.35; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ============ VOID MODE ============ */
#voidCanvas {
    position: fixed;
    inset: 0;
    z-index: 10;
    pointer-events: none;
}
.void-warp {
    position: fixed;
    inset: 0;
    z-index: 9;
    pointer-events: none;
    opacity: 0;
    transition: opacity 2s var(--ease-entry);
    background: radial-gradient(ellipse at center,
        transparent 20%,
        rgba(0, 0, 0, 0.15) 45%,
        rgba(0, 0, 0, 0.4) 65%,
        rgba(0, 0, 0, 0.75) 80%,
        rgba(0, 0, 0, 0.95) 100%
    );
}
.void-warp.active { opacity: 1; }
.void-vignette {
    position: fixed;
    inset: 0;
    background: radial-gradient(ellipse at center,
        transparent 50%,
        rgba(0,0,0,0.02) 65%,
        rgba(0,0,0,0.05) 80%,
        rgba(0,0,0,0.05) 100%
    );
    opacity: 0;
    transition: opacity 2.5s var(--ease-entry);
    pointer-events: none;
    z-index: 8;
}
.void-vignette.active { opacity: 1; }

@keyframes galeForce {
    0%   { translate: 0px 0px;   rotate: 0deg; }
    10%  { translate: 3px -2px;   rotate: 0.4deg; }
    20%  { translate: -4px 1px;   rotate: -0.6deg; }
    30%  { translate: 2px 4px;    rotate: 0.3deg; }
    40%  { translate: -3px -3px;  rotate: -0.5deg; }
    50%  { translate: 5px 2px;    rotate: 0.6deg; }
    60%  { translate: -2px -1px;  rotate: -0.3deg; }
    70%  { translate: 4px -3px;   rotate: 0.5deg; }
    80%  { translate: -5px 2px;   rotate: -0.2deg; }
    90%  { translate: 1px -2px;   rotate: 0.3deg; }
    100% { translate: 0px 0px;    rotate: 0deg; }
}

.void-reset-btn {
    position: fixed;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    z-index: 5;
    font-family: var(--font-sans);
    font-size: 13px;
    color: #444;
    background: transparent;
    border: 1px solid rgba(255,255,255,0.06);
    padding: 8px 20px;
    border-radius: 8px;
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--dur-medium) var(--ease-entry), color var(--dur-base), border-color var(--dur-base);
    pointer-events: none;
}
.void-reset-btn.visible { opacity: 1; pointer-events: auto; transition: opacity 2.5s var(--ease-entry) 3s, color var(--dur-base), border-color var(--dur-base); }
.void-reset-btn:hover { color: #888; border-color: rgba(255,255,255,0.15); }
/* ============ PEN TOOL ============ */
.draw-layer {
    position: fixed;
    inset: 0;
    z-index: 3;
    pointer-events: none;
}
.draw-layer.active {
    pointer-events: auto;
    cursor: crosshair;
}
.draw-toolbar {
    position: fixed;
    left: 50%;
    bottom: 40px;
    transform: translateX(-50%);
    transition: transform 0.5s var(--ease-entry), opacity 0.4s ease;
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    background: var(--window-bg);
    border: 1px solid var(--window-border);
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0,0,0,0.06);
    z-index: 1001;
}
.draw-toolbar.tucked {
    transform: translateX(-50%) translateY(calc(100% + 60px));
    opacity: 0;
    pointer-events: none;
}
.draw-tool {
    width: 32px; height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 8px;
    border: none;
    background: transparent;
    color: var(--text-2);
    cursor: pointer;
    transition: background 0.12s, color 0.12s;
}
.draw-tool:hover { background: var(--file-hover); color: var(--text-1); }
.draw-tool.active { background: var(--accent-soft); color: var(--accent); }
.draw-tool svg {
    width: 16px; height: 16px;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.draw-sep {
    width: 1px;
    height: 20px;
    background: var(--window-border);
    margin: 0 4px;
}
.draw-color {
    width: 18px; height: 18px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    transition: border-color 0.12s, transform 0.12s;
}
.draw-color:hover { transform: scale(1.15); }
.draw-color.active { border-color: var(--text-1); }
.draw-size {
    font-family: var(--font-sans);
    font-size: 10px;
    color: var(--text-3);
    background: var(--file-hover);
    border: 1px solid var(--window-border);
    border-radius: 6px;
    padding: 3px 8px;
    cursor: pointer;
    transition: color 0.12s;
}
.draw-size:hover { color: var(--text-1); }

/* ============ CASE STUDY TAB BAR ============ */
.cs-tab-bar {
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 0;
    overflow: hidden;
    display: flex;
    align-items: flex-end;
    background: transparent;           /* show the canvas/print behind the deck */
    /* No z-index on purpose: the bar must NOT form a stacking context, so each
       card's z-index competes directly with .cs-overlay (z:250) in the canvas
       context — active card (z>250) merges in front of the content, the resting
       deck (z<250) tucks behind it. */
    transition: height 0.35s var(--ease-entry);
}
.cs-tab-bar.visible {
    height: 58px;
    overflow: visible;
}
/* Canvas view has no content panel under the deck, so the cards float. Give the
   bar a faint ledge (subtle surface + hairline) only when the Canvas tab is
   active; while reading a case study the content itself anchors the deck and the
   bar stays transparent. No backdrop-filter (would create a stacking context and
   break the card↔overlay z-merge). */
/* Bar stays transparent on the canvas view; the pile + canvas tab anchor it.
   z-index lifts the bar above .canvas-inner (windows) so they don't bleed through
   when the canvas is scrolled — and so pointer events reach the pile cards
   reliably (cursor over a card that's visually atop a window stays on the card).
   Safe to set z-index here because the overlay is closed in canvas mode, so the
   reading-view z-merge isn't needed. */
.cs-tab-bar.cs-bar-canvas { background: transparent; z-index: 300; }
.cs-bar-canvas .cs-tab-bar-inner { align-items: center; }
/* Reading view (a case study / about is open): give the shelf a solid surface so
   the canvas + dot-grid stop showing through behind the tabs, and lift it above
   the canvas windows (z<=12) — but BELOW the overlay (250) — so it also blocks
   accidental click-through to the canvas. z<250 keeps the active-card↔overlay
   tuck-behind merge intact (only z>250 would break it). */
.cs-tab-bar.visible:not(.cs-bar-canvas) {
    background: var(--canvas-bg);
    z-index: 200;
}

/* Canvas tab in canvas mode: full size but level (no exaggerated lift), above
   the pile so the first pile card tucks behind it. Override the generic
   .cs-tab.active rule that lifts -7px and adds 8px horizontal margins. */
.cs-bar-canvas .cs-tab-canvas {
    height: 38px;
    padding: 0 13px 0 10px;
    align-items: center;
    position: relative;
    z-index: 50;
}
.cs-bar-canvas .cs-tab-canvas.active {
    transform: translateY(0) rotate(0) !important;
    margin-left: 0 !important;
    margin-right: 0 !important;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
/* No favicon on the Canvas tab anywhere — it's the orientation anchor, label-only. */
.cs-tab-canvas .cs-tab-fav { display: none; }
.cs-bar-canvas .cs-tab-canvas { padding: 0 13px; }   /* tighten without the chip */
/* Pile mode (canvas active): non-canvas tabs collapse into a small overlapping
   fanned stack beside the Canvas tab (the orientation anchor). Hover the pile to
   straighten + spread the cards with names. Reading view (fan) is untouched. */
/* Pile container: STABLE position (no margin shift on hover) — required so the
   cursor doesn't lose :hover on the container while cards expand. */
.cs-bar-canvas .cs-pile {
    position: relative;
    display: flex;
    align-items: center;
    margin-left: -8px;                  /* first card tucks slightly behind the canvas tab */
    padding: 8px 0;                     /* extend the hover hit-area above/below the cards
                                           so rotated-card overshoot can't drop the :hover */
}

/* Pile cards: chip-only with a larger favicon so it reads. */
.cs-bar-canvas .cs-pile .cs-tab {
    height: 32px;
    width: 36px;
    padding: 0;
    margin-left: -14px;
    border-radius: 9px;
    border: 1px solid var(--window-border);   /* no accent border-top in canvas mode either */
    justify-content: center;
    align-items: center;
    transform-origin: 50% 130%;
    transform: rotate(var(--tab-rot, 0deg));
    box-shadow: 0 2px 6px rgba(0,0,0,0.14);
    transition: transform .28s cubic-bezier(.2,.9,.25,1), width .28s, padding .28s, gap .28s, margin .28s, box-shadow .2s;
}
.cs-bar-canvas .cs-pile .cs-tab:first-child { margin-left: 0; }
.cs-bar-canvas .cs-pile .cs-tab .cs-tab-label,
.cs-bar-canvas .cs-pile .cs-tab .cs-tab-close { display: none; }
.cs-bar-canvas .cs-pile .cs-tab-fav { width: 26px; height: 26px; border-radius: 7px; font-size: 11px; }

/* Hover the pile → cards straighten + spread; ALL cards translate right 12px so
   the first card clears the canvas tab and every gap is equal. The pile box
   itself never moves (no margin change), which kills hover oscillation. */
.cs-bar-canvas .cs-pile:hover .cs-tab {
    width: auto;
    padding: 0 11px 0 9px;
    gap: 7px;
    margin-left: 4px;
    transform: translateX(12px) rotate(0);
}
.cs-bar-canvas .cs-pile:hover .cs-tab:first-child { margin-left: 0; }
.cs-bar-canvas .cs-pile:hover .cs-tab .cs-tab-label { display: flex; }
.cs-bar-canvas .cs-pile:hover .cs-tab .cs-tab-close { display: flex; }

/* Individual card hover within the hovered pile: SHADOW ONLY — no position
   change. Position-changing hovers caused the oscillation. */
.cs-bar-canvas .cs-pile:hover .cs-tab:hover { box-shadow: 0 6px 14px rgba(0,0,0,0.22); }

/* A tab being closed: animate width/opacity to 0 so the surrounding tabs slide
   smoothly to fill — and so a user can rapid-fire close several without the bar
   ever fully rebuilding mid-action. */
.cs-tab.cs-tab-closing {
    width: 0 !important;
    min-width: 0 !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    margin-left: -8px !important;
    opacity: 0 !important;
    pointer-events: none;
    overflow: hidden;
    transition: width .26s cubic-bezier(.4,0,.2,1),
                padding .26s cubic-bezier(.4,0,.2,1),
                margin .26s cubic-bezier(.4,0,.2,1),
                opacity .22s ease;
}

/* Returning to the canvas — PARALLEL spring-close. The departing fan tabs get
   pulled out of layout flow (position:absolute) and animated to fade/squish
   toward the canvas tab; in the same frame, the new pile is inserted and runs
   its own arrival animation. Both happen concurrently — no gap, no belated
   movement. */
.cs-tab.cs-tab-collapsing-fan {
    position: absolute !important;
    /* top/left/width/height are frozen inline by JS to the card's live fan
       position (relative to the position:relative bar-inner) so the card
       dissolves IN PLACE. The old top:0/left:0 snapped every departing card to
       the bar corner under the Canvas tab — that was the fade-behind-canvas
       artifact. No horizontal fly now: a gentle in-place scale + fade only. */
    margin: 0 !important;
    pointer-events: none;
    /* Fade NEAR-INSTANT — the fan should vanish before the eye registers it, so
       the only motion read is the pile spring. Not a visible dissolve. */
    transition: transform .1s ease, opacity .08s ease;
    transform: scale(0.88) !important;
    opacity: 0;
    z-index: 1;
}

/* Pile arrival: each card springs out from behind the canvas tab into its
   resting fan position, staggered slightly so the deck feels assembled. */
.cs-bar-canvas .cs-pile.cs-pile-arriving .cs-tab {
    animation: cs-pile-arrive .5s cubic-bezier(.34,1.3,.55,1) backwards;
    animation-delay: calc(var(--idx) * 45ms);
}
@keyframes cs-pile-arrive {
    0%   { transform: translateX(-32px) scale(0.6) rotate(0deg); opacity: 0; }
    60%  { opacity: 1; }
    100% { transform: rotate(var(--tab-rot, 0deg)) translateX(0) scale(1); opacity: 1; }
}
.cs-tab-bar-inner {
    display: flex;
    align-items: flex-end;
    height: 100%;
    padding: 0 16px 0 14px;
    gap: 0;
    position: relative;   /* anchor for the frozen .cs-tab-collapsing-fan cards
                             (relative, no z-index → no stacking context, so the
                             fan-mode active-card↔overlay z-merge is unaffected) */
}
/* Desktop canvas: tabs ARE the chrome — hide the duplicate titlebar row.
   Route pages (single case study, no tab bar) and mobile keep their titlebar. */
@media (min-width: 641px) {
    body:not(.route-page) .cs-titlebar { display: none; }
}
/* CASE STUDY TABS — a gently fanned deck of cards (the "F1" treatment). Resting
   cards lean a couple degrees and tuck their bottom behind the content (z below
   the overlay, bottom never visible). The active card straightens, rises a touch
   higher, and reveals a brief title that fades after a word or two.
   --tab-color = true brand colour (favicon chip); --tab-fg = luminance-aware chip
   text; --tab-ui = readable accent for thin lines (pale brands get darkened).
   --tab-rot/--tab-dy (the fan) are computed per tab count in csRenderTabs(). */
.cs-tab {
    --tab-color: var(--accent);
    --tab-fg: var(--canvas-bg);
    --tab-ui: var(--accent);
    position: relative;
    display: flex;
    align-items: flex-start;          /* title rides the visible upper band */
    gap: 8px;
    height: 50px;                     /* tall enough the bottom always hides behind
                                         the content area, never visible */
    padding: 9px 12px 0 11px;
    margin-left: -12px;               /* overlap → deck */
    color: var(--text-2);
    background: var(--canvas-bg);
    border: 1px solid var(--window-border);
    border-radius: 11px 11px 10px 10px;
    corner-shape: superellipse(1.7);
    font-family: var(--font-sans);
    font-size: 12.5px;
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transform-origin: 50% 150%;
    transform: rotate(var(--tab-rot, 0deg)) translateY(var(--tab-dy, 0px));
    box-shadow: 0 1px 4px rgba(0,0,0,0.07);
    filter: none;
    opacity: 1;                       /* solid fill — readable over the canvas, no bleed-through.
                                         depth cue comes from the dimmer --text-2 resting colour
                                         + the lean, not from translucency */
    transition: transform 0.34s cubic-bezier(.2,.9,.25,1), box-shadow 0.28s ease,
                filter 0.3s ease, opacity 0.3s ease, color 0.2s ease,
                background 0.25s ease, margin 0.34s cubic-bezier(.2,.9,.25,1);
}
.cs-tab:first-child { margin-left: 0; }

/* hover a resting card in the FAN view: float up + sharpen (peek). Scoped so it
   doesn't leak into canvas-pile mode (caused hover oscillation). */
.cs-tab-bar:not(.cs-bar-canvas) .cs-tab:not(.active):hover {
    transform: rotate(0deg) translateY(-3px);
    filter: none;
    opacity: 1;
    color: var(--text-1);
}

/* active — straighten, rise a little higher, sharpen. Stays BEHIND the content
   (z below the overlay) so its bottom is hidden too; it reads as the page's tab
   emerging from behind the content edge. */
.cs-tab.active {
    color: var(--text-1);
    background: var(--canvas-bg);
    transform: rotate(0deg) translateY(-7px) !important;
    z-index: 120 !important;          /* above sibling cards, below .cs-overlay (250) */
    margin-left: -4px !important;     /* overlap the LEFT neighbour ~4px so the active card sits
                                         in front on both sides — symmetric with the right edge
                                         (next card's -12px base margin gives ~4px there too).
                                         Positive margin here left an 8px canvas-bleed gap. */
    margin-right: 8px !important;
    border-color: var(--window-border);
    filter: none !important;
    opacity: 1 !important;
    box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}

/* favicon chip — monogram in the project's true brand colour */
.cs-tab-fav {
    width: 20px; height: 16px; flex: 0 0 auto;   /* height = .cs-tab-label line-height so the chip centers on the text under the tab's align-items:flex-start */
    border-radius: 6px;
    corner-shape: superellipse(1.7);
    background: var(--tab-color);
    color: var(--tab-fg);
    display: flex; align-items: center; justify-content: center;
    font-size: 10px; font-weight: 700; line-height: 1;
    overflow: hidden;
}
/* real logo / brand-mark chips: light surface so transparent or dark marks read */
.cs-tab-fav--art {
    background: #fff;
    padding: 1.5px;
}
.cs-tab-fav--art img,
.cs-tab-fav--art svg {
    width: 100%; height: 100%;
    object-fit: contain;
    display: block;
}
/* avatar chip (About = Tim's face): full-bleed circular photo */
.cs-tab-fav--avatar {
    background: transparent;
    padding: 0;
    border-radius: 50%;
    corner-shape: round;
}
.cs-tab-fav--avatar img {
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}

/* label = name + a brief title that fades in (and out at its right edge) only
   when the tab is active */
.cs-tab-label {
    display: flex;
    align-items: baseline;
    overflow: hidden;
    line-height: 16px;
    max-width: 220px;
}
.cs-tab-name { white-space: nowrap; }
.cs-tab-sub {
    white-space: nowrap;
    color: var(--text-3);
    max-width: 0;
    opacity: 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;   /* plain … truncation, no edge fade */
    transition: max-width 0.34s cubic-bezier(.2,.9,.25,1), opacity 0.3s ease;
}
.cs-tab.active .cs-tab-sub { max-width: 150px; opacity: 1; }
/* Fan view hover: reveal the description, reserve right-side room for the close,
   and fade the label's right edge so the close X dissolves out of the text.
   Excluded from .cs-tab-canvas — it has no close, so the fade would be a ghost. */
.cs-tab-bar:not(.cs-bar-canvas) .cs-tab:not(.cs-tab-canvas):hover { padding-right: 28px; }
.cs-tab-bar:not(.cs-bar-canvas) .cs-tab:not(.cs-tab-canvas):hover .cs-tab-sub { max-width: 150px; opacity: 1; }
/* Title truncates with a plain ellipsis (… dots) — the right-edge mask fade
   was unreliable, so the sub span clips itself via text-overflow. */
.cs-tab-accent { display: none; }

.cs-tab-close {
    position: absolute;
    right: 8px;
    top: 8px;
    width: 16px; height: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 5px;
    color: var(--text-1);
    background: transparent;
    opacity: 0;
    transition: opacity 0.12s, background 0.12s;
}
.cs-tab:hover .cs-tab-close { opacity: 0.85; background: var(--accent-soft); }
.cs-tab-close:hover { opacity: 1 !important; background: var(--accent-soft); color: var(--text-1); }
.cs-tab-close svg {
    width: 9px; height: 9px;
    stroke: currentColor;
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
}

/* ============ CASE STUDY WINDOW ============ */
.cs-overlay {
    position: absolute;
    left: 0; top: 36px; right: 0; bottom: 0;
    z-index: 250;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    /* Matches .cs-window so the tab cross-fade doesn't reveal a lighter
       layer behind the content as the cs-window fades opacity. */
    background: var(--canvas-bg);
    box-shadow: 0 12px 48px rgba(0,0,0,0.1);
    transform: translateX(100%);
    opacity: 0;
    pointer-events: none;
}
.cs-overlay.sliding-in {
    transform: translateX(0);
    opacity: 1;
    pointer-events: auto;
    transition: transform 0.35s var(--ease-entry),
                opacity 0.15s ease;
}
.cs-overlay.open {
    transform: translateX(0);
    opacity: 1;
    pointer-events: auto;
}
/* Tab switch: content slides inside the overlay */
.cs-window.slide-out-left {
    animation: csSlideOutLeft 0.25s cubic-bezier(0.4,0,1,1) forwards;
}
.cs-window.slide-in-right {
    animation: csSlideInRight 0.3s var(--ease-entry) both;
}
.cs-window.slide-out-right {
    animation: csSlideOutRight 0.25s cubic-bezier(0.4,0,1,1) forwards;
}
.cs-window.slide-in-left {
    animation: csSlideInLeft 0.3s var(--ease-entry) both;
}
/* Tab cross-fade: outgoing recedes (slides away + scales down), incoming
   presents forward (slides in + scales from slightly large). The 1.02 / 0.97
   scale gives a subtle depth cue without dramatic movement.

   ─── ROLLBACK RECIPE ───
   To revert to the pre-scale, flat-slide version:
     1. Replace `100px` with `60px` in all four keyframes below.
     2. Remove the ` scale(1)`, ` scale(0.97)`, ` scale(1.02)` segments
        from every transform — leave just `translateX(...)`.
   To dial down without removing entirely: try 80px + scale 0.98 / 1.01.
   To make more dramatic: try 140px + scale 0.95 / 1.03 and bump
   .cs-window.slide-out-* duration from 0.25s to 0.28s. */
@keyframes csSlideOutLeft {
    from { transform: translateX(0) scale(1); opacity: 1; }
    to { transform: translateX(-100px) scale(0.97); opacity: 0; }
}
@keyframes csSlideInRight {
    from { transform: translateX(100px) scale(1.02); opacity: 0; }
    to { transform: translateX(0) scale(1); opacity: 1; }
}
@keyframes csSlideOutRight {
    from { transform: translateX(0) scale(1); opacity: 1; }
    to { transform: translateX(100px) scale(0.97); opacity: 0; }
}
@keyframes csSlideInLeft {
    from { transform: translateX(-100px) scale(1.02); opacity: 0; }
    to { transform: translateX(0) scale(1); opacity: 1; }
}
.cs-overlay.closing {
    transform: translateX(100%);
    opacity: 0;
    pointer-events: none;
    transition: transform 0.3s var(--ease-entry),
                opacity 0.18s ease;
}
.cs-window {
    flex: 1;
    position: relative;
    background: var(--canvas-bg);
    overflow-y: auto;
    overflow-x: hidden;
    scroll-behavior: smooth;
    container-type: inline-size;
}
.resume-embed {
    display: flex;
    flex-direction: column;
    height: 100%;
    position: absolute;
    inset: 0;
}
.cs-titlebar {
    display: flex;
    align-items: center;
    height: 36px;
    padding: 0 14px;
    gap: 10px;
    background: var(--canvas-bg);
    border-bottom: 1px solid var(--window-border);
    flex-shrink: 0;
}
.cs-titlebar .traffic-lights { display: flex; gap: 7px; }
.cs-titlebar .traffic-light {
    width: 12px; height: 12px;
    border-radius: 50%;
    opacity: 0.85;
    cursor: pointer;
    transition: opacity 0.15s, transform 0.15s;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
}
.cs-titlebar .traffic-light:hover { opacity: 1; transform: scale(1.1); }
.cs-titlebar .traffic-light svg {
    width: 6px; height: 6px;
    stroke: rgba(0,0,0,0.5);
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
    opacity: 0;
    transition: opacity 0.1s;
}
.cs-titlebar:hover .traffic-light svg { opacity: 1; }
.cs-titlebar-name {
    font-family: var(--font-sans);
    font-size: 12px;
    color: var(--title-text);
    flex: 1;
    text-align: center;
}
.cs-accent-line {
    height: 2px;
    flex-shrink: 0;
}

/* ============ CASE STUDY CONTENT ============ */
.cs-content {
    max-width: 1000px;
    margin: 0 auto;
    padding: 48px 32px 80px;
}
.cs-hero-img {
    width: 100%;
    border-radius: 12px;
    margin-bottom: 32px;
}
.cs-carousel {
    position: relative;
    background: var(--title-bar);
    padding: 40px 0;
    margin-top: 48px;
    margin-bottom: 48px;
    overflow: hidden;
    width: 100cqi;
    margin-left: calc((100% - 100cqi) / 2);
    margin-right: calc((100% - 100cqi) / 2);
}
.cs-carousel-track {
    display: flex;
    justify-content: safe center;
    gap: 16px;
    height: 800px;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scroll-behavior: smooth;
    padding: 0 40px;
}
.cs-carousel-track .cs-image-slot {
    flex: 0 0 auto;
    height: 100%;
    overflow: hidden;
    scroll-snap-align: start;
}
.cs-carousel-track .cs-image-slot img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 0;
    border: none !important;
    margin: 0;
    box-shadow: none;
}
.cs-carousel-dots {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 20px;
}
.cs-carousel-dots .cs-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--text-3, #808080);
    opacity: 0.25;
    transition: opacity 0.2s;
    cursor: pointer;
}
.cs-carousel-dots .cs-dot.active {
    opacity: 0.8;
}
/* Simple image row (no slots, e.g. phone mockups) */
.cs-image-row {
    display: flex;
    gap: 12px;
    margin-top: 24px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 8px;
}
.cs-image-row > img {
    flex: 0 0 auto;
    width: 320px;
    height: auto;
    border-radius: 8px;
    scroll-snap-align: start;
    border: none !important;
    box-shadow: none;
}
.cs-figma-embed {
    width: 100%;
    height: 500px;
    border: 1px solid var(--border, #e5e5e5);
    border-radius: 8px;
    margin-top: 24px;
}
.cs-hero {
    margin-bottom: 12px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: left;
    width: 100%;
}
.cs-hero h1, .cs-hero p, .cs-hero h2 { max-width: 600px; width: 100%; }
.cs-hero h2 {
    font-size: 20px;
    font-weight: 600;
    color: var(--text-1);
    margin-bottom: 0;
    letter-spacing: -0.02em;
}
.cs-hero h1 {
    font-family: var(--font-serif);
    font-size: 40px;
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.12;
    color: var(--text-1);
    margin-bottom: 16px;
}
.cs-hero-subtitle {
    font-size: 19px;
    line-height: 1.55;
    color: var(--text-2);
    margin-bottom: 20px;
    max-width: 600px;
    width: 100%;
}
.cs-metrics-line {
    font-family: var(--font-sans);
    font-size: 12px;
    color: var(--text-3);
    padding: 10px 14px;
    background: var(--accent-soft);
    border-radius: 8px;
    letter-spacing: 0.01em;
    max-width: 600px;
    width: 100%;
}
.cs-section {
    margin-bottom: 48px;
    scroll-margin-top: 48px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: left;
}
.cs-section > *:last-child { margin-bottom: 0; }
.cs-section h2 {
    font-family: var(--font-serif);
    font-size: 27px;
    font-weight: 600;
    color: var(--text-1);
    margin-bottom: 14px;
    letter-spacing: -0.01em;
    max-width: 600px;
    width: 100%;
}
.cs-section h3 {
    font-family: var(--font-serif);
    font-size: 20px;
    font-weight: 600;
    color: var(--text-1);
    margin-bottom: 8px;
    margin-top: 24px;
    max-width: 600px;
    width: 100%;
}
.cs-section p {
    font-size: 17px;
    line-height: 1.7;
    color: var(--text-2);
    margin-bottom: 16px;
    max-width: 600px;
    width: 100%;
}
.cs-section ul {
    list-style: none;
    padding: 0;
    margin-bottom: 16px;
    max-width: 600px;
    width: 100%;
}
.cs-section ul li {
    font-size: 17px;
    line-height: 1.7;
    color: var(--text-2);
    padding: 3px 0 3px 18px;
    position: relative;
}
.cs-section ul li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 11px;
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--text-3);
}
.cs-section img {
    width: 100%;
    max-width: 1000px;
    border-radius: 10px;
    border: none;
    margin: 16px 0;
    cursor: zoom-in;
}
.cs-before-stack img {
    margin: 0;
    border-radius: 0;
    cursor: default;
}
.cs-after-scroll {
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}
.cs-after-scroll img {
    margin: 0;
    border-radius: 0;
    cursor: default;
    display: block;
}
.cs-lightbox {
    position: fixed;
    inset: 0;
    z-index: 10000;
    background: rgba(0,0,0,0.85);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    cursor: zoom-out;
    opacity: 0;
    transition: opacity var(--dur-base) var(--ease-entry);
    pointer-events: none;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 4vh 0;
}
.cs-lightbox.active {
    opacity: 1;
    pointer-events: auto;
}
.cs-lightbox img {
    width: 92vw;
    max-width: 1200px;
    height: auto;
    border-radius: 8px;
    box-shadow: 0 8px 40px rgba(0,0,0,0.4);
    transform: scale(0.95);
    transition: transform var(--dur-base) ease;
    flex-shrink: 0;
}
.cs-lightbox.active img {
    transform: scale(1);
}
.cs-section figure img {
    margin: 0;
}
.about-carousel {
    width: 100%;
    overflow: hidden;
    margin-bottom: 32px;
    margin-top: -48px;
}
.about-carousel-track {
    display: flex;
    gap: 12px;
    animation: aboutCarouselScroll 40s linear infinite;
    width: max-content;
}
.about-carousel-track:hover {
    animation-play-state: paused;
}
.about-carousel-track img {
    height: 480px;
    width: auto;
    border-radius: 0;
    object-fit: cover;
    flex-shrink: 0;
}
@keyframes aboutCarouselScroll {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}
@keyframes logoScroll {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}
.cs-projected {
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-2);
    padding: 20px 24px;
    background: var(--title-bar);
    border-radius: 10px;
    margin-bottom: 16px;
    display: inline-block;
    max-width: 600px;
    width: 100%;
}
.cs-impact-table {
    max-width: 600px;
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 16px;
}
.cs-impact-table th, .cs-impact-table td {
    font-size: 13px;
    padding: 10px 12px;
    text-align: left;
    border-bottom: 1px solid var(--window-border);
}
.cs-impact-table th {
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 500;
}
.cs-impact-table td { color: var(--text-2); }
.cs-impact-table td:last-child { font-weight: 600; color: var(--text-1); }
.cs-impact-table tr:last-child td {
    border-bottom: none;
    font-weight: 700;
    color: var(--text-1);
}
.cs-note {
    font-size: 12px;
    color: var(--text-3);
    font-style: italic;
    line-height: 1.6;
    margin-top: 8px;
}
.cs-callout-card {
    background: var(--title-bar);
    border-radius: 10px;
    padding: 20px 24px;
    margin: 32px auto;
    max-width: 600px;
    width: 100%;
}
.cs-callout-card p {
    font-size: 17px;
    line-height: 1.6;
    color: var(--text-2);
    margin: 0 0 14px;
}
.cs-callout-card .cs-role-tags {
    margin-top: 0;
}
.cs-callout-card .cs-role-tag {
    background: var(--accent-soft);
    color: var(--text-1);
}
.cs-role-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 16px;
    max-width: 600px;
    width: 100%;
}
.cs-role-tag {
    font-family: var(--font-sans);
    font-size: 10px;
    padding: 3px 8px;
    border-radius: 5px;
    background: var(--accent-soft);
    color: var(--text-3);
}
.cs-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 300px;
    color: var(--text-3);
    font-family: var(--font-sans);
    gap: 12px;
}
.cs-placeholder-title {
    font-size: 20px;
    font-weight: 700;
    color: var(--text-2);
}
.cs-placeholder-sub { font-size: 13px; }

/* ============ SIDEBAR CASE STUDY TOC ============ */
.sidebar-cs-nav {
    display: none;
    flex-direction: column;
    padding: 0 8px;
    flex: 1;
    overflow-y: auto;
}
.sidebar-cs-nav.visible {
    display: flex;
}
.sidebar-cs-back {
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--text-3);
    padding: 6px 8px;
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 6px;
    border-radius: 6px;
    transition: color 0.15s, background 0.15s;
    margin-bottom: 8px;
}
.sidebar-cs-back:hover { color: var(--text-1); background: var(--file-hover); }
.sidebar-cs-back svg {
    width: 12px; height: 12px;
    stroke: currentColor;
    fill: none;
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.sidebar-cs-title {
    font-family: var(--font-sans);
    font-size: 14px;
    font-weight: 600;
    color: var(--text-1);
    padding: 4px 8px 10px;
}
.sidebar-toc-item {
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--text-3);
    padding: 5px 8px;
    border-radius: 6px;
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sidebar-toc-item:hover { color: var(--text-1); background: var(--file-hover); }
.sidebar-toc-item.active { color: var(--text-1); background: var(--sidebar-active); }

/* Profile photo window */
.profile-window, .podcast-window { overflow: hidden; }
.profile-window .window-content {
    padding: 0;
}
.profile-window img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    border-radius: 0 0 12px 12px;
}
.profile-placeholder {
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, #E8E7E3 0%, #D4D3CD 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 48px;
    font-weight: 800;
    color: var(--text-3);
    border-radius: 0 0 12px 12px;
}

/* Reviews window */
.review-item { padding: 12px 0; }
.review-item + .review-item { border-top: 1px solid var(--window-border); }
.review-quote {
    font-style: italic;
    font-size: 16px;
    line-height: 1.6;
    color: var(--text-1);
    margin-bottom: 8px;
}
.review-author-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-top: 12px;
}
.review-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
}
.review-author {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-2);
}
.review-role {
    font-size: 13px;
    color: var(--text-3);
}

/* About window */
.about-window { cursor: pointer; }
.about-window .hero-bio {
    margin-bottom: 10px;
}
.about-teaser {
    font-size: 15px;
    line-height: 1.6;
    color: var(--text-2);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.about-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 12px;
}
.about-tag {
    font-family: var(--font-sans);
    font-size: 11.5px;
    padding: 3px 8px;
    border-radius: 5px;
    background: var(--accent-soft);
    color: var(--text-3);
}

/* Social links in sidebar footer */
/* Footer row: the sun/moon/mountain control + the social deck share one line. */
.footer-row { display: flex; align-items: center; gap: 10px; }
.footer-row .mode-pills { flex: 1; min-width: 0; }

/* Social deck (V4): four social links as a small deck that spreads UP on hover.
   Transform-only (GPU). A transparent hover-bridge + JS hover-intent keep the
   cursor from crossing dead gaps between icons, so it doesn't flicker/dismiss. */
.social-deck { position: relative; width: 28px; height: 28px; flex: 0 0 28px; }
.social-deck .sidebar-social {
    position: absolute; left: 0; bottom: 0;
    border-radius: 50%;                         /* perfect circles */
    background: var(--social-fill);             /* glassy translucent fill (frosted frame shows through) */
    box-shadow: 0 0 0 1px var(--window-border), 0 2px 6px rgba(0,0,0,0.16);
    color: var(--text-2);
    transition: transform 0.24s cubic-bezier(.23,1,.32,1), opacity 0.2s ease, color 0.15s ease, background 0.15s ease;
}
/* Hover: fill goes more solid AND the glyph jumps to full per-mode contrast — the
   same hover-color fix as the segmented control (light→dark glyph, dark→light glyph). */
.social-deck .sidebar-social:hover { background: var(--social-fill-hover); color: var(--text-1); }
/* dormant deck: LinkedIn (1) is the face; the rest peek up behind it — taller peek,
   gentler shrink, higher opacity floor + a drop shadow so the 3 behind clearly hint. */
.social-deck .sidebar-social:nth-child(1) { transform: translateY(0)     scale(1);   opacity: 1;   z-index: 4; }
.social-deck .sidebar-social:nth-child(2) { transform: translateY(-7px)  scale(.94); opacity: .8;  z-index: 3; }
.social-deck .sidebar-social:nth-child(3) { transform: translateY(-13px) scale(.88); opacity: .6;  z-index: 2; }
.social-deck .sidebar-social:nth-child(4) { transform: translateY(-18px) scale(.82); opacity: .42; z-index: 1; }
/* spread: rise into a vertical column (28px icon + 4px gap = 32px steps). 20ms stagger
   deals the deck out; collapse is instant (delay lives only in the open state). */
.social-deck.open .sidebar-social, .social-deck:focus-within .sidebar-social { opacity: 1; }
.social-deck.open .sidebar-social:nth-child(1), .social-deck:focus-within .sidebar-social:nth-child(1) { transform: translateY(0)    scale(1); }
.social-deck.open .sidebar-social:nth-child(2), .social-deck:focus-within .sidebar-social:nth-child(2) { transform: translateY(-32px) scale(1); transition-delay: .02s; }
.social-deck.open .sidebar-social:nth-child(3), .social-deck:focus-within .sidebar-social:nth-child(3) { transform: translateY(-64px) scale(1); transition-delay: .04s; }
.social-deck.open .sidebar-social:nth-child(4), .social-deck:focus-within .sidebar-social:nth-child(4) { transform: translateY(-96px) scale(1); transition-delay: .06s; }
.social-deck::after { content: ''; position: absolute; left: -8px; right: -8px; bottom: -8px; height: 54px; z-index: 0; }
.social-deck.open::after, .social-deck:focus-within::after { height: 140px; }
@media (prefers-reduced-motion: reduce) { .social-deck .sidebar-social { transition: color 0.15s ease, background 0.15s ease; } }
.sidebar-social {
    width: 28px; height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    color: var(--text-2);
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
    text-decoration: none;
}
.sidebar-social:hover { color: var(--text-1); background: var(--file-hover); }
/* Inline simple-icons brand glyphs + Heroicons envelope (fill currentColor). */
.sidebar-social svg {
    width: 15px; height: 15px;
    color: currentColor;
}
@keyframes windowJitter {
    0%, 100% { transform: translateX(0); }
    15% { transform: translateX(-3px) rotate(-0.5deg); }
    30% { transform: translateX(2px) rotate(0.3deg); }
    45% { transform: translateX(-2px) rotate(-0.3deg); }
    60% { transform: translateX(2px) rotate(0.2deg); }
    80% { transform: translateX(-1px); }
}
.window.jitter {
    animation: windowJitter 0.4s ease-out;
    box-shadow: 0 0 0 2px var(--accent), var(--window-shadow) !important;
}

/* =============================================
   MOBILE RESPONSIVE — 640px breakpoint
   ============================================= */

/* Hide mobile elements on desktop */
.mobile-top-bar,
.drawer-backdrop,
.drawer-close,
.cs-mobile-back,
.cs-section-nav { display: none; }

@media (max-width: 640px) {

/* ── Global Resets ── */
html, body {
    overflow: hidden;
    height: 100dvh;
}

/* ── Hide Desktop-Only Elements ── */
.draw-layer,
.draw-toolbar,
.tim-watermark,
#voidCanvas,
.void-vignette,
.void-warp,
.void-reset-btn,
.cmd-overlay,
.shortcuts-overlay,
.cs-tab-bar,
.sidebar-hint,
.tim-ascii,
.tree-item[data-action="void"],
.tree-item[data-action="terminal"],
.tree-item[data-action="playground"] { display: none !important; }

/* ── Mobile Top Bar ── */
.mobile-top-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    background: var(--canvas-bg);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-bottom: 1px solid var(--window-border);
    position: sticky;
    top: 0;
    z-index: 100;
}

.hamburger {
    width: 36px;
    height: 36px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px;
    border-radius: 8px;
    transition: background 0.15s;
}
.hamburger:active { background: var(--accent-soft); }
.hamburger span {
    display: block;
    width: 18px;
    height: 1.5px;
    background: var(--text-1);
    border-radius: 1px;
    transition: transform 0.3s var(--ease-entry), opacity 0.3s var(--ease-entry);
}


.mobile-mode-pills {
    display: none;
}

.mobile-mode-pill {
    font-family: var(--font-sans);
    font-size: 10px;
    padding: 4px 8px;
    border-radius: 6px;
    border: 1px solid var(--window-border);
    background: transparent;
    color: var(--text-3);
    cursor: pointer;
    transition: background var(--dur-fast) ease, color var(--dur-fast) ease, border-color var(--dur-fast) ease;
}
.mobile-mode-pill.active {
    background: var(--text-1);
    color: var(--canvas-bg);
    border-color: var(--text-1);
}

/* ── Drawer Backdrop ── */
.drawer-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.3);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s var(--ease-entry);
    z-index: 200;
}
.drawer-backdrop.open {
    opacity: 1;
    pointer-events: auto;
}

/* ── Sidebar → Drawer ── */
.sidebar {
    position: fixed !important;
    top: 0;
    left: 0;
    bottom: 0;
    width: 280px !important;
    z-index: 300;
    transform: translateX(-100%);
    transition: transform 0.4s var(--ease-entry);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    flex: none !important;
}
.sidebar.drawer-open {
    transform: translateX(0);
}
.sidebar.visible > * { opacity: 1; }

.drawer-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: none;
    border: none;
    cursor: pointer;
    border-radius: 8px;
    color: var(--text-2);
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 1;
    transition: background 0.15s;
}
.drawer-close:active { background: var(--accent-soft); }

/* ── Canvas Frame → Scrollable Container ── */
.canvas-frame {
    position: relative !important;
    inset: auto !important;
    margin: clamp(0px, calc((100vw - 320px) / 55 * 16), 16px);
    border-radius: 16px;
    height: calc(100dvh - clamp(0px, calc((100vw - 320px) / 55 * 32), 32px));
    flex-direction: column;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
}

/* ── Route Pages: overlay fills canvas-frame ── */
body.route-page .canvas-frame {
    overflow: hidden;
}
body.route-page .mobile-top-bar {
    display: none;
}
body.route-page .canvas {
    display: flex;
    flex-direction: column;
    min-height: 0;
}
body.route-page .canvas-inner {
    display: none !important;
}
body.route-page .cs-overlay {
    position: relative !important;
    inset: auto !important;
    z-index: auto !important;
    flex: 1;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    min-height: 0;
    display: block !important;
}
body.route-page .cs-overlay.open,
body.route-page .cs-overlay.sliding-in {
    opacity: 1 !important;
    pointer-events: auto !important;
}
body.route-page .cs-accent-line {
    position: sticky;
    top: 44px;
    z-index: 99;
}
body.route-page .cs-window {
    position: relative;
}
body.route-page .resume-embed {
    display: flex;
    flex-direction: column;
    height: calc(100dvh - clamp(0px, calc((100vw - 320px) / 55 * 32), 32px) - 46px - 16px);
}

/* ── Canvas → Static Flow ── */
.canvas {
    position: static !important;
    overflow: visible !important;
    flex: 1;
}

.canvas-inner {
    position: static !important;
    transform: none !important;
    display: flex !important;
    flex-direction: row;
    flex-wrap: wrap;
    gap: 14px;
    padding: 16px 14px 40px;
}

/* ── Windows → Stacked Feed ── */
.window {
    position: static !important;
    width: 100% !important;
    height: auto !important;
    left: auto !important;
    top: auto !important;
    right: auto !important;
    bottom: auto !important;
    z-index: auto !important;
    opacity: 1 !important;
    flex: 0 0 100%;
    animation: mobileWindowIn 0.5s var(--ease-entry) both;
}

/* Disable thumbnail clipping on mobile */
.window.ws-thumb {
    opacity: 1 !important;
    pointer-events: auto !important;
    overflow: visible !important;
}
.window.ws-thumb .window-content {
    display: block !important;
    max-height: none !important;
    overflow: visible !important;
}

/* ── Window Order ── every visible window gets an explicit order so none
   defaults to 0 and floats to the top. Hey → About → Tim → Projects →
   Reviews → Facsimile → Community. */
#winHero { order: 1; }
#winAbout { order: 2; }
#winProfile { order: 3; }
#winProjects { order: 4; }
#winReview1 { order: 5; }
#winFacsimile { order: 6; }
#winCommunity { order: 7; }
#winReview2, #winReview3, #winReview4 { display: none !important; }
.terminal-fixture { display: none !important; }

/* ── Staggered Entrance Animation ── */
@keyframes mobileWindowIn {
    from { opacity: 0; transform: scale(0.96) translateY(12px); }
    to { opacity: 1; transform: none; }
}
.canvas-inner > :nth-child(1) { animation-delay: 0.05s; }
.canvas-inner > :nth-child(2) { animation-delay: 0.1s; }
.canvas-inner > :nth-child(3) { animation-delay: 0.15s; }
.canvas-inner > :nth-child(4) { animation-delay: 0.2s; }
.canvas-inner > :nth-child(5) { animation-delay: 0.25s; }
.canvas-inner > :nth-child(6) { animation-delay: 0.3s; }
.canvas-inner > :nth-child(7) { animation-delay: 0.35s; }
.canvas-inner > :nth-child(8) { animation-delay: 0.4s; }

/* ── Traffic Lights (smaller on mobile) ── */
.traffic-light::before {
    width: 10px !important;
    height: 10px !important;
}
.window-titlebar {
    padding: 10px 14px;
    min-height: 36px;
    cursor: default !important;
}
.window-titlebar svg { display: none; }

/* ── Window Content ── */
.window-content {
    max-height: none !important;
    overflow: visible !important;
    padding: 14px 12px;
}


/* ── Profile Window ── */
#winProfile .window-content img {
    width: 100%;
    height: auto;
    aspect-ratio: 1/1;
    object-fit: cover;
}

/* ── Case Study Overlay → Fullscreen ── */
.cs-overlay {
    position: fixed !important;
    inset: 0 !important;
    z-index: 500 !important;
    transform: none !important;
    background: var(--canvas-bg);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Keep hidden by default */
    opacity: 0;
    pointer-events: none;
}
.cs-overlay.open,
.cs-overlay.sliding-in {
    opacity: 1 !important;
    pointer-events: auto !important;
}

.cs-overlay .cs-titlebar {
    position: sticky;
    top: 0;
    z-index: 100;
    height: 44px;
    display: flex;
    align-items: center;
    padding: 0 16px;
    background: var(--canvas-bg);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    border-bottom: 1px solid var(--window-border);
}

.cs-overlay .traffic-lights { display: none !important; }

/* ── Mobile Back Button ── */
.cs-mobile-back {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    background: none;
    border: none;
    cursor: pointer;
    border-radius: 8px;
    color: var(--text-1);
    transition: background 0.15s;
    margin-right: 8px;
    flex-shrink: 0;
}
.cs-mobile-back:active { background: var(--accent-soft); }

/* ── Mobile Hamburger (case study titlebar) ── */
.cs-mobile-hamburger {
    width: 36px;
    height: 36px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px;
    border-radius: 8px;
    margin-right: 8px;
    flex-shrink: 0;
    transition: background 0.15s;
}
.cs-mobile-hamburger:active { background: var(--accent-soft); }
.cs-mobile-hamburger span {
    display: block;
    width: 18px;
    height: 1.5px;
    background: var(--text-1);
    border-radius: 1px;
}

/* ── Case Study Section Nav ── */
.cs-section-nav {
    display: flex;
    gap: 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    position: sticky;
    top: 46px;
    z-index: 99;
    background: var(--canvas-bg);
    border-bottom: 1px solid var(--window-border);
    padding: 0 16px;
}
.cs-section-nav::-webkit-scrollbar { display: none; }

.cs-nav-item {
    font-family: var(--font-sans);
    font-size: 10px;
    letter-spacing: 0.02em;
    padding: 10px 12px;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-3);
    cursor: pointer;
    white-space: nowrap;
    transition: color var(--dur-fast) ease, border-color var(--dur-fast) ease;
    flex-shrink: 0;
}
.cs-nav-item.active {
    color: var(--text-1);
    border-bottom-color: var(--text-1);
}

/* ── Case Study Content Overrides ── */
.cs-window {
    overflow: visible !important;
    height: auto !important;
    padding: 0 16px;
}

.cs-carousel-track {
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
}
.cs-image-slot {
    flex: 0 0 85% !important;
    scroll-snap-align: start;
}

.cs-projected {
    padding: 10px 14px;
    border-left: 3px solid;
    border-radius: 8px;
    font-style: italic;
}

/* ── About Page: Carousel Sizing ── */
.about-carousel-track img {
    height: 260px !important;
}
.about-sub-images img {
    height: 120px !important;
}

/* ── Reviews Carousel ── */
.reviews-carousel {
    overflow: hidden;
    position: relative;
}
.reviews-track {
    display: flex;
    transition: transform 0.4s var(--ease-entry);
}
.review-slide {
    flex: 0 0 100%;
    min-width: 0;
}
.reviews-controls {
    display: flex;
    justify-content: center;
    gap: 6px;
    padding: 12px 0 4px;
}
.review-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    border: none;
    background: var(--text-3);
    opacity: 0.3;
    cursor: pointer;
    padding: 0;
    transition: width 0.2s var(--ease-entry), opacity 0.2s var(--ease-entry), background 0.2s ease;
}
.review-dot.active {
    width: 20px;
    border-radius: 3px;
    opacity: 0.7;
    background: var(--text-1);
}

/* ── About Next Actions ── */
.about-next-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 32px 0;
}
.about-next-btn {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px;
    background: var(--title-bar);
    border-radius: 10px;
    text-decoration: none;
    color: var(--text-1);
    transition: transform var(--dur-fast) ease-out, background var(--dur-fast) ease;
    border: none;
    cursor: pointer;
    width: 100%;
    text-align: left;
}
.about-next-btn:active { transform: scale(0.98); background: var(--window-border); }
.about-next-btn-icon { font-size: 18px; flex-shrink: 0; }
.about-next-btn-text { flex: 1; }
.about-next-btn-label { font-size: 14px; font-weight: 600; }
.about-next-btn-desc { font-size: 12px; color: var(--text-3); margin-top: 2px; }
.about-next-btn-arrow { font-size: 16px; color: var(--text-3); }

/* ── Logo Scroll (mobile sizing) ── */
.logo-scroll-wrap {
    overflow: hidden;
    padding: 16px 0;
}
.logo-scroll img {
    height: 20px !important;
}

.file-row {
    flex-direction: column;
}
.file-row {
    padding: 10px 8px;
    gap: 10px;
}
.file-hero {
    height: auto;
    width: 100%;
}
.file-icon { display: none; }

.personal-item:hover .personal-accent {
    width: 3px;
    border-radius: 2px;
}
.personal-item:active .personal-accent {
    width: 48px;
    aspect-ratio: 16/9;
    align-self: center;
    border-radius: 0;
}

} /* end @media (max-width: 640px) */

/* ============ GLASS + FRAMED SHELL (desktop) ============ */
/* Desktop-only: backdrop-filter on several surfaces is too costly for phone GPUs,
   so mobile keeps solid surfaces. Frosted chrome across all modes.
   The framed shell: the frame is a single glass tray that blurs the wallpaper
   video; the sidebar is transparent over it; the canvas is an inset rounded panel
   matted by that glass all around. One backdrop-filter layer (no nesting — nested
   filters blur the frosted parent, not the video). The terminal is a normal card
   now, so it shares the same frosted glass as every other window. */
@media (min-width: 641px) {
    .window {
        background: var(--glass-window-fill);
        -webkit-backdrop-filter: blur(28px) saturate(165%);
        backdrop-filter: blur(28px) saturate(165%);
    }
    /* Titlebar shares the frosted surface (no separate fill over the blur). */
    .window .window-titlebar {
        background: transparent;
    }
    /* Frame = glass tray. */
    .canvas-frame {
        background: var(--glass-sidebar-fill);
        -webkit-backdrop-filter: blur(40px) saturate(160%);
        backdrop-filter: blur(40px) saturate(160%);
    }
    /* Sidebar transparent over the tray (no own blur, no divider line). */
    .sidebar {
        background: transparent;
        border-right: none;
    }
    /* Canvas = inset rounded panel, matted by the glass all around. Squircle
       corners to match the windows + tab pills (was plain circular). */
    .canvas {
        margin: var(--shell-width);
        border-radius: var(--shell-radius);
        corner-shape: superellipse(1.7);
        box-shadow: 0 0 0 1px var(--sidebar-border), 0 2px 10px rgba(0,0,0,0.05);
    }
}

/* ============ HOVER-3D — canvas windows tilt toward the cursor (desktop) ============ */
/* app.js sets the per-window transform (tilt + lift, size-scaled). Here: the
   perspective plane, a fast transform transition added lazily on first hover (the
   .tilt class, so it never overrides the slower entry/workspace transforms), a
   deepened lift-shadow, and a faint top-edge sheen — the card top catching
   ambient light as it rises (subtle on dark, near-silent on light where the
   lift-shadow carries depth). Desktop-only; the sheen ::after is inert until
   hover. */
.window::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    opacity: 0;
    z-index: 2;
    background-image: linear-gradient(180deg, rgba(255,255,255,0.06) 0%, transparent 28%);
    corner-shape: inherit;
    transition: opacity 0.2s ease;
}
@media (min-width: 641px) {
    /* Flat perspective (1500 vs a punchier 800) keeps foreshortening shallow, so the
       small-angle tilt barely re-samples the text bitmap = sharp. */
    .canvas-inner { perspective: 1500px; }
    .window.tilt {
        transition: transform 0.14s ease-out,
                    opacity 0.35s var(--ease-entry),
                    background var(--dur-mode) ease,
                    box-shadow var(--dur-base) ease;
    }
    /* Crispness rule: NEVER add will-change / backface-visibility / translateZ /
       opacity<1 / filter to the cards. Each forces a GPU layer that drops LCD
       subpixel anti-aliasing (soft/grainy text) and pins the raster. The tilt is a
       small-angle rotateX/Y + translateY lift (app.js); at rest the transform is
       cleared so the layer de-promotes and text is fully subpixel-crisp. */
    .window:hover { box-shadow: var(--window-shadow-active); }
    .window:hover::after { opacity: 1; }
}

/* ============ REDUCED MOTION ============ */
/* Kill movement (transforms, slide-ins, infinite loops) but preserve accessible
   cross-fades — instant snaps feel jarring even when motion is unwanted. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    /* Preserve opacity cross-fades on the load-bearing transitions */
    .cs-overlay.sliding-in,
    .cs-overlay.closing {
        transition: opacity var(--dur-base) var(--ease-entry) !important;
        transform: none !important;
    }
    .desktop-video video { display: none; }
}
