/* ===========================================================================
   loiclelay.designer — redesign system
   One stylesheet for every page. A page only sets its own flame colour:

       <html style="--flame-1:#480000; --flame-2:#600000; --flame-3:#301818">

   Home uses the red from the profile photograph's backdrop (#300000 → #600000).
   Each project page uses its own cover's dominant colour, sampled from the
   artwork rather than chosen by eye.
   =========================================================================== */
/* General Sans, served from this domain (it used to come from api.fontshare.com +
   cdn.fontshare.com: two extra connections before the first paint on a phone) */
@font-face{font-family:'General Sans';font-style:normal;font-weight:300;font-display:swap;src:url('/assets/fonts/general-sans-300.woff2') format('woff2')}
@font-face{font-family:'General Sans';font-style:normal;font-weight:400;font-display:swap;src:url('/assets/fonts/general-sans-400.woff2') format('woff2')}
@font-face{font-family:'General Sans';font-style:normal;font-weight:500;font-display:swap;src:url('/assets/fonts/general-sans-500.woff2') format('woff2')}
@font-face{font-family:'General Sans';font-style:normal;font-weight:600;font-display:swap;src:url('/assets/fonts/general-sans-600.woff2') format('woff2')}
@font-face{font-family:'General Sans';font-style:normal;font-weight:700;font-display:swap;src:url('/assets/fonts/general-sans-700.woff2') format('woff2')}


:root{
  --font:'General Sans',-apple-system,system-ui,sans-serif;

  --t-hero:clamp(37px,5.5vw,80px); --t-h2:clamp(26px,3.2vw,44px); --t-h3:17px;
  --t-body:clamp(15.5px,1.1vw,17px); --t-lead:clamp(16.5px,1.4vw,20px);
  --t-small:13.5px; --t-label:11.5px;

  --gut:clamp(20px,5vw,56px); --maxw:1120px;
  --r-lg:24px; --r-md:16px; --r-sm:11px; --r-pill:980px;
  --ease:cubic-bezier(.32,.72,0,1);

  /* ARGENT, the only skin. Silver type on true black. */
  --ground:#08080A;
  --surface:rgba(255,255,255,.048);
  --surface-2:rgba(255,255,255,.085);
  --hairline:rgba(255,255,255,.1);
  --ink:#EDEFF2; --ink-2:#9BA1A9; --ink-3:#6E747C;

  /* the amber-red nuances: amber for small accents, red for the flame */
  --amber:#FFA742;
  --red:#E8431F;
  --amber-ink:#1B1006;

  /* LIQUID GLASS — the material, carried over from the live site's own tokens
     and cooled for the silver skin. Three parts make it read as glass rather
     than as a grey box: a saturating blur, a specular TOP edge (the thin bright
     line where light catches the lip), and a soft inner shadow at the bottom. */
  --glass-bg:rgba(255,255,255,.055);
  --glass-blur:blur(20px) saturate(1.55);
  --glass-border:rgba(255,255,255,.14);
  --glass-edge:rgba(255,255,255,.30);          /* the lit lip                */
  --glass-hi:rgba(255,255,255,.07);            /* the sheen down the face    */
  --glass-shadow:0 22px 48px -26px rgba(0,0,0,.8);

  /* brushed silver, for display type only. Highlights pick up along the
     stroke the way they do on polished metal. */
  --silver:linear-gradient(97deg,#767D86 0%,#FFFFFF 18%,#B4BBC4 36%,#F4F7FA 54%,#8C939C 70%,#FFFFFF 86%,#A2A9B2 100%);

  /* default flame, overridden per page */
  /* flame: the photograph's hue, lifted two stops so it survives a 64px blur */
  --flame-1:#7A1408; --flame-2:#A82410; --flame-3:#5A1A10;
}

*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--ground);color:var(--ink);font-family:var(--font);font-size:var(--t-body);
  line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit}
::selection{background:var(--amber);color:var(--amber-ink)}

/* Apple-style corner smoothing. `corner-shape` is the real superellipse and
   lands in recent Chrome; everywhere else the plain radius is the fallback,
   which is why every radius below is a little larger than it looks like it
   should be. */
.sq{border-radius:var(--r-md);corner-shape:squircle}
.sq-lg{border-radius:var(--r-lg);corner-shape:squircle}
.sq-sm{border-radius:var(--r-sm);corner-shape:squircle}

/* the glass material, applied by class so every surface is the same object */
.glass{
  position:relative;isolation:isolate;
  background:linear-gradient(180deg, var(--glass-hi), transparent 42%), var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge),
             inset 0 0 0 1px var(--glass-border),
             inset 0 -24px 36px -28px rgba(0,0,0,.9),
             var(--glass-shadow);
}
/* a slow specular travelling across the face, so the surface looks wet rather
   than frosted. Pure transform, and it only runs on hover-capable pointers. */
@media(hover:hover){
  .glass::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
    border-radius:inherit;opacity:0;transition:opacity .5s var(--ease);
    background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.1) 48%,transparent 58%);
    background-size:260% 100%;background-position:120% 0}
  .glass:hover::after{opacity:1;animation:sheen 1.1s var(--ease) forwards}
}
@keyframes sheen{to{background-position:-40% 0}}

.wrap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gut)}
/* NOTE vertical padding is always padding-block, never the `padding`
   shorthand: the shorthand would zero the gutter that .wrap sets. */
/* a figure never has a forced ratio: the live template sets
   .ph.has-img{aspect-ratio:auto!important} so a cover is shown at the ratio it
   was exported at (~1.88). Nothing here may crop one. */
.shotbox img{aspect-ratio:auto!important;height:auto}
.sec{padding-block:clamp(96px,15vh,176px)}
.lab{font-size:var(--t-label);letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);font-weight:500}

/* ===========================================================================
   BACKGROUND — a halftone field, and one low ember along the bottom edge
   ===========================================================================
   The first version put three big drifting blobs across the whole viewport and
   it fought every piece of text on the page. This one is the opposite: the
   colour lives only along the BOTTOM edge, like a fire banked low in the room,
   and the rest of the page is near-black so the type keeps its contrast.
*/
.bg{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;background:var(--ground)}

/* the ember: fixed to the bottom, very low, breathing slowly. Two layers only,
   both anchored off-screen so you never see an edge. */
/* no CSS blur and no blend mode here (2026-10-06): a 78px blur on two animated full-width layers was
   recomputed every frame and cost ~60% of the GPU work while scrolling. The gradient is already soft;
   it now fades a little further out instead, and screen over near-black is visually the same. */
.bg i{position:absolute;display:block;border-radius:50%;will-change:transform,opacity}
.bg i:nth-child(1){width:120vw;height:46vh;left:-10vw;bottom:-28vh;opacity:.42;
  background:radial-gradient(ellipse at 50% 100%,var(--flame-2) 0%,var(--flame-1) 42%,transparent 78%);
  animation:ember1 26s ease-in-out infinite alternate}
