/* Self-hosted fonts (latin subsets from Google Fonts, SIL Open Font License) */
@font-face { font-family: Unbounded; font-weight: 900; font-display: swap; src: url(../fonts/unbounded-900.woff2) format("woff2"); }
@font-face { font-family: Inter; font-weight: 400 700; font-display: swap; src: url(../fonts/inter-var.woff2) format("woff2"); }
@font-face { font-family: "JetBrains Mono"; font-weight: 400 700; font-display: swap; src: url(../fonts/jetbrainsmono-var.woff2) format("woff2"); }

/* Rules: neutral ground (near-black / off-white), pure black and white text, mid-grey micro-text,
   one fluo accent (acid) for CTAs, active state and focus. No gradients, no soft shadows, no glass. */
:root {
    --acid: #C6FF00;
    --blue: #2F3DFF;
    --magenta: #FF2BD6;
    --ink: #0E0E0E;
    --ink-deep: #2D3538;
    --paper: #E8E6E1;
    /* Alternative palettes, switched with the "palette" command (data-palette on <html>) */
    /* Fine grain, on the paper and acid surfaces only */
    --grain-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 .16 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    --dots: radial-gradient(rgba(255,255,255,.09) 1px, transparent 1.4px);
    --hairlines: repeating-linear-gradient(35deg, rgba(14,14,14,.07) 0 1px, transparent 1px 4px);
    --scanlines: repeating-linear-gradient(0deg, transparent 0 3px, rgba(255,255,255,.035) 3px 4px);
    --fibres: repeating-linear-gradient(90deg, rgba(14,14,14,.035) 0 1px, transparent 1px 7px);
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.95' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.13'/%3E%3C/svg%3E");
    --white: #FFFFFF;
    --grey: #8A8A8A;
    --line: rgba(255,255,255,.14);
    --line-dark: rgba(14,14,14,.18);
    --display: Unbounded, Impact, sans-serif;
    --mono: "JetBrains Mono", monospace;
    /* Side gutter: 5% of the viewport */
    --gutter: 5vw;
    --z: 1;
    --nav-h: 66px;
    /* 60px hatch mark //// in the current text colour */
    --hatch: repeating-linear-gradient(-45deg, currentColor 0 2px, transparent 2px 6px);
    /* 12-column grid, 1px lines, shown on a few sections */
    --grid12: repeating-linear-gradient(90deg, var(--line) 0 1px, transparent 1px calc(100% / 12));
    /* Dry motion: 100–200ms, stepped or linear */
    --snap: 150ms steps(3);
    --quick: 120ms linear;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; scrollbar-width: thin; scrollbar-color: var(--acid) var(--ink); }
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-track { background: var(--ink); }
::-webkit-scrollbar-thumb { background: var(--acid); }
html, body { overflow-x: hidden; }
body { background: var(--ink); color: var(--white); font: 14px/1.6 var(--mono); }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
main { counter-reset: section; }
h1, h2, h3, .words { font-family: var(--display); font-weight: 900; text-transform: uppercase; }
:focus-visible { outline: 2px solid var(--acid); outline-offset: 3px; }
.cmd input:focus-visible { outline: none; }
#skills :focus-visible, #about :focus-visible { outline-color: var(--ink); }
.skip { position: fixed; top: 8px; left: 8px; z-index: 70; padding: 10px 14px; background: var(--acid); color: var(--ink); font: 700 11px var(--mono); letter-spacing: 2px; text-transform: uppercase; transform: translateY(-200%); }
.skip:focus { transform: none; }

/* Micro-text: 11px mono, uppercase, tracked */
.label, .meta, .roles, .btn, .menu-btn, .lang, .chips li, .jobs .n, .jobs .role, .edu, .wall span, .project .stack, .project a, .project::before, .wall li::before, .contact ul, .looking, .hey {
    font-family: var(--mono); font-weight: 700; font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
}

/* Nav: logo, coordinates and the current block code, MENU button, language */
.nav {
    position: sticky; top: 0; z-index: 35;
    display: flex; align-items: center; gap: 28px;
    height: var(--nav-h); padding: 0 var(--gutter);
    background: var(--ink); color: var(--white); border-bottom: 1px solid var(--line);
}
.logo { font: 900 15px var(--display); text-transform: uppercase; }
.logo span { color: var(--acid); }
.meta { margin-right: auto; color: var(--grey); }
#where { color: var(--acid); }
#where::after { content: "_"; animation: blink 1s steps(2) infinite; }
@keyframes blink { 50% { opacity: 0; } }
.menu-btn { padding: 12px 16px; border: 1px solid var(--white); background: transparent; color: var(--white); cursor: pointer; transition: background var(--quick), color var(--quick); }
.menu-btn:hover, .menu-open .menu-btn { background: var(--acid); color: var(--ink); border-color: var(--acid); }
.lang { width: 48px; height: 40px; border: 1px solid var(--white); background: transparent; color: var(--white); cursor: pointer; letter-spacing: 1px; }
.lang:hover { background: var(--white); color: var(--ink); }

