﻿/* Portfolio — Kanit dark template */
/* Self-hosted so the page never blocks on fonts.googleapis.com, and so the
   type still renders on networks that block third-party CDNs. */
@font-face{font-family:Kanit;font-style:normal;font-weight:300;font-display:swap;src:url(assets/fonts/kanit-300.woff2) format('woff2')}
@font-face{font-family:Kanit;font-style:normal;font-weight:400;font-display:swap;src:url(assets/fonts/kanit-400.woff2) format('woff2')}
@font-face{font-family:Kanit;font-style:normal;font-weight:500;font-display:swap;src:url(assets/fonts/kanit-500.woff2) format('woff2')}
@font-face{font-family:Kanit;font-style:normal;font-weight:700;font-display:swap;src:url(assets/fonts/kanit-700.woff2) format('woff2')}
@font-face{font-family:Kanit;font-style:normal;font-weight:900;font-display:swap;src:url(assets/fonts/kanit-900.woff2) format('woff2')}
:root{--bg:#0C0C0C;--fg:#D7E2EA;--grad:linear-gradient(180deg,#646973 0%,#BBCCD7 100%)}
*{box-sizing:border-box;margin:0;padding:0}
html,body{background:var(--bg)}
/* In-page nav is plain browser anchor behaviour — no JS and no scroll
   animation in the path, deliberately: an instant native jump is the single
   most reliable thing a browser does. scroll-behavior:smooth is driven by the
   compositor and has been observed to stall, which is the exact symptom being
   chased. The scroll-margin keeps a jumped-to section off the viewport edge. */
#about,#expertise,#portfolio,#contact,#references{scroll-margin-top:24px}
body{font-family:'Kanit',sans-serif;color:var(--fg);overflow-x:clip}
a{color:var(--fg);text-decoration:none}
a:hover{opacity:.7}
/* Keyboard users need to see where they are. */
:focus-visible{outline:2px solid #BBCCD7;outline-offset:3px;border-radius:2px}
.skip{position:absolute;left:-9999px;top:0;z-index:100;background:var(--fg);color:var(--bg);padding:12px 20px;font-weight:500;text-transform:uppercase;letter-spacing:.1em;font-size:.8rem}
.skip:focus{left:12px;top:12px}
/* Honour the OS "reduce motion" setting: kill the drift, the magnet and the
   fade-ins rather than merely shortening them. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;scroll-behavior:auto!important}
  .fi,.fi.pre{opacity:1!important;transform:none!important}
  .hero-portrait,.hero-portrait.pre{opacity:1!important;transform:translateX(-50%)!important}
  /* Preview panels park at the top and never move. The JS checks the same
     query and never starts its loop, so this is belt and braces. */
  .mk-scroll{transform:none!important}
}
/* Scroll progress — this page is long; give people a sense of position. */
.progress{position:fixed;top:0;left:0;height:2px;width:100%;transform:scaleX(0);transform-origin:0 50%;background:linear-gradient(90deg,#646973,#BBCCD7);z-index:60;pointer-events:none}
img{display:block}
.grad-text{background:var(--grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent}
/* FadeIn — visible by default; JS adds .pre to set the from-state, so a JS
   failure or a non-firing IntersectionObserver can never leave the page blank */
.fi{transition:opacity .7s cubic-bezier(.25,.1,.25,1),transform .7s cubic-bezier(.25,.1,.25,1);transition-delay:var(--fd,0s)}
.fi.pre{opacity:0;transform:translate(var(--fx,0),var(--fy,30px))}
.fi.in{opacity:1;transform:translate(0,0)}
/* HERO */
.hero{height:100vh;display:flex;flex-direction:column;overflow-x:clip;position:relative}
/* Sits above the portrait, which is absolutely positioned at z-index:10 and
   overlaps this band on short viewports. */
.nav{position:relative;z-index:20;display:flex;justify-content:space-between;padding:32px 40px 0;font-weight:500;text-transform:uppercase;letter-spacing:.05em;font-size:clamp(.85rem,1.2vw,1.4rem)}
.nav a{transition:opacity .2s;padding-bottom:4px;border-bottom:1px solid transparent}
.nav a:hover{opacity:1;border-bottom-color:currentColor}
.hero-h1-wrap{padding:0 40px}
/* Was 12.5vw + white-space:nowrap for a three-word greeting. The headline is
   now a real sentence, so it wraps, and the size is capped so it stops
   dominating every other element on the page. */
.hero h1{font-size:clamp(1.9rem,5.6vw,5.2rem);font-weight:900;text-transform:uppercase;letter-spacing:-.025em;line-height:1.02;text-wrap:balance;width:100%;text-align:center;margin-top:.5rem}
.hero-bottom{margin-top:auto;display:flex;justify-content:space-between;align-items:flex-end;padding:0 40px 40px}
.hero-tag{font-weight:300;text-transform:uppercase;letter-spacing:.04em;line-height:1.35;font-size:clamp(.75rem,1.4vw,1.5rem);max-width:260px}
/* pointer-events:none here is load-bearing, not cosmetic. This is a decorative
   cutout with nothing interactive inside it, but it is absolutely positioned,
   horizontally centred and up to 480px wide — so on a wide, short window its
   box covers the middle of the nav and swallows the clicks meant for Expertise
   and Portfolio, while About and Contact stay reachable at the outer edges.
   The magnet effect listens on window, not on this element, so it still works. */
.hero-portrait{position:absolute;left:50%;bottom:0;z-index:10;pointer-events:none;width:clamp(280px,34vw,480px);will-change:transform}
.hero-portrait.pre{opacity:0;transform:translateX(-50%) translateY(30px)}
.hero-portrait,.hero-portrait.in{opacity:1;transform:translateX(-50%)}
/* Was a design-tool <image-slot>; now a plain <img>. contain + bottom anchoring
   reproduces the component's fit="contain" position="50% 100%". */
.hero-portrait img{display:block;width:100%;height:clamp(340px,42vw,560px);object-fit:contain;object-position:50% 100%}
/* The avatar is a baked-in transparent cutout, not an upload target — so no
   dashed frame, no component backdrop, and nothing clipping it. Just the
   portrait floating over the hero. */
.avatar-drop{position:relative}
/* Grounds the cutout so it doesn't look pasted onto the hero. */
.hero-portrait img{filter:saturate(.95) contrast(1.03) drop-shadow(0 24px 40px rgba(0,0,0,.55))}
/* Contact button */
/* The old magenta-to-orange gradient with a white outline and inset shadow was
   the only element fighting the palette. Solid light-on-dark instead: it reads
   as the primary action precisely because nothing else on the page is solid. */
.btn-contact{display:inline-block;white-space:nowrap;border-radius:999px;padding:clamp(12px,1vw,16px) clamp(32px,3vw,48px);background:var(--fg);color:var(--bg);font-weight:500;text-transform:uppercase;letter-spacing:.15em;font-size:clamp(.7rem,1vw,1rem);border:1px solid var(--fg);cursor:pointer;position:relative;z-index:20;transition:background .2s,color .2s,transform .2s}
.btn-contact:hover{background:transparent;color:var(--fg);transform:translateY(-2px);opacity:1}
/* BRANDS */
.brands{padding:clamp(56px,7vw,96px) 40px;border-top:1px solid rgba(215,226,234,.1);border-bottom:1px solid rgba(215,226,234,.1)}
.brands-label{text-align:center;font-weight:300;text-transform:uppercase;letter-spacing:.25em;font-size:clamp(.6rem,.9vw,.75rem);opacity:.45;margin-bottom:clamp(32px,4vw,56px)}
.brands-row{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:clamp(28px,4vw,64px);max-width:1100px;margin:0 auto}
.bmark{font-weight:500;font-size:clamp(1rem,1.9vw,1.75rem);letter-spacing:-.01em;opacity:.55;transition:opacity .25s;white-space:nowrap}
.bmark:hover{opacity:1}
.bmark small{display:block;font-weight:300;font-size:.5em;letter-spacing:.16em;text-transform:uppercase;opacity:.6;margin-top:2px}
.bmark-caps{text-transform:uppercase;letter-spacing:.14em;font-weight:300}
.bmark-bold{font-weight:900;letter-spacing:-.03em}
/* MARQUEE */
.marquee{padding:clamp(96px,12vw,160px) 0 40px;overflow:hidden}
.marquee-label{text-align:center;font-weight:300;text-transform:uppercase;letter-spacing:.25em;font-size:clamp(.6rem,.9vw,.75rem);opacity:.45;margin-bottom:clamp(32px,4vw,56px)}
.mrow{display:flex;gap:12px;margin-bottom:12px;will-change:transform}
/* Smaller, flatter tiles: more of the reel visible at once, and the number is
   the only thing shouting. The old 420x270 gradient slabs left ~200px of dead
   space under a five-word label. */
.mtile{width:300px;height:188px;border-radius:16px;flex-shrink:0;display:flex;flex-direction:column;justify-content:space-between;padding:clamp(16px,1.4vw,22px);background:#131519;border:1px solid rgba(215,226,234,.09);cursor:default}
.mtile i{font-style:normal;font-weight:400;text-transform:uppercase;letter-spacing:.2em;font-size:.55rem;opacity:.3}
.mtile b{display:block;font-weight:900;font-size:1.6rem;letter-spacing:-.025em;line-height:1.06;margin-bottom:8px;background:var(--grad);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent}
.mtile span{display:block;font-weight:300;font-size:.72rem;line-height:1.45;opacity:.5}
.mrow .mtile{transition:opacity .3s,border-color .3s,transform .3s}
.mrow:hover .mtile{opacity:.55}
.mrow:hover .mtile:hover{opacity:1;border-color:rgba(215,226,234,.4);transform:translateY(-6px)}
/* ABOUT */
.about{min-height:100vh;overflow-x:clip;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:clamp(40px,5vw,64px);padding:80px 40px;position:relative}
.about h2{font-size:clamp(3rem,12vw,160px);font-weight:900;text-transform:uppercase;line-height:1;letter-spacing:-.02em;text-align:center}
.about-txt{color:var(--fg);font-weight:500;text-align:center;line-height:1.65;max-width:560px;font-size:clamp(1rem,2vw,1.35rem)}
.about-txt span{transition:opacity .15s linear}
.deco{position:absolute;pointer-events:none;white-space:nowrap;font-weight:900;font-size:clamp(1.5rem,3.2vw,3.2rem);line-height:1;opacity:.5}
.deco-tl{top:5%;left:5%}
.deco-bl{bottom:9%;left:5%}
.deco-tr{top:5%;right:5%}
.deco-br{bottom:9%;right:5%}
/* SERVICES */
.services{background:#fff;color:var(--bg);border-radius:clamp(40px,5vw,60px) clamp(40px,5vw,60px) 0 0;padding:clamp(80px,10vw,128px) 40px;position:relative;z-index:5}
.services h2{font-size:clamp(3rem,12vw,160px);font-weight:900;text-transform:uppercase;text-align:center;line-height:1;margin-bottom:clamp(64px,8vw,112px)}
.svc-list{max-width:1024px;margin:0 auto}
.svc{display:flex;gap:clamp(24px,4vw,64px);align-items:flex-start;padding:clamp(32px,4vw,48px) 0;border-bottom:1px solid rgba(12,12,12,.15)}
.svc:first-child{border-top:1px solid rgba(12,12,12,.15)}
.svc-num{font-weight:900;font-size:clamp(3rem,10vw,140px);line-height:.9;flex-shrink:0}
.svc-name{font-weight:500;text-transform:uppercase;font-size:clamp(1rem,2.2vw,2.1rem);margin-bottom:8px}
.svc-desc{font-weight:300;line-height:1.65;max-width:672px;font-size:clamp(.85rem,1.6vw,1.25rem);opacity:.75}
/* LOGO WALL */
.logo-wall{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:12px;max-width:1100px;margin:0 auto}
.lcell{position:relative;height:clamp(92px,10vw,124px);border:1px solid rgba(215,226,234,.12);border-radius:14px;display:flex;align-items:center;justify-content:center;padding:clamp(16px,1.8vw,26px);overflow:hidden;transition:border-color .25s,transform .25s}
.lcell:hover{border-color:rgba(215,226,234,.35);transform:translateY(-2px)}
.lcell.drop{border-style:dashed;border-color:rgba(215,226,234,.22)}
.lcell.drop:hover{transform:none}
.lcell img{max-height:100%;max-width:100%;width:auto;object-fit:contain;mix-blend-mode:screen;filter:grayscale(1) invert(1) brightness(1.12) contrast(1.2);opacity:.82;transition:opacity .25s}
.lcell:hover img{opacity:1}
.lcell img.lg-tall{max-height:calc(100% + clamp(10px,1.2vw,18px))}
.lcell:has(.lsub) img.lg-tall{max-height:100%}
.lcell-word span{font-weight:900;font-size:clamp(.95rem,1.5vw,1.35rem);letter-spacing:-.03em;opacity:.8}
.lcell-word i{font-style:normal;font-weight:300;opacity:.55}
.lcell-word:hover span{opacity:1}
.lsub{position:absolute;left:0;right:0;bottom:clamp(8px,1vw,12px);text-align:center;font-weight:300;text-transform:uppercase;letter-spacing:.14em;font-size:clamp(.45rem,.62vw,.56rem);opacity:.35;pointer-events:none}
.lcell:has(.lsub) img{margin-bottom:clamp(8px,1vw,12px)}
.lcell .lname{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;padding:12px;text-align:center;pointer-events:none;z-index:1}
.lcell .lname b{font-weight:500;text-transform:uppercase;letter-spacing:.08em;font-size:clamp(.68rem,.95vw,.82rem);line-height:1.2;opacity:.7}
.lcell .lname span{font-weight:300;text-transform:uppercase;letter-spacing:.14em;font-size:clamp(.5rem,.68vw,.58rem);opacity:.3}
.lcell.filled .lname{display:none}
.brands-note{text-align:center;max-width:640px;margin:clamp(28px,3.5vw,44px) auto 0;font-weight:300;font-size:clamp(.75rem,1.05vw,.92rem);line-height:1.6;opacity:.6;text-wrap:pretty}
/* TRACK RECORD + CREDENTIALS (inside white block) */
.tr,.creds{max-width:1024px;margin:clamp(56px,7vw,88px) auto 0}
.tr-head{font-weight:500;text-transform:uppercase;letter-spacing:.2em;font-size:clamp(.62rem,.88vw,.74rem);opacity:.4;padding-bottom:16px;border-bottom:1px solid rgba(12,12,12,.15)}
.tr-row{display:grid;grid-template-columns:130px 1fr 1.15fr;gap:clamp(12px,2.5vw,32px);align-items:baseline;padding:clamp(16px,1.8vw,22px) 0;border-bottom:1px solid rgba(12,12,12,.1)}
.tr-yr{font-weight:500;text-transform:uppercase;letter-spacing:.1em;font-size:clamp(.65rem,.9vw,.78rem);opacity:.45}
.tr-co{font-weight:900;font-size:clamp(1rem,1.7vw,1.45rem);letter-spacing:-.02em;line-height:1.1}
.tr-co em{font-style:normal;font-weight:300;font-size:.62em;opacity:.5;display:block}
.tr-role{font-weight:300;font-size:clamp(.8rem,1.15vw,1rem);line-height:1.45;opacity:.55;text-wrap:pretty}
/* REFERENCE — sits inside the white block, directly under the timeline it
   corroborates. Set larger and lighter than the rows above so it reads as a
   change of voice rather than more of the same list. */
.quote{max-width:1024px;margin:clamp(56px,7vw,88px) auto 0}
.quote blockquote{margin-top:clamp(24px,3vw,36px);max-width:64ch}
.quote blockquote p{font-weight:300;font-size:clamp(1rem,1.55vw,1.35rem);line-height:1.62;letter-spacing:-.005em;text-wrap:pretty}
.quote blockquote p:first-child::before{content:'\201C';margin-left:-.42em}
.quote .q-close{margin-top:1em;font-weight:500;opacity:.95}
.quote .q-close::after{content:'\201D'}
.quote figcaption{display:flex;flex-wrap:wrap;align-items:center;gap:4px 14px;margin-top:clamp(20px,2.4vw,28px);padding-top:16px;border-top:1px solid rgba(12,12,12,.15)}
/* A real face next to a real name is the cheapest credibility on the page —
   it is the difference between a quote and a person. */
.quote .q-photo{width:clamp(44px,4vw,54px);height:clamp(44px,4vw,54px);border-radius:50%;object-fit:cover;flex-shrink:0;background:rgba(12,12,12,.06)}
.quote .q-who{display:flex;flex-direction:column;gap:2px}
.quote .q-name{font-weight:900;font-size:clamp(.92rem,1.25vw,1.1rem);letter-spacing:-.015em}
.quote .q-role{font-weight:500;font-size:clamp(.75rem,1vw,.88rem);opacity:.6}
.quote .q-rel{font-weight:300;text-transform:uppercase;letter-spacing:.14em;font-size:clamp(.6rem,.82vw,.7rem);opacity:.42;margin-left:auto}
@media(max-width:640px){.quote .q-rel{margin-left:0;flex-basis:100%}}
.creds-row{display:flex;flex-wrap:wrap;gap:10px;margin-top:22px}
.creds-row span{border:1px solid rgba(12,12,12,.2);border-radius:999px;padding:8px 18px;font-weight:300;font-size:clamp(.7rem,.95vw,.85rem);opacity:.7}
.stack{max-width:1024px;margin:clamp(48px,6vw,72px) auto 0;display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:clamp(22px,3.2vw,44px)}
.stack img{height:clamp(20px,2.2vw,27px);width:auto;opacity:.35;transition:opacity .25s}
.stack img:hover{opacity:.85}
/* PROJECTS */
.projects{background:var(--bg);border-radius:clamp(40px,5vw,60px) clamp(40px,5vw,60px) 0 0;margin-top:-56px;position:relative;z-index:10;padding:clamp(80px,10vw,128px) 40px 120px}
.projects h2{font-size:clamp(3rem,12vw,160px);font-weight:900;text-transform:uppercase;text-align:center;line-height:1;margin-bottom:16px}
.projects-lede{text-align:center;font-weight:300;text-transform:uppercase;letter-spacing:.14em;font-size:clamp(.65rem,.95vw,.8rem);opacity:.45;margin-bottom:clamp(56px,7vw,100px)}
.pcard-desc{font-weight:300;font-size:clamp(.82rem,1.15vw,1rem);line-height:1.55;opacity:.78;margin-top:10px;max-width:640px;text-wrap:pretty}
.pcard-chips{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
.pcard-chips span{border:1px solid rgba(215,226,234,.25);border-radius:999px;padding:5px 14px;font-weight:300;text-transform:uppercase;letter-spacing:.1em;font-size:clamp(.55rem,.75vw,.66rem);opacity:.7}
/* WIP */
.wip{max-width:1024px;margin:clamp(24px,4vw,48px) auto 0}
.wip-head{font-weight:500;text-transform:uppercase;letter-spacing:.2em;font-size:clamp(.62rem,.9vw,.74rem);opacity:.45;margin-bottom:20px;text-align:center}
.wip-row{display:grid;grid-template-columns:repeat(2,1fr);gap:12px}
.wip-card{border:2px dashed rgba(215,226,234,.25);border-radius:clamp(20px,2.5vw,32px);padding:clamp(24px,3vw,40px)}
.wip-img{height:clamp(120px,14vw,180px);margin-bottom:20px;border-radius:clamp(14px,1.6vw,20px)}
.wip-card b{display:block;font-weight:900;font-size:clamp(1rem,1.6vw,1.4rem);letter-spacing:-.02em;opacity:.7}
.wip-card span{display:block;font-weight:300;font-size:clamp(.75rem,1vw,.88rem);line-height:1.5;opacity:.4;margin-top:8px}
.pcard-wrap{min-height:85vh;padding-bottom:96px}
.pcard{position:sticky;top:96px;border-radius:clamp(40px,5vw,60px);border:2px solid var(--fg);background:var(--bg);padding:clamp(16px,2.5vw,32px);will-change:transform;transform-origin:top center}
.pcard-top{display:flex;flex-wrap:wrap;align-items:flex-start;gap:16px 32px;margin-bottom:clamp(16px,2vw,32px)}
.pcard-num{font-weight:900;font-size:clamp(3rem,8vw,110px);line-height:.9}
.pcard-meta{flex:1;min-width:200px;padding-top:8px}
.pcard-cat{font-weight:300;text-transform:uppercase;letter-spacing:.15em;font-size:clamp(.65rem,1vw,.85rem);opacity:.6;margin-bottom:4px}
.pcard-name{font-weight:500;text-transform:uppercase;font-size:clamp(1.2rem,2.6vw,2.4rem);line-height:1.1}
.btn-ghost{border-radius:999px;border:2px solid var(--fg);color:var(--fg);background:transparent;font-family:inherit;font-weight:500;text-transform:uppercase;letter-spacing:.15em;padding:clamp(10px,1vw,14px) clamp(28px,2.5vw,40px);font-size:clamp(.8rem,1vw,1rem);cursor:pointer;align-self:center;transition:background .2s}
.btn-ghost:hover{background:rgba(215,226,234,.1)}
.pcard-imgs{display:grid;grid-template-columns:40% 1fr;gap:12px}
.pcard-col1{display:flex;flex-direction:column;gap:12px}
.pcard-imgs .pi-a{height:clamp(130px,16vw,230px);flex-shrink:0}
.pcard-imgs .pi-b{height:clamp(160px,22vw,340px);flex-shrink:0}
.pcard-imgs .pi-c{height:calc(clamp(130px,16vw,230px) + clamp(160px,22vw,340px) + 12px)}
/* FOOTER */
/* Honest framing for the project cards: 01/02 are real product screens,
   03/04 are schematics. Saying so outright is worth more than the ambiguity. */
.projects-note{max-width:720px;margin:14px auto 0;text-align:center;font-weight:300;font-size:clamp(.75rem,1.05vw,.9rem);line-height:1.6;opacity:.55;text-wrap:pretty}
.pcard{transition:border-color .25s}
.pcard:hover{border-color:#BBCCD7}
/* CONTACT */
.foot-lede{max-width:44ch;font-weight:300;font-size:clamp(.85rem,1.2vw,1.05rem);line-height:1.55;opacity:.65;text-wrap:pretty}
.cform{width:100%;max-width:520px;display:flex;flex-direction:column;gap:14px;text-align:left}
.cform-row{display:flex;flex-direction:column;gap:6px}
.cform label{font-weight:300;text-transform:uppercase;letter-spacing:.14em;font-size:.66rem;opacity:.6}
.cform input,.cform textarea{width:100%;background:rgba(215,226,234,.05);border:1px solid rgba(215,226,234,.2);border-radius:10px;padding:12px 14px;color:var(--fg);font-family:inherit;font-size:.95rem;font-weight:300;transition:border-color .2s,background .2s}
.cform input:focus,.cform textarea:focus{outline:none;border-color:#BBCCD7;background:rgba(215,226,234,.09)}
.cform textarea{resize:vertical;min-height:96px}
.cform .btn-contact{align-self:flex-start;margin-top:4px}
/* Honeypot: a field only a bot fills in. Hidden from people and assistive tech. */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* Booking is the primary action, so the form is visibly the secondary one. */
.foot-or{font-weight:300;text-transform:uppercase;letter-spacing:.16em;font-size:.66rem;opacity:.45;margin-top:-4px}
.cform-send{align-self:flex-start;margin-top:4px;font-family:inherit;cursor:pointer}
.foot-alt{font-weight:300;font-size:.85rem;opacity:.55}
.foot-alt a{border-bottom:1px solid rgba(215,226,234,.35)}
.updated{opacity:.5}
.foot{padding:80px 40px 60px;display:flex;flex-direction:column;align-items:center;gap:24px;text-align:center}
.foot h3{font-size:clamp(2rem,6vw,72px);font-weight:900;text-transform:uppercase;line-height:1}
.foot-links{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;font-weight:300;text-transform:uppercase;letter-spacing:.1em;font-size:clamp(.75rem,1vw,.95rem)}
/* Padding rather than gap carries the spacing, so one-letter labels like "X"
   still get a thumb-sized hit area. */
.foot-links a,.foot-links span{padding:10px 7px}
.foot-links a{transition:opacity .2s}
@media (max-width:640px){
  .nav{padding:24px 24px 0}
  /* Below 640px the tag and the button fight over one row: the button cannot
     shrink (nowrap + padding), so the tag gets crushed to ~100px and the two
     end up edge to edge with no gap. Let the row wrap instead — the tag takes
     the full width and the button drops beneath it. */
  .hero-bottom{padding:0 24px 28px;flex-wrap:wrap;gap:20px;align-items:flex-start}
  .hero-tag{max-width:none}
  .hero-portrait{top:50%;bottom:auto}
  .hero-portrait img{border-radius:24px}
  .hero-portrait.pre{transform:translate(-50%,-50%) translateY(30px)}
  .hero-portrait,.hero-portrait.in{transform:translate(-50%,-50%)}
  .deco{font-size:clamp(1.1rem,4vw,1.8rem)}
  .deco-tl,.deco-tr{top:3%}
  .deco-bl,.deco-br{bottom:5%}
  .mtile{width:242px;height:162px}
  .mtile b{font-size:1.32rem}
  .mtile span{font-size:.66rem}
  .svc{flex-direction:column;gap:12px}
  .pcard-imgs{grid-template-columns:1fr}
  .pi-c{height:clamp(200px,40vw,340px)}
  .services,.projects{padding-left:20px;padding-right:20px}
  .tr-row{grid-template-columns:1fr;gap:4px}
  .wip-row{grid-template-columns:1fr}
  .logo-wall{grid-template-columns:repeat(auto-fill,minmax(120px,1fr))}
  .about{padding:80px 20px}
}

/* PROJECT MOCK VISUALS */
.mk{position:relative;overflow:hidden;border-radius:clamp(24px,3vw,48px);background:linear-gradient(155deg,#16181D,#0F1114 55%,#1A1E25);border:1px solid #23282F;padding:clamp(14px,1.7vw,26px);display:flex;flex-direction:column;gap:clamp(8px,1vw,14px)}
/* Cards 03/04 show the shape of the work rather than any one account, so their
   panels are drawn as schematics — flat ground, dotted grid, dashed edges —
   instead of the product-UI look 01/02 use. */
.pcard.schematic .mk{
  background:#111317;
  background-image:radial-gradient(rgba(215,226,234,.085) 1px,transparent 1px);
  background-size:14px 14px;
  border-style:dashed;
  border-color:rgba(215,226,234,.16)
}
.pcard.schematic .mk-tile,
.pcard.schematic .mk-node,
.pcard.schematic .mk-code{border-style:dashed}
.mk-lbl{font-weight:300;text-transform:uppercase;letter-spacing:.16em;font-size:clamp(.5rem,.68vw,.62rem);opacity:.6}
.mk-foot{margin-top:auto;font-weight:300;font-size:clamp(.52rem,.72vw,.66rem);opacity:.58;line-height:1.45;text-wrap:pretty}
.mk-big{font-weight:900;letter-spacing:-.03em;line-height:1;font-size:clamp(1.5rem,3.2vw,3rem)}
.mk-row{display:flex;align-items:center;gap:clamp(10px,1.4vw,20px)}
.mk-grow{flex:1;min-height:0}
.mk-fill{flex:1;min-width:0}
.mk-hl{display:flex;align-items:baseline;gap:8px}
.mk-hl span{font-weight:300;text-transform:uppercase;letter-spacing:.12em;font-size:clamp(.5rem,.68vw,.6rem);opacity:.45}
.mk-inline{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.mk-chip{border:1px solid rgba(215,226,234,.18);border-radius:999px;padding:3px 10px;font-weight:300;text-transform:uppercase;letter-spacing:.1em;font-size:clamp(.46rem,.62vw,.56rem);opacity:.6;white-space:nowrap}
.mk-chip.on{border-color:rgba(215,226,234,.45);opacity:.95}
.ring{width:clamp(58px,6.4vw,100px);aspect-ratio:1;border-radius:50%;flex-shrink:0;display:grid;place-items:center;background:conic-gradient(#BBCCD7 calc(var(--v,70)*1%),rgba(215,226,234,.12) 0)}
.ring::after{content:'';position:absolute;inset:clamp(7px,.9vw,12px);border-radius:50%;background:#101216}
.ring{position:relative}
.ring b{position:relative;z-index:1;font-weight:900;font-size:clamp(.95rem,1.5vw,1.5rem);letter-spacing:-.02em}
.mk-bars{display:flex;flex-direction:column;gap:clamp(6px,.8vw,10px)}
.mk-bar span{display:flex;justify-content:space-between;gap:8px;font-weight:300;font-size:clamp(.52rem,.72vw,.68rem);opacity:.62;margin-bottom:4px}
.mk-bar em{font-style:normal;font-weight:500;opacity:.85;font-variant-numeric:tabular-nums}
.mk-bar i{display:block;height:5px;border-radius:999px;background:rgba(215,226,234,.12)}
.mk-bar i::before{content:'';display:block;height:100%;width:var(--w,50%);border-radius:999px;background:linear-gradient(90deg,#646973,#BBCCD7)}
.mk-kv{display:flex;align-items:center;gap:8px;font-weight:300;font-size:clamp(.54rem,.74vw,.7rem);opacity:.7;padding:4px 0}
.mk-kv em{margin-left:auto;font-style:normal;font-weight:500;font-variant-numeric:tabular-nums}
.dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;display:inline-block}
.dot.crit{background:oklch(.63 .12 28)}.dot.ser{background:oklch(.76 .1 78)}.dot.mod{background:oklch(.8 .07 165)}
.mk-list{display:flex;flex-direction:column}
.mk-item{display:flex;align-items:center;gap:8px;padding:clamp(5px,.7vw,9px) 0;border-bottom:1px solid rgba(215,226,234,.07);font-weight:300;font-size:clamp(.52rem,.74vw,.7rem);opacity:.75;line-height:1.3}
.mk-item:last-child{border-bottom:0}
.mk-item b{font-weight:500;opacity:.9;font-variant-numeric:tabular-nums}
.mk-item em{margin-left:auto;font-style:normal;opacity:.5;white-space:nowrap;font-variant-numeric:tabular-nums}
.mk-chrome{display:flex;align-items:center;gap:8px}
.mk-dots{display:flex;gap:4px}
.mk-dots i{width:7px;height:7px;border-radius:50%;background:rgba(215,226,234,.18)}
.mk-url{flex:1;min-width:0;background:rgba(215,226,234,.06);border-radius:999px;padding:5px 12px;font-weight:300;font-size:clamp(.5rem,.68vw,.62rem);opacity:.5;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mk-hero{flex:1;display:flex;flex-direction:column;justify-content:center;gap:clamp(8px,1.2vw,16px);padding:clamp(6px,1.5vw,20px) 0}
.mk-hero h4{font-weight:900;font-size:clamp(1.15rem,2.5vw,2.5rem);line-height:1.04;letter-spacing:-.035em}
.mk-hero p{font-weight:300;font-size:clamp(.58rem,.88vw,.86rem);line-height:1.5;opacity:.5;max-width:36ch;text-wrap:pretty}
.mk-btns{display:flex;flex-wrap:wrap;gap:8px}
.mk-btn{border-radius:999px;padding:7px 16px;font-weight:500;text-transform:uppercase;letter-spacing:.12em;font-size:clamp(.46rem,.64vw,.58rem);background:var(--fg);color:var(--bg);border:1px solid var(--fg)}
.mk-btn.alt{background:transparent;color:var(--fg);border-color:rgba(215,226,234,.3)}
.mk-tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(6px,.8vw,10px)}
.mk-tile{background:rgba(215,226,234,.045);border:1px solid rgba(215,226,234,.08);border-radius:clamp(10px,1.2vw,16px);padding:clamp(8px,1vw,14px)}
.mk-tile b{display:block;font-weight:900;font-size:clamp(.85rem,1.5vw,1.5rem);line-height:1.05;letter-spacing:-.02em}
.mk-tile span{display:block;font-weight:300;text-transform:uppercase;letter-spacing:.12em;font-size:clamp(.44rem,.6vw,.54rem);opacity:.42;margin-top:5px;line-height:1.3}
.mk-split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(10px,1.4vw,20px)}
.mk-split>div{display:flex;flex-direction:column;gap:8px}
.mk-swatch{border-radius:10px;padding:clamp(7px,.9vw,12px);border:1px solid rgba(215,226,234,.1)}
.mk-swatch b{display:block;font-weight:500;font-size:clamp(.58rem,.8vw,.78rem)}
.mk-swatch span{display:block;font-weight:300;font-size:clamp(.46rem,.62vw,.56rem);text-transform:uppercase;letter-spacing:.1em;margin-top:5px;opacity:.6}
.mk-swatch.fail{background:rgba(215,226,234,.05)}
.mk-swatch.fail b{color:rgba(215,226,234,.3)}
.mk-swatch.fail span{color:oklch(.63 .12 28)}
.mk-swatch.pass{background:rgba(215,226,234,.9)}
.mk-swatch.pass b{color:#20262C}
.mk-swatch.pass span{color:oklch(.5 .08 165)}
.mk-code{display:flex;flex-direction:column;gap:3px;background:rgba(215,226,234,.04);border:1px solid rgba(215,226,234,.08);border-radius:10px;padding:clamp(8px,1vw,12px);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:clamp(.44rem,.62vw,.58rem);opacity:.8}
.mk-code span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.mk-code .del{color:oklch(.68 .1 28)}
.mk-code .add{color:oklch(.8 .08 165)}
.mk-flow{display:flex;flex-direction:column;flex:1;justify-content:center}
.mk-node{display:flex;align-items:center;gap:8px;background:rgba(215,226,234,.05);border:1px solid rgba(215,226,234,.12);border-radius:10px;padding:clamp(6px,.8vw,10px) clamp(8px,1vw,13px);font-weight:400;font-size:clamp(.52rem,.72vw,.68rem);opacity:.85}
.mk-node span{margin-left:auto;font-weight:300;text-transform:uppercase;letter-spacing:.1em;font-size:.82em;opacity:.4}
.mk-link{width:1px;height:clamp(10px,1.4vw,20px);margin-left:clamp(14px,1.8vw,26px);background:linear-gradient(180deg,rgba(215,226,234,.4),rgba(215,226,234,.1))}
.mk-chart{flex:1;min-height:clamp(70px,10vw,150px)}
.mk-chart svg{width:100%;height:100%;display:block}
.mk-axis{display:flex;justify-content:space-between;font-weight:300;font-size:clamp(.44rem,.6vw,.54rem);opacity:.35;letter-spacing:.08em}
.mk-key{display:flex;align-items:center;gap:6px;font-weight:300;text-transform:uppercase;letter-spacing:.12em;font-size:clamp(.44rem,.6vw,.54rem);opacity:.55}
.mk-key::before{content:'';width:14px;height:2px;background:#BBCCD7}
.mk-key.faint::before{background:rgba(215,226,234,.35)}
/* ---- Live preview: a fixed window onto oversized content ----
   .mk already clips (overflow:hidden). What was missing was anything to clip:
   every panel's content was authored to fit its frame exactly, so there was
   nothing to reveal. .mk-view is the window; .mk-scroll is absolutely
   positioned so its natural height can exceed that window, and JS translates
   it. The travel distance is measured per panel at runtime, never hardcoded. */
/* The min-height is load-bearing, not cosmetic. `.pcard-imgs .mk{height:auto}`
   removes the panel's fixed height below 720px, and the track is absolutely
   positioned so it contributes nothing to layout — leaving flex:1 with nothing
   to fill. Without a floor the window collapses to 0 and the preview vanishes
   on mobile. */
.mk-view{position:relative;flex:1 1 auto;min-height:clamp(190px,26vw,420px);overflow:hidden;border-radius:clamp(8px,1vw,14px)}
.mk-scroll{position:absolute;top:0;left:0;right:0;display:flex;flex-direction:column;gap:clamp(8px,1vw,14px);will-change:transform}
/* Inside the track, content sizes to itself — flex:1 and margin-top:auto are
   meant for a fixed-height parent and would fight the overflow we want. */
.mk-scroll .mk-hero,.mk-scroll .mk-doc{flex:0 0 auto}
/* A real page capture. Width-driven so its height scales with the panel, which
   is what makes the measured travel distance correct at every breakpoint. */
.mk-shot{width:100%;height:auto;display:block;border-radius:clamp(6px,.8vw,10px)}
.mk-scroll .mk-foot{margin-top:0}
/* Softens the clip at the bottom edge so content leaves the frame rather than
   being guillotined by it. */
.mk-view::after{content:'';position:absolute;left:0;right:0;bottom:0;height:clamp(20px,3vw,40px);background:linear-gradient(180deg,transparent,#101216);pointer-events:none;opacity:.9}
.pcard.schematic .mk-view::after{background:linear-gradient(180deg,transparent,#111317)}
.mk-doc{flex:1;display:flex;flex-direction:column;gap:clamp(7px,.9vw,12px);min-height:0}
.mk-doc b{font-weight:500;font-size:clamp(.68rem,1vw,1rem);letter-spacing:-.01em}
.mk-doc p{font-weight:300;font-size:clamp(.54rem,.78vw,.76rem);line-height:1.5;opacity:.55;text-wrap:pretty}
.pcard-cat em{font-style:normal;border:1px solid rgba(215,226,234,.3);border-radius:999px;padding:2px 9px;margin-left:10px;font-size:.82em;letter-spacing:.14em;opacity:.8}
@media(max-width:720px){.mk-split{grid-template-columns:1fr}.mk-tiles{grid-template-columns:1fr 1fr}}

.pcard-imgs .mk{height:auto}
.pcard-imgs .mk.pi-a{min-height:clamp(130px,16vw,230px)}
.pcard-imgs .mk.pi-b{min-height:clamp(160px,22vw,340px)}
.pcard-imgs .mk.pi-c{min-height:100%;justify-content:flex-start}

/* Analytics consent bar. Sits above everything, styled like the rest of the
   site rather than a bolted-on plugin. Nothing is loaded until Accept. */
.cbar{position:fixed;left:50%;bottom:20px;transform:translate(-50%,120%);z-index:80;width:min(560px,calc(100vw - 32px));
  display:flex;flex-wrap:wrap;align-items:center;gap:14px 18px;padding:18px 20px;
  background:#141619;border:1px solid rgba(215,226,234,.16);border-radius:18px;
  box-shadow:0 18px 50px rgba(0,0,0,.55);opacity:0;
  transition:transform .45s cubic-bezier(.25,.1,.25,1),opacity .45s}
.cbar.in{transform:translate(-50%,0);opacity:1}
.cbar p{flex:1;min-width:220px;margin:0;font-weight:300;font-size:clamp(.72rem,1vw,.84rem);line-height:1.5;opacity:.75;text-wrap:pretty}
.cbar-btns{display:flex;gap:8px;margin-left:auto}
.cbar button{font-family:inherit;cursor:pointer;border-radius:999px;padding:8px 18px;
  font-weight:500;text-transform:uppercase;letter-spacing:.12em;font-size:clamp(.52rem,.7vw,.62rem);
  transition:opacity .2s,background .2s}
.cbar .cbar-yes{background:var(--fg);color:var(--bg);border:1px solid var(--fg)}
.cbar .cbar-no{background:transparent;color:var(--fg);border:1px solid rgba(215,226,234,.3)}
.cbar button:hover{opacity:.82}
@media (max-width:520px){.cbar-btns{margin-left:0;width:100%}.cbar button{flex:1}}
@media (prefers-reduced-motion:reduce){.cbar{transition:none}}

/* Conferences & industry events. Deliberately typographic pills, not a second
   image grid — stacking two logo walls would read as one long wall and blur
   the distinction between companies worked for and rooms attended. */
.events{max-width:1100px;margin:clamp(40px,5vw,64px) auto 0}
.events-label{margin-bottom:clamp(18px,2.2vw,28px)}
.event-row{display:flex;flex-wrap:wrap;justify-content:center;gap:clamp(9px,1.2vw,16px)}
.ecell{display:flex;flex-direction:column;align-items:center;gap:3px;
  padding:clamp(11px,1.3vw,17px) clamp(18px,2.2vw,30px);
  border:1px solid rgba(215,226,234,.12);border-radius:999px;
  transition:border-color .25s,transform .25s}
.ecell:hover{border-color:rgba(215,226,234,.35);transform:translateY(-2px)}
.ecell b{font-weight:500;font-size:clamp(.78rem,1.1vw,1rem);letter-spacing:-.01em;white-space:nowrap}
.ecell span{font-weight:300;text-transform:uppercase;letter-spacing:.16em;font-size:clamp(.48rem,.64vw,.56rem);opacity:.45;white-space:nowrap}
@media (prefers-reduced-motion:reduce){.ecell:hover{transform:none}}