.bg i:nth-child(2){width:70vw;height:34vh;right:-8vw;bottom:-22vh;opacity:.3;
  background:radial-gradient(ellipse at 50% 100%,var(--flame-3) 0%,transparent 70%);
  animation:ember2 38s ease-in-out infinite alternate}
.bg i:nth-child(3){display:none}        /* the third blob is gone on purpose */
@keyframes ember1{from{transform:translate3d(0,0,0) scaleY(1);opacity:.36}
                  to{transform:translate3d(4vw,-2vh,0) scaleY(1.16);opacity:.5}}
@keyframes ember2{from{transform:translate3d(0,0,0) scaleX(1);opacity:.22}
                  to{transform:translate3d(-5vw,-1vh,0) scaleX(1.2);opacity:.36}}

/* HALFTONE — a fine dot matrix, the LED-screen texture. Two offset grids at
   5px give the woven look of a real halftone rather than a flat polka dot, and
   the whole thing is held at a few percent so it reads as grain. */
.bg b{position:absolute;inset:0;display:block;opacity:.5;
  background-image:
    radial-gradient(rgba(255,255,255,.22) .5px, transparent .5px),
    radial-gradient(rgba(255,255,255,.12) .5px, transparent .5px);
  background-size:5px 5px, 5px 5px;
  background-position:0 0, 2.5px 2.5px;
  -webkit-mask:linear-gradient(to top, #000 0%, rgba(0,0,0,.55) 38%, rgba(0,0,0,.18) 100%);
          mask:linear-gradient(to top, #000 0%, rgba(0,0,0,.55) 38%, rgba(0,0,0,.18) 100%)}

main,header,footer{position:relative;z-index:1}

/* ===========================================================================
   NAV
   =========================================================================== */
/* FLOATING HEADER — a glass pill detached from the top edge, as on the live
   site, not a bar welded to the viewport. */
.nav{position:fixed;top:14px;left:0;right:0;z-index:50;padding-inline:var(--gut);
  pointer-events:none}
.nav-in{max-width:calc(var(--maxw) - 40px);margin-inline:auto;padding:7px 7px 7px 20px;height:56px;
  display:flex;align-items:center;justify-content:space-between;gap:14px;
  border-radius:var(--r-pill);pointer-events:auto;
  background:linear-gradient(180deg,var(--glass-hi),transparent 46%),var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border), var(--glass-shadow);
  transition:transform .5s var(--ease), box-shadow .5s var(--ease)}
/* a round glass control, for back / language / anything iconic */
.icbtn{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;flex:none;
  background:var(--glass-bg);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border);
  color:var(--ink-2);transition:transform .4s var(--ease),color .3s var(--ease)}
.icbtn svg{width:15px;height:15px}
.icbtn:hover{color:var(--ink);transform:translateY(-1px)}
.icbtn.back:hover svg{transform:translateX(-2px)}
.icbtn svg{transition:transform .4s var(--ease)}
.nav-l{display:flex;align-items:center;gap:13px;min-width:0}
/* a page with a back control balances its own padding */
.nav-in:has(.icbtn){padding-left:7px}
/* his real wordmark, as a mask so it takes the ink colour */
.brand{display:block;height:17px;width:124px;background:var(--ink);
  -webkit-mask:url('/assets/logo-wordmark-mask.png') left center/contain no-repeat;
          mask:url('/assets/logo-wordmark-mask.png') left center/contain no-repeat;
  transition:opacity .3s var(--ease)}
.brand:hover{opacity:.78}
.nav nav{display:flex;align-items:center;gap:20px}
.nav a.l{font-size:var(--t-small);color:var(--ink-2);transition:color .3s var(--ease)}
.nav a.l:hover{color:var(--ink)}
/* the nav links keep the live site's signature hover: two stacked copies of
   every letter rolling up one after the other. The spans are injected by ll.js. */
.nav a.l .lr{display:inline-grid;overflow:hidden;vertical-align:top}
.nav a.l .lr>span{grid-area:1/1;display:block;
  transition:transform .4s var(--ease);transition-delay:calc(var(--i) * 28ms)}
.nav a.l .lr>span:nth-child(2){transform:translateY(105%)}
.nav a.l:hover .lr>span:first-child{transform:translateY(-105%)}
.nav a.l:hover .lr>span:nth-child(2){transform:translateY(0)}
.lang{font-size:var(--t-small);color:var(--ink-3)}
.lang a{transition:color .25s var(--ease)}
.lang a.on{color:var(--ink)}
.lang a:hover{color:var(--amber)}
/* PHONES. The text links go, the language switch STAYS (it is how a French
   visitor finds the French site). To make room the bar tightens: smaller gaps,
   a smaller wordmark and button, and — as on the original site — a project page
   on a narrow phone drops the wordmark, its round back button already leading
   home. */
@media(max-width:880px){
  .nav a.l{display:none}
  .nav nav{gap:14px}
  .lang{font-size:12.5px;white-space:nowrap}
}
@media(max-width:560px){
  .nav-in{padding-left:16px;gap:10px}
  .nav-in:has(.icbtn){padding-left:7px}
  .brand{width:104px;height:15px}
  .nav nav{gap:12px}
  .nav .btn.sm{padding:8px 13px;font-size:12.5px;white-space:nowrap}
}
/* a project page fits back + wordmark + EN/FR + the French button from ~420px
   (measured); narrower, the wordmark gives way to the round back button */
@media(max-width:419px){.nav-l:has(.icbtn) .brand{display:none}}
@media(max-width:360px){
  .brand{width:92px;height:13px}
  .nav nav{gap:10px}
  .nav .btn.sm{padding:8px 11px;font-size:12px}
}

/* ===========================================================================
   BUTTONS, ICONS
   =========================================================================== */
.btn{position:relative;display:inline-flex;align-items:center;gap:9px;border-radius:var(--r-pill);
  padding:13px 24px;font-size:15px;font-weight:500;overflow:hidden;isolation:isolate;
  transition:transform .4s var(--ease),box-shadow .4s var(--ease),background .35s var(--ease)}
.btn-1{background:var(--ink);color:#0A0A0C;box-shadow:0 1px 0 rgba(255,255,255,.6) inset}
.btn-2{background:linear-gradient(180deg,var(--glass-hi),transparent 46%),var(--glass-bg);
  color:var(--ink);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border)}
.btn:hover{transform:translateY(-2px)}
.btn-1:hover{box-shadow:0 1px 0 rgba(255,255,255,.7) inset, 0 16px 30px -16px rgba(255,255,255,.3)}
.btn-2:hover{box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px rgba(255,255,255,.22),
  0 16px 34px -20px rgba(0,0,0,.9)}
/* the sweep: a band of light crossing the button once per hover */
.btn::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(105deg,transparent 40%,rgba(255,255,255,.22) 50%,transparent 60%);
  background-size:280% 100%;background-position:130% 0;opacity:0;transition:opacity .3s}