.menu {
    position: fixed; inset: 0; z-index: 30; counter-reset: menu;
    display: grid; align-content: center; gap: 0; padding: var(--nav-h) var(--gutter) 0;
    background: var(--ink);
    transform: translateY(-100%); visibility: hidden; transition: transform var(--snap), visibility 0s 150ms;
}
.menu-open .menu { transform: none; visibility: visible; transition: transform var(--snap), visibility 0s; }
.menu-open { overflow: hidden; }
.menu a {
    display: flex; align-items: baseline; gap: 24px; padding: 12px 0; border-top: 1px solid var(--line);
    font: 900 clamp(32px, 6vw, 76px)/1 var(--display); text-transform: uppercase; letter-spacing: -.02em;
    opacity: 0; transition: color var(--quick), opacity 0s;
}
.menu a:last-child { border-bottom: 1px solid var(--line); }
.menu-open .menu a { opacity: 1; }
.menu-open .menu a:nth-child(2) { transition-delay: 40ms; }
.menu-open .menu a:nth-child(3) { transition-delay: 80ms; }
.menu-open .menu a:nth-child(4) { transition-delay: 120ms; }
.menu-open .menu a:nth-child(5) { transition-delay: 160ms; }
.menu a::before { content: "[0" counter(menu) "]"; counter-increment: menu; font: 700 11px var(--mono); letter-spacing: 2px; color: var(--grey); }
.menu a:hover, .menu a.active { color: var(--acid); }

/* Hero: full viewport on the 12-column grid, 3D scatter behind, the name huge at the bottom */
.hero {
    position: relative; overflow: hidden; min-height: calc(100vh / var(--z) - var(--nav-h));
    display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: auto 1fr auto; row-gap: 24px;
    padding: 48px var(--gutter); background: var(--grain-light), var(--scanlines), var(--ink);
}
.hero > :not(model-viewer):not(.hud) { position: relative; z-index: 2; }
/* The 3D card fills the hero behind the text; wheel and touch pass through so the page keeps scrolling */
#card3d { position: absolute; top: 0; bottom: 14%; left: 42%; width: 58%; height: 86%; z-index: 0; pointer-events: none; --poster-color: transparent; transition: transform 120ms linear; }
.hero-top { grid-column: 1; grid-row: 1; }
.hero-top::after { content: ""; display: block; width: 60px; height: 6px; margin-top: 16px; background: var(--hatch); color: var(--acid); }
.hey { display: block; margin-bottom: 12px; color: var(--grey); }
.roles { display: inline-block; padding: 8px 12px; border: 1px solid var(--white); color: var(--white); }
.roles b { color: var(--acid); }
.hero-cta { grid-column: 1; grid-row: 2; justify-self: start; align-self: start; display: flex; flex-wrap: wrap; gap: 12px; margin-top: 8px; }
/* Pedestal under the 3D card: a short acid line and its label */
.pedestal { grid-column: 2; grid-row: 3; align-self: end; margin-bottom: 10px; justify-self: center; margin-right: -8%; padding-top: 10px; border-top: 2px solid var(--acid); display: flex; align-items: center; gap: 12px; color: var(--grey); }
.hero-name { grid-column: 1 / -1; grid-row: 3; align-self: end; margin-left: -.04em; font-size: clamp(2.2rem, 6.6vw, 6.2rem); line-height: .95; letter-spacing: -.03em; }
.hero-name span { display: block; overflow: hidden; }
.hero-name span:last-child { color: var(--acid); }
.hero-name i { display: block; font-style: normal; }
.js .hero-name i { transform: translateY(110%); transition: transform 200ms steps(4) 150ms; }
.js .hero-name span:last-child i { transition-delay: 250ms; }
.ready .hero-name i { transform: none; }

/* Buttons: flat accent with black text, or a thin outline */
.btn { padding: 12px 18px; border: 1px solid var(--acid); transition: background var(--quick), color var(--quick), border-color var(--quick); }
.btn-main { background: var(--acid); color: var(--ink); }
.btn-main::after { content: "→"; display: inline-block; margin-left: 10px; }
.btn-outline { color: var(--white); border-color: var(--white); }
.btn:hover { background: var(--white); color: var(--ink); border-color: var(--white); }
.btn-main:hover { background: var(--ink); color: var(--acid); border-color: var(--acid); }

