/* 
  FILE: css/site.css
  SECTIONS:
    L001–L027  :root variables
    L029–L267  Tailwind utilities
    L268–L281  Lenis smooth scroll
    L282–L287  Scrollbar
    L288–L306  Skip nav / Focus
    L315–L360  Loading screen
    L361–L527  Navbar + Hero
    L528–L575  Hero
    L576–L792  Section helpers + Cards
    L793–L855  Nav dropdown + Palette + Mobile menu
    L886–L932  Terminal
    L933–L992  SOC Lab
    L993–L1209 Attack path
    L1210–L1318 Navbar clock + Feed + Badges + Tickets + Easing + 3D tilt
    L1319–L1354 Section rail
    L1355–L1422 Ticker + Typewriter + Tint chapters
    L1423–L1476 Mission + Compact nav + Section accent
    L1477–L1701 Defense diagram + Widgets + Modal + Mobile
    L1702–L2263 Mobile responsiveness
*/
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:JetBrains Mono,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0}.bottom-6{bottom:1.5rem}.bottom-8{bottom:2rem}.left-1\/2{left:50%}.left-6{left:1.5rem}.right-6{right:1.5rem}.top-6{top:1.5rem}.z-10{z-index:10}.z-\[2\]{z-index:2}.mx-auto{margin-left:auto;margin-right:auto}.my-4{margin-top:1rem;margin-bottom:1rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-7{margin-bottom:1.75rem}.mb-8{margin-bottom:2rem}.ml-3{margin-left:.75rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-10{margin-top:2.5rem}.mt-12{margin-top:3rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-2\.5{height:.625rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-9{height:2.25rem}.h-\[17px\]{height:17px}.h-\[18px\]{height:18px}.h-full{height:100%}.min-h-screen{min-height:100vh}.w-10{width:2.5rem}.w-2\.5{width:.625rem}.w-3\.5{width:.875rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-9{width:2.25rem}.w-\[17px\]{width:17px}.w-\[18px\]{width:18px}.w-\[calc\(100\%-2rem\)\]{width:calc(100% - 2rem)}.w-full{width:100%}.min-w-0{min-width:0}.min-w-\[200px\]{min-width:200px}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-5xl{max-width:64rem}.max-w-6xl{max-width:72rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.translate-y-\[-1px\]{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-1px\]{--tw-translate-y:-1px}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.resize{resize:both}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-10{gap:2.5rem}.gap-12{gap:3rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.divide-stroke>:not([hidden])~:not([hidden]){--tw-divide-opacity:1;border-color:rgb(27 39 64/var(--tw-divide-opacity,1))}.self-start{align-self:flex-start}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-stroke{--tw-border-opacity:1;border-color:rgb(27 39 64/var(--tw-border-opacity,1))}.bg-\[\#28c840\]{--tw-bg-opacity:1;background-color:rgb(40 200 64/var(--tw-bg-opacity,1))}.bg-\[\#febc2e\]{--tw-bg-opacity:1;background-color:rgb(254 188 46/var(--tw-bg-opacity,1))}.bg-\[\#ff5f57\]{--tw-bg-opacity:1;background-color:rgb(255 95 87/var(--tw-bg-opacity,1))}.bg-stroke{--tw-bg-opacity:1;background-color:rgb(27 39 64/var(--tw-bg-opacity,1))}.bg-surface{--tw-bg-opacity:1;background-color:rgb(13 21 38/var(--tw-bg-opacity,1))}.bg-surface\/40{background-color:rgba(13,21,38,.4)}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-7{padding-left:1.75rem;padding-right:1.75rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-16{padding-bottom:4rem}.pb-24{padding-bottom:6rem}.pl-10{padding-left:2.5rem}.pt-24{padding-top:6rem}.pt-28{padding-top:7rem}.pt-8{padding-top:2rem}.text-center{text-align:center}.font-mono{font-family:JetBrains Mono,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[0\.65rem\]{font-size:.65rem}.text-\[0\.72rem\]{font-size:.72rem}.text-\[0\.85rem\]{font-size:.85rem}.text-\[0\.92rem\]{font-size:.92rem}.text-\[0\.95rem\]{font-size:.95rem}.text-base{font-size:1rem;line-height:1.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.uppercase{text-transform:uppercase}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-\[1\.05\]{line-height:1.05}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.tracking-\[0\.12em\]{letter-spacing:.12em}.tracking-\[0\.14em\]{letter-spacing:.14em}.tracking-\[0\.16em\]{letter-spacing:.16em}.tracking-\[0\.18em\]{letter-spacing:.18em}.tracking-\[0\.22em\]{letter-spacing:.22em}.tracking-\[0\.24em\]{letter-spacing:.24em}.tracking-\[0\.28em\]{letter-spacing:.28em}.tracking-\[0\.2em\]{letter-spacing:.2em}.tracking-\[0\.32em\]{letter-spacing:.32em}.tracking-\[0\.3em\]{letter-spacing:.3em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-accent{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-muted{--tw-text-opacity:1;color:rgb(124 138 163/var(--tw-text-opacity,1))}.text-txt{--tw-text-opacity:1;color:rgb(232 237 245/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-80{opacity:.8}.ring{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.hover\:border-accent:hover{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.hover\:text-txt:hover{--tw-text-opacity:1;color:rgb(232 237 245/var(--tw-text-opacity,1))}.group:focus-within .group-focus-within\:block{display:block}.group:hover .group-hover\:block{display:block}.group:hover .group-hover\:translate-x-1{--tw-translate-x:0.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:text-txt{--tw-text-opacity:1;color:rgb(232 237 245/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:block{display:block}.sm\:w-auto{width:auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}}@media (min-width:768px){.md\:bottom-8{bottom:2rem}.md\:left-10{left:2.5rem}.md\:right-10{right:2.5rem}.md\:top-6{top:1.5rem}.md\:top-8{top:2rem}.md\:flex{display:flex}.md\:hidden{display:none}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-start{align-items:flex-start}.md\:justify-between{justify-content:space-between}.md\:gap-4{gap:1rem}.md\:p-8{padding:2rem}.md\:px-5{padding-left:1.25rem;padding-right:1.25rem}.md\:py-32{padding-bottom:8rem}.md\:pt-32,.md\:py-32{padding-top:8rem}.md\:text-2xl{font-size:1.5rem;line-height:2rem}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}.md\:text-4xl{font-size:2.25rem;line-height:2.5rem}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-base{font-size:1rem;line-height:1.5rem}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}}@media (min-width:1024px){.lg\:mx-0{margin-left:0;margin-right:0}.lg\:flex{display:flex}.lg\:max-w-none{max-width:none}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.lg\:justify-start{justify-content:flex-start}.lg\:gap-10{gap:2.5rem}.lg\:text-left{text-align:left}}
    :root {
      --bg: #05070d;
      --surface: #0d1526;
      --text: #ffffff;
      --muted: #e9effc;
      --stroke: #1b2740;
      --gradient-accent: linear-gradient(90deg, #1e3a5f 0%, #3b82f6 100%);
      --glow: rgba(59, 130, 246, 0.35);
      --sev-critical: #ef4444;
      --sev-high: #f97316;
      --sev-medium: #eab308;
      --sev-low: #22c55e;
      /* Semantic colour roles */
      --cyan-live: #22d3ee;          /* live-data state (counters, stats, terminal readouts) */
      --font-body: 'Inter', sans-serif;
      --font-display: 'JetBrains Mono', monospace;
      --font-mono: 'JetBrains Mono', monospace;
    }

    /* ---------- Missing Tailwind responsive utilities ---------- */
    .grid { display: grid; }
    .flex { display: flex; }
    .hidden { display: none; }
    .block { display: block; }
    .inline-block { display: inline-block; }
    .inline-flex { display: inline-flex; }

    /* Flex utilities */
    .flex-col { flex-direction: column; }
    .flex-wrap { flex-wrap: wrap; }
    .items-center { align-items: center; }
    .items-start { align-items: flex-start; }
    .justify-center { justify-content: center; }
    .justify-between { justify-content: space-between; }
    .gap-2 { gap: 0.5rem; }
    .gap-3 { gap: 0.75rem; }
    .gap-4 { gap: 1rem; }
    .gap-6 { gap: 1.5rem; }
    .gap-10 { gap: 2.5rem; }
    .gap-12 { gap: 3rem; }

    /* Grid utilities */
    .grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
    .grid-cols-3 { grid-template-columns: repeat(3, 1fr); }

    /* Spacing */
    .p-5 { padding: 1.25rem; }
    .p-6 { padding: 1.5rem; }
    .px-4 { padding-left: 1rem; padding-right: 1rem; }
    .px-5 { padding-left: 1.25rem; padding-right: 1.25rem; }
    .px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }
    .px-7 { padding-left: 1.75rem; padding-right: 1.75rem; }
    .py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; }
    .py-3 { padding-top: 0.75rem; padding-bottom: 0.75rem; }
    .py-4 { padding-top: 1rem; padding-bottom: 1rem; }
    .py-12 { padding-top: 3rem; padding-bottom: 3rem; }
    .py-16 { padding-top: 4rem; padding-bottom: 4rem; }
    .pt-24 { padding-top: 6rem; }
    .pt-28 { padding-top: 7rem; }
    .pb-24 { padding-bottom: 6rem; }
    .pb-0 { padding-bottom: 0; }
    .pb-4 { padding-bottom: 1rem; }
    .mb-3 { margin-bottom: 0.75rem; }
    .mb-4 { margin-bottom: 1rem; }
    .mb-5 { margin-bottom: 1.25rem; }
    .mb-6 { margin-bottom: 1.5rem; }
    .mb-7 { margin-bottom: 1.75rem; }
    .mb-8 { margin-bottom: 2rem; }
    .mb-10 { margin-bottom: 2.5rem; }
    .mb-12 { margin-bottom: 3rem; }
    .mt-1 { margin-top: 0.25rem; }
    .mt-2 { margin-top: 0.5rem; }
    .mt-4 { margin-top: 1rem; }
    .mt-6 { margin-top: 1.5rem; }
    .mt-8 { margin-top: 2rem; }
    .mt-10 { margin-top: 2.5rem; }
    .mt-12 { margin-top: 3rem; }
    .mx-auto { margin-left: auto; margin-right: auto; }

    /* Sizing */
    .w-full { width: 100%; }
    .h-full { height: 100%; }
    .h-9 { height: 2.25rem; }
    .h-10 { height: 2.5rem; }
    .w-9 { width: 2.25rem; }
    .w-10 { width: 2.5rem; }
    .w-5 { width: 1.25rem; }
    .h-5 { height: 1.25rem; }
    .w-4 { width: 1rem; }
    .h-4 { height: 1rem; }
    .w-2\.5 { width: 0.625rem; }
    .h-2\.5 { height: 0.625rem; }
    .max-w-3xl { max-width: 48rem; }
    .max-w-5xl { max-width: 64rem; }
    .max-w-6xl { max-width: 72rem; }
    .max-w-xl { max-width: 36rem; }
    .max-w-2xl { max-width: 42rem; }
    .min-w-0 { min-width: 0; }

    /* Typography */
    .text-sm { font-size: 0.875rem; line-height: 1.25rem; }
    .text-base { font-size: 1rem; line-height: 1.5rem; }
    .text-lg { font-size: 1.125rem; line-height: 1.75rem; }
    .text-xl { font-size: 1.25rem; line-height: 1.75rem; }
    .text-2xl { font-size: 1.5rem; line-height: 2rem; }
    .text-3xl { font-size: 1.875rem; line-height: 2.25rem; }
    .text-4xl { font-size: 2.25rem; line-height: 2.5rem; }
    .text-5xl { font-size: 3rem; line-height: 1; }
    .text-xs { font-size: 0.75rem; line-height: 1rem; }
    .text-base { font-size: 1rem; line-height: 1.5rem; }
    .font-bold { font-weight: 700; }
    .font-medium { font-weight: 500; }
    .uppercase { text-transform: uppercase; }
    .text-center { text-align: center; }
    .text-left { text-align: left; }
    .leading-relaxed { line-height: 1.625; }
    .leading-snug { line-height: 1.375; }
    .tracking-wide { letter-spacing: 0.025em; }
    .tracking-tight { letter-spacing: -0.025em; }
    .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

    /* Colors */
    .text-txt { color: var(--text); }
    .text-muted { color: var(--muted); }
    .text-accent { color: #3b82f6; }
    .text-white { color: #fff; }
    .bg-surface { background-color: var(--surface); }

    /* Borders */
    .rounded-full { border-radius: 9999px; }
    .rounded-xl { border-radius: 0.75rem; }
    .rounded-2xl { border-radius: 1rem; }
    .border { border-width: 1px; border-style: solid; }
    .border-t { border-top-width: 1px; border-top-style: solid; }
    .border-b { border-bottom-width: 1px; border-bottom-style: solid; }
    .border-stroke { border-color: var(--stroke); }
    .divide-y > * + * { border-top-width: 1px; border-top-style: solid; border-color: var(--stroke); }

    /* Positioning */
    .relative { position: relative; }
    .absolute { position: absolute; }
    .fixed { position: fixed; }
    .inset-0 { top: 0; right: 0; bottom: 0; left: 0; }
    .top-6 { top: 1.5rem; }
    .left-1\/2 { left: 50%; }
    .bottom-8 { bottom: 2rem; }
    .-translate-x-1\/2 { transform: translateX(-50%); }
    .-translate-y-1\/2 { transform: translateY(-50%); }
    .z-10 { z-index: 10; }

    /* Overflow */
    .overflow-hidden { overflow: hidden; }
    .overflow-y-auto { overflow-y: auto; }

    /* Opacity */
    .opacity-80 { opacity: 0.8; }

    /* Pointer */
    .cursor-pointer { cursor: pointer; }

    /* Misc */
    .shrink-0 { flex-shrink: 0; }
    .whitespace-nowrap { white-space: nowrap; }
    .min-h-screen { min-height: 100vh; }

    /* Responsive sm: (640px) */
    @media (min-width: 640px) {
      .sm\:flex-row { flex-direction: row; }
      .sm\:w-auto { width: auto; }
      .sm\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
      .sm\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }}

    /* Responsive md: (768px) */
    @media (min-width: 768px) {
      .md\:flex { display: flex; }
      .md\:hidden { display: none; }
      .md\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
      .md\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
      .md\:grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
      .md\:text-base { font-size: 1rem; line-height: 1.5rem; }
      .md\:p-6 { padding: 1.5rem; }
      .md\:p-8 { padding: 2rem; }
      .md\:px-6 { padding-left: 1.5rem; padding-right: 1.5rem; }
      .md\:px-10 { padding-left: 2.5rem; padding-right: 2.5rem; }
      .md\:py-16 { padding-top: 4rem; padding-bottom: 4rem; }
      .md\:py-32 { padding-top: 8rem; padding-bottom: 8rem; }
      .md\:gap-4 { gap: 1rem; }
      .md\:gap-6 { gap: 1.5rem; }
      .md\:gap-10 { gap: 2.5rem; }
      .md\:mb-4 { margin-bottom: 1rem; }
      .md\:mb-8 { margin-bottom: 2rem; }
      .md\:mb-12 { margin-bottom: 3rem; }
      .md\:mt-1 { margin-top: 0.25rem; }
      .md\:top-6 { top: 1.5rem; }
      .md\:left-10 { left: 2.5rem; }
      .md\:bottom-8 { bottom: 2rem; }
      .md\:right-10 { right: 2.5rem; }
      .md\:text-4xl { font-size: 2.25rem; line-height: 2.5rem; }
      .md\:text-5xl { font-size: 3rem; line-height: 1; }}

    /* Responsive lg: (1024px) */
    @media (min-width: 1024px) {
      .lg\:flex { display: flex; }
      .lg\:hidden { display: none; }
      .lg\:grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
      .lg\:grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
      .lg\:grid-cols-5 { grid-template-columns: repeat(5, 1fr); }
      .lg\:col-span-2 { grid-column: span 2 / span 2; }
      .lg\:col-span-3 { grid-column: span 3 / span 3; }
      .lg\:text-left { text-align: left; }
      .lg\:justify-start { justify-content: flex-start; }
      .lg\:max-w-none { max-width: none; }
      .lg\:mx-0 { margin-left: 0; margin-right: 0; }
      .lg\:gap-10 { gap: 2.5rem; }}

    * { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }

    a:active, button:active, .cursor-pointer:active, [role="button"]:active { opacity: 0.7; transition: opacity 0.1s; }

    body { -webkit-text-size-adjust: 100%; touch-action: manipulation; }

    html { overflow-y: scroll; scrollbar-gutter: stable; }
    html, body {
      margin: 0;
      padding: 0;
    }

    /* ---------- Lenis smooth scroll reset ---------- */
    html.lenis, html.lenis body { height: auto; }
    .lenis.lenis-smooth { scroll-behavior: auto !important; }

    body {
      background: var(--bg);
      color: var(--text);
      font-family: var(--font-body);
      font-weight: 400;
      overflow-x: hidden;
    }

    ::selection { background: rgba(59, 130, 246, 0.30); color: #ffffff; }

    /* ---------- Scrollbar (kept on-palette) ---------- */
    ::-webkit-scrollbar { width: 10px; }
    ::-webkit-scrollbar-track { background: #05070d; }
    ::-webkit-scrollbar-thumb { background: #1b2740; border-radius: 8px; }
    ::-webkit-scrollbar-thumb:hover { background: #1e3a5f; }

    /* ---------- Skip navigation link ---------- */
    .skip-nav {
      position: absolute;
      top: -100%;
      left: 16px;
      z-index: 200;
      padding: 12px 24px;
      background: var(--surface);
      color: var(--text);
      border: 1px solid var(--stroke);
      border-radius: 0 0 8px 8px;
      font-family: var(--font-mono);
      font-size: 0.85rem;
      font-weight: 500;
      text-decoration: none;
      transition: top 0.2s ease;
    }
    .skip-nav:focus { top: 0; }

    /* ---------- Focus visible styles ---------- */
    :focus-visible {
      outline: 2px solid #3b82f6;
      outline-offset: 2px;
    }

    /* ---------- Scroll lock handled by JS (overflow: hidden) ---------- */

    /* ---------- Hide page scrollbar while loading screen is up ---------- */
    html:has(#loader:not(.done)) { overflow: hidden; }
    html:has(#loader:not(.done)) .star,
    html:has(#loader:not(.done)) #starfield,
    html:has(#loader:not(.done)) #bg-tint {
      animation: none !important;
    }

    /* ---------- Loading screen ---------- */
    #loader {
      position: fixed;
      inset: 0;
      z-index: 100;
      background: var(--bg);
      display: flex;
      align-items: center;
      justify-content: center;
      transition: opacity 0.6s ease, visibility 0.6s ease;
    }
    #loader.done { opacity: 0; visibility: hidden; pointer-events: none; }

    #loader-word {
      font-family: var(--font-display);
      font-weight: 700;
      letter-spacing: -0.03em;
      font-size: clamp(2.6rem, 9vw, 6rem);
      line-height: 1;
      opacity: 0;
      color: var(--text);
      animation: word-in 0.9s ease 0.35s forwards;
    }
    @keyframes word-in {
      from { opacity: 0; transform: translateY(24px); }
      to   { opacity: 1; transform: translateY(0); }
    }

    #loader-word.l-anim .l-char { opacity: 0; animation: l-char-in 0.3s ease-out forwards; }
    @keyframes l-char-in {
      from { opacity: 0; transform: translateY(22px); }
      to   { opacity: 1; transform: translateY(0); }
    }

    #loader-bar-track {
      position: absolute;
      left: 0; right: 0; bottom: 0;
      height: 3px;
      background: rgba(27, 39, 64, 0.6);
    }
    #loader-bar {
      height: 100%;
      width: 100%;
      background: var(--gradient-accent);
      box-shadow: 0 0 14px var(--glow), 0 0 32px var(--glow);
      transform: scaleX(0);
      transform-origin: left center;
    }

    /* ---------- Navbar (docker → full-width glass) ----------
       header is always fixed top-0 full-width. Only nav-pill morphs.   */
    header {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      z-index: 50;
      pointer-events: none;
    }
    header * { pointer-events: auto; }

    .nav-pill {
      position: relative;
      margin: 0 auto;
      max-width: 48rem;
      width: calc(100% - 2rem);
      border-radius: 9999px;
      background: rgba(210, 220, 245, 0.08);
      border: 1px solid rgba(255, 255, 255, 0.1);
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
      transform: translateY(1rem);
      /* NOTE: backdrop-filter is deliberately NOT in will-change or the transition
         list. It is a fixed, full-width bar; animating/among-hinting the blur made
         the GPU re-rasterise the whole strip behind it on every smooth-scroll frame
         (Lenis glides ~1s after each wheel notch) — that was the page-wide scroll
         lag. Blur radius is now static and small; only cheap props transition. */
      will-change: border-radius, background, box-shadow, transform, padding, width, max-width;
      transition: background 0.8s cubic-bezier(0.4, 0, 0.2, 1),
                   box-shadow 0.8s cubic-bezier(0.4, 0, 0.2, 1),
                   width 0.8s cubic-bezier(0.4, 0, 0.2, 1),
                   max-width 0.8s cubic-bezier(0.4, 0, 0.2, 1),
                   border-radius 0.8s cubic-bezier(0.4, 0, 0.2, 1),
                   padding 0.8s cubic-bezier(0.4, 0, 0.2, 1),
                   border-width 0.8s cubic-bezier(0.4, 0, 0.2, 1),
                   transform 0.8s cubic-bezier(0.4, 0, 0.2, 1);
    }

    @supports (backdrop-filter: blur(10px)) {
      .nav-pill {
        background: rgba(210, 220, 245, 0.06);
        -webkit-backdrop-filter: blur(6px);
        backdrop-filter: blur(6px);
      }}

    header.scrolled .nav-pill {
      background: rgba(18, 26, 44, 0.78);
      box-shadow: 0 4px 32px rgba(0, 0, 0, 0.35);
      -webkit-backdrop-filter: blur(6px);
      backdrop-filter: blur(6px);
      width: 100%;
      max-width: 72rem;
      border-radius: 0.75rem;
      padding: 0.6rem 2.5rem;
      border-width: 0;
      transform: translateY(0);
    }
    @media (max-width: 768px) {
      .nav-pill, header.scrolled .nav-pill {
        -webkit-backdrop-filter: none;
        backdrop-filter: none;
      }
      #starfield span { animation: none !important; }
    }

    /* Bottom border line — fades in on scroll via GSAP */
    .nav-border-line {
      position: absolute;
      left: 0;
      right: 0;
      bottom: -1px;
      height: 1px;
      background: linear-gradient(90deg, transparent 4%, rgba(255, 255, 255, 0.08) 15%, rgba(255, 255, 255, 0.08) 85%, transparent 96%);
      opacity: 0;
      pointer-events: none;
    }

    /* Scrolled class toggle — no layout changes, all handled by GSAP */

    /* Twinkling stars inside the header bar */
    .nav-pill .star {
      position: absolute;
      border-radius: 50%;
      background: #fff;
      box-shadow: 0 0 3px 1px rgba(255,255,255,0.4);
      pointer-events: none;
      animation: star-twinkle 3s ease-in-out infinite;
    }
    #nav-clock { color: var(--muted); }
    @keyframes star-twinkle {
      0%, 100% { opacity: 0.15; transform: scale(0.6); }
      50% { opacity: 1; transform: scale(1.2); box-shadow: 0 0 5px 2px rgba(255,255,255,0.6); }
    }

    /* Full-page background starfield */
    #starfield {
      position: fixed;
      inset: 0;
      z-index: -1;
      pointer-events: none;
      overflow: hidden;
    }
    #starfield span {
      position: absolute;
      border-radius: 50%;
      background: #fff;
      pointer-events: none;
      animation: star-pulse var(--dur) ease-in-out infinite alternate;
      animation-delay: var(--delay);
    }
    @keyframes star-pulse {
      0% { opacity: 0.15; transform: scale(0.6); }
      100% { opacity: 1; transform: scale(1.2); }
    }

    .nav-link {
      color: #e2e8f0;
      transition: color 0.25s ease;
      position: relative;
      font-size: 0.92rem;
      backface-visibility: hidden;
      -webkit-font-smoothing: antialiased;
    }
    .nav-link::after {
      content: '';
      position: absolute;
      left: 0;
      bottom: -2px;
      width: 0;
      height: 1.5px;
      background: linear-gradient(90deg, #3b82f6, #60a5fa);
      border-radius: 1px;
      transition: width 0.3s cubic-bezier(0.22, 1, 0.36, 1);
    }
    .nav-link:hover {
      color: #ffffff;
    }
    .nav-link:hover::after {
      width: 100%;
    }

    /* Gradient border hover for CTA buttons */
    .btn-gradient-border {
      position: relative;
      background:
        linear-gradient(#0d1526, #0d1526) padding-box,
        linear-gradient(90deg, #1b2740, #1b2740) border-box;
      border: 1px solid transparent;
      transition: background 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease;
    }
    .btn-gradient-border:hover {
      background:
        linear-gradient(#0d1526, #0d1526) padding-box,
        linear-gradient(90deg, #1e3a5f 0%, #3b82f6 100%) border-box;
    }
    .download-btn {
      animation: btn-float-wobble 3s ease-in-out infinite;
      box-shadow: 0 0 24px var(--glow), 0 0 48px color-mix(in srgb, var(--glow) 30%, transparent);
    }
    .download-btn:hover {
      animation-duration: 1.5s;
      box-shadow: 0 0 40px var(--glow), 0 0 80px color-mix(in srgb, var(--glow) 40%, transparent);
    }
    @keyframes btn-float-wobble {
      0%, 100% { transform: translateY(0) rotate(0deg); }
      25% { transform: translateY(-6px) rotate(-0.5deg); }
      50% { transform: translateY(-8px) rotate(0.5deg); }
      75% { transform: translateY(-3px) rotate(-0.3deg); }
    }
    .chevron-arrow {
      opacity: 0.5;
      transition: opacity 0.3s ease, transform 0.3s ease;
    }
    .download-btn:hover .left-arrow {
      opacity: 1;
      transform: translateX(-6px);
    }
    .download-btn:hover .right-arrow {
      opacity: 1;
      transform: translateX(6px);
    }
    .btn-solid-gradient {
      background: var(--gradient-accent);
      transition: box-shadow 0.3s ease, transform 0.3s ease, filter 0.3s ease;
    }
    .btn-solid-gradient:hover {
      box-shadow: 0 0 24px var(--glow);
      filter: brightness(1.1);
    }

    /* ---------- Hero ---------- */
    #hero-canvas {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      display: block;
    }
    .hero-overlay {
      position: absolute;
      inset: 0;
      background: rgba(3, 5, 10, 0.20);
    }
    .hero-fade {
      position: absolute;
      left: 0; right: 0; bottom: 0;
      height: 12rem;
      background: linear-gradient(to top, #05070d 0%, transparent 100%);
      pointer-events: none;
    }

    /* Scroll indicator */
    .scroll-line {
      width: 1px;
      height: 56px;
      background: var(--stroke);
      position: relative;
      overflow: hidden;
    }
    .scroll-dot {
      position: absolute;
      left: 50%;
      top: 0;
      width: 5px;
      height: 5px;
      margin-left: -2.5px;
      border-radius: 9999px;
      background: #3b82f6;
      box-shadow: 0 0 8px var(--glow), 0 0 16px var(--glow);
      animation: scroll-down 1.5s cubic-bezier(0.65, 0, 0.35, 1) infinite;
    }
    @keyframes scroll-down {
      0%   { transform: translateY(-8px); opacity: 0; }
      25%  { opacity: 1; }
      75%  { opacity: 1; }
      100% { transform: translateY(56px); opacity: 0; }
    }

    /* ---------- Section containment ---------- */
    /* Isolates layout+paint per section so scrolling one stops re-validating
       the page. Skipped where unsafe: #about + #investigations host
       pinType:fixed pins (containment would re-anchor them), #home has
       overflowing hero decor, #experience/#soc-lab are hands-off. */
    #mission, #defense-depth, #skills, #attack-coverage,
    #live-activity, #credentials, #contact, #ticker {
      contain: layout paint;
    }

    /* ---------- Section helpers ---------- */
    .eyebrow {
      font-family: var(--font-mono);
      font-size: 0.72rem;
      letter-spacing: 0.22em;
      color: var(--muted);
      text-transform: uppercase;
    }
    .eyebrow .sec-num { color: #60a5fa; }
    .display-h {
      font-family: var(--font-display);
      font-weight: 700;
      font-style: normal;
      letter-spacing: -0.03em;
    }
    .hero-display { font-size: clamp(2.5rem, 7vw, 6rem); }

    /* ---------- Cards ---------- */
    .card {
      position: relative;
      background: var(--surface);
      border: 1px solid var(--stroke);
      transition: transform 0.35s ease, box-shadow 0.35s ease, border-color 0.35s ease;
      backface-visibility: hidden;
    }
    /* Layer only while interacting — base rule stays unpromoted to save VRAM. */
    .card:hover { will-change: transform; }
    /* cursor-reactive spotlight (position driven by --mx/--my from JS) */
    .card::after {
      content: '';
      position: absolute;
      inset: 0;
      border-radius: inherit;
      background: radial-gradient(250px circle at var(--mx, 50%) var(--my, 50%), rgba(59, 130, 246, 0.08), transparent 70%);
      opacity: 0;
      transition: opacity 0.4s ease;
      pointer-events: none;
    }
    .card:hover::after { opacity: 1; }
    .card:hover {
      border-color: rgba(59, 130, 246, 0.45);
      box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5), 0 0 24px var(--glow);
    }

    /* ---------- Skill cards (compact tool categories) ---------- */
    #skills-grid {
      grid-template-columns: repeat(4, 1fr);
    }
    .skill-card {
      position: relative;
      background: linear-gradient(135deg, rgba(14, 24, 46, 0.95), rgba(10, 18, 34, 0.98));
      border: 1.5px solid color-mix(in srgb, var(--cat-color, #3b82f6) 30%, var(--stroke));
      border-radius: 0.75rem;
      padding: 0.85rem 1rem;
      transform-style: preserve-3d;
      transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
      transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
                  box-shadow 0.35s ease;
    }
    /* Layer only while interacting — base rule stays unpromoted to save VRAM. */
    .skill-card:hover { will-change: transform; }
    .skill-card::after {
      content: '';
      position: absolute;
      inset: 0;
      border-radius: inherit;
      background: radial-gradient(250px circle at var(--mx, 50%) var(--my, 50%),
        color-mix(in srgb, var(--cat-color, #3b82f6) 10%, transparent),
        transparent 70%);
      opacity: 0;
      transition: opacity 0.4s ease;
      pointer-events: none;
    }
    .skill-card:hover::after { opacity: 1; }
    .skill-card:hover {
      box-shadow: 0 14px 40px rgba(0, 0, 0, 0.5),
                  0 0 30px color-mix(in srgb, var(--cat-color, #3b82f6) 25%, transparent);
      transform: translateY(-4px);
    }
    .cat-header {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      margin-bottom: 0.35rem;
      position: relative;
      z-index: 1;
    }
    .cat-num {
      font-family: 'Chakra Petch', monospace;
      font-size: 0.78rem;
      font-weight: 600;
      letter-spacing: 0.04em;
      color: var(--cat-color, #3b82f6);
      line-height: 1;
    }
    .cat-name {
      font-family: var(--font-mono);
      font-size: 0.8rem;
      font-weight: 500;
      letter-spacing: 0.1em;
      color: var(--muted);
      text-transform: uppercase;
      line-height: 1;
    }
    .cat-track {
      width: 100%;
      height: 1px;
      background: color-mix(in srgb, var(--cat-color, #3b82f6) 15%, transparent);
      margin-bottom: 0.65rem;
      position: relative;
      z-index: 1;
    }
    .skill-chips {
      display: flex;
      flex-wrap: wrap;
      gap: 0.35rem;
      position: relative;
      z-index: 1;
      max-height: calc(2 * (0.6rem + 0.75rem * 1.4) + 0.35rem);
      overflow: hidden;
    }
    .skill-chip {
      padding: 0.3rem 0.6rem;
      border-radius: 4px;
      font-family: var(--font-mono);
      font-size: 0.75rem;
      color: color-mix(in srgb, var(--chip-color, #3b82f6) 80%, #ffffff);
      background: color-mix(in srgb, var(--chip-color, #3b82f6) 8%, transparent);
      border: 1px solid color-mix(in srgb, var(--chip-color, #3b82f6) 18%, transparent);
      cursor: default;
      transition: color 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
    }
    .skill-chip:hover {
      color: #ffffff;
      border-color: color-mix(in srgb, var(--chip-color, #3b82f6) 60%, transparent);
      box-shadow: 0 0 12px color-mix(in srgb, var(--chip-color, #3b82f6) 30%, transparent);
      transform: translateY(-2px);
    }

    /* ---------- Hanging cards — dual-rope (left + right pins) ---------- */
    .skill-card-wrapper {
      display: flex;
      flex-direction: column;
      align-items: stretch;
      transform-origin: center top;
    }
    .skill-card-wrapper.swaying {
      animation: sway 4s ease-in-out infinite;
      will-change: transform;
    }
    .ropes-container {
      position: relative;
      width: 100%;
      height: 60px;
      flex-shrink: 0;
    }
    .ropes-container svg {
      display: block;
      width: 100%;
      height: 100%;
      overflow: visible;
    }
    .squiggle-path {
      fill: none;
      stroke-width: 1.2;
      stroke-linecap: round;
      opacity: 0.6;
    }
    .anchor-pin {
      position: absolute;
      top: 0;
      left: 50%;
      transform: translateX(-50%);
      width: 8px;
      height: 8px;
      border-radius: 50%;
      z-index: 2;
    }
    @keyframes sway {
      0%, 100% { transform: rotate(-1.1deg); }
      50% { transform: rotate(1.1deg); }
    }

    /* ============ PROJECT SHOWCASE ============ */

    /* Horizontal slider — the strip is one screen tall and scrolls sideways
       between full-viewport project panels. Native scroll (touch / trackpad) +
       mouse click-and-drag + on-screen arrows + rail, all wired in main.js.
       No pin, no scroll-hijacking: vertical scroll just moves the page. */
    #projects-pinned {
      position: relative;
      z-index: 2;
      width: 100%;
      height: 100vh;
      overflow: hidden;
      background: #05070d;
    }
    #projects-track {
      display: flex;
      flex-direction: row;
      height: 100%;
      overflow-x: auto;
      overflow-y: hidden;
      /* snap: none, DELIBERATELY — restored after proximity proved to fight
         the wheel handler below (per-tick direct scrollLeft sets). Snap
         re-evaluates after every programmatic set and drags the strip back,
         so text zones felt stuck while image zones (native scroll) glided.
         Documented conflict (SO 72703101 / Mozilla bug 1753188). The 82vw
         peek + edge fades carry the scroll cue instead — no snap needed. */
      /* Do not let snap physics fight wheel/trackpad momentum. */
      scroll-snap-type: none;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
      -ms-overflow-style: none;
      cursor: default;
      overscroll-behavior-x: contain;
      touch-action: pan-x pan-y pinch-zoom;
    }
    #projects-track::-webkit-scrollbar { display: none; }

    /* Project panel — 82vw slide in the horizontal strip, so the next
       project peeks ~18% on the right edge as a static scroll cue.
       (Mobile + reduced-motion layouts below force 100% — untouched.) */
    .project-panel {
      position: relative;
      flex: 0 0 82vw;
      width: 82vw;
      height: 100%;
      scroll-snap-align: start;
      display: flex;
      /* top-align, not center — centering a fixed-height text column inside a
         tall (e.g. 1080px) panel left a big dead gap above the badge. A small
         fixed top offset keeps the badge near the top on any viewport height. */
      align-items: flex-start;
      gap: 2.5rem;
      overflow: hidden;
      padding: 1.75rem 4.5rem 3rem;
      background: #05070d;
      /* Keep all five panels laid out before the strip enters view. Using
         content-visibility:auto here caused a large activation hitch as the
         full-screen panels became visible during page scrolling. */
      contain: layout paint;
    }
    @media (max-width: 1400px) { .project-panel { padding: 1.5rem 3rem 4rem; gap: 1.75rem; }}

    /* Reduced-motion Desktop/tablet: the slider controller bails (native
       horizontal scrolling stays available, but we don't animate arrow jumps).
       Un-stack the flex strip into a normal vertical column of full-width cards
       so every project is reachable without any sideways motion. */
    @media (prefers-reduced-motion: reduce) and (min-width: 768px) {
      #projects-pinned { height: auto !important; overflow: visible !important; }
      #projects-track {
        display: block !important;
        height: auto !important;
        overflow: visible !important;
        scroll-snap-type: none !important;
        cursor: auto !important;
      }
      .project-panel {
        position: relative !important;
        flex: none !important;
        width: 100% !important;
        height: auto !important;
        min-height: auto;
      }
      #project-rail, .proj-arrow { display: none; }}

    /* Premium intro divider + rail progress — transform/opacity only, no blur */
    .projects-intro-divider { max-width: none; margin: 1.5rem calc(50% - 50vw) 0; padding: 0; }
    .projects-intro-divider span { display: block; height: 2px; background: linear-gradient(to right, transparent 0%, color-mix(in srgb, var(--stroke) 70%, transparent) 8%, color-mix(in srgb, var(--project-accent, #3b82f6) 55%, transparent) 30%, var(--project-accent, #3b82f6) 50%, color-mix(in srgb, var(--project-accent, #3b82f6) 55%, transparent) 70%, color-mix(in srgb, var(--stroke) 70%, transparent) 92%, transparent 100%); background-size: 200% 100%; opacity: 1; box-shadow: 0 0 10px color-mix(in srgb, var(--project-accent, #3b82f6) 45%, transparent); animation: divider-flow 10s ease-in-out infinite; }
    @keyframes divider-flow { 0%,100% { background-position: 0% 50%; opacity: .7; } 50% { background-position: 100% 50%; opacity: 1; } }
    @media (prefers-reduced-motion: reduce) { .projects-intro-divider span { animation: none; } }
    #project-rail { position: relative; }
    .rail-progress { height: 3px; margin: 0 0 .5rem; background: rgba(148,163,184,.35); border-radius: 999px; overflow: hidden; }
    .rail-progress span { display: block; height: 100%; transform: scaleX(0); transform-origin: left; background: linear-gradient(to right, var(--project-accent, #3b82f6), color-mix(in srgb, var(--project-accent, #3b82f6) 40%, white)); }
    @media (max-width: 768px) { .projects-intro-divider, .rail-progress { display: none; } }

    /* Sun-like glow — even circular, whole-edge smooth blend into #05070d */
    .project-panel::before {
      content: "";
      position: absolute;
      left: 50%;
      top: 50%;
      z-index: 0;
      width: min(115vh, 1100px);
      height: min(115vh, 1100px);
      transform: translate(-50%, -50%);
      border-radius: 50%;
      background:
        radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--project-accent, #3b82f6) 85%, white) 0%, transparent 62%),
        radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--project-accent, #3b82f6) 55%, transparent) 0%, transparent 72%);
      filter: blur(22px);
      opacity: calc(var(--glow-op, 0) * 0.72);
      transition: opacity 0.9s ease;
      pointer-events: none;
      animation: none;
      backface-visibility: hidden;
      -webkit-mask-image: radial-gradient(circle at 50% 50%, black 38%, transparent 86%);
      mask-image: radial-gradient(circle at 50% 50%, black 38%, transparent 86%);
    }
    .project-panel.is-active::before {
      filter: blur(22px);
      transform: translate3d(-50%, -50%, 0);
    }
    @keyframes glow-pulse {
      0%, 100% { transform: translate(-50%, -50%) scale(1) translate(0, 0); }
      33%      { transform: translate(-50%, -50%) scale(1.12) translate(3%, -2%); }
      66%      { transform: translate(-50%, -50%) scale(1.06) translate(-2.5%, 2%); }
      100%     { transform: translate(-50%, -50%) scale(1) translate(0, 0); }
    }

    /* second glow layer removed — a single subtler orb keeps the accent identity
       without washing out the text */
    .project-panel::after {
      content: "";
      display: none;
      position: absolute;
      left: 18%;
      top: 68%;
      z-index: 0;
      width: min(38vh, 420px);
      height: min(38vh, 420px);
      transform: translate(-50%, -50%);
      border-radius: 50%;
      background: radial-gradient(circle,
        color-mix(in srgb, var(--project-accent, #3b82f6) 34%, transparent) 0%,
        color-mix(in srgb, var(--project-accent, #3b82f6) 12%, transparent) 55%,
        transparent 74%);
      filter: blur(56px);
      opacity: 0.55;
      pointer-events: none;
      animation: glow-drift 13s ease-in-out infinite;
      animation-play-state: paused;
    }
    @keyframes glow-drift {
      0%, 100% { transform: translate(-50%, -50%) scale(1) translate(0, 0); opacity: 0.4; }
      50%      { transform: translate(-50%, -50%) scale(1.2) translate(4%, -3%); opacity: 0.65; }
    }

    @media (prefers-reduced-motion: reduce) {
      .project-panel::before { animation: none; opacity: 0.85; }
      .project-panel::after { animation: none; opacity: 0.4; }}
    /* run glows only while the showcase is on screen */
    #projects-pinned.is-live .project-panel::before,
    #projects-pinned.is-live .project-panel::after { animation-play-state: paused; }
    .panel-accent-wash {
      position: absolute;
      inset: 0;
      z-index: 0;
      pointer-events: none;
      opacity: 0.4;
      animation: none;
    }
    @keyframes wash-drift {
      0%, 100% { transform: scale(1) translate(0, 0); opacity: 0.3; }
      50%      { transform: scale(1.12) translate(2%, -1.5%); opacity: 0.5; }
    }
    #projects-pinned.is-live .panel-accent-wash { animation-play-state: paused; }

    /* Edge fades — static "more this way" cues over the 82vw peek.
       Sit above panels but below rail (10) / HUD (13); never intercept input.
       Each side hides while no content remains beyond it (JS toggles
       at-start / at-end on #projects-pinned from setActive). */
    .scroll-fade-right,
    .scroll-fade-left {
      position: absolute;
      top: 0;
      bottom: 0;
      width: 120px;
      pointer-events: none;
      z-index: 5;
      opacity: 1;
      transition: opacity 0.5s ease;
    }
    .scroll-fade-right {
      right: 0;
      background: linear-gradient(to left, #05070d, transparent);
    }
    .scroll-fade-left {
      left: 0;
      background: linear-gradient(to right, #05070d, transparent);
    }
    #projects-pinned.at-start .scroll-fade-left { opacity: 0; }
    #projects-pinned.at-end .scroll-fade-right { opacity: 0; }
    @media (max-width: 767px) { .scroll-fade-right, .scroll-fade-left { display: none; } }

    /* Horizontal-scroll HUD: endpoint arrows + an oversized vertical label. */
    .project-scroll-hud {
      position: absolute;
      left: 50%;
      top: 1.25rem;
      right: auto;
      z-index: 13;
      display: flex;
      flex-direction: row;
      align-items: center;
      justify-content: center;
      gap: 0.5rem;
      width: max-content;
      height: auto;
      padding: 0;
      color: color-mix(in srgb, var(--project-accent, #3b82f6) 58%, white);
      font-family: var(--font-mono);
      font-weight: 700;
      background: transparent;
      border: 0;
      border-radius: 0;
      -webkit-backdrop-filter: none;
      backdrop-filter: none;
      text-shadow:
        0 0 8px color-mix(in srgb, var(--project-accent, #3b82f6) 100%, white),
        0 0 24px color-mix(in srgb, var(--project-accent, #3b82f6) 90%, transparent);
      box-shadow: none;
      pointer-events: none;
      transform: translateX(-50%);
    }
    .project-scroll-hud::before,
    .project-scroll-hud::after {
      display: none;
    }
    .scroll-hud-arrow {
      font-family: 'Chakra Petch', var(--font-mono);
      font-size: 1.35rem;
      font-weight: 700;
      letter-spacing: 0.04em;
      line-height: 1;
      text-shadow: 0 0 12px currentColor;
    }
    .scroll-hud-arrow span {
      display: inline-block;
      opacity: 0.62;
    }
    /* Chevron pulse — both sides always on, each nudging the way it points.
       Right ripples outward to the right (leftmost first); left ripples
       outward to the left (rightmost first). (One-side-dark gating was
       tried and rejected — a dark side reads as broken.) */
    .scroll-hud-arrow span { animation: hud-nudge-x 1.5s ease-in-out infinite; }
    /* Right: points right → nudge right, ripple outward (leftmost first) */
    .scroll-hud-right span:nth-child(1) { animation-delay: 0s; }
    .scroll-hud-right span:nth-child(2) { animation-delay: 0.12s; }
    .scroll-hud-right span:nth-child(3) { animation-delay: 0.24s; }
    .scroll-hud-right span:nth-child(4) { animation-delay: 0.36s; }
    .scroll-hud-right span:nth-child(5) { animation-delay: 0.48s; }
    .scroll-hud-right span:nth-child(6) { animation-delay: 0.60s; }
    /* Left: points left → nudge left, ripple outward (rightmost first) */
    .scroll-hud-left span { animation-name: hud-nudge-x-left; }
    .scroll-hud-left span:nth-child(1) { animation-delay: 0.60s; }
    .scroll-hud-left span:nth-child(2) { animation-delay: 0.48s; }
    .scroll-hud-left span:nth-child(3) { animation-delay: 0.36s; }
    .scroll-hud-left span:nth-child(4) { animation-delay: 0.24s; }
    .scroll-hud-left span:nth-child(5) { animation-delay: 0.12s; }
    .scroll-hud-left span:nth-child(6) { animation-delay: 0s; }
    /* Direction-aware visibility — only the side with content stays lit:
       project 1 shows right only, middle shows both, last shows left only. */
    .scroll-hud-left, .scroll-hud-right { transition: opacity 0.5s ease; }
    #projects-pinned.at-start .scroll-hud-left { opacity: 0; }
    #projects-pinned.at-end .scroll-hud-right { opacity: 0; }
    @keyframes hud-nudge-x {
      0%, 100% { opacity: 0.4; transform: translateX(0); }
      50%      { opacity: 1;   transform: translateX(6px); }
    }
    @keyframes hud-nudge-x-left {
      0%, 100% { opacity: 0.4; transform: translateX(0); }
      50%      { opacity: 1;   transform: translateX(-6px); }
    }
    @media (prefers-reduced-motion: reduce) {
      .scroll-hud-arrow span { animation: none; }
    }
    .scroll-hud-label {
      padding: 0;
      font-family: 'Chakra Petch', var(--font-mono);
      font-size: 1.02rem;
      line-height: 1.15;
      letter-spacing: 0.17em;
      writing-mode: horizontal-tb;
      text-orientation: mixed;
      transform: none;
      white-space: nowrap;
      animation: hud-pulse 1.8s ease-in-out infinite;
    }
    @keyframes hud-pulse {
      0%, 100% { opacity: 0.72; }
      50% { opacity: 1; }
    }
    @media (max-width: 767px) { .project-scroll-hud { display: none; } }

    /* Edge arrows removed per owner request. */

    /* Columns — text left, framed screenshot right */
    .panel-left {
      flex: 0 0 54%;
      max-width: 54%;
      position: relative;
      z-index: 2;
      transform: translateX(2rem);
    }
    .panel-right {
      flex: 1 1 46%;
      min-width: 0;
      position: relative;
      z-index: 2;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      gap: 1rem;
      /* text column is top-aligned; keep the image reel vertically centered
         against it so it reads as floating beside the text */
      align-self: stretch;
      transform: translate(-0.5rem, -2rem);
    }

    /* Badge */
    .badge-wrap {
      position: relative;
      display: flex;
      align-items: center;
      gap: 1rem;
      margin-bottom: 1rem;
    }
    /* Project badge — circular index ring, rebuilt on the same crisp SVG idiom
       as the stats/skills rings (.stat-ring / .ring-fill): a thin dark track
       + an accent-filled arc that sweeps to (project)/(total), capped with a
       bright leading dot, and a mono numeral at the centre. No fills, no
       wobble: the arc and dot are GSAP-tweened from zero on arrival.
       circumference = 2π·18 = 113.1 (identical to the skills rings). */
    .badge-ring-v2 {
      flex-shrink: 0;
      width: 64px;
      height: 64px;
      display: block;
    }
    .badge-ring-v2 svg { display: block; width: 100%; height: 100%; }
    .badge-track {
      stroke: rgba(255, 255, 255, 0.14);
      stroke-width: 3;
    }
    .badge-arc {
      stroke: var(--project-accent);
      stroke-width: 3.5;
      stroke-linecap: round;
      transform: rotate(-90deg);
      transform-origin: center;
      filter:
        drop-shadow(0 0 6px color-mix(in srgb, var(--project-accent) 100%, transparent))
        drop-shadow(0 0 20px color-mix(in srgb, var(--project-accent) 60%, transparent));
    }
    /* white-hot leading edge of the sweep — a short arc that rides the head */
    .badge-head {
      stroke: #fff;
      stroke-width: 3.5;
      opacity: 0;
      filter:
        drop-shadow(0 0 4px #fff)
        drop-shadow(0 0 12px var(--project-accent));
    }
    /* soft light bleed behind the leading dot (blurred accent bloom) */
    .badge-head-glow {
      fill: var(--project-accent);
      opacity: 0;
      filter: blur(3px);
    }
    .badge-dot {
      fill: #fff;
      opacity: 0;
      filter:
        drop-shadow(0 0 5px #fff)
        drop-shadow(0 0 10px var(--project-accent))
        drop-shadow(0 0 20px color-mix(in srgb, var(--project-accent) 80%, transparent));
    }
    /* ONE glow for the whole spark layer per ring — consolidating 24 per-star
       drop-shadows into a single filtered group cut the paint cost drastically */
    .badge-sparks {
      pointer-events: none;
      filter:
        drop-shadow(0 0 4px color-mix(in srgb, var(--project-accent) 100%, transparent))
        drop-shadow(0 0 9px color-mix(in srgb, var(--project-accent) 55%, transparent));
    }
    .badge-spark {
      opacity: 1;
    }
    .badge-spark-path {
      fill: #fff;
      opacity: 0;
      transform-box: fill-box;
      transform-origin: center;
    }
    /* the twinkle is pure CSS opacity keyframes — compositor-only, zero JS.
       Lit stars twinkle while the showcase is on-screen; the base rule keeps
       them visible off-screen without burning any frames. */
    .badge-spark.lit .badge-spark-path {
      opacity: 1;
    }
    #projects-pinned.is-live .badge-spark.lit .badge-spark-path {
      animation: badge-sparkle 2.2s ease-in-out infinite;
    }

    @keyframes badge-sparkle {
      0%, 100% { opacity: 0.4; }
      50% { opacity: 1; }
    }
    .badge-num {
      font-family: var(--font-mono);
      font-size: 16px;
      font-weight: 700;
      fill: #fff;
      letter-spacing: 0.02em;
      paint-order: stroke;
      stroke: rgba(4, 6, 9, 0.7);
      stroke-width: 1px;
      filter:
        drop-shadow(0 0 6px color-mix(in srgb, var(--project-accent) 90%, transparent))
        drop-shadow(0 0 14px color-mix(in srgb, var(--project-accent) 50%, transparent));
    }
    /* same gate for the CTA glow — no repaints while the section is off-screen */
    @media (min-width: 768px) {
      #projects-pinned.is-live .open-case-btn { animation-play-state: paused; }
      #projects-pinned.is-live .project-panel.is-active .open-case-btn { animation-play-state: running; }
    }
    @media (max-width: 767px) {
      #projects-pinned.is-live .open-case-btn { animation-play-state: running; }
    }
    .badge-label {
      font-family: var(--font-mono);
      font-size: 0.9rem;
      letter-spacing: 0.18em;
      color: var(--muted);
    }

    /* Category pill */
    .cat-pill {
      display: inline-flex;
      align-items: center;
      border: 1px solid;
      border-radius: 9999px;
      padding: 0.25rem 0.75rem;
      font-family: var(--font-mono);
      font-size: 0.85rem;
      letter-spacing: 0.16em;
      text-transform: uppercase;
      margin-bottom: 0.75rem;
      background: linear-gradient(135deg, color-mix(in srgb, var(--project-accent, #3b82f6) 18%, transparent) 0%, color-mix(in srgb, var(--project-accent, #3b82f6) 4%, transparent) 100%);
    }

    /* Title */
    .panel-title {
      font-family: var(--font-display);
      font-size: clamp(2rem, 3.5vw, 3rem);
      font-weight: 700;
      line-height: 1.15;
      letter-spacing: -0.02em;
      color: var(--text);
      margin-bottom: 0.5rem;
    }

    /* Description */
    .panel-desc {
      color: var(--muted);
      font-size: 1.125rem;
      line-height: 1.7;
      margin-bottom: 0.75rem;
      max-width: 600px;
    }

    /* Challenge blockquote */
    .panel-challenge {
      border-left: 2px solid var(--project-accent, #3b82f6);
      padding-left: 1rem;
      margin-bottom: 1rem;
      color: var(--muted);
      font-size: 1.05rem;
      line-height: 1.6;
      opacity: 1;
    }
    .challenge-label {
      color: var(--project-accent, #3b82f6);
      font-family: var(--font-mono);
      font-size: 0.85rem;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      display: block;
      margin-bottom: 0.25rem;
    }

    /* Tech chips */
    .tech-stack {
      display: flex;
      flex-wrap: wrap;
      gap: 0.5rem;
      margin-bottom: 1rem;
    }
    .tech-chip {
      display: inline-flex;
      align-items: center;
      border-radius: 9999px;
      padding: 0.2rem 0.65rem;
      font-family: var(--font-mono);
      font-size: 0.85rem;
      letter-spacing: 0.04em;
      background: linear-gradient(135deg, color-mix(in srgb, var(--project-accent, #3b82f6) 14%, transparent) 0%, color-mix(in srgb, var(--project-accent, #3b82f6) 4%, transparent) 100%);
      color: color-mix(in srgb, var(--project-accent, #3b82f6) 82%, var(--text));
      border: 1px solid color-mix(in srgb, var(--project-accent, #3b82f6) 20%, var(--stroke));
    }

    /* Feature list */
    .panel-features {
      list-style: none;
      margin: 0 0 1.25rem;
      padding: 0;
      display: flex;
      flex-direction: column;
      gap: 0.42rem;
    }
    .panel-features li {
      position: relative;
      padding-left: 1.2rem;
      font-size: 0.97rem;
      line-height: 1.5;
      color: color-mix(in srgb, var(--muted) 92%, var(--text));
    }
    .panel-features li::before {
      content: "";
      position: absolute;
      left: 0;
      top: 0.5em;
      width: 7px;
      height: 7px;
      border-radius: 2px;
      background: var(--project-accent, #3b82f6);
      box-shadow: 0 0 8px color-mix(in srgb, var(--project-accent, #3b82f6) 60%, transparent);
    }

    /* Actions */
    .panel-actions {
      display: flex;
      align-items: center;
      gap: 1.25rem;
    }
    .open-case-btn {
      display: inline-flex;
      align-items: center;
      gap: 0.55rem;
      padding: 0.85rem 2.1rem;
      border: 1.5px solid var(--project-accent, #3b82f6);
      border-radius: 9999px;
      background: color-mix(in srgb, var(--project-accent, #3b82f6) 8%, transparent);
      color: var(--text);
      font-family: var(--font-mono);
      font-size: 1.1rem;
      letter-spacing: 0.06em;
      cursor: pointer;
      transition: all 0.3s ease;
      box-shadow:
        0 0 18px color-mix(in srgb, var(--project-accent, #3b82f6) 35%, transparent),
        inset 0 0 14px color-mix(in srgb, var(--project-accent, #3b82f6) 12%, transparent);
      animation: btn-glow 3.5s ease-in-out infinite;
      animation-play-state: paused;
    }
    @keyframes btn-glow {
      0%, 100% {
        box-shadow:
          0 0 16px color-mix(in srgb, var(--project-accent, #3b82f6) 30%, transparent),
          inset 0 0 12px color-mix(in srgb, var(--project-accent, #3b82f6) 10%, transparent);
      }
      50% {
        box-shadow:
          0 0 30px color-mix(in srgb, var(--project-accent, #3b82f6) 55%, transparent),
          inset 0 0 18px color-mix(in srgb, var(--project-accent, #3b82f6) 18%, transparent);
      }
    }
    .open-case-btn:hover {
      background: color-mix(in srgb, var(--project-accent, #3b82f6) 20%, transparent);
      box-shadow:
        0 0 38px color-mix(in srgb, var(--project-accent, #3b82f6) 65%, transparent),
        inset 0 0 22px color-mix(in srgb, var(--project-accent, #3b82f6) 25%, transparent);
      transform: translateY(-2px);
    }
    .open-case-btn .arrow { transition: transform 0.3s ease; }
    .open-case-btn:hover .arrow { transform: translateX(4px); }
    .panel-gh-link {
      display: inline-flex;
      align-items: center;
      gap: 0.4rem;
      font-family: var(--font-mono);
      font-size: 1.1rem;
      color: var(--text);
      text-decoration: none;
      padding: 0.85rem 1.6rem;
      border: 1.5px solid color-mix(in srgb, var(--project-accent, #3b82f6) 55%, var(--stroke));
      border-radius: 9999px;
      transition: all 0.3s ease;
    }
    .panel-gh-link:hover {
      color: var(--text);
      border-color: var(--project-accent, #3b82f6);
      box-shadow:
        0 0 22px color-mix(in srgb, var(--project-accent, #3b82f6) 40%, transparent),
        inset 0 0 12px color-mix(in srgb, var(--project-accent, #3b82f6) 12%, transparent);
      transform: translateY(-2px);
    }

    /* =====================================================================
       Vertical image reel — each project shows its own folder of shots. The
       baseline (mobile / reduced-motion) is a plain native-scroll column.
       On desktop a CSS scroll-driven animation (animation-timeline: view())
       scales whichever shot is centred up to 1x and dims + shrinks its
       neighbours so they "peek" — the small / BIG / small stack, but static
       and driven purely by the user's own scroll: no JS per-frame loop, no
       WebGL. Where scroll timelines are unsupported it degrades to a clean
       uniform native-scroll column. JS (syncTick) only marks the focal shot.
    ===================================================================== */
    .reel-viewport {
      position: relative;
      width: 100%;
      max-width: 600px;
      height: min(66vh, 480px);
      margin: 0 auto;
      border-radius: 16px;
      /* native vertical scroll through the shots — proximity (not mandatory)
         so it scrolls freely and naturally, only settling near a shot at rest,
         instead of the old forced one-image-per-gesture snap */
      overflow-y: auto;
      overflow-x: hidden;
      scroll-snap-type: y proximity;
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
      -ms-overflow-style: none;
    }
    .reel-viewport::-webkit-scrollbar { display: none; }

    .reel-track {
      display: flex;
      flex-direction: column;
      gap: 1rem;
      padding: 0.5rem 0;
    }
    .reel-item {
      position: relative;
      flex: 0 0 auto;
      width: 100%;
      aspect-ratio: 16 / 10;
      border-radius: 14px;
      overflow: hidden;
      background: var(--surface);
      border: 1px solid var(--stroke);
      box-shadow: 0 14px 36px rgba(0, 0, 0, 0.45);
      scroll-snap-align: center;
    }
    .reel-item img {
      width: 100%;
      height: 100%;
      object-fit: contain;
      object-position: center;
      display: block;
    }

    /* [ VIEW PROJECT ] tag — revealed only on the focal image */
    .view-tag {
      position: absolute;
      left: 50%;
      bottom: 0.9rem;
      transform: translate(-50%, 8px);
      padding: 0.34rem 0.8rem;
      font-family: var(--font-mono);
      font-size: 0.72rem;
      letter-spacing: 0.14em;
      color: color-mix(in srgb, var(--project-accent, #3b82f6) 70%, var(--text));
      background: rgba(5, 7, 13, 0.72);
      border: 1px solid color-mix(in srgb, var(--project-accent, #3b82f6) 40%, var(--stroke));
      border-radius: 9999px;
      backdrop-filter: blur(6px);
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.45s ease 0.1s, transform 0.45s var(--ease-out-quint, ease) 0.1s;
    }
    .reel-item.focal .view-tag { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
    .view-tag { text-decoration: none; }

    /* small mono readout — "03 / 14" */
    .reel-counter {
      position: absolute;
      right: 0.7rem;
      bottom: 0.65rem;
      z-index: 6;
      font-family: var(--font-mono);
      font-size: 0.72rem;
      letter-spacing: 0.12em;
      color: color-mix(in srgb, var(--project-accent, #3b82f6) 72%, var(--text));
      background: rgba(5, 7, 13, 0.7);
      border: 1px solid color-mix(in srgb, var(--project-accent, #3b82f6) 34%, var(--stroke));
      border-radius: 9999px;
      padding: 0.2rem 0.62rem;
      pointer-events: none;
      backdrop-filter: blur(6px);
    }

    /* ---- Desktop static "stack": scroll-driven small / BIG / small ----
       No JS rAF loop, no WebGL. As a reel scrolls, each shot scales up to 1x as
       it reaches the viewport's vertical centre and eases back down + dims as it
       leaves, so the centred shot reads BIG and its neighbours peek in small —
       advanced entirely by the native scroll position. Guarded to browsers with
       scroll-linked timelines; elsewhere the reel is a clean uniform scroll
       column (still fully usable). */
    /* Keep reels compositor-light. The old scroll-linked transform animation
       ran once for every screenshot in every project and caused the page to
       hitch when entering/leaving this section. */

    /* Desktop focal accent — the centred shot (JS marks it .focal) takes the
       project-accent frame + glow so it clearly reads as the active screenshot. */
    @media (min-width: 768px) {
      .reel-item { transition: border-color 0.45s ease, box-shadow 0.45s ease; }
      .reel-item.focal {
        border-color: color-mix(in srgb, var(--project-accent, #3b82f6) 45%, var(--stroke));
        box-shadow:
          0 20px 50px rgba(0, 0, 0, 0.5),
          0 0 34px color-mix(in srgb, var(--project-accent, #3b82f6) 22%, transparent);
      }
    }

    /* Short viewports — keep the text block in the upper half so the
       left text / right image split stays clean */
    @media (max-height: 840px) {
      .project-panel { padding: 1rem 3rem 3rem; }
      .panel-left { padding-top: 0; }
      .reel-viewport { max-width: 500px; }
      .badge-wrap { margin-bottom: 0.75rem; gap: 0.75rem; }
      .badge-ring-v2 { width: 52px; height: 52px; }
      .cat-pill { margin-bottom: 0.5rem; }
      .panel-title { font-size: clamp(1.6rem, 2.8vw, 2.2rem); margin-bottom: 0.5rem; }
      .panel-desc { font-size: 0.95rem; line-height: 1.55; margin-bottom: 0.5rem; }
      .panel-challenge { font-size: 0.9rem; margin-bottom: 0.75rem; padding-left: 0.75rem; }
      .panel-features { margin-bottom: 0.75rem; gap: 0.28rem; }
      .panel-features li { font-size: 0.82rem; padding-left: 1rem; }
      .panel-features li::before { width: 6px; height: 6px; top: 0.48em; }

      .tech-stack { margin-bottom: 0.75rem; gap: 0.4rem; }
      .tech-chip { font-size: 0.75rem; padding: 0.15rem 0.55rem; }
      .panel-actions { gap: 1rem; }
      .open-case-btn { padding: 0.65rem 1.6rem; font-size: 0.95rem; }
      .panel-gh-link { font-size: 1rem; padding: 0.65rem 0.4rem; }}

    /* Progress rail — bottom-center horizontal strip */
    #project-rail {
      position: absolute;
      left: 50%;
      /* the showcase is pinned 60px down (top+=60) to clear the fixed header,
         so its bottom 60px sit below the fold — lift the rail clear of that */
      bottom: 6rem;
      transform: translateX(-50%);
      z-index: 10;
      display: flex;
      flex-direction: row;
      align-items: center;
      gap: 1rem;
    }
    .rail-strip {
      display: flex;
      flex-direction: row;
      align-items: center;
      gap: 8px;
    }
    .rail-segment {
      width: 30px;
      height: 3px;
      padding: 12px 0;                    /* 27px hitbox, 3px visual (finish pass) */
      background: var(--stroke);
      background-clip: content-box;
      border: 0;
      cursor: pointer;
      border-radius: 9999px;
      transition: background 0.4s ease, box-shadow 0.4s ease, transform 0.4s ease;
    }
    .rail-segment:hover {
      background: color-mix(in srgb, var(--project-accent, #3b82f6) 55%, var(--stroke));
    }
    .rail-segment.active {
      background: var(--project-accent, #3b82f6);
      box-shadow: 0 0 12px color-mix(in srgb, var(--project-accent, #3b82f6) 60%, transparent);
      transform: scaleY(1.6);
    }
    .rail-num {
      font-family: var(--font-mono);
      font-size: 0.8rem;
      letter-spacing: 0.18em;
      color: var(--muted);
      white-space: nowrap;
    }

    /* Prev / next arrow buttons — overlay the slider, vertically centred */
    .proj-arrow {
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
      z-index: 12;
      width: 46px;
      height: 46px;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 0;
      border-radius: 9999px;
      border: 1px solid var(--stroke);
      background: rgba(5, 7, 13, 0.62);
      backdrop-filter: blur(8px);
      color: var(--text);
      font-size: 1.7rem;
      line-height: 1;
      cursor: pointer;
      transition: background 0.3s ease, border-color 0.3s ease, opacity 0.3s ease, transform 0.3s ease;
    }
    .proj-arrow:hover {
      background: rgba(5, 7, 13, 0.9);
      border-color: color-mix(in srgb, var(--project-accent, #3b82f6) 55%, var(--stroke));
    }
    .proj-arrow:active { transform: translateY(-50%) scale(0.92); }
    .proj-arrow-prev { left: 1.5rem; }
    .proj-arrow-next { right: 1.5rem; }
    .proj-arrow[disabled] { opacity: 0.22; pointer-events: none; }
    /* The text indicator replaces the arrow controls. */
    .proj-arrow { display: none; }

    /* Mobile fallback */
    @media (max-width: 767px) {
      #projects-pinned {
        height: auto !important;
        overflow: visible !important;
        opacity: 1 !important;
      }
      #projects-track {
        display: block !important;
        height: auto !important;
        transform: none !important;
        will-change: auto !important;
      }
      .project-panel {
        position: relative !important;
        top: auto;
        left: auto;
        flex: none !important;
        width: 100% !important;
        height: auto !important;
        min-height: 100vh;
        flex-direction: column;
        align-items: stretch;
        padding: 2rem 1.25rem;
        gap: 2rem;
        box-shadow: none;
      }
      .panel-left { flex: none !important; max-width: 100%; padding-right: 0; transform: none; }
      .panel-right { flex: none !important; width: 100%; transform: none; }
      .reel-viewport { max-width: 100%; }
      .badge-wrap { margin-bottom: 1rem; }
      .panel-title { font-size: 1.75rem; }
      .panel-desc { font-size: 1.05rem; }
      .panel-accent-wash { opacity: 0.3; }
      #project-rail, .proj-arrow { display: none; }}



    /* Skill chips */
    .chip {
      background: rgba(13, 21, 38, 0.85);
      border: 1px solid var(--stroke);
      font-family: var(--font-mono);
      font-size: 0.78rem;
      color: var(--muted);
      transition: color 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
      cursor: default;
    }
    .chip:hover {
      color: var(--text);
      border-color: var(--chip-accent, rgba(59, 130, 246, 0.55));
      box-shadow: 0 0 14px color-mix(in srgb, var(--chip-accent, var(--glow)) 60%, transparent);
      transform: translateY(-2px);
    }
    @media (prefers-reduced-motion: no-preference) {
      .float-pill {
        animation: pill-float var(--float-dur, 3s) ease-in-out infinite;
        animation-delay: var(--float-delay, 0s);
      }}
    @keyframes pill-float {
      0%, 100% { transform: translateY(0); border-color: var(--stroke); }
      50% { transform: translateY(-3px); border-color: color-mix(in srgb, var(--pill-accent, var(--stroke)) 40%, var(--stroke)); }
    }

    /* Timeline */
    .timeline-rail {
      position: absolute;
      left: 7px;
      top: 8px;
      bottom: 0;
      width: 1px;
      background: linear-gradient(to bottom, #3b82f6, #1b2740 80%);
    }
    .timeline-node {
      position: absolute;
      left: 0;
      top: 6px;
      width: 15px;
      height: 15px;
      border-radius: 9999px;
      background: #0d1526;
      border: 2px solid #3b82f6;
      box-shadow: 0 0 12px var(--glow);
    }
    .timeline-node::after {
      content: '';
      position: absolute;
      inset: 3px;
      border-radius: 9999px;
      background: #3b82f6;
      animation: node-pulse 2s ease-in-out infinite;
    }
    @keyframes node-pulse {
      0%, 100% { opacity: 1; }
      50% { opacity: 0.35; }
    }

    /* Gradient text */
    .grad-text {
      background: linear-gradient(90deg, #6ea8ff 0%, #3b82f6 100%);
      -webkit-background-clip: text;
      background-clip: text;
      -webkit-text-fill-color: transparent;
      background-size: 200% auto;
    }
    @keyframes shimmer {
      0% { background-position: -200% center; }
      100% { background-position: 200% center; }
    }
    .grad-text {
      animation: shimmer 4s linear infinite;
    }
    @media (prefers-reduced-motion: reduce) {
      .grad-text { animation: none; }}

    /* Social icon buttons */
    .icon-btn {
      border: 1px solid var(--stroke);
      color: var(--muted);
      transition: color 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
    }
    .icon-btn:hover {
      color: var(--text);
      border-color: rgba(59, 130, 246, 0.55);
      box-shadow: 0 0 14px var(--glow);
      transform: translateY(-2px);
    }

    /* Reveal-on-scroll baseline (GSAP animates these in) */
    .reveal { opacity: 0; transform: translateY(40px); }

    /* ---------- Case timeline ---------- */

    /* counter chip */
    .tl-node {
      position: relative;
    }
    .tl-case-num {
      position: absolute;
      font-size: 1rem;
      letter-spacing: 0.04em;
      color: var(--cat-color);
      white-space: nowrap;
      font-family: monospace;
      font-weight: 700;
      line-height: 1;
      top: 50%;
      transform: translateY(-50%);
      padding: 0.4rem 0.3rem;
      border: 1.5px solid var(--cat-color);
      border-radius: 4px;
      background: color-mix(in srgb, var(--cat-color) 12%, transparent);
      z-index: 10;
    }
    .tl-case-num::before {
      content: '';
      position: absolute;
      top: 50%;
      width: 0.5rem;
      height: 1px;
      background: var(--stroke);
      transform: translateY(-50%);
    }
    /* chip on opposite side from card, connected by line */
    .tl-item[data-side="left"] .tl-case-num {
      left: calc(100% + 0.6rem);
      right: auto;
    }
    .tl-item[data-side="left"] .tl-case-num::before {
      right: 100%;
      margin-right: 0.125rem;
    }
    .tl-item[data-side="right"] .tl-case-num {
      right: calc(100% + 0.6rem);
      left: auto;
    }
    .tl-item[data-side="right"] .tl-case-num::before {
      left: 100%;
      margin-left: 0.125rem;
    }

    .tl-wrap { position: relative; }

    .tl-svg {
      position: absolute; top: 0; left: 50%;
      width: 2px; height: 100%;
      transform: translateX(-50%);
      pointer-events: none; z-index: 0;
    }

    .tl-items { position: relative; z-index: 1; max-width: 900px; margin: 0 auto; }

    .tl-item {
      display: grid;
      grid-template-columns: 1fr 2.5rem 1fr;
      align-items: start;
      margin-bottom: 4rem;
    }

    /* node */
    .tl-item[data-side="left"]  .tl-node { order: 2; }
    .tl-item[data-side="right"] .tl-node { order: 2; }
    .tl-node {
      grid-column: 2;
      justify-self: center;
      width: 36px; height: 36px;
      display: flex; align-items: center; justify-content: center;
      margin-top: 0.35rem;
    }
    .tl-node-inner {
      width: 8px; height: 8px;
      transform: rotate(45deg);
      border: 1.5px solid var(--cat-color);
      border-radius: 1px;
      background: var(--bg);
      transition: box-shadow 0.3s ease, border-color 0.3s ease, background 0.3s ease;
    }
    .tl-node.active-node .tl-node-inner {
      border-color: var(--cat-color);
      background: var(--cat-color);
      box-shadow: 0 0 8px var(--cat-color), 0 0 16px color-mix(in srgb, var(--cat-color) 40%, transparent);
    }

    /* card */
    .tl-item[data-side="left"] .tl-card {
      grid-column: 1; order: 1;
      text-align: right;
      padding-right: 1.5rem;
      border-right: 3px solid var(--cat-color);
      border-left: 1px solid var(--stroke);
    }
    .tl-item[data-side="right"] .tl-card {
      grid-column: 3; order: 3;
      text-align: left;
      padding-left: 1.5rem;
      border-left: 3px solid var(--cat-color);
    }
    .tl-card {
      position: relative;
      padding: 1rem 1.25rem;
      border-radius: 0.75rem;
      border: 1px solid var(--stroke);
      background: var(--surface);
    }
    .tl-id {
      font-size: 0.65rem;
      letter-spacing: 0.14em;
      color: var(--cat-color);
      display: block;
      margin-bottom: 0.2rem;
    }
    .tl-title {
      font-size: 0.92rem;
      font-weight: 600;
      color: var(--text);
      line-height: 1.4;
      margin-bottom: 0.2rem;
    }
    .tl-title .text-muted { font-weight: 400; }
    .tl-desc {
      font-size: 0.65rem;
      letter-spacing: 0.08em;
      color: var(--muted);
      text-transform: uppercase;
    }
    .tl-link {
      display: inline-flex;
      align-items: center;
      gap: 0.3rem;
      margin-top: 0.5rem;
      font-size: 0.72rem;
      font-weight: 600;
      letter-spacing: 0.03em;
      color: #fff;
      background: #2563eb;
      padding: 0.35rem 0.75rem;
      border-radius: 4px;
      text-decoration: none;
      transition: background 0.2s ease;
    }
    .tl-link:hover { background: #1d4ed8; color: #fff; }

    /* pulse dot on current item */
    .tl-item[data-current="true"] .tl-card::after {
      content: '';
      position: absolute; top: 0.5rem; right: 0.75rem;
      width: 8px; height: 8px;
      border-radius: 50%;
      background: #22c55e;
      box-shadow: 0 0 8px rgba(34,197,94,0.6);
      animation: tl-pulse 2s ease-in-out infinite;
    }
    .tl-item[data-side="left"][data-current="true"] .tl-card::after {
      right: auto; left: 0.75rem;
    }
    @keyframes tl-pulse {
      0%, 100% { opacity: 1; transform: scale(1); }
      50% { opacity: 0.5; transform: scale(0.85); }
    }

    /* mobile timeline */
    @media (max-width: 767px) {
      .tl-svg { display: none; }
      .tl-item {
        grid-template-columns: auto 1fr;
        gap: 0 0.75rem;
        margin-bottom: 1.5rem;
      }
      .tl-node {
        grid-column: 1;
        margin-top: 0.25rem;
      }
      .tl-item[data-side="left"] .tl-case-num,
      .tl-item[data-side="right"] .tl-case-num {
        left: calc(100% + 0.4rem);
        right: auto;
        top: 50%;
        transform: translateY(-50%);
      }
      .tl-case-num::before { display: none; }
      .tl-item[data-side="left"] .tl-card,
      .tl-item[data-side="right"] .tl-card {
        grid-column: 2;
        text-align: left;
        padding: 0.75rem 1rem;
      }
      .tl-item[data-current="true"] .tl-card::after {
        right: 0.75rem; left: auto;
      }}

    /* reduced motion */
    @media (prefers-reduced-motion: reduce) {
      .tl-svg { opacity: 0.25; }
      .tl-node-inner { box-shadow: none !important; }}

    /* ---------- Nav dropdown ---------- */

    /* ---------- Command palette ---------- */
    #palette {
      position: fixed;
      inset: 0;
      z-index: 120;
      background: rgba(5, 7, 13, 0.85);
      display: none;
      align-items: flex-start;
      justify-content: center;
      padding: 14vh 1rem 0;
    }
    @supports (backdrop-filter: blur(8px)) {
      #palette {
        background: rgba(5, 7, 13, 0.7);
        -webkit-backdrop-filter: blur(8px);
        backdrop-filter: blur(8px);
      }}
    #palette.open { display: flex; }
    #palette-box {
      width: 100%;
      max-width: 520px;
      background: var(--surface);
      border: 1px solid var(--stroke);
      border-radius: 1rem;
      overflow: hidden;
      box-shadow: 0 24px 70px rgba(0, 0, 0, 0.6), 0 0 30px rgba(59, 130, 246, 0.12);
    }
    #palette-input {
      width: 100%;
      background: transparent;
      border: none;
      outline: none;
      color: var(--text);
      font-family: var(--font-mono);
      font-size: 0.85rem;
      padding: 0.9rem 1.1rem;
      border-bottom: 1px solid var(--stroke);
      caret-color: #3b82f6;
    }
    #palette-list { max-height: 320px; overflow-y: auto; }
    .palette-item {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 1rem;
      width: 100%;
      text-align: left;
      padding: 0.65rem 1.1rem;
      font-family: var(--font-mono);
      font-size: 0.78rem;
      color: var(--muted);
      background: transparent;
      border: none;
    }
    .palette-item .p-hint { font-size: 0.62rem; letter-spacing: 0.12em; opacity: 0.9; }
    .palette-item.selected, .palette-item:hover {
      color: var(--text);
      background: rgba(59, 130, 246, 0.1);
    }

    /* ---------- Mobile menu ---------- */
    #mobile-menu {
      position: fixed;
      inset: 0;
      z-index: 60;
      background: rgba(5, 7, 13, 0.96);
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.35s ease, visibility 0.35s ease;
    }
    #mobile-menu.open { opacity: 1; visibility: visible; }
    #mobile-menu .menu-panel {
      transform: translateY(-16px);
      transition: transform 0.35s ease;
      overflow-y: auto;
    }
    #mobile-menu.open .menu-panel { transform: translateY(0); }

    /* ---------- Terminal ---------- */
    .terminal {
      background: var(--surface);
      border: 1px solid var(--stroke);
      box-shadow: 0 18px 50px rgba(0, 0, 0, 0.5), 0 0 30px rgba(59, 130, 246, 0.12);
    }
    .terminal-bar {
      border-bottom: 1px solid var(--stroke);
      background: rgba(5, 7, 13, 0.55);
    }
    #terminal-body {
      height: 300px;
      overflow-y: auto;
      font-family: var(--font-mono);
      font-size: 0.78rem;
      line-height: 1.7;
      scrollbar-width: thin;
      scrollbar-color: #1b2740 transparent;
    }
    #terminal-body::-webkit-scrollbar { width: 6px; }
    #terminal-body::-webkit-scrollbar-track { background: transparent; }
    #terminal-body::-webkit-scrollbar-thumb { background: #1b2740; border-radius: 8px; }
    #terminal-body::-webkit-scrollbar-thumb:hover { background: #1e3a5f; }
    .term-muted { color: var(--muted); }
    .term-accent { color: #3b82f6; }
    #terminal-input {
      background: transparent;
      border: none;
      outline: none;
      color: var(--text);
      font-family: var(--font-mono);
      font-size: 0.78rem;
      caret-color: #3b82f6;
      flex: 1;
      min-width: 0;
    }
    @keyframes term-blink { 50% { opacity: 0; } }

    /* ---------- SOC Lab Environment ---------- */
    .lab-node { opacity: 0; }
    .lab-conn { stroke-dasharray: 2000; stroke-dashoffset: 2000; }
    @media (prefers-reduced-motion: reduce) {
      .lab-node { animation: none !important; opacity: 1 !important; }
      .lab-conn { stroke-dasharray: none; stroke-dashoffset: 0; }}
    .lab-tab.active {
      background: rgba(59, 130, 246, 0.1);
      border-color: rgba(59, 130, 246, 0.4);
      color: #3b82f6;
    }
    .lab-detail-content { animation: fadeIn 0.3s ease; }
    @keyframes fadeIn {
      from { opacity: 0; transform: translateY(8px); }
      to { opacity: 1; transform: translateY(0); }
    }
    /* SVG node hover effects */
    .lab-node rect {
      transition: filter 0.3s ease, stroke-width 0.3s ease, transform 0.3s ease;
      transform-origin: center;
    }
    .lab-node:hover rect,
    .lab-node.active rect {
      stroke-width: 2;
      filter: url(#lab-glow);
    }
    /* Stat box hover effects */
    .lab-stat {
      transition: transform 0.3s var(--ease-out-expo), border-color 0.3s ease, box-shadow 0.3s ease;
    }
    .lab-stat:hover {
      transform: translateY(-2px);
      border-color: rgba(59, 130, 246, 0.35);
      box-shadow: 0 8px 24px rgba(59, 130, 246, 0.1);
    }
    /* Tab hover effects */
    .lab-tab {
      transition: all 0.3s ease;
    }
    /* a11y (finish pass): screen-reader labels, inline form errors,
       44px minimum targets. .sr-only/.form-err are global so both
       contact forms (desktop + #m-page) share them. */
    .sr-only {
      position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
      overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
    }
    .form-err {
      font-family: var(--font-mono, monospace); font-size: 0.72rem; line-height: 1.5;
      color: #f87171; margin: 0 0 0.5rem;
    }
    .lab-tab, #did-touch-buttons .did-touch-btn { min-height: 44px; }
    .lab-tab:hover:not(.active) {
      border-color: rgba(59, 130, 246, 0.3);
      color: var(--text);
    }
    @keyframes attackDash {
      to { stroke-dashoffset: -6; }
    }
    @keyframes ringPulse {
      0%, 100% { opacity: 0.15; transform: scale(1); }
      50% { opacity: 0.3; transform: scale(1.08); }
    }

    /* ---------- Attack path diagram ---------- */
    #attack-diagram { overflow: hidden; position: relative; }
    #attack-canvas .ap-pill, #attack-canvas .ap-connection, #attack-canvas .ap-machine { opacity: 0; }
    #attack-canvas svg { display: block; width: 100%; height: auto; }
    .ap-machine { cursor: pointer; }
    .ap-machine-label {
      font-family: var(--font-mono);
      font-size: 13px;
      fill: rgba(110, 168, 255, 0.8);
      letter-spacing: 0.18em;
      text-anchor: middle;
    }

    .ap-pill { cursor: pointer; }
    .ap-pill-bg {
      fill: rgba(8, 15, 30, 0.88);
      stroke: rgba(27, 39, 64, 0.7);
      stroke-width: 1.3;
      rx: 6;
      transition: stroke 0.5s ease, filter 0.5s ease;
    }
    .ap-pill-accent { rx: 2; }
    .ap-pill-id {
      font-family: var(--font-mono);
      font-size: 15px;
      fill: rgba(110, 168, 255, 0.95);
      letter-spacing: 0.12em;
    }
    .ap-pill-name {
      font-family: var(--font-mono);
      font-size: 14px;
      fill: var(--text);
      font-weight: 600;
    }
    .ap-pill-step {
      font-family: var(--font-mono);
      font-size: 12px;
      font-weight: 700;
      fill: rgba(110, 168, 255, 0.75);
    }
    .ap-pill:hover .ap-pill-bg {
      stroke: rgba(59, 130, 246, 0.85) !important;
      filter: drop-shadow(0 0 22px rgba(59, 130, 246, 0.55)) !important;
    }
    .ap-pill:hover .ap-pill-accent {
      filter: brightness(1.6);
    }
    .ap-pill.active .ap-pill-bg {
      stroke: rgba(59, 130, 246, 0.95) !important;
      filter: drop-shadow(0 0 28px rgba(59, 130, 246, 0.6)) !important;
    }
    .ap-pill.active .ap-pill-id { fill: #60a5fa; }
    .ap-pill.active .ap-pill-name { fill: #f0f4ff; }

    .ap-connection {
      fill: none;
      stroke: rgba(59, 130, 246, 0.55);
      stroke-width: 3;
      stroke-linecap: round;
      stroke-linejoin: round;
    }
    .ap-connection-glow {
      fill: none;
      stroke: rgba(59, 130, 246, 0.15);
      stroke-width: 6;
      stroke-linecap: round;
      stroke-linejoin: round;
    }
    .ap-connection.active { stroke: rgba(59, 130, 246, 0.85); }
    .ap-connection-glow.active {
      stroke: rgba(59, 130, 246, 0.4);
      stroke-width: 7;
    }
    .ap-conn-att {
      stroke: rgba(239, 68, 68, 0.7) !important;
      stroke-width: 3.5 !important;
    }
    .ap-glow-att {
      stroke: rgba(239, 68, 68, 0.15) !important;
      stroke-width: 10 !important;
    }
    .ap-arrow-att { fill: rgba(239, 68, 68, 0.85) !important; }
    .ap-conn-vic {
      stroke: rgba(45, 212, 191, 0.7) !important;
      stroke-width: 3.5 !important;
    }
    .ap-glow-vic {
      stroke: rgba(45, 212, 191, 0.15) !important;
      stroke-width: 10 !important;
    }
    .ap-arrow-vic { fill: rgba(45, 212, 191, 0.85) !important; }
    .ap-connection:hover { stroke: rgba(59, 130, 246, 0.7); }
    .ap-connection-glow:hover { stroke: rgba(59, 130, 246, 0.3); }
    .ap-arrow {
      fill: rgba(59, 130, 246, 0.9);
    }

    .ap-phase-text {
      font-family: var(--font-mono);
      font-size: 11px;
      letter-spacing: 0.08em;
      fill: rgba(205, 216, 238, 0.95);
      text-anchor: middle;
      dominant-baseline: central;
    }

    /* ---------- Attack path tooltip ---------- */
    #ap-tooltip {
      position: absolute;
      pointer-events: none;
      z-index: 20;
      opacity: 0;
      transition: opacity 0.2s ease;
      max-width: 280px;
    }
    #ap-tooltip.visible { opacity: 1; }
    .ap-tooltip-inner {
      background: rgba(5, 7, 13, 0.94);
      border: 1px solid rgba(27, 39, 64, 0.8);
      border-radius: 8px;
      padding: 0.85rem 1rem;
      -webkit-backdrop-filter: blur(8px);
      backdrop-filter: blur(8px);
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
    }
    .ap-tt-header {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      margin-bottom: 0.4rem;
    }
    .ap-tt-id {
      font-family: var(--font-mono);
      font-size: 0.7rem;
      font-weight: 700;
      color: #3b82f6;
    }
    .ap-tt-name {
      font-family: var(--font-mono);
      font-size: 0.75rem;
      font-weight: 700;
      color: var(--text);
    }
    .ap-tt-meta {
      font-family: var(--font-mono);
      font-size: 0.58rem;
      color: var(--muted);
      letter-spacing: 0.08em;
      margin-bottom: 0.5rem;
    }
    .ap-tt-desc {
      font-family: var(--font-mono);
      font-size: 0.62rem;
      color: rgba(205, 216, 238, 0.95);
      line-height: 1.5;
      margin-bottom: 0.4rem;
    }
    .ap-tt-detect {
      font-family: var(--font-mono);
      font-size: 0.6rem;
      color: rgba(205, 216, 238, 0.85);
      line-height: 1.4;
      padding-top: 0.4rem;
      border-top: 1px solid rgba(27, 39, 64, 0.6);
    }
    .ap-tt-detect span { color: #3b82f6; }

    @media (max-width: 767px) {
      #attack-canvas svg { min-height: 340px; }
      #ap-tooltip { display: none !important; }}

    /* ---------- Navbar clock ---------- */
    .pulse-dot {
      width: 6px;
      height: 6px;
      border-radius: 9999px;
      background: #3b82f6;
      box-shadow: 0 0 8px var(--glow);
      animation: node-pulse 2s ease-in-out infinite;
    }

    /* ---------- Write-up feed rows ---------- */
    .writeup-row {
      background: var(--surface);
      border: 1px solid var(--stroke);
      transition: border-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease;
    }
    .writeup-row:hover {
      border-color: rgba(59, 130, 246, 0.45);
      box-shadow: 0 0 18px var(--glow);
      transform: translateY(-2px);
    }
    .writeup-row:hover .writeup-arrow { transform: translateX(4px); color: var(--text); }
    .writeup-arrow { transition: transform 0.3s ease, color 0.3s ease; }

    /* ---------- Ambient ops-room atmosphere ---------- */
    #ambient-vignette {
      position: fixed;
      inset: 0;
      z-index: 89;
      pointer-events: none;
      background: radial-gradient(ellipse at center, transparent 55%, rgba(2, 4, 9, 0.5) 100%);
    }

    /* ---------- Severity badges (signal colors — badges only) ---------- */
    .sev-badge {
      font-family: var(--font-mono);
      font-size: 0.62rem;
      font-weight: 700;
      letter-spacing: 0.16em;
      padding: 0.28rem 0.65rem;
      border-radius: 9999px;
      border: 1px solid;
      text-transform: uppercase;
      white-space: nowrap;
    }
    .sev-critical { color: var(--sev-critical); border-color: rgba(239, 68, 68, 0.45); background: rgba(239, 68, 68, 0.08); }
    .sev-high     { color: var(--sev-high);     border-color: rgba(249, 115, 22, 0.45); background: rgba(249, 115, 22, 0.08); }
    .sev-medium   { color: var(--sev-medium);   border-color: rgba(234, 179, 8, 0.45);  background: rgba(234, 179, 8, 0.08); }
    .sev-low      { color: var(--sev-low);      border-color: rgba(34, 197, 94, 0.45);  background: rgba(34, 197, 94, 0.08); }

    /* ---------- Keyboard focus visibility ---------- */
    a:focus-visible,
    button:focus-visible,
    input:focus-visible,
    [tabindex]:focus-visible {
      outline: 2px solid #3b82f6;
      outline-offset: 3px;
      border-radius: 4px;
    }
    .rounded-full:focus-visible { border-radius: 9999px; }

    /* ---------- Easing variable system ---------- */
    :root {
      --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
      --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
    }

    /* ---------- 3D tilt ---------- */
    .card, .writeup-row {
      transform-style: preserve-3d;
    }
    .card { transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.35s ease, border-color 0.35s ease; }
    .card.tilting { transition: box-shadow 0.35s ease, border-color 0.35s ease; }

    /* ---------- Scroll progress rail ---------- */
    #section-rail {
      position: fixed;
      right: 1.4rem;
      top: 50%;
      transform: translateY(-50%);
      z-index: 55;
      display: none;
      flex-direction: column;
      align-items: center;
      gap: 14px;
    }
    @media (min-width: 1024px) { #section-rail { display: flex; }}
    .rail-dot {
      display: none;
      width: 9px; height: 9px;
      border-radius: 9999px;
      border: 1.5px solid #3d4d6b;
      background: transparent;
      padding: 0;
      transition: background 0.3s ease, border-color 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease;
    }
    .rail-dot:hover { border-color: #3b82f6; transform: scale(1.3); }
    .rail-dot.active {
      background: #3b82f6;
      border-color: #3b82f6;
      box-shadow: 0 0 10px var(--glow), 0 0 20px var(--glow);
    }

    /* ---------- Ticker band ---------- */
    #ticker {
      background: var(--surface);
      border-top: 1px solid var(--stroke);
      border-bottom: 1px solid var(--stroke);
      overflow: hidden;
      position: relative;
    }
    .ticker-track {
      display: flex;
      align-items: center;
      gap: 2.5rem;
      width: max-content;
      padding: 0.65rem 0;
      animation: ticker-scroll 42s linear infinite;
    }
    #ticker:hover .ticker-track { animation-play-state: paused; }
    .ticker-item {
      font-family: var(--font-mono);
      font-size: 0.66rem;
      letter-spacing: 0.18em;
      color: var(--muted);
      white-space: nowrap;
      display: flex;
      align-items: center;
      gap: 2.5rem;
    }
    .ticker-sep {
      width: 5px; height: 5px;
      border-radius: 9999px;
      background: #3b82f6;
      box-shadow: 0 0 6px var(--glow);
      flex-shrink: 0;
    }
    @keyframes ticker-scroll {
      from { transform: translateX(0); }
      to   { transform: translateX(-50%); }
    }

    /* ---------- Typewriter caret for ticket descriptions ---------- */
    .type-caret {
      display: inline-block;
      width: 7px;
      height: 0.9em;
      background: #3b82f6;
      vertical-align: text-bottom;
      margin-left: 2px;
      box-shadow: 0 0 8px var(--glow);
      animation: term-blink 0.8s step-end infinite;
    }

    /* ---------- Background tint layers (scroll chapters) ---------- */
    #bg-tint {
      position: fixed;
      inset: 0;
      z-index: -1;
      background: #05070d;
      pointer-events: none;
    }
    #stats-tint {
      position: fixed;
      inset: 0;
      z-index: -1;
      background: #05070d;
      opacity: 0;
      pointer-events: none;
    }

    /* ---------- Mission statement chapter ---------- */
    #mission-bg {
      position: absolute;
      inset: -12%;
      background-image: none;
    }
    .mission-line {
      font-family: var(--font-display);
      font-weight: 700;
      letter-spacing: -0.03em;
      font-size: clamp(1.5rem, 4.5vw, 4rem);
      line-height: 1.18;
      max-width: 900px;
    }
    .m-word { display: inline-block; }
    .m-char { display: inline-block; }
    .l-char { display: inline-block; white-space: pre; }

    /* NOTE: dead .stat-card system removed (finish pass) — live cards
       use .xcard/.xstat/.xlabel. Kept the XStats grid below. */

    /* ---------- XStats grid (direct transplant) ---------- */
    .xgrid {
      --c-soc: #06B6D4;
      --c-intel: #F59E0B;
      --c-cd: #8B5CF6;
      --c-kcu: #EAB308;
      --c-res: #2dd4bf;
      display: grid;
      grid-template-columns: repeat(5, 1fr);
      gap: 16px;
      width: 100%;
    }
    @media (max-width: 1100px) { .xgrid { grid-template-columns: repeat(3, 1fr); } }
    @media (max-width: 820px) { .xgrid { grid-template-columns: repeat(2, 1fr); } }
    @media (max-width: 480px) { .xgrid { grid-template-columns: 1fr; } }
    .xcard {
      --a: var(--c-soc);
      position: relative;
      background: #0E1421;
      border: 1px solid #1A2438;
      border-left: 3px solid var(--a);
      border-radius: 12px;
      padding: 26px 22px 24px;
      overflow: hidden;
      opacity: 0;
      transform: translateY(14px);
      transition: opacity 0.5s ease, transform 0.5s ease;
    }
    .xcard.soc { --a: var(--c-soc); }
    .xcard.intel { --a: var(--c-intel); }
    .xcard.cd { --a: var(--c-cd); }
    .xcard.kcu { --a: var(--c-kcu); }
    .xcard.res { --a: var(--c-res); }
    .xcard:nth-child(2) { transition-delay: 0.08s; }
    .xcard:nth-child(3) { transition-delay: 0.16s; }
    .xcard:nth-child(4) { transition-delay: 0.24s; }
    .xcard:nth-child(5) { transition-delay: 0.32s; }
    .xcard.show { opacity: 1; transform: translateY(0); }
    .xcard::after {
      content: '';
      position: absolute;
      top: -20px; right: -20px;
      width: 120px; height: 120px;
      background: radial-gradient(circle, var(--a), transparent 68%);
      opacity: 0.09;
      pointer-events: none;
    }
    .xtag {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      font-size: 10px;
      font-weight: 500;
      letter-spacing: 0.1em;
      text-transform: uppercase;
      color: var(--a);
      margin-bottom: 18px;
    }
    .xtag-dot {
      width: 5px; height: 5px;
      border-radius: 50%;
      background: var(--a);
      flex-shrink: 0;
    }
    .xstat {
      font-family: 'Space Grotesk', 'Chakra Petch', sans-serif;
      font-size: 42px;
      font-weight: 700;
      color: #fff;
      line-height: 1;
      letter-spacing: -0.03em;
      margin-bottom: 8px;
    }
    .xbar {
      width: 30px; height: 2px;
      background: var(--a);
      border-radius: 2px;
      margin-bottom: 12px;
    }
    .xlabel {
      font-family: 'Space Grotesk', 'Chakra Petch', sans-serif;
      font-size: 13px;
      font-weight: 500;
      color: #E2E8F0;
      margin-bottom: 6px;
    }
    .xcontext {
      font-size: 11.5px;
      color: #a8bad6;
      line-height: 1.6;
    }
    .xcontext a { color: var(--a); text-decoration: none; }
    .xcontext a:hover { color: #fff; }
    .xwm {
      position: absolute;
      right: 12px; bottom: 12px;
      width: 88px; height: 88px;
      opacity: 0.065;
      pointer-events: none;
      color: var(--a);
    }
    .xwm svg { width: 100%; height: 100%; overflow: visible; }
    /* --- Card hover: border glow + bar grow (no tilt, no spotlight) --- */
    .xcard:hover {
      border-color: color-mix(in srgb, var(--a) 45%, #1A2438);
      box-shadow: 0 22px 55px -24px rgba(0, 0, 0, 0.75), 0 0 24px color-mix(in srgb, var(--a) 18%, transparent);
    }
    .xbar { transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1); }
    .xcard:hover .xbar { width: 60px; }
    @media (prefers-reduced-motion: reduce) {
      .xcard { opacity: 1; transform: none; transition: none; }
    }

    /* Sleep off-screen perpetual motion (paused = invisible savings).
       Sections gain .sleeping only when fully out of view. */
    .sleeping .did-ring.active,
    .sleeping .swaying,
    .sleeping .ticker-track,
    .sleeping .grad-text,
    .sleeping .timeline-node::after,
    .sleeping .pulse-dot,
    .sleeping .type-caret { animation-play-state: paused; }

    /* ---------- Compact (shrunk) nav ---------- */
    .logo-ring { transition: none; }


    /* ---------- Section accent (single blue identity) ----------
       Every section shares --layer-accent = #3b82f6.
       data-layer attributes are kept for semantic hooks only. */
    [data-layer] { --layer-accent: #3b82f6; }
    [data-layer] .eyebrow .sec-num { color: color-mix(in srgb, var(--layer-accent, #3b82f6) 55%, #ffffff); }
    [data-layer] .eyebrow::after {
      content: '';
      display: inline-block;
      width: 40px;
      height: 2px;
      background: var(--layer-accent);
      margin-left: 12px;
      vertical-align: middle;
      border-radius: 1px;
      opacity: 0.6;
    }
    [data-layer] .grad-text {
      background: linear-gradient(90deg, #f0f4ff 0%, var(--layer-accent) 100%);
      -webkit-background-clip: text;
      background-clip: text;
      -webkit-text-fill-color: transparent;
    }

    /* ---------- Defense-in-Depth diagram ---------- */
    .did-ring {
      fill: rgba(13, 21, 38, 0.01);
      stroke-width: 4;
      opacity: 0.85;
      cursor: pointer;
      transition: opacity 0.3s ease, stroke-width 0.3s ease, filter 0.3s ease, stroke-dashoffset 1.5s var(--ease-out-expo);
      stroke-dasharray: 1340;
      stroke-dashoffset: 1340;
    }
    .did-ring:hover {
      opacity: 1;
      stroke-width: 5;
      filter: drop-shadow(0 0 12px currentColor);
    }
    .did-ring.drawn {
      stroke-dashoffset: 0;
      opacity: 1;
    }
    .did-ring.active {
      opacity: 1;
      stroke-width: 5;
      filter: drop-shadow(0 0 8px var(--glow));
      stroke-dasharray: 8 12;
      animation: dsiflow 2s linear infinite;
    }
    @keyframes dsiflow {
      to { stroke-dashoffset: -40; }
    }
    .did-label {
      font-family: var(--font-mono);
      font-size: 9px;
      letter-spacing: 0.14em;
      fill: currentColor;
      pointer-events: none;
      transition: fill 0.3s ease;
    }
    .did-label.active { fill: #ffffff; }
    #did-detail {
      --accent: #3B82F6;
      min-height: 172px;
      background: #0E1421;
      border: 1px solid #1A2438;
      border-left: 3px solid var(--accent);
      border-radius: 10px;
      padding: 22px 20px 20px;
      transition: border-left-color 0.3s ease;
    }
    #did-title {
      display: inline-flex;
      align-items: center;
      gap: 7px;
      font-family: var(--font-mono);
      font-size: 10px;
      letter-spacing: 0.12em;
      text-transform: uppercase;
      margin-bottom: 12px;
    }
    #did-title::before {
      content: '';
      width: 5px; height: 5px;
      border-radius: 50%;
      background: currentColor;
      flex-shrink: 0;
    }
    #did-skills {
      font-size: 13px;
      line-height: 1.68;
      color: #a8bad6;
      margin-bottom: 16px;
    }
    #did-chips { display: flex; flex-wrap: wrap; gap: 6px; }
    .did-chip {
      font-family: var(--font-mono);
      font-size: 10px;
      color: var(--accent, #3B82F6);
      border: 1px solid var(--accent, #3B82F6);
      border-radius: 3px;
      padding: 3px 8px;
      opacity: 0.9;
      white-space: nowrap;
    }
    .ring-hit { cursor: pointer; }

    /* ---------- SOC status widget + feed ---------- */
    #soc-widget {
      background: rgba(13, 21, 38, 0.88);
      border: 1px solid var(--stroke);
    }
    @supports (backdrop-filter: blur(10px)) {
      #soc-widget {
        background: rgba(13, 21, 38, 0.72);
        -webkit-backdrop-filter: blur(10px);
        backdrop-filter: blur(10px);
      }}
    #soc-feed { max-height: 150px; overflow: hidden; position: relative; }
    #soc-feed::after {
      content: '';
      position: absolute;
      left: 0; right: 0; bottom: 0;
      height: 40px;
      background: linear-gradient(to top, rgba(13, 21, 38, 0.95), transparent);
      pointer-events: none;
    }
    @keyframes feed-in {
      from { opacity: 0; transform: translateY(-6px); }
      to   { opacity: 1; transform: translateY(0); }
    }

    /* ---------- Case study modal ---------- */
    #case-modal {
      position: fixed;
      inset: 0;
      z-index: 110;
      background: rgba(5, 7, 13, 0.88);
      display: none;
      align-items: center;
      justify-content: center;
      padding: 1.5rem;
      overflow: hidden;
    }
    @supports (backdrop-filter: blur(10px)) {
      #case-modal {
        background: rgba(5, 7, 13, 0.75);
        -webkit-backdrop-filter: blur(10px);
        backdrop-filter: blur(10px);
      }}
    #case-modal.open { display: flex; }
    /* Scroll lock while a case study modal is open (toggled in features.js
       as .modal-open on <html>) — blocks native + Lenis page scroll behind it */
    html.modal-open,
    html.modal-open body { overflow: hidden; }

    /* ---------- Screenshot lightbox ---------- */
    #shot-lightbox {
      position: fixed;
      inset: 0;
      z-index: 220;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 2rem;
      background: rgba(5, 7, 13, 0.6);
      opacity: 0;
      visibility: hidden;
      transition: opacity 0.3s ease, visibility 0.3s;
    }
    @supports (backdrop-filter: blur(16px)) {
      #shot-lightbox {
        background: rgba(5, 7, 13, 0.5);
        -webkit-backdrop-filter: blur(16px);
        backdrop-filter: blur(16px);
      }}
    #shot-lightbox.open { opacity: 1; visibility: visible; }
    #shot-lightbox .shot-lb-img {
      max-width: 92vw;
      max-height: 88vh;
      object-fit: contain;
      border-radius: 14px;
      box-shadow: 0 30px 90px rgba(0, 0, 0, 0.65);
      border: 1px solid rgba(255, 255, 255, 0.1);
      transform: scale(0.96);
      transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
    }
    #shot-lightbox.open .shot-lb-img { transform: scale(1); }
    #shot-lightbox .shot-lb-close {
      position: absolute;
      top: 1.25rem;
      right: 1.25rem;
      width: 2.6rem;
      height: 2.6rem;
      display: grid;
      place-items: center;
      border-radius: 9999px;
      border: 1px solid color-mix(in srgb, var(--project-accent, #3b82f6) 40%, var(--stroke));
      background: rgba(5, 7, 13, 0.72);
      color: var(--text);
      font-size: 1.05rem;
      line-height: 1;
      cursor: pointer;
      backdrop-filter: blur(6px);
      transition: background 0.2s ease, transform 0.2s ease;
    }
    #shot-lightbox .shot-lb-close:hover {
      background: rgba(255, 255, 255, 0.12);
      transform: rotate(90deg);
    }
    #cm-box {
      width: 100%;
      max-width: 680px;
      max-height: 86vh;
      display: flex;
      flex-direction: column;
      overflow: hidden;
    }
    #cm-body {
      flex: 1;
      min-height: 0;
      overflow-y: auto;
      overscroll-behavior: contain;
      scrollbar-width: thin;
      scrollbar-color: #1b2740 transparent;
    }
    #cm-body::-webkit-scrollbar { width: 6px; }
    #cm-body::-webkit-scrollbar-thumb { background: #1b2740; border-radius: 8px; }

    @media (prefers-reduced-motion: reduce) {
      .scroll-dot, .timeline-node::after { animation: none; }
      html { scroll-behavior: auto; }
      .card::after { display: none; }
      .pulse-dot,.type-caret{ animation: none; }
      #mobile-menu, #mobile-menu .menu-panel { transition: none; }
      .ticker-track { animation: none; }}

    /* ---------- Mobile pill nav items (Antigravity-style) ---------- */
    .mobile-pill {
      display: flex;
      align-items: center;
      justify-content: center;
      gap: 0.75rem;
      width: 100%;
      padding: 1rem 2.5rem;
      font-family: var(--font-display);
      font-weight: 700;
      font-size: 1.3rem;
      letter-spacing: -0.02em;
      color: var(--text);
      border: 1px solid var(--stroke);
      border-radius: 9999px;
      transition: border-color 0.3s ease, background 0.3s ease, transform 0.2s ease;
    }
    .mobile-pill:active {
      border-color: rgba(59, 130, 246, 0.55);
      background: rgba(59, 130, 246, 0.1);
      transform: scale(0.97);
    }

    /* ---------- Hamburger morph animation ---------- */
    .hamburger {
      flex-direction: column;
      justify-content: center;
      align-items: center;
      gap: 5px;
      padding: 0;
      background: none;
      border: none;
    }
    .hamburger span {
      display: block;
      width: 18px;
      height: 2px;
      background: var(--muted);
      border-radius: 1px;
      transition: transform 0.3s ease, opacity 0.3s ease;
    }
    .hamburger[aria-expanded="true"] span:nth-child(1) {
      transform: translateY(7px) rotate(45deg);
    }
    .hamburger[aria-expanded="true"] span:nth-child(2) {
      opacity: 0;
    }
    .hamburger[aria-expanded="true"] span:nth-child(3) {
      transform: translateY(-7px) rotate(-45deg);
    }

    /* ---------- Mobile contact form ---------- */
    .mobile-input {
      -webkit-appearance: none;
      appearance: none;
    }
    .mobile-input:focus {
      border-color: rgba(59, 130, 246, 0.55);
      box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.12);
    }

    #mobile-contact-form .mobile-input {
      border-radius: 8px !important;
    }
    #mobile-contact-form button {
      border-radius: 8px !important;
    }
    #mobile-contact-form > * + * {
      margin-top: 1rem;
    }

    /* ---------- Bottom sheet modal (mobile) ---------- */
    #case-modal.bottom-sheet {
      align-items: flex-end;
      padding: 0;
    }
    #case-modal.bottom-sheet #cm-box {
      border-radius: 1rem 1rem 0 0;
      max-height: 85vh;
      max-width: 100%;
      transform: translateY(100%);
      transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
    }
    #case-modal.bottom-sheet.open #cm-box {
      transform: translateY(0);
    }

    /* ---------- Mobile responsiveness ---------- */

    /* Tablet (max-width: 1024px) */
    @media (max-width: 1024px) {
      #section-rail { display: none !important; }}
    @media (min-width: 768px) and (max-width: 1150px) {
      #skills-grid { grid-template-columns: repeat(3, 1fr) !important; }}
    @media (min-width: 640px) and (max-width: 767px) {
      #skills-grid { grid-template-columns: repeat(2, 1fr) !important; }}










    @media (max-width: 374px) {
      #mobile-menu nav { grid-template-columns: 1fr; }
      #mobile-menu .menu-panel { max-height: 94dvh; }
      .hero-display { font-size: 2.45rem !important; }
      #stats-chapter { grid-template-columns: 1fr !important; }
      #attack-canvas svg { min-height: 340px; }
      #credentials .grid.grid-cols-2 { grid-template-columns: 1fr !important; }}

    #credentials { padding-bottom: 3rem; }
    @media (min-width: 768px) {
      #credentials { padding-bottom: 3rem; }}

    /* ============ CONTACT SPLIT + INTERACTIVE PARTICLE PORTRAIT ============
       Left column = contact intro + email + send-message form (unchanged content).
       Right column = the kinematic point-cloud portrait (js/particle-portrait.js).
       On narrow screens the columns stack (form first, portrait below). */
    .contact-split {
      display: grid;
      grid-template-columns: 1fr;
      gap: 2.5rem;
      align-items: center;
    }
    @media (min-width: 900px) {
      .contact-split {
        /* Both halves capped to ~the portrait's width: the form fields never
           stretch across half the page and the portrait column carries no dead
           space. The pair centers as one block — symmetric gutters, and the
           form hugs the middle gap next to the portrait. */
        grid-template-columns: minmax(0, 470px) minmax(0, 470px);
        justify-content: center;
        gap: 3.5rem;
        align-items: center;
      }
      /* Left-align the intro on desktop (it was centered as a single column) */
      .contact-left { text-align: left; }}
    .contact-left { text-align: center; }
    @media (min-width: 900px) { .contact-left .eyebrow { justify-content: flex-start; }}

    /* ---- Portrait stage: the canvas fills it; source img sits behind ---- */
    .contact-right { display: flex; flex-direction: column; align-items: center; }
    .pp-stage {
      position: relative;
      width: 100%;
      max-width: 460px;
      aspect-ratio: 529 / 480;      /* source is 529x445; a touch taller for drift room */
      border-radius: 18px;
      overflow: hidden;
      background:
        radial-gradient(120% 120% at 50% 42%,
          rgba(59, 130, 246, 0.10) 0%,
          rgba(34, 211, 238, 0.05) 34%,
          rgba(5, 7, 13, 0) 68%),
        #05070d;
      box-shadow:
        inset 0 0 0 1px rgba(59, 130, 246, 0.14),
        inset 0 0 60px rgba(5, 7, 13, 0.9),
        0 30px 70px rgba(0, 0, 0, 0.55);
      cursor: none;                 /* replaced by the .pp-cursor ring while live */
      touch-action: pan-y;          /* let the page still scroll on touch */
    }
    /* Faint scan-grid to reinforce the tech/data aesthetic (behind the particles) */
    .pp-stage::before {
      content: "";
      position: absolute; inset: 0;
      background-image:
        linear-gradient(rgba(59,130,246,0.05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(59,130,246,0.05) 1px, transparent 1px);
      background-size: 28px 28px;
      opacity: 0.5;
      pointer-events: none;
      z-index: 0;
    }
    /* Corner brackets — HUD framing */
    .pp-stage::after {
      content: "";
      position: absolute; inset: 12px;
      border: 1px solid transparent;
      background:
        linear-gradient(var(--pp-accent, #3b82f6), var(--pp-accent, #3b82f6)) left top,
        linear-gradient(var(--pp-accent, #3b82f6), var(--pp-accent, #3b82f6)) left top,
        linear-gradient(var(--pp-accent, #3b82f6), var(--pp-accent, #3b82f6)) right top,
        linear-gradient(var(--pp-accent, #3b82f6), var(--pp-accent, #3b82f6)) right top,
        linear-gradient(var(--pp-accent, #3b82f6), var(--pp-accent, #3b82f6)) left bottom,
        linear-gradient(var(--pp-accent, #3b82f6), var(--pp-accent, #3b82f6)) left bottom,
        linear-gradient(var(--pp-accent, #3b82f6), var(--pp-accent, #3b82f6)) right bottom,
        linear-gradient(var(--pp-accent, #3b82f6), var(--pp-accent, #3b82f6)) right bottom;
      background-repeat: no-repeat;
      background-size: 18px 1px, 1px 18px, 18px 1px, 1px 18px, 18px 1px, 1px 18px, 18px 1px, 1px 18px;
      opacity: 0.5;
      pointer-events: none;
      z-index: 3;
    }
    .pp-canvas {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      z-index: 2;
      pointer-events: none;         /* pointer events handled on .pp-stage */
    }
    /* ---- Circular lens reveal ---------------------------------------------
       A clean, brighter copy of the portrait (.pp-lens-img) is pinned to the
       exact particle draw-box; .pp-lens is a fixed-size circular window that
       trails the cursor (rAF lerp in JS) and clips it, so only a moving circle
       of the picture shows through — sharp against the grainy particle field.
       It is NOT a magnifier: the image never scales, we only move the window,
       counter-translating the inner image so the picture stays perfectly still.
       .pp-ring is a separate thin champagne ring that follows and pops on enter.
       Both sit ABOVE the canvas (z 5 / 6 > 2) so the reveal occludes particles. */
    .pp-lens {
      position: absolute; top: 0; left: 0;
      width: var(--pp-lens-d, 176px);
      height: var(--pp-lens-d, 176px);
      border-radius: 50%;
      overflow: hidden;
      z-index: 5;
      opacity: 0;
      pointer-events: none;
      transform: translate3d(-999px, -999px, 0);
      will-change: transform, opacity;
      /* Soft feather: the picture is fully opaque in the core and dissolves to
         nothing before the physical edge, so it melts into the particles — no
         hard photographic disc. */
      -webkit-mask-image: radial-gradient(closest-side, #000 62%, rgba(0,0,0,0.55) 84%, transparent 100%);
              mask-image: radial-gradient(closest-side, #000 62%, rgba(0,0,0,0.55) 84%, transparent 100%);
    }
    .pp-lens-img {
      position: absolute; top: 0; left: 0;
      width: 100px; height: 100px;         /* real size set per-fit in JS (draw box) */
      background-image: url("../assets/Manic.png");
      background-repeat: no-repeat;
      background-position: 0 0;
      background-size: 100% 100%;           /* box IS the contain-fit rect → no stretch */
      transform: translate3d(0, 0, 0);
      will-change: transform;
      /* Blue duotone: strip the photo's own colour, remap luminance onto a single
         theme-blue tone (sepia + hue-rotate lands ~217deg = accent #3b82f6). This
         keeps every facial edge/shadow crisp (structure = luminance) while reading
         as "dull" (monochrome) and fully part of the blue scene — not a raw cut-out.
         Saturation pulled down and brightness tempered so the reveal reads as a
         subdued blue — never a bright saturated wash — with the face still present. */
      filter: grayscale(1) sepia(1) hue-rotate(178deg) saturate(0.85) brightness(0.95) contrast(1.22);
    }
    /* Grade overlay — paints ABOVE the photo (last child): a theme-blue rim
       vignette that dissolves the picture into the dark scene, plus a faint cyan
       core glow. This is what turns a pasted cut-out into a premium reveal. */
    .pp-lens::after {
      content: "";
      position: absolute; inset: 0;
      border-radius: 50%;
      pointer-events: none;
      background:
        radial-gradient(closest-side,
          rgba(34, 211, 238, 0.07) 0%,
          rgba(34, 211, 238, 0) 46%),
        radial-gradient(closest-side,
          rgba(5, 7, 13, 0) 44%,
          rgba(16, 26, 46, 0.42) 74%,
          rgba(5, 7, 13, 0.9) 100%);
      mix-blend-mode: screen, normal;
    }
    .pp-ring {
      position: absolute; top: 0; left: 0;
      width: var(--pp-lens-d, 176px);
      height: var(--pp-lens-d, 176px);
      border-radius: 50%;
      border: 1.5px solid rgba(240, 234, 214, 0.82);
      box-shadow: 0 0 16px rgba(240, 234, 214, 0.18), inset 0 0 12px rgba(240, 234, 214, 0.10);
      z-index: 6;
      opacity: 0;
      pointer-events: none;
      transform: translate3d(-999px, -999px, 0) scale(0.82);
      transform-origin: center center;
      will-change: transform, opacity;
    }
    .pp-stage.pp-fallback .pp-lens,
    .pp-stage.pp-fallback .pp-ring { display: none; }
    /* The source portrait is hidden while the cloud is live; shown as a styled
       still on fallback (no WebGL / tainted sample / img error). */
    .pp-source {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      opacity: 0;
      z-index: 1;
      pointer-events: none;
      transition: opacity 0.4s ease;
    }
    .pp-stage.pp-fallback .pp-source.pp-source--shown {
      opacity: 1;
      filter: grayscale(0.35) contrast(1.05) brightness(0.9);
    }
    /* Custom cursor ring (matches the reference) */
    .pp-cursor {
      position: absolute;
      top: 0; left: 0;
      width: 22px; height: 22px;
      margin: -11px 0 0 -11px;      /* centre on the pointer position */
      border: 1.5px solid var(--cyan-live, #22d3ee);
      border-radius: 50%;
      box-shadow: 0 0 10px rgba(34, 211, 238, 0.6);
      opacity: 0;
      z-index: 7;
      pointer-events: none;
      transition: opacity 0.2s ease;
      will-change: transform;
    }
    .pp-stage.pp-fallback .pp-cursor { display: none; }
    .pp-stage.pp-fallback { cursor: default; }
    @media (max-width: 899px) {
      .pp-stage { max-width: 400px; --pp-lens-d: 140px; }}
    @media (max-width: 560px) {
      .pp-stage { --pp-lens-d: 112px; }}