.btn:hover::before{opacity:1;animation:sheen .85s var(--ease) forwards}
.btn-1:hover::before{background:linear-gradient(105deg,transparent 40%,rgba(0,0,0,.14) 50%,transparent 60%);
  background-size:280% 100%}
/* the label rolls, exactly as it does on the live site */
.roll{display:inline-grid;overflow:hidden;line-height:1.3;padding-bottom:.1em;margin-bottom:-.1em}
.roll > span{grid-area:1/1;transition:transform .5s var(--ease)}
.roll > span:nth-child(2){transform:translateY(110%)}
.btn:hover .roll > span:first-child,a:hover > .roll > span:first-child{transform:translateY(-110%)}
.btn:hover .roll > span:nth-child(2),a:hover > .roll > span:nth-child(2){transform:translateY(0)}
.btn svg{transition:transform .45s var(--ease)}
.btn:hover svg{transform:translateX(3px)}
.btn svg{width:15px;height:15px}
.btn.sm{padding:9px 17px;font-size:13.5px}
/* the real brand marks, kept as they are on the live site */
.ic{width:17px;height:17px;flex:none;display:block;object-fit:contain}
.btn .ic{width:15px;height:15px}

/* ===========================================================================
   SECTION HEADS, DISPLAY TYPE
   =========================================================================== */
.sec-head{text-align:center;margin-bottom:clamp(44px,6vh,72px)}
.sec-head h2,.disp{font-size:var(--t-h2);line-height:1.08;letter-spacing:-.028em;font-weight:600;
  text-wrap:balance;
  background-image:var(--silver);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent}
.sec-head h2{margin-top:12px;max-width:22ch;margin-inline:auto}
.sec-head p{color:var(--ink-2);max-width:54ch;margin:18px auto 0}
.center{display:flex;justify-content:center}

/* ===========================================================================
   SEGMENTED CONTROL
   =========================================================================== */
.seg{position:relative;display:inline-flex;padding:3px;border-radius:var(--r-pill);
  background:var(--surface);isolation:isolate;max-width:100%}
.seg button{position:relative;z-index:2;border:0;background:none;cursor:pointer;color:var(--ink-2);
  font-size:var(--t-small);font-weight:500;padding:7px 16px;border-radius:var(--r-pill);
  white-space:nowrap;transition:color .35s var(--ease)}
.seg button[aria-selected="true"],.seg button[aria-pressed="true"]{color:var(--ink)}
.seg .thumb{position:absolute;z-index:1;top:3px;bottom:3px;border-radius:var(--r-pill);
  background:var(--surface-2);box-shadow:0 1px 2px rgba(0,0,0,.35);
  transition:transform .42s var(--ease),width .42s var(--ease)}
.seg.sm button{font-size:12.5px;padding:5px 13px}
/* SECONDARY tabs (Physical › Personal / Commissioned) are a different object from
   the primary segmented control above them, one step down the hierarchy: plain
   labels on a hairline, the selected one in full ink with a short amber
   underline that slides beneath it (the same .thumb, the same motion). */
.seg.sub{background:none;padding:0;border-radius:0;gap:28px;isolation:auto;
  box-shadow:inset 0 -1px 0 var(--hairline)}
.seg.sub button{padding:9px 1px 11px;border-radius:0;font-size:13px;font-weight:500;color:var(--ink-3);
  letter-spacing:.005em}
.seg.sub button:hover{color:var(--ink-2)}
.seg.sub button[aria-selected="true"]{color:var(--ink)}
.seg.sub .thumb{left:3px;top:auto;bottom:0;height:2px;border-radius:2px;background:var(--amber);box-shadow:none}
@media(max-width:680px){.seg{overflow-x:auto;scrollbar-width:none}.seg::-webkit-scrollbar{display:none}}
/* PRIMARY tab (Digital / Physical), .seg.glow: a dark glass capsule. On hover a warm light
   follows the pointer inside it (white-hot core, then the site's ember red #E8431F / #A82410), specked with
   fine dots like the site's LED panels; on a phone it lights where the finger presses.
   ll.js writes --gx/--gy and toggles .lit. The thumb gets a glass sheen. */
.seg.glow{padding:5px;overflow:hidden;
  background:linear-gradient(180deg,rgba(255,255,255,.075),rgba(255,255,255,.022));
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.1),inset 0 1px 0 rgba(255,255,255,.16),0 18px 40px -24px rgba(0,0,0,.9)}
.seg.glow button{padding:11px 22px;font-size:14px}
.seg.glow button:hover{color:var(--ink)}
.seg.glow .thumb{left:3px;top:5px;bottom:5px;
  background:linear-gradient(180deg,rgba(255,255,255,.17),rgba(255,255,255,.06));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.24),inset 0 0 0 1px rgba(255,255,255,.08),0 6px 16px -8px rgba(0,0,0,.8)}