/* HUD corners, registration marks, canvases */
#fx2 { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; }
.hud { position: absolute; width: 22px; height: 22px; border: 1px solid var(--acid); z-index: 1; }
.hud-tl { top: 14px; left: 14px; border-right: 0; border-bottom: 0; }
.hud-tr { top: 14px; right: 14px; border-left: 0; border-bottom: 0; }
.hud-bl { bottom: 14px; left: 14px; border-right: 0; border-top: 0; }
.hud-br { bottom: 14px; right: 14px; border-left: 0; border-top: 0; }
.cross { position: absolute; width: 18px; height: 18px; color: currentColor; opacity: .55; pointer-events: none; z-index: 1; }
.hero .cross { color: var(--acid); }
/* Data readouts: typewriter lines (js/fx.js) and a slow tape of training metrics along the bottom */
.readout { position: absolute; top: 46%; z-index: 1; font: 700 10px/1 var(--mono); letter-spacing: 2px; color: var(--acid); opacity: .8; }
.readout-1 { right: var(--gutter); }
.hero > p.readout, .hero > div.tape { position: absolute; }
.tape { position: absolute; left: 0; right: 0; bottom: 0; z-index: 1; overflow: hidden; white-space: nowrap; border-top: 1px solid var(--line); padding: 6px 0; font: 700 10px/1 var(--mono); letter-spacing: 2px; text-transform: uppercase; color: var(--grey); }
.tape span { display: inline-block; animation: tape 60s linear infinite; }
@keyframes tape { to { transform: translateX(-100%); } }

/* Sparkline in each project card, drawn in the band colour when the card appears */

/* Training log ticking inside one of the stats wall's black tiles (js/main.js) */
.wall .log { align-self: end; margin: 0; font: 400 10px/1.7 var(--mono); letter-spacing: 1px; color: var(--acid); opacity: .75; white-space: pre; overflow: hidden; }
.wall .log::after { content: "_"; animation: blink 1s steps(2) infinite; }

/* Glitch on card hover: two clipped copies of the stat, offset, three stepped frames */
.stat[data-text] { position: relative; }
.stat[data-text]::before, .stat[data-text]::after { content: attr(data-text); position: absolute; inset: 0; pointer-events: none; opacity: 0; color: var(--white); }
.stat[data-text]::before { clip-path: inset(0 0 55% 0); transform: translateX(-3px); }
.stat[data-text]::after { clip-path: inset(55% 0 0 0); transform: translateX(3px); }
.project:hover .stat::before, .project:hover .stat::after { animation: glitch 200ms steps(3) forwards; }
@keyframes glitch { from { opacity: 1; } to { opacity: 0; } }

/* Intro flash: two bands sweep across once the preloader lifts, and again on a menu click */
.flash { position: fixed; inset: 0; z-index: 45; pointer-events: none; overflow: hidden; visibility: hidden; }
.ready .flash, .flash.go { visibility: visible; }
.flash::before, .flash::after { content: ""; position: absolute; top: 0; bottom: 0; transform: translateX(-120vw); }
.flash::before { width: 18vw; background: var(--acid); }
.flash::after { width: 4vw; background: var(--white); }
.ready .flash::before { animation: sweep 200ms linear 200ms both; }
.ready .flash::after { animation: sweep 200ms linear 260ms both; }
.flash.go::before { animation: sweep 200ms linear both; }
.flash.go::after { animation: sweep 200ms linear 50ms both; }
@keyframes sweep { to { transform: translateX(120vw); } }

/* Gutters: two fixed rails with tick marks and a scroll marker, the block number written vertically on the left */
.rail { position: fixed; top: var(--nav-h); bottom: 0; z-index: 5; width: 1px; pointer-events: none; background: repeating-linear-gradient(0deg, transparent 0 23px, var(--line) 23px 24px); }
.rail-l { left: calc(var(--gutter) / 2); }
.rail-r { right: calc(var(--gutter) / 2); }
.rail::after { content: ""; position: absolute; left: -4px; top: calc(var(--progress, 0) * (100% - 9px)); width: 9px; height: 9px; background: var(--acid); }
.card[data-n]::before {
    content: "[" attr(data-n) "]"; position: absolute; top: 160px; left: calc(var(--gutter) / 2); transform: translateX(-50%);
    writing-mode: vertical-rl; font: 900 clamp(40px, 5vw, 96px)/1 var(--display); letter-spacing: -.02em;
    color: transparent; -webkit-text-stroke: 1px currentColor; opacity: .35;
}

/* Stats wall: acid plates with a cut corner, numbers that count up, black voids staggered between */
.stats { position: relative; background: var(--grain-light), var(--scanlines), var(--ink); }
.wall { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 1px; background: rgb(from var(--acid) r g b /.35); counter-reset: tile; }
.wall li { position: relative; aspect-ratio: 1; padding: 24px; display: grid; align-content: end; gap: 8px; color: var(--ink); background: var(--grain), var(--hairlines), var(--acid); clip-path: polygon(0 0, 100% 0, 100% calc(100% - 28px), calc(100% - 28px) 100%, 0 100%); }
.wall li:not(.void)::before { content: "[S.0" counter(tile) "]"; counter-increment: tile; position: absolute; top: 16px; left: 24px; color: rgba(14,14,14,.6); }
.wall .void { background: var(--ink); clip-path: none; }
.wall b { font: 900 clamp(28px, 4.4vw, 80px)/1 var(--display); font-variant-numeric: tabular-nums; }
.wall b em, .wall b i { font-style: normal; }
.wall b em { font-size: .5em; }

/* Sections: full-bleed bands, lots of empty, a block code on each */
.card { position: relative; padding: 160px var(--gutter); }
#projects { background: var(--grain-light), var(--dots) 0 0 / 7px 7px, var(--ink-deep); }
/* Skills on paper: light grain, two acid bands on the bias behind the rows */
#skills { padding-block: 64px; color: var(--ink); background: var(--paper); }
#parcours { background: var(--grain-light), var(--ink-deep); }
#about { padding-block: 200px; background: var(--grain), var(--hairlines), var(--acid); color: var(--ink); }
.marker { position: relative; display: flex; align-items: flex-start; gap: 16px; margin: 0 0 48px -2px; padding-bottom: 16px; font-size: 44px; letter-spacing: -.02em; line-height: 1; background: var(--hatch) left bottom / 60px 6px no-repeat; }
.marker::before { content: "[" counter(section, decimal-leading-zero) "] //"; counter-increment: section; margin-top: 10px; color: var(--grey); font: 700 11px var(--mono); letter-spacing: 2px; }
.js .reveal .marker { clip-path: inset(0 100% 0 0); transition: clip-path 200ms steps(6) 50ms; }
.js .reveal.in .marker { clip-path: inset(0 0 0 0); }
/* A 1px line sweeps the section once it is revealed */
.js .reveal::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px; background: var(--acid); opacity: 0; pointer-events: none; }
.js .reveal.in::after { animation: scan 300ms linear both; }
@keyframes scan { 0% { top: 0; opacity: 1; } 100% { top: 100%; opacity: 0; } }

/* Projects: four columns, the final-year project featured on two; cut-corner plates, 1px borders, a code on each */
.projects { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; counter-reset: card; }
.project {
    position: relative; display: grid; align-content: start; gap: 10px; padding: 48px 24px 24px;
    color: var(--white); border: 1px solid rgb(from var(--acid) r g b /.2); border-top: 6px solid var(--band, var(--acid));
    background: var(--grain-light), var(--ink);
    /* Machined plate: cut top-right and bottom-left corners, a notch on the right edge */
    clip-path: polygon(0 0, calc(100% - 24px) 0, 100% 24px, 100% 42%, calc(100% - 8px) calc(42% + 8px), calc(100% - 8px) calc(58% - 8px), 100% 58%, 100% 100%, 24px 100%, 0 calc(100% - 24px));
    transition: transform 100ms linear, border-color var(--quick);
}
.project::before { content: "[P.0" counter(card) "] // PROJECT"; counter-increment: card; position: absolute; top: 16px; left: 24px; color: var(--grey); }
.project:hover { transform: translateY(-4px); border-color: var(--acid); border-top-color: var(--band, var(--acid)); }
.featured, .wide { grid-column: span 2; }
.featured { grid-template-columns: auto 1fr; column-gap: 40px; padding: 48px 32px 32px; }
.featured .stat { grid-row: 1 / span 4; font-size: 56px; }
.featured h3 { font-size: 18px; }
.project .stat { font: 900 26px/1 var(--display); text-transform: uppercase; color: var(--band, var(--acid)); }
.project h3 { font-size: 14px; }
.project p:not(.stat):not(.stack) { max-width: 40ch; color: var(--grey); font: 15px/1.5 Inter, sans-serif; }
.project .stack { color: var(--white); }
.project a { margin-top: auto; color: var(--acid); text-underline-offset: 4px; }
.project a:hover { text-decoration: underline; }
.cmd-hint { cursor: pointer; transition: color var(--quick), border-color var(--quick); }
.cmd-hint:hover { color: var(--acid); border-color: var(--acid); }
.project a::after { content: ""; position: absolute; inset: 0; }