.seg.glow::after{content:"";position:absolute;top:0;bottom:0;left:0;width:var(--sw,100%);z-index:1;border-radius:inherit;pointer-events:none;
  opacity:0;transition:opacity .55s var(--ease);mix-blend-mode:screen;
  background:
    radial-gradient(circle 185px at var(--gx,30%) var(--gy,50%),rgba(255,226,210,.86) 0,rgba(255,138,104,.68) 12%,
      rgba(232,67,31,.5) 30%,rgba(168,36,16,.22) 56%,transparent 100%),
    radial-gradient(rgba(255,255,255,.34) .5px,transparent .9px) 0 0/8px 8px;
  -webkit-mask:radial-gradient(circle 165px at var(--gx,30%) var(--gy,50%),#000 0,rgba(0,0,0,.6) 45%,transparent 100%);
          mask:radial-gradient(circle 165px at var(--gx,30%) var(--gy,50%),#000 0,rgba(0,0,0,.6) 45%,transparent 100%)}
.seg.glow button{transition:color .35s var(--ease),text-shadow .55s var(--ease)}
.seg.glow.lit button{text-shadow:0 0 14px rgba(24,8,6,.6),0 1px 2px rgba(24,8,6,.35)}
.seg.glow.lit::after{opacity:1}
@media(max-width:680px){.seg.glow{overflow-x:auto}.seg.glow button{padding:9px 16px;font-size:13.5px}}

/* ===========================================================================
   HERO
   =========================================================================== */
.hero{position:relative;padding-block:calc(70px + 15vh) 13vh;text-align:center;overflow:hidden}
.reel-wrap{position:absolute;inset:0;z-index:0;pointer-events:none}
/* THE HERO IS AN LED WALL.
   The reel is masked by a dot grid, so the footage only shows through the
   dots and reads as a halftone screen rather than as video behind glass. Two
   masks, two elements, because they do different jobs:
     · the WRAPPER carries the vertical dissolve, so nothing paints the page
       colour and the fixed ember behind continues without a seam
     · the VIDEO carries the dot matrix
   The dots also do the contrast work for free: at ~40% coverage the footage
   loses more than half its luminance, so the silver title sits on a much
   quieter field than it did over raw video. */
.reel-wrap{-webkit-mask:linear-gradient(to bottom,transparent 0%,#000 14%,#000 46%,transparent 92%);
                   mask:linear-gradient(to bottom,transparent 0%,#000 14%,#000 46%,transparent 92%)}
.reel-wrap video,.reel-pic img{width:100%;height:100%;object-fit:cover;opacity:1;
  filter:saturate(.12) contrast(1.6) brightness(1.55);
  -webkit-mask:radial-gradient(circle at 50% 50%, #000 40%, transparent 46%) 0 0 / 4.5px 4.5px;
          mask:radial-gradient(circle at 50% 50%, #000 40%, transparent 46%) 0 0 / 4.5px 4.5px}
/* a second, coarser grid at a slight offset gives the woven, physical quality
   of a real LED panel instead of a flat screen door */
.reel-wrap::before{content:"";position:absolute;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(circle at 50% 50%, rgba(255,255,255,.07) 38%, transparent 42%) 2.25px 2.25px / 9px 9px}
@media(max-width:700px){
  .reel-wrap video,.reel-pic img{-webkit-mask-size:3.5px 3.5px;mask-size:3.5px 3.5px}
  .reel-wrap::before{background-size:7px 7px}
}

/* PHONES GET THE REEL AS AN IMAGE. Safari plays an MP4 inside <img>/<picture> the
   moment it arrives: no media-player start-up (range probes, buffering heuristics),
   so it moves at once, and it keeps moving in Low Power Mode, where iOS refuses to
   autoplay any <video>. A browser that cannot do that falls back to the poster
   JPEG, and the starter script hands it the light cut as a regular video. */
.reel-pic{position:absolute;inset:0;display:block}
@media(min-width:821px){.reel-pic{display:none}}
@media(max-width:820px){
  .reel-wrap video{display:none}
  .reel-wrap.reel-video video{display:block}
  .reel-wrap.reel-video .reel-pic{display:none}
}

/* THE CURSOR HALO.
   An amber-red pool that follows the pointer and is punched through the SAME
   dot grid, so the light lands on the cells and never between them — the panel
   lights up rather than a blob being drawn over it. --mx/--my are written by
   ll.js on a rAF, and only transform-free properties change. */
.led-halo{position:absolute;inset:0;z-index:2;pointer-events:none;opacity:0;
  transition:opacity .45s var(--ease);mix-blend-mode:screen;
  /* the flame's own colour, spread much wider and much softer: the panel should
     warm up around the pointer, not carry a hot spot */
  background:radial-gradient(circle 360px at var(--mx,50%) var(--my,50%),
    var(--flame-2) 0%, var(--flame-1) 26%, color-mix(in srgb, var(--flame-1) 22%, transparent) 52%, transparent 80%);
  -webkit-mask:radial-gradient(circle at 50% 50%, #000 40%, transparent 46%) 0 0 / 4.5px 4.5px;
          mask:radial-gradient(circle at 50% 50%, #000 40%, transparent 46%) 0 0 / 4.5px 4.5px}
.led-halo.on{opacity:.85}
@media(pointer:coarse){.led-halo{display:none}}
/* only a radial darkening behind the headline, so the type wins without the
   scrim ever reaching the section's edges */
.reel-wrap::after{content:"";position:absolute;inset:0;pointer-events:none;background:
  radial-gradient(58vw 46vh at 50% 38%,rgba(5,5,6,.72),rgba(5,5,6,.4) 58%,rgba(5,5,6,0) 84%)}
.hero > .wrap{position:relative;z-index:1}
/* over an LED panel the plain line was sometimes lost in a bright cell, so it
   gets its own small piece of glass to sit on */
.trust{display:inline-block;max-width:100%;text-align:center;line-height:1.55;text-wrap:balance;
  font-size:var(--t-small);color:var(--ink);
  padding:8px 16px;border-radius:var(--r-pill);
  background:var(--glass-bg);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border)}
/* The YC mark is sized so its wordmark reaches the same height as the text beside
   it (the 'b' of Combinator = the 'b' of the font, 9.9px at 13.5px), and sits IN
   the line of text rather than beside it, its wordmark's baseline (124/173 of the
   image) on the text's baseline. Inline, so a longer sentence (the French one)
   wraps like a sentence instead of splitting into three columns on a phone. */
.trust img{display:inline-block;height:1.34em;width:auto;vertical-align:-.38em;margin-inline:.28em}
.hero h1{font-size:var(--t-hero);line-height:.98;letter-spacing:-.038em;font-weight:600;
  max-width:17ch;margin:26px auto 0;text-wrap:balance;
  background-image:var(--silver);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
  /* silver on a moving image needs a hold: a soft dark bloom under the glyphs
     keeps the lighter stops of the gradient readable over any frame */
  filter:drop-shadow(0 2px 14px rgba(0,0,0,.7)) drop-shadow(0 0 38px rgba(0,0,0,.45))}
.lead{font-size:var(--t-lead);line-height:1.55;color:var(--ink-2);max-width:48ch;margin:28px auto 0;
  text-shadow:0 1px 14px rgba(0,0,0,.7)}
/* the two hero buttons are the same width: two equal grid tracks, each as wide
   as the longer label needs. When the pair no longer fits side by side they
   stack, still equal, at a comfortable thumb width. */
.acts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;width:max-content;max-width:100%;
  margin:40px auto 0}
.acts .btn{justify-content:center}
.acts:has(> :only-child){grid-template-columns:auto}   /* a lone button (the closing CTA) stays centred */
@media(max-width:480px){.acts{grid-template-columns:1fr;width:100%;max-width:340px}}
.proof{display:flex;flex-wrap:wrap;justify-content:center;gap:12px 32px;margin-top:46px}
.proof span{font-size:var(--t-small);color:var(--ink-2);display:inline-flex;align-items:center;gap:9px}
.proof svg{width:15px;height:15px;color:var(--amber);flex:none}

/* ===========================================================================
   RESULTS
   =========================================================================== */
.results{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(24px,4vw,56px)}
/* no card: a figure does not need a container to be a figure */
.res{padding:8px 4px;text-align:center}
.res b{display:block;font-size:clamp(34px,4.4vw,60px);font-weight:300;letter-spacing:-.035em;line-height:1;
  background-image:var(--silver);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent}
.res span{display:block;font-size:var(--t-small);color:var(--ink-3);margin-top:9px}
@media(max-width:700px){.results{grid-template-columns:1fr}}

/* ===========================================================================
   MARQUEE
   =========================================================================== */
.mq{overflow:hidden;margin:0 calc(var(--gut) * -1) 30px;
  -webkit-mask:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
          mask:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.mq-track{display:flex;gap:12px;width:max-content;animation:slide 64s linear infinite}
.mq:hover .mq-track{animation-play-state:paused}
.mq a{flex:none;width:clamp(150px,17vw,210px);overflow:hidden;background:var(--surface);
  border-radius:var(--r-sm);corner-shape:squircle}
.mq img{width:100%;height:100%;object-fit:cover;aspect-ratio:4/3;transition:transform .8s var(--ease)}
.mq a:hover img{transform:scale(1.05)}
@keyframes slide{from{transform:translateX(0)}to{transform:translateX(-50%)}}
.mq-head{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-bottom:14px}

/* ===========================================================================
   GROUPED LIST
   =========================================================================== */
.group{background:linear-gradient(180deg,var(--glass-hi),transparent 42%),var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border), var(--glass-shadow);overflow:hidden}
.item{display:grid;grid-template-columns:56px 1fr auto auto 18px;align-items:center;gap:20px;
  padding:19px 22px;position:relative;transition:background .3s var(--ease)}
.item + .item::before{content:"";position:absolute;left:86px;right:0;top:0;height:1px;background:var(--hairline)}
.item:hover{background:var(--surface-2)}
.item .th{width:56px;height:37px;object-fit:cover;background:#000;border-radius:8px;corner-shape:squircle}
.item .t{display:block;font-size:var(--t-h3);font-weight:500;letter-spacing:-.015em}
.item .k{display:block;font-size:12.5px;color:var(--ink-3);margin-top:2px}
.item .tag{font-size:12px;color:var(--ink-2);background:var(--surface-2);padding:4px 10px;
  border-radius:var(--r-pill);white-space:nowrap}
.item .y{font-size:12.5px;color:var(--ink-3);font-variant-numeric:tabular-nums;white-space:nowrap}
.item .ch{width:8px;height:13px;color:var(--ink-3);opacity:.65}
@media(max-width:980px){.item .tag{display:none}}
@media(max-width:640px){
  .item{grid-template-columns:48px 1fr 16px;gap:14px}
  .item .y{display:none} .item + .item::before{left:76px} .item .th{width:48px;height:32px}
}
.panel[hidden],[data-sub-pane][hidden]{display:none}
.subbar{display:flex;justify-content:center;margin:26px 0}
.more{display:flex;justify-content:center;gap:10px;flex-wrap:wrap;margin-top:24px}
.disclaimer{font-size:12px;color:var(--ink-3);text-align:center;max-width:70ch;margin:30px auto 0;line-height:1.6}

/* ===========================================================================
   ABOUT — the halo behind the portrait is the same flame colour
   =========================================================================== */
.about{display:block;text-align:center;max-width:70ch;margin-inline:auto}
.pf{position:relative;isolation:isolate}
.pf::before{content:"";position:absolute;inset:-18%;z-index:-1;border-radius:50%;
  background:radial-gradient(circle,var(--flame-2),transparent 66%);
  filter:blur(38px);opacity:.85}
.pf{width:clamp(136px,16vw,184px);margin:0 auto 30px}
.pf img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:50%}
.about h2{margin-top:10px}
.about p{color:var(--ink-2);margin-top:18px;max-width:58ch;margin-inline:auto}
.about .where{display:inline-flex;align-items:center;gap:8px;margin-top:22px;font-size:var(--t-small);color:var(--ink-3)}
.about .where::before{content:"";width:4px;height:4px;border-radius:50%;background:var(--amber)}
.socials{display:flex;gap:10px;margin-top:30px;flex-wrap:wrap;justify-content:center}


/* the software marks, carried over from the live site with their brand colours */
.tools{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:13px;margin:38px 0 10px}
.tool{width:40px;height:40px;border-radius:11px;corner-shape:squircle;flex:none;display:grid;
  place-items:center;overflow:hidden;background:var(--tb,#1e1e1e);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), 0 10px 22px -14px rgba(0,0,0,.9);
  transition:transform .4s var(--ease)}
.tool:hover{transform:translateY(-3px)}
.tool.full > svg{width:100%;height:100%;display:block}
.tool.mark > svg{width:56%;height:56%;display:block}
.tool-more{display:inline-flex;align-items:center;gap:7px;margin-left:5px;color:var(--ink-3);
  font-size:13px;letter-spacing:.02em;transition:color .3s}
.tool-more:hover{color:var(--ink)}
.tool-more > svg{width:13px;height:13px}

/* ===========================================================================
   PULL QUOTE
   =========================================================================== */
/* THE QUOTE — the one piece of motion that is allowed to be a performance.
   Each word is its own element so the sentence can be lit one word at a time
   as it is scrolled through, the way a line of neon warms up. The unlit state
   is not transparent but a dim ink, so the full sentence is always readable
   and the effect reads as emphasis rather than as missing text. */
/* the quote sits on its own patch of the same LED panel, so the one piece of
   motion on the page is framed by the page's own material */
/* the quote's panel is FULL-BLEED, like the hero's, and dissolves at the top
   and bottom so it never shows an edge. Two masks have to be composited: the
   dot matrix AND the vertical fade, which is what mask-composite:intersect is
   for — a single mask property can only hold one of them. */
.pullwrap{position:relative;isolation:isolate;padding-block:clamp(56px,11vh,130px)}
/* the same pointer halo as the hero, punched through the same dot matrix */
.pullwrap .led-halo{top:0;bottom:0;left:50%;width:100vw;right:auto;transform:translateX(-50%);z-index:-1}
.pullwrap::before{content:"";position:absolute;top:0;bottom:0;left:50%;width:100vw;
  transform:translateX(-50%);z-index:-1;pointer-events:none;
  background:
    radial-gradient(44vw 40vh at 50% 50%, rgba(255,167,66,.20), transparent 72%),
    radial-gradient(76vw 52vh at 50% 50%, rgba(255,255,255,.085), transparent 74%);
  -webkit-mask:
    radial-gradient(circle at 50% 50%, #000 40%, transparent 46%) 0 0 / 4.5px 4.5px,
    linear-gradient(to bottom, transparent 0%, #000 26%, #000 74%, transparent 100%);
  -webkit-mask-composite:source-in;
  mask:
    radial-gradient(circle at 50% 50%, #000 40%, transparent 46%) 0 0 / 4.5px 4.5px,
    linear-gradient(to bottom, transparent 0%, #000 26%, #000 74%, transparent 100%);
  mask-composite:intersect}
.pull{text-align:center;font-size:clamp(23px,3.2vw,44px);line-height:1.26;letter-spacing:-.026em;
  font-weight:400;max-width:21ch;margin-inline:auto;text-wrap:balance}
.pull .pw{display:inline-block;color:var(--ink-3);transition:none;will-change:color,opacity}
.pull .pw.lit{color:var(--ink)}
/* the amber only lands on the two words that carry the joke */
.pull .pw.hot.lit{color:var(--amber)}
.pull .q{color:var(--ink-3);opacity:.5}

/* ===========================================================================
   HOW I WORK
   =========================================================================== */
.demo{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.dcard{background:linear-gradient(180deg,var(--glass-hi),transparent 42%),var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border), var(--glass-shadow);overflow:hidden;display:flex;flex-direction:column;
  transition:background .3s var(--ease)}
.dcard:hover{background:var(--surface-2)}
.dcard .dhead{display:flex;align-items:center;gap:10px;padding:15px 18px}
.dcard .dhead b{font-size:var(--t-h3);font-weight:500;letter-spacing:-.015em}
.dcard .dhead .lab{margin-left:auto}
.dcard .shot{aspect-ratio:16/10;background:#000;overflow:hidden}
.dcard .shot img{width:100%;height:100%;object-fit:cover;object-position:top center}
@media(max-width:800px){.demo{grid-template-columns:1fr}}
.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:14px}
.step{background:linear-gradient(180deg,var(--glass-hi),transparent 42%),var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border), var(--glass-shadow);padding:22px 20px}
.step .n{font-size:var(--t-label);letter-spacing:.14em;color:var(--amber);font-variant-numeric:tabular-nums}
.step b{display:block;font-size:var(--t-h3);font-weight:500;letter-spacing:-.015em;margin-top:9px}
.step p{font-size:13.5px;color:var(--ink-3);margin-top:7px;line-height:1.55}
.step .meta{display:block;font-size:12px;color:var(--ink-3);margin-top:12px;opacity:.75}
@media(max-width:820px){.steps{grid-template-columns:1fr}}
/* a How I work ARTICLE page: the demo and its steps get the room the home row
   now points to */
.article-body{padding-block:0 clamp(80px,12vh,140px)}
.article-more{margin-top:34px;text-align:center}
.article-more a{font-size:var(--t-small);color:var(--ink-2);padding-bottom:2px;
  border-bottom:1px solid var(--hairline);transition:color .3s var(--ease),border-color .3s var(--ease)}
.article-more a:hover{color:var(--ink);border-bottom-color:var(--ink-3)}

/* ===========================================================================
   TESTIMONIALS
   =========================================================================== */
.says{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
.say{background:linear-gradient(180deg,var(--glass-hi),transparent 42%),var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border), var(--glass-shadow);padding:24px 22px 22px}
.say p{font-size:var(--t-small);line-height:1.62;color:var(--ink-2)}
.say .who{margin-top:18px;font-size:12.5px;color:var(--ink-3)}
.say .who b{display:block;color:var(--ink);font-weight:500;font-size:13.5px}
.stars{display:flex;gap:3px;margin-bottom:13px}
.stars i{width:11px;height:11px;background:var(--amber);display:block;
  clip-path:polygon(50% 0,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%)}
@media(max-width:900px){.says{grid-template-columns:1fr}}

/* ===========================================================================
   FAQ
   =========================================================================== */
.faq{background:linear-gradient(180deg,var(--glass-hi),transparent 42%),var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border), var(--glass-shadow);overflow:hidden}
.faq details{position:relative}
.faq details + details::before{content:"";position:absolute;left:20px;right:0;top:0;height:1px;background:var(--hairline)}
.faq summary{list-style:none;cursor:pointer;padding:18px 20px;display:flex;align-items:center;
  justify-content:space-between;gap:18px;font-size:var(--t-h3);font-weight:500;letter-spacing:-.012em}
.faq summary::-webkit-details-marker{display:none}
.faq summary .pl{width:13px;height:13px;flex:none;position:relative;opacity:.6}
.faq summary .pl::before,.faq summary .pl::after{content:"";position:absolute;background:currentColor;
  border-radius:1px;transition:transform .4s var(--ease)}
.faq summary .pl::before{inset:6px 0;height:1.5px}
.faq summary .pl::after{inset:0 6px;width:1.5px}
.faq details[open] summary .pl::after{transform:scaleY(0)}
.faq .ans{padding:0 20px 20px;font-size:var(--t-small);color:var(--ink-2);line-height:1.68;max-width:78ch}

/* ===========================================================================
   STRIP
   =========================================================================== */
.strip{overflow:hidden;padding-block:4px;
  -webkit-mask:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent);
          mask:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent)}
.strip-track{display:flex;gap:28px;width:max-content;animation:slide 48s linear infinite;white-space:nowrap}
.strip span{font-size:clamp(26px,3.6vw,52px);font-weight:600;letter-spacing:-.03em;
  color:transparent;-webkit-text-stroke:1px var(--ink-3);opacity:.45}

/* ===========================================================================
   END, FOOTER
   =========================================================================== */
.end{text-align:center;padding-block:clamp(100px,16vh,180px) clamp(56px,8vh,100px)}
.end h2{font-size:var(--t-hero);line-height:1.04;letter-spacing:-.032em;font-weight:600;
  max-width:14ch;margin-inline:auto;text-wrap:balance;
  background-image:var(--silver);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent}
.tags{display:flex;flex-wrap:wrap;justify-content:center;gap:9px;margin-top:52px}
.tags span{font-size:12.5px;color:var(--ink-2);padding:8px 15px;border-radius:var(--r-pill);background:var(--glass-bg);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border)}
footer{padding-block:0 46px;text-align:center}
footer .fl{display:flex;justify-content:center;gap:10px 24px;flex-wrap:wrap}
footer a{font-size:12.5px;color:var(--ink-3);transition:color .3s}
footer a:hover{color:var(--ink-2)}
footer .cr{font-size:12.5px;color:var(--ink-3);margin-top:12px}

/* ===========================================================================
   ARTICLE PAGES (legal, 404, bespoke case studies)
   =========================================================================== */
.page{padding-block:calc(54px + 12vh) 10vh}
.page h1{font-size:var(--t-hero);line-height:1.04;letter-spacing:-.032em;font-weight:600;
  max-width:16ch;text-wrap:balance;
  background-image:var(--silver);-webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent}
.page .lead{margin-inline:0}
/* the positioning, read at first glance, right above the headline. Typographic on purpose (no icon,
   no glowing rule, no letter-spaced caps): two short statements in sentence case, the first in the
   bright ink, the second a step quieter. They stack on phones. */
.hero .kick{margin:30px 0 0;font-size:clamp(15.5px,1.25vw,18px);line-height:1.45;letter-spacing:-.01em;
  font-weight:500;color:var(--ink-2);text-wrap:balance}
.hero .kick b{color:var(--ink);font-weight:500}
/* his face, a small round next to who he is */
.hero .kick-face{display:inline-block;width:1.6em;height:1.6em;border-radius:50%;object-fit:cover;vertical-align:-.48em;
  margin-right:.5em;box-shadow:0 0 0 1px rgba(255,255,255,.18),0 4px 12px -4px rgba(0,0,0,.8)}
.hero .kick + h1{margin-top:16px}
@media(max-width:700px){.hero .kick span{display:block}}
.prose{max-width:72ch;margin-top:40px}
.prose h2{font-size:var(--t-h3);font-weight:600;margin-top:36px;letter-spacing:-.015em;
  display:flex;align-items:baseline;gap:12px}
.prose .sn{font-size:var(--t-label);letter-spacing:.14em;color:var(--amber);font-weight:500;
  font-variant-numeric:tabular-nums;flex:none}
.prose p,.prose li{color:var(--ink-2);margin-top:12px;font-size:var(--t-small);line-height:1.72}
.prose ul{margin-left:18px}

/* ===========================================================================
   RENDERS — the expanding-panel carousel, carried over from the live ADX page
   ===========================================================================
   Every panel shares the track equally, the first one is given extra weight so
   the band has a subject, and hovering the track compresses them all before
   letting the hovered one take the stage. On touch the same markup becomes a
   snap strip, because there is no hover to drive it with.
*/
.renders{margin-top:24px;display:flex;gap:12px;height:clamp(360px,44vw,540px)}
.r-item{position:relative;flex:1 1 0;min-width:0;overflow:hidden;cursor:zoom-in;
  border-radius:var(--r-lg);corner-shape:squircle;
  box-shadow:inset 0 0 0 1px var(--glass-border);
  transition:flex-grow .85s var(--ease), box-shadow .35s var(--ease)}
.r-item:first-child{flex-grow:2.1}
.r-item img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform 1s var(--ease)}
@media(hover:hover){
  .renders:hover .r-item{flex-grow:1}
  .renders .r-item:hover{flex-grow:2.6;box-shadow:inset 0 0 0 1px rgba(255,255,255,.22)}
  .r-item:hover img{transform:scale(1.03)}
}
@media(max-width:760px){
  .renders{overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;
    height:clamp(300px,74vw,420px);
    margin-inline:calc(var(--gut) * -1);padding-inline:var(--gut);scroll-padding-left:var(--gut)}
  .renders::-webkit-scrollbar{display:none}
  .r-item,.r-item:first-child{flex:0 0 82%;scroll-snap-align:start}
  .renders:hover .r-item{flex-grow:0}
}

/* ===========================================================================
   ROW PREVIEW — the floating thumbnail that trails the cursor over a list
   =========================================================================== */
.peek{position:fixed;top:0;left:0;z-index:45;width:min(23vw,290px);pointer-events:none;
  opacity:0;border-radius:var(--r-md);corner-shape:squircle;overflow:hidden;
  transition:opacity .34s var(--ease);
  box-shadow:0 40px 80px -42px rgba(0,0,0,.95), inset 0 0 0 1px var(--glass-border)}
.peek.on{opacity:1}
.peek img{width:100%;aspect-ratio:1000/531;object-fit:cover;display:block}
@media(pointer:coarse){.peek{display:none}}

/* ===========================================================================
   LIGHTBOX — the live site's viewer: next / previous, a counter, keyboard
   ===========================================================================
   One dialog for the whole page. Clicking any figure opens it at that index
   and the whole set becomes navigable, which is the difference between a zoom
   and a viewer: you can go through the work without closing and reopening.
*/
.lightbox{position:fixed;inset:0;z-index:300;display:none;
  background:rgba(5,5,6,.93);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  overscroll-behavior:contain}
.lightbox.open{display:block}
.lb-stage{position:absolute;inset:0;display:grid;place-items:center;overflow:hidden;
  padding:clamp(14px,4vw,56px);overscroll-behavior:contain}
.lb-img{max-width:94vw;max-height:86vh;width:auto;height:auto;display:block;cursor:zoom-in;
  border-radius:var(--r-md);corner-shape:squircle;user-select:none;-webkit-user-drag:none;
  box-shadow:0 48px 120px -40px rgba(0,0,0,.95);
  opacity:0;transform:scale(.97);transition:opacity .34s var(--ease),transform .45s var(--ease)}
.lightbox.open .lb-img{opacity:1;transform:scale(1)}
.lightbox.zoomed .lb-stage{overflow:auto;cursor:grab}
.lightbox.zoomed .lb-img{max-width:none;max-height:none;border-radius:0;cursor:grab}
.lightbox.zoomed.grabbing .lb-stage,.lightbox.zoomed.grabbing .lb-img{cursor:grabbing}
.lb-btn{position:absolute;z-index:2;width:48px;height:48px;border-radius:50%;border:0;
  display:grid;place-items:center;cursor:pointer;color:var(--ink);
  background:var(--glass-bg);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border);
  transition:transform .35s var(--ease),box-shadow .35s var(--ease)}
.lb-btn:hover{box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px rgba(255,255,255,.26)}
.lb-btn svg{width:19px;height:19px}
.lb-close{top:20px;right:20px}
.lb-prev{left:20px;top:50%;transform:translateY(-50%)}
.lb-next{right:20px;top:50%;transform:translateY(-50%)}
.lb-prev:hover{transform:translateY(-50%) translateX(-2px)}
.lb-next:hover{transform:translateY(-50%) translateX(2px)}
.lb-count{position:absolute;bottom:22px;left:50%;transform:translateX(-50%);z-index:2;
  font-size:12.5px;letter-spacing:.09em;color:var(--ink-2);font-variant-numeric:tabular-nums;
  padding:7px 15px;border-radius:var(--r-pill);
  background:var(--glass-bg);backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 0 0 1px var(--glass-border)}
@media(max-width:700px){
  .lb-btn{width:42px;height:42px}
  .lb-prev{left:10px}.lb-next{right:10px}.lb-close{top:12px;right:12px}
}

/* ===========================================================================
   MOTION — the states the engine animates from. GSAP owns the timing; CSS only
   provides the line masks and the pre-paint hiding, so nothing flashes before
   the first tween runs.
   =========================================================================== */
/* Each line is a mask (overflow) and, since the Safari fix, carries its own
   clipped gradient. A display title is set tighter than its glyphs (line-height
   .98–1.08), so g/p/y hang ~.13em below the line box and accents rise ~.15em
   above it: both the mask and the painted area are padded by .2em on each side,
   and pulled back by the same margin so the layout does not move. */
.is-split{display:flex;flex-direction:column}
.ln{display:block;overflow:hidden;padding-block:.2em;margin-block:-.2em}
.ln > span{display:block;padding-block:.2em;margin-block:-.2em;will-change:transform,opacity}
/* hidden until the engine takes over. The .js class is set by an inline script
   in <head>, so a reader without JS still sees everything. */
.js [data-split],.js [data-fade]{opacity:0}
.js [data-batch] > *,.js [data-stagger] > *{opacity:0}

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{transition-duration:.01ms!important;animation:none!important}
  .js [data-split],.js [data-fade],
  .js [data-batch] > *,.js [data-stagger] > *{opacity:1!important}
  .reel-wrap video,.reel-pic{display:none}
}

/* ===========================================================================
   CONTACT CHOOSER — "Work with me" opens a small WhatsApp / Email menu, as on
   the live site. Built on the same glass as the nav pill.
   =========================================================================== */
.contact-pop{position:fixed;z-index:120;min-width:198px;padding:6px;
  border-radius:16px;corner-shape:squircle;
  background:linear-gradient(180deg,var(--glass-hi),transparent 46%),var(--glass-bg);
  backdrop-filter:var(--glass-blur);-webkit-backdrop-filter:var(--glass-blur);
  box-shadow:inset 0 1px 0 var(--glass-edge), inset 0 0 0 1px var(--glass-border),
             0 26px 54px -22px rgba(0,0,0,.72);
  opacity:0;transform:translateY(-6px) scale(.97);transform-origin:top center;
  transition:opacity .22s var(--ease),transform .22s var(--ease);pointer-events:none}
.contact-pop.open{opacity:1;transform:none;pointer-events:auto}
.contact-pop a{display:flex;align-items:center;gap:12px;padding:11px 13px;
  border-radius:11px;corner-shape:squircle;color:var(--ink);
  font-size:var(--t-small);font-weight:500;letter-spacing:.01em;
  transition:background .2s var(--ease),color .2s var(--ease)}
.contact-pop a:hover,.contact-pop a:focus-visible{
  background:color-mix(in srgb, var(--amber) 13%, transparent);color:var(--amber);outline:none}
.contact-pop a svg{width:19px;height:19px;flex:none;color:var(--amber)}

/* ===========================================================================
   LOADER — only on a slow first visit (the head script decides), never on a
   reload, a back/forward visit or a second page. The site's own LED wall: the
   dot grid lit by a slow flame-coloured breath from the centre, and the
   wordmark itself set in LED dots. It fades in only after 250ms, so a fast
   load never shows it, and hands over to the hero intro as it fades out.
   =========================================================================== */
.ll-loader{position:fixed;inset:0;z-index:1000;display:grid;place-items:center;background:var(--ground,#08080A);
  opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .55s cubic-bezier(.32,.72,0,1),visibility 0s linear .55s}
html.ll-loading .ll-loader{opacity:1;visibility:visible;pointer-events:auto;
  transition:opacity .35s ease .25s,visibility 0s linear 0s}
.ll-loader .ll-dots{position:absolute;inset:0;overflow:hidden;
  -webkit-mask:radial-gradient(circle at 50% 50%,#000 40%,transparent 46%) 0 0/5px 5px;
          mask:radial-gradient(circle at 50% 50%,#000 40%,transparent 46%) 0 0/5px 5px}
.ll-loader .ll-dots b{position:absolute;inset:-25%;display:block;
  background:radial-gradient(closest-side,var(--flame-2,#A82410) 0%,var(--flame-1,#7A1408) 38%,rgba(255,255,255,.07) 62%,rgba(255,255,255,.035) 100%);
  animation:ll-breath 1.8s ease-in-out infinite}
@keyframes ll-breath{0%,100%{transform:scale(.55);opacity:.55}50%{transform:scale(1);opacity:1}}
.ll-loader .ll-mark{position:relative;width:min(58vw,280px);aspect-ratio:3443/486;
  background:linear-gradient(97deg,#767D86 0%,#FFFFFF 18%,#B4BBC4 36%,#F4F7FA 54%,#8C939C 70%,#FFFFFF 86%,#A2A9B2 100%) 0 0/220% 100%;
  -webkit-mask:url('/assets/logo-wordmark-mask.png') center/contain no-repeat,
               radial-gradient(circle at 50% 50%,#000 42%,transparent 48%) 0 0/3px 3px;
  -webkit-mask-composite:source-in;
          mask:url('/assets/logo-wordmark-mask.png') center/contain no-repeat,
               radial-gradient(circle at 50% 50%,#000 42%,transparent 48%) 0 0/3px 3px;
          mask-composite:intersect;
  animation:ll-sheen 1.8s ease-in-out infinite}
@keyframes ll-sheen{0%{background-position:100% 0}100%{background-position:0 0}}
@media(prefers-reduced-motion:reduce){.ll-loader .ll-dots b,.ll-loader .ll-mark{animation:none}}

/* ===========================================================================
   LITE — Windows Chrome. Same look, without the effects that cost a full
   recomposite on every frame there: the ember stops breathing (a static blurred
   layer is rasterised once), the blend modes go (screen over near-black is
   visually the same), the glass blurs less, and the reel drops to 720p.
   =========================================================================== */
.ll-lite .bg i{animation:none!important;will-change:auto}
.ll-lite .bg i,.ll-lite .reel-wrap video,.ll-lite .reel-pic img,.ll-lite .reel-wrap::before{mix-blend-mode:normal}
.ll-lite{--glass-blur:blur(10px) saturate(1.3)}
.ll-lite .ll-loader .ll-dots b{animation-duration:2.4s}

/* ===========================================================================
   CTA LIGHT (2026-10-06): the Digital / Physical tab's light, on every button.
   A glass button (.btn-2) glows from inside: a warm white core, then the site's
   ember red, specked like the LED dots. A white button (.btn-1) takes a golden tint
   under the pointer and an amber halo that leans towards it (red read as "danger" on white). The script writes
   --gx/--gy (the pointer inside the button) and --hx/--hy (the lean) and toggles
   .lit (mouse hover, or 750ms where a finger lands). The light replaces the old
   sweep band. The same block lives in ll.css and ll-skin.css.
   =========================================================================== */
.btn{transition:transform .4s var(--ease),box-shadow .45s var(--ease),background .35s var(--ease),text-shadow .5s var(--ease)}
.btn::before{display:none}
.btn::after{content:"";position:absolute;inset:0;z-index:-1;border-radius:inherit;pointer-events:none;
  opacity:0;transition:opacity .5s var(--ease)}
.btn.lit::after{opacity:1}
.btn-2::after{mix-blend-mode:screen;
  background:
    radial-gradient(circle 120px at var(--gx,50%) var(--gy,50%),rgba(255,226,210,.84) 0,rgba(255,138,104,.62) 13%,
      rgba(232,67,31,.44) 32%,rgba(168,36,16,.2) 58%,transparent 100%),
    radial-gradient(rgba(255,255,255,.32) .5px,transparent .9px) 0 0/7px 7px;
  -webkit-mask:radial-gradient(circle 115px at var(--gx,50%) var(--gy,50%),#000 0,rgba(0,0,0,.6) 45%,transparent 100%);
          mask:radial-gradient(circle 115px at var(--gx,50%) var(--gy,50%),#000 0,rgba(0,0,0,.6) 45%,transparent 100%)}
.btn-2.lit{text-shadow:0 0 12px rgba(24,8,6,.6),0 1px 2px rgba(24,8,6,.3)}
.btn-1::after{mix-blend-mode:multiply;
  background:radial-gradient(circle 95px at var(--gx,50%) var(--gy,50%),rgba(255,222,160,.78) 0,rgba(255,196,110,.4) 30%,
    rgba(255,167,66,.12) 62%,transparent 100%)}
.btn-1.sm::after{background:radial-gradient(circle 58px at var(--gx,50%) var(--gy,50%),rgba(255,222,160,.7) 0,rgba(255,196,110,.32) 34%,
    transparent 100%)}
.btn-1.sm.lit{box-shadow:0 1px 0 rgba(255,255,255,.7) inset,var(--hx,0px) var(--hy,8px) 22px -8px rgba(255,167,66,.55)}
.btn-1.lit{box-shadow:0 1px 0 rgba(255,255,255,.7) inset,var(--hx,0px) var(--hy,10px) 30px -8px rgba(255,167,66,.62)}