/* Skills on paper: one ruled row per category, big category name on the left, chips on the right */
.skill-row { display: grid; grid-template-columns: 1fr 2fr; gap: 24px; align-items: center; padding: 18px 0; }
.skill-row h3 { font-size: 24px; letter-spacing: -.02em; line-height: 1; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chips li { display: inline-flex; align-items: center; gap: 8px; padding: 8px 12px; border: 1px solid var(--ink); color: var(--ink); transition: background var(--quick), color var(--quick); }
.chips img { width: 16px; height: 16px; }
.chips li:hover { background: var(--ink); color: var(--acid); }
.chips li:hover img { filter: invert(1); }
#skills .marker { margin-bottom: 24px; }
#skills .marker::before { color: var(--grey); }

/* Journey: a numbered, ruled list, education on a single line below */
.jobs li { position: relative; z-index: 1; display: grid; grid-template-columns: 80px 1fr 1.4fr; gap: 24px; align-items: start; padding: 32px 0; border-top: 1px solid var(--line); }
.jobs li:last-child { border-bottom: 1px solid var(--line); }
.jobs .n { color: var(--blue); }
.jobs h3 { font-size: 26px; letter-spacing: -.02em; line-height: 1; transition: color var(--quick); }
.jobs li:hover h3 { color: var(--acid); }
.jobs .role { margin-top: 10px; color: var(--acid); }
.jobs p:not(.role) { color: var(--grey); font: 15px/1.5 Inter, sans-serif; }
.edu { margin-top: 24px; line-height: 1.8; color: var(--grey); }
.edu b { color: var(--white); }

/* About as a manifesto: acid column sticky on the left, a big statement that decodes word by word on the right */
.manifesto { display: grid; grid-template-columns: 1fr 2fr; gap: 48px; align-items: start; }
/* The poster as a 3D card, sticky; the camera orbits toward the mouse (js/main.js) */
.about-visual { position: sticky; z-index: 1; top: calc(var(--nav-h) + 24px); perspective: 1200px; }
.tilt { position: relative; }
#data3d { display: block; width: 100%; height: auto; aspect-ratio: 66 / 86; background: transparent; --poster-color: transparent; }
.about-visual .looking { position: absolute; left: 16px; bottom: 16px; }
.statement { margin-bottom: 40px; font: 900 clamp(20px, 2.5vw, 38px)/1.12 var(--display); text-transform: uppercase; text-align: justify; letter-spacing: -.01em; }
.statement .w { opacity: .22; transition: opacity 100ms steps(2); }
.statement .w.on { opacity: 1; }
.about-copy p:not(.statement) { max-width: 60ch; margin-bottom: 12px; font: 15px/1.6 Inter, sans-serif; color: var(--ink-deep); }
#about .marker::before { color: var(--ink-deep); }
.looking { display: inline-block; padding: 4px 10px; background: var(--magenta); color: var(--ink); }

/* Contact as the finale: the title at the hero's scale, links as buttons, a barcode and serial number */
.contact { position: relative; overflow: hidden; padding: 160px var(--gutter) 120px; display: grid; gap: 48px; background: var(--grain-light), var(--scanlines), var(--ink); color: var(--white); border-top: 1px solid var(--line); }
.contact > :not(canvas) { position: relative; z-index: 1; }
.contact .marker { display: block; margin: 0 0 0 -.02em; font-size: clamp(2.2rem, 6.2vw, 5.8rem); line-height: .95; letter-spacing: -.03em; }
.contact .marker::before { display: none; }
.contact em { padding: 0 .08em; background: var(--acid); color: var(--ink); font-style: normal; white-space: nowrap; }
.contact ul { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.contact a { display: inline-block; padding: 12px 16px; border: 1px solid var(--acid); color: var(--acid); transition: background var(--quick), color var(--quick); }
.contact a:hover { background: var(--acid); color: var(--ink); }
.contact li:last-child { color: var(--grey); }
.contact::after {
    content: "SN 2026-1029 · MRS"; position: absolute; right: var(--gutter); bottom: 24px; z-index: 1; padding-top: 40px;
    font: 700 10px var(--mono); letter-spacing: 2px; color: var(--grey);
    background: repeating-linear-gradient(90deg, var(--white) 0 2px, transparent 2px 4px, var(--white) 4px 7px, transparent 7px 9px, var(--white) 9px 10px, transparent 10px 14px) top / 100% 32px no-repeat;
}
#fx2 { opacity: .18; pointer-events: none; }

/* Scroll reveal (class toggled by js/main.js): a stepped fade, no slide */
.js .reveal { opacity: 0; transition: opacity 150ms steps(3); }
.js .reveal.in { opacity: 1; }
/* Cascade: chips, rows, cards and tiles appear one after another (--i set in js/main.js) */
.js .reveal :is(.chips li, .jobs li, .project, .wall li) { opacity: 0; transition: opacity 100ms steps(2); transition-delay: calc(var(--i) * 40ms); }
.js .reveal.in :is(.chips li, .jobs li, .project, .wall li) { opacity: 1; }
.js .reveal.in .project { transition: opacity 100ms steps(2), transform 100ms linear, border-color var(--quick); }

/* Intro: hero content appears once the preloader is done */
.js .hero > :is(.hero-top, .hero-cta, .hero-name) { opacity: 0; transition: opacity 100ms steps(2); }
.ready .hero > :is(.hero-top, .hero-cta, .hero-name) { opacity: 1; }
.ready .hero-cta { transition-delay: 100ms; }

/* Preloader: counts up, then lifts; hidden and click-through once gone */
.loader { position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center; background: var(--ink); color: var(--acid); font: 900 clamp(48px, 9vw, 120px)/1 var(--display); transition: transform 200ms steps(4); }
.loader.done { transform: translateY(-100%); visibility: hidden; pointer-events: none; transition: transform 200ms steps(4), visibility 0s 200ms; }
.loader .count { font-variant-numeric: tabular-nums; }

/* Custom cursor: a reticle (dot, ring, four ticks) with live coordinates beside it; the ring spins over links */
.has-cursor, .has-cursor a, .has-cursor button { cursor: none; }
.cursor { position: fixed; z-index: 60; pointer-events: none; width: 6px; height: 6px; margin: -3px 0 0 -3px; background: var(--acid); mix-blend-mode: difference; }
.cursor::before { content: ""; position: absolute; inset: -14px; border: 1px solid var(--acid); transition: inset var(--quick), transform 300ms linear; }
.cursor::after { content: ""; position: absolute; inset: -22px; background:
    linear-gradient(var(--acid), var(--acid)) top center / 1px 8px no-repeat,
    linear-gradient(var(--acid), var(--acid)) bottom center / 1px 8px no-repeat,
    linear-gradient(var(--acid), var(--acid)) left center / 8px 1px no-repeat,
    linear-gradient(var(--acid), var(--acid)) right center / 8px 1px no-repeat; }
.cursor.big::before { inset: -22px; transform: rotate(45deg); }
.cursor-xy { position: fixed; z-index: 60; pointer-events: none; margin: 18px 0 0 22px; font: 700 9px/1 var(--mono); letter-spacing: 2px; color: var(--acid); mix-blend-mode: difference; display: none; }
.has-cursor .cursor-xy { display: block; }

@media (max-width: 900px) { .meta { display: none; } }

@media (max-width: 760px) {
    :root { --gutter: 20px; }
    .rail, .card[data-n]::before, .cross, .contact::after, .readout { display: none; }
    #card3d { left: 0; width: 100%; opacity: .5; }
    .hero { grid-template-columns: 1fr; grid-template-rows: auto 1fr auto; padding: 32px 20px; gap: 20px; }
    .hero-top, .hero-cta, .hero-name { grid-column: 1; }
    .hero-cta { grid-row: 2; justify-self: start; justify-content: flex-start; }
    .hero-name { grid-row: 3; font-size: clamp(30px, 10.5vw, 48px); }
    .roles, .hey { white-space: normal; }
    .statement { text-align: left; }
    .wall { grid-template-columns: repeat(2, 1fr); }
    .wall .void { display: none; }
    .wall li:nth-child(9) { grid-column: 1 / -1; aspect-ratio: 2; }
    .card, .contact, #skills, #about { padding: 80px 20px; }
    .projects, .manifesto, .skill-row { grid-template-columns: 1fr; }
    .project { clip-path: none; }
    .featured, .wide { grid-column: auto; }
    .featured { grid-template-columns: 1fr; padding: 48px 24px 24px; }
    .featured .stat { grid-row: auto; font-size: 56px; }
    .jobs li { grid-template-columns: 1fr; gap: 10px; }
    .jobs h3, .skill-row h3 { font-size: 28px; }
    .about-visual { position: static; }
    .marker { font-size: 40px; letter-spacing: -1px; margin-bottom: 32px; }
    .contact em { white-space: normal; }
}
@media (max-width: 1000px) and (min-width: 761px) { .projects { grid-template-columns: repeat(2, 1fr); } }

@media print {
    .loader, .flash, .cursor, .rail, .menu, .menu-btn, .lang, canvas, .hud, .skip, .badge, .cmd, .cmd-hint, .cursor-xy { display: none !important; }
    .js .reveal, .js .reveal *, .statement .w, .hero > *, .hero-name i { opacity: 1 !important; transform: none !important; animation: none !important; clip-path: none !important; }
    .js .reveal::after { display: none; }
    .hero { min-height: 0; }
    .card, .contact { padding: 40px var(--gutter); break-inside: avoid; }
    .project a::after { content: " (" attr(href) ")"; position: static; font-size: 9px; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
    html { scroll-behavior: auto; }
    .loader, .flash { display: none; }
    .js .reveal, .js .reveal :is(.chips li, .jobs li, .project, .wall li), .statement .w { opacity: 1; }
    .js .hero > :is(.hero-top, .hero-cta, .hero-name) { opacity: 1; }
    .js .hero-name i { transform: none; }
    .js .reveal .marker { clip-path: none; }
    .js .reveal::after { display: none; }
    .menu a { opacity: 1; }
    #where::after, .wall .log::after, .cm i, .loss .curve, .bar.big::after, .tape span { animation: none; }
}

/* Sober futurist furniture: barcodes, tick rulers, project pictos, data tiles */
.bar { display: inline-block; width: 72px; height: 18px; vertical-align: middle; opacity: .7;
    background: repeating-linear-gradient(90deg, currentColor 0 2px, transparent 2px 4px, currentColor 4px 7px, transparent 7px 9px, currentColor 9px 10px, transparent 10px 14px); }
.bar.big { position: relative; width: 100%; height: 100%; color: var(--acid); opacity: .85; }
/* A scan line sweeps the barcode */
.bar.big::after { content: ""; position: absolute; top: -4px; bottom: -4px; left: 0; width: 2px; background: var(--white); animation: scanbar 2s linear infinite; }
@keyframes scanbar { to { left: 100%; } }
.ruler { display: block; width: 160px; height: 8px; margin: -36px 0 40px; opacity: .5;
    background: repeating-linear-gradient(90deg, currentColor 0 1px, transparent 1px 8px) bottom / 100% 4px no-repeat, repeating-linear-gradient(90deg, currentColor 0 1px, transparent 1px 40px) bottom / 100% 8px no-repeat; }
.wall .void { display: grid; grid-template-rows: 1fr auto; gap: 12px; padding: 20px; color: var(--acid); overflow: hidden; }
.wall .tag { font: 700 10px var(--mono); letter-spacing: 2px; color: var(--grey); }
.cm { display: grid; grid-template-columns: repeat(16, 1fr); grid-auto-rows: 1fr; gap: 1px; }
.cm i { background: rgba(255,255,255,.05); }
.cm i.low { background: rgba(255,255,255,.12); animation: cell 6s steps(1) infinite; animation-delay: calc(var(--i) * -37ms); }
.cm i.mid { background: rgb(from var(--acid) r g b /.35); animation: cell 5s steps(1) infinite; animation-delay: calc(var(--i) * -53ms); }
.cm i.on { animation-name: cell-on; }
@keyframes cell { 0%, 100% { opacity: 1; } 30% { opacity: .35; } 60% { opacity: .8; } }
@keyframes cell-on { 0%, 100% { background: var(--acid); } 50% { background: rgb(from var(--acid) r g b /.55); } }
.loss { width: 100%; height: 100%; }
.loss polyline { fill: none; vector-effect: non-scaling-stroke; }
.loss .grid { fill: none; stroke: rgba(255,255,255,.12); stroke-width: 1; vector-effect: non-scaling-stroke; }
.loss .curve { stroke: var(--acid); stroke-width: 2; stroke-dasharray: 400; animation: draw 3s linear infinite; }
@keyframes draw { 0% { stroke-dashoffset: 400; } 70%, 100% { stroke-dashoffset: 0; } }
.edu .bar { color: var(--grey); width: 56px; height: 12px; }
.pedestal .bar { color: var(--acid); }
@media (max-width: 760px) { .pedestal, .ruler { display: none; } #card3d { left: 0; width: 100%; height: 100%; bottom: 0; } }


#skills .ruler { color: var(--ink); }
/* Status dot in the header */
.status i { display: inline-block; width: 6px; height: 6px; margin-right: 6px; background: var(--acid); vertical-align: middle; animation: blink 1.4s steps(2) infinite; }
/* Lock-on: reticle corners appear on the hovered project card */
.project::after, .jobs li::after { content: ""; position: absolute; inset: 6px; pointer-events: none; opacity: 0; transition: opacity var(--quick);
    background: linear-gradient(var(--acid), var(--acid)) top left / 14px 1px no-repeat, linear-gradient(var(--acid), var(--acid)) top left / 1px 14px no-repeat,
                linear-gradient(var(--acid), var(--acid)) bottom right / 14px 1px no-repeat, linear-gradient(var(--acid), var(--acid)) bottom right / 1px 14px no-repeat; }
.project:hover::after, .jobs li:hover::after { opacity: 1; }
.wall .log { align-self: end; }
@media (prefers-reduced-motion: reduce) { .status i { animation: none; } }

/* open-design / industrial brutalist: ASCII framing, halftone on the poster, compartment lines */
.wall .tag::before, .pedestal::before { content: "// "; color: rgba(255,255,255,.35); }
.readout-1::before { content: "> "; }
/* Projects and stats read as one machined panel: cards flush, hover lifts the card out of the panel */
.projects > li { background: var(--ink); }
.project:hover { transform: translateY(-4px); z-index: 1; }

/* Wide screens lay out like a 1536px laptop: js/main.js sets zoom and --z on <html> to innerWidth / 1536 (vw follows the
   zoomed viewport, vh and pointer coordinates do not: --z corrects those). Continuous, so browser zoom changes nothing. */

/* Boot log under the preloader counter */
.boot { position: absolute; left: var(--gutter); bottom: 32px; margin: 0; font: 700 11px/1.7 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--grey); }
.boot b { color: var(--acid); font-weight: 700; }
/* Command line: "/" opens it, Enter runs, Escape closes */
.cmd { position: fixed; left: var(--gutter); bottom: 24px; z-index: 40; display: grid; grid-template-columns: auto 1fr; column-gap: 10px; align-items: center; width: min(520px, calc(100vw - 2 * var(--gutter))); padding: 10px 14px; border: 1px solid var(--acid); background: var(--ink); font: 700 12px/1.4 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--acid);
    clip-path: polygon(0 0, calc(100% - 12px) 0, 100% 12px, 100% 100%, 12px 100%, 0 calc(100% - 12px)); }
.cmd[hidden] { display: none; }
.cmd input { width: 100%; border: 0; background: transparent; color: var(--white); font: inherit; letter-spacing: inherit; text-transform: inherit; caret-color: var(--acid); outline: none; }
.cmd input::placeholder { color: var(--grey); }
.cmd output { grid-column: 1 / -1; color: var(--grey); }
.cmd output:empty { display: none; }
.cmd-hint { padding: 0 5px; border: 1px solid var(--line); color: var(--grey); font: inherit; }
/* Project key number: counts up on hover (js/main.js) */
.project .kpi { white-space: nowrap; font: 700 11px/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--grey); }
.project .kpi b { display: inline-block; min-width: 3ch; margin-right: 4px; font: 900 22px/1 var(--display); color: var(--white); font-variant-numeric: tabular-nums; }
.featured .kpi b { font-size: 32px; }
/* Parcours: barcode dates, a timeline the marker travels down on scroll (js/main.js sets --jp) */
.jobs .bar { width: 48px; height: 10px; margin-left: 6px; color: var(--grey); vertical-align: -1px; }
.jobs { position: relative; }
.jobs::before { content: ""; position: absolute; left: 52px; top: 0; bottom: 0; width: 1px; background: var(--line); }
.jobs::after { content: ""; position: absolute; left: 49px; top: calc(var(--jp) * 100%); width: 7px; height: 7px; background: var(--acid); transition: top 150ms steps(3); }
@media (max-width: 760px) { .jobs::before, .jobs::after, .cmd-hint { display: none; } .cmd { left: 12px; width: calc(100vw - 24px); } .boot { left: 20px; } }

/* GitHub live tile in the stats wall (js/main.js fills it from the public API) */
.wall .gh { grid-template-rows: 1fr auto; }
.ghl { align-self: end; display: grid; grid-template-columns: auto 1fr; column-gap: 14px; row-gap: 6px; margin: 0; font: 700 11px/1.3 var(--mono); letter-spacing: .08em; text-transform: uppercase; }
.ghl dt { color: var(--grey); }
.ghl dd { margin: 0; color: var(--acid); overflow-wrap: anywhere; }

/* Lanyard badges (badges.blend): hang from the top edge of a section at the right, sway, turn toward the mouse (js/main.js) */
.badge { position: absolute; right: calc(var(--gutter) + 40px); top: 0; z-index: 3; width: 300px; height: 600px; pointer-events: none; background: transparent; --poster-color: transparent;
    transform-origin: 50% 0; animation: sway 5s ease-in-out infinite; }
.badge::before { content: ""; position: absolute; left: calc(50% - 11px); bottom: 100%; width: 22px; height: 700px; background: #2A2A2A; box-shadow: inset 2px 0 0 #3A3A3A, inset -2px 0 0 #171717; }
#badge-kheir { top: -390px; right: calc(var(--gutter) - 110px); width: 360px; height: 720px; transform-origin: 50% 50%; animation-name: sway-h; }
@keyframes sway-h { 0%, 100% { rotate: 88.5deg; } 50% { rotate: 91.5deg; } }
body { overflow-x: clip; }
#projects { overflow: hidden; }
#badge-data { top: -260px; }
#badge-kheir::before { height: 400px; }
@keyframes sway { 0%, 100% { rotate: -8.5deg; } 50% { rotate: -5.5deg; } }
@media (max-width: 1000px) { .badge { display: none; } }
@media (prefers-reduced-motion: reduce) { .badge { animation: none; rotate: -7deg; } #badge-kheir { rotate: 90deg; } .jobs::after { transition: none; } }

/* Under the wide-screen zoom a viewer's canvas is rendered at CSS size then upscaled: give it the physical size and zoom it back down */
/* always on: with --z = 1 these are identities */
    .badge, #data3d, #card3d { zoom: calc(1 / var(--z)); }
    /* inside the un-zoomed viewer, vw and % already match the screen; only px lengths need scaling by --z */
    .badge { width: calc(300px * var(--z)); height: calc(600px * var(--z)); right: calc(var(--gutter) + 40px * var(--z)); }
    #badge-kheir { width: calc(360px * var(--z)); height: calc(720px * var(--z)); top: calc(-390px * var(--z)); right: calc(var(--gutter) - 110px * var(--z)); }
    #badge-data { top: calc(-260px * var(--z)); }
    .badge::before { left: calc(50% - 11px * var(--z)); width: calc(22px * var(--z)); height: calc(700px * var(--z)); }
    #badge-kheir::before { height: calc(400px * var(--z)); }

/* Palettes: one neutral + one fluo each. The 3D assets stay acid green, so the fluo is the only thing that moves. */
[data-palette="ember"] { --acid: #FF5A1F; --blue: #2F3DFF; --magenta: #00E5FF; --ink: #0B0B0C; --ink-deep: #26282E; --paper: #EFE9DF; }
[data-palette="cyan"] { --acid: #00F0FF; --blue: #5B6CFF; --magenta: #FF2BD6; --ink: #07090C; --ink-deep: #1B2630; --paper: #E6ECEE; }
[data-palette="safety"] { --acid: #FFE600; --blue: #2F3DFF; --magenta: #FF2BD6; --ink: #0E0E0E; --ink-deep: #2A2A2A; --paper: #EDEBE4; }
[data-palette="mint"] { --acid: #7CFFB2; --blue: #3B5BFF; --magenta: #FF5FA2; --ink: #0A0F0D; --ink-deep: #1F2A26; --paper: #E7EDE8; }
/* 404 page */
.case-body { color: var(--white); background: var(--grain-light), var(--ink); }
.case { max-width: 960px; margin: 0 auto; padding: calc(var(--nav-h) + 64px) var(--gutter) 96px; }
.case-head h1 { margin: 8px 0 16px; font-size: clamp(2.4rem, 7vw, 5.5rem); line-height: .95; letter-spacing: -.03em; }
.case-sub { max-width: 60ch; margin: 0 0 32px; font: 17px/1.5 Inter, sans-serif; color: var(--grey); }
