/* ============================================================
   TAMON — design system
   Layers: tokens · base · type · layout · components · motion
   The gradient is Tamon's ink: the signature ring, selection, caret,
   focus, link underline, the Book button's outline, and the hero's
   light field. Always the one definition below.
   ============================================================ */

/* ---------- Fonts (self-hosted, no CDN) ---------- */
@font-face{font-family:"Jost";src:url("../fonts/jost-300.woff2") format("woff2");font-weight:300;font-style:normal;font-display:swap}
@font-face{font-family:"Jost";src:url("../fonts/jost-400.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Jost";src:url("../fonts/jost-500.woff2") format("woff2");font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:"Comfortaa";src:url("../fonts/comfortaa-400.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:"Comfortaa";src:url("../fonts/comfortaa-700.woff2") format("woff2");font-weight:700;font-style:normal;font-display:swap}
/* metrics-matched fallbacks so text keeps its box when the webfont lands.
   Measured with fontTools from the self-hosted woff2 files against Arial (typo metrics,
   USE_TYPO_METRICS set). Jost is tuned to the hero headline, the LCP element: rendered
   width within 0.15%, identical height. Comfortaa: width within 0.7%, identical height. */
@font-face{font-family:"Jost Fallback";src:local("Arial"),local("Helvetica"),local("Liberation Sans"),local("Roboto");size-adjust:92.35%;ascent-override:115.86%;descent-override:40.61%;line-gap-override:0%}
@font-face{font-family:"Comfortaa Fallback";src:local("Arial"),local("Helvetica"),local("Liberation Sans"),local("Roboto");size-adjust:117.11%;ascent-override:75.23%;descent-override:19.98%;line-gap-override:0%}

/* ---------- Tokens ---------- */
:root{
  /* brand gradient — single source of truth */
  --grad-a:#72AEDD;         /* sky */
  --grad-b:#FBF06F;         /* khaki */
  --grad-c:#C42B27;         /* firebrick */
  --gradient:linear-gradient(90deg,var(--grad-a) 0%,var(--grad-b) 50%,var(--grad-c) 100%);
  /* the same three stops as channels, for light that needs alpha (hero light field) */
  --grad-a-rgb:114 174 221;
  --grad-b-rgb:251 240 111;
  --grad-c-rgb:196 43 39;

  /* ground & ink (navy, not black) */
  --ink:#0A141C;
  --ink-2:#0D1922;          /* raised panel */
  --ink-3:#101f2b;          /* hover panel */
  --text:#E9EFF4;           /* body on ink */
  --text-soft:#B9C5CF;      /* secondary text that sits over moving light: 10.6:1 on ink */
  --text-dim:#93A3B0;       /* secondary */
  --text-faint:#5F6E7A;     /* tertiary / meta */
  --hair:rgba(233,239,244,.13);
  --hair-strong:rgba(233,239,244,.24);

  /* type */
  --display:"Jost","Jost Fallback",system-ui,sans-serif;
  --body:"Comfortaa","Comfortaa Fallback",system-ui,sans-serif;

  /* fluid type scale */
  --fs-hero:clamp(3rem,.75rem + 6vw,7.5rem);      /* one line from 600px: 9.15em wide, about 70% of the content width */
  --fs-h2:clamp(1.9rem,1.3rem + 2.6vw,3.1rem);
  --fs-h3:clamp(1.35rem,1.1rem + 1vw,1.7rem);
  --fs-lead:clamp(1.12rem,1.02rem + .5vw,1.42rem);
  --fs-body:1.0625rem;
  --fs-sm:.875rem;
  --fs-xs:.78rem;

  /* space */
  --gutter:clamp(1.15rem,4vw,3rem);
  --maxw:75rem;              /* 1200px */
  --maxw-wide:84rem;
  --section-y:clamp(4.5rem,3rem + 9vw,9rem);

  /* misc */
  --radius:14px;
  --radius-sm:9px;
  --ease-out:cubic-bezier(.22,1,.36,1);
  --ease-inout:cubic-bezier(.65,0,.35,1);

  /* motion timing */
  --dur-fast:140ms;         /* direct feedback */
  --dur-state:360ms;        /* state changes */
  --dur-enter:720ms;        /* entrances */
  --ease-enter:cubic-bezier(.16,1,.3,1);    /* long, soft landing */
  --ease-exit:cubic-bezier(.7,0,.84,0);     /* quick departure */
  --ease-morph:cubic-bezier(.68,0,.24,1);   /* menu toggle morph */

  /* neon: one definition for every neon light on the site (see "Neon") */
  --neon-cycle:4s;          /* a whole colour loop passes any point of any neon in this time */
  --neon-tube:1.5px;        /* the lit line of a neon outline */
  --neon-glow:6px;          /* how far the light blooms: the blur's standard deviation (the offer's computed
                               glow is matched to 6px; recompute its factors if this changes) */
  --neon-glow-strength:.85; /* how bright the bloom is */

  /* glass: frosted ink panels on the inner pages (see "Glass") */
  --glass-ground:rgb(16 31 43 / .46);
  --glass-edge:rgb(233 239 244 / .1);
  --glass-blur:20px;
  --radius-lg:24px;

  /* header geometry. Logo heights are unitless px so they can be divided for the compact scale. */
  --logo-h:48;
  --logo-h-c:38;
  --logo-clear:.4754;       /* clear space = ring radius; ring outer radius / lockup height, measured */
  --logo-nudge-x:0%;        /* optical correction, % of logo width */
  --logo-nudge-y:-3%;       /* optical correction, % of logo height: ink sits 8.5-9.6% below the box centre */
  --bar-h:calc(var(--logo-h) * (1 + 2 * var(--logo-clear)) * 1px);
  --bar-h-c:calc(var(--logo-h-c) * (1 + 2 * var(--logo-clear)) * 1px);
}
@media (max-width:359px){:root{--logo-h:40;--logo-h-c:34}}
@media (min-width:768px){:root{--logo-h:58;--logo-h-c:42}}
@media (min-width:1280px){:root{--logo-h:68;--logo-h-c:46}}
@media (min-width:1680px){:root{--logo-h:76;--logo-h-c:48}}

/* ---------- Reset / base ---------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;scroll-padding-top:var(--bar-h-c)}
html.is-locked{overflow:hidden}
/* Guard: overflow inside any section must never widen the page, or the fixed header
   (and its centred logo) widens with it on phones. Clips, does not create a scroller. */
main{overflow-x:clip}
html.is-locked body{padding-right:var(--sbw,0px)}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
/* while site.js glides the page on the wheel it moves it frame by frame; CSS smoothing would fight each step */
html.is-gliding{scroll-behavior:auto}
body{
  margin:0;background:var(--ink);color:var(--text);
  font-family:var(--body);font-size:var(--fs-body);line-height:1.62;
  font-weight:400;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:hidden;
}
img,svg,video{display:block;max-width:100%}
h1,h2,h3,h4{font-family:var(--display);font-weight:400;margin:0;line-height:1.06;letter-spacing:-.015em}
p{margin:0}
a{color:inherit;text-decoration:none}
ul{margin:0;padding:0;list-style:none}
strong{font-weight:400;color:var(--text)}

/* ---------- The gradient as ink ---------- */
::selection{background:var(--grad-a);color:var(--ink)}
:root{caret-color:var(--grad-a)}
:where(a,button,input,textarea,summary,[tabindex]):focus-visible{
  outline:2px solid var(--grad-a);outline-offset:3px;border-radius:3px;
}

/* text link with a gradient underline that grows on hover */
.link{
  position:relative;color:var(--text);
  background-image:var(--gradient);
  background-repeat:no-repeat;
  background-position:0 100%;
  background-size:100% 2px;
  padding-bottom:2px;
  transition:color .3s var(--ease-out);
}
.link--grow{background-size:0 2px;transition:background-size .4s var(--ease-out),color .3s var(--ease-out)}
.link--grow:hover,.link--grow:focus-visible{background-size:100% 2px}

/* ---------- Neon ----------
   One neon for the site: the header's Book now, See our work, the hero's arc and the offer's arc.
   · Colour: the brand stops as a mirrored loop (sky, khaki, firebrick, khaki) flowing along the shape.
     .neon-flow paints the loop as a conic texture and turns it. Large shapes repeat the loop
     (--neon-loops) and turn in --neon-cycle per loop, so on every neon a whole loop passes each point
     every --neon-cycle.
   · Glow: .neon-glow blurs a copy of the lit shape by --neon-glow at --neon-glow-strength. The offer's
     arc is too large to blur live every frame, so its mask carries the same blur, computed.
   · Only rotation animates, on the compositor. A neon rests with its section (off screen, hidden tab,
     open menu) and holds still with reduced motion. */
.neon-flow{--neon-loops:1;
  background:repeating-conic-gradient(var(--grad-a) 0deg,var(--grad-b) calc(90deg / var(--neon-loops)),
    var(--grad-c) calc(180deg / var(--neon-loops)),var(--grad-b) calc(270deg / var(--neon-loops)),
    var(--grad-a) calc(360deg / var(--neon-loops)));
  animation:neon-turn calc(var(--neon-cycle) * var(--neon-loops)) linear infinite}
@keyframes neon-turn{to{rotate:360deg}}
.neon-glow{filter:blur(var(--neon-glow));opacity:var(--neon-glow-strength)}
@media (prefers-reduced-motion:reduce){.neon-flow{animation:none}}

/* A neon outline for a rounded box: a crisp tube and, under it, the glow (the tube doubled, blurred).
   The loop turns on a square wide enough to cover the box at every angle. The host needs
   position:relative and isolation:isolate, so the neon sits above its background and below its text. */
.neon-ring{position:absolute;inset:0;z-index:-1;border-radius:inherit;pointer-events:none}
.neon-ring .neon-glow,.neon-ring__tube{position:absolute;inset:0;border-radius:inherit}
.neon-ring__tube{padding:var(--neon-tube);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;
          mask:linear-gradient(#000 0 0) content-box exclude,linear-gradient(#000 0 0)}
.neon-ring .neon-glow .neon-ring__tube{padding:calc(var(--neon-tube) * 2)}
.neon-ring .neon-flow{position:absolute;left:50%;top:50%;width:120%;aspect-ratio:1;translate:-50% -50%}

/* A straight neon line (underlines, the horizon, rails): the same loop sliding along it, so a loop of
   --neon-len passes each point every --neon-cycle, with the same glow. .neon-line--v stands it up. */
.neon-line{--neon-len:360px;position:relative;display:block;height:var(--neon-tube);pointer-events:none}
.neon-line__tube{position:absolute;inset:0;overflow:hidden;border-radius:999px}
.neon-line .neon-glow{position:absolute;inset:calc(var(--neon-tube) * -.5) 0}
.neon-flow--line{position:absolute;inset:0 auto 0 0;width:calc(100% + var(--neon-len));
  background:repeating-linear-gradient(90deg,var(--grad-a) 0,var(--grad-b) calc(var(--neon-len) * .25),
    var(--grad-c) calc(var(--neon-len) * .5),var(--grad-b) calc(var(--neon-len) * .75),var(--grad-a) var(--neon-len));
  animation:neon-slide var(--neon-cycle) linear infinite}
@keyframes neon-slide{to{translate:calc(var(--neon-len) * -1) 0}}
.neon-line--v{width:var(--neon-tube);height:auto}
.neon-line--v .neon-glow{inset:0 calc(var(--neon-tube) * -.5)}
.neon-line--v .neon-flow--line{inset:0 0 auto 0;width:auto;height:calc(100% + var(--neon-len));
  background:repeating-linear-gradient(180deg,var(--grad-a) 0,var(--grad-b) calc(var(--neon-len) * .25),
    var(--grad-c) calc(var(--neon-len) * .5),var(--grad-b) calc(var(--neon-len) * .75),var(--grad-a) var(--neon-len));
  animation-name:neon-slide-v}
@keyframes neon-slide-v{to{translate:0 calc(var(--neon-len) * -1)}}
@media (prefers-reduced-motion:reduce){.neon-flow--line{animation:none}}
/* any section marked [data-rest] pauses its neon while off screen, under the menu or in a hidden tab (site.js) */
.is-paused .neon-flow{animation-play-state:paused}

/* ---------- Glass ----------
   Frosted ink for panels on the inner pages: a translucent ground over whatever light sits behind it, a
   hairline edge and a faint top highlight. Kept off moving light where possible (the browser re-blurs a
   moving background every frame). [data-spotlight] adds a soft light that follows the pointer. */
.glass{position:relative;border-radius:var(--radius-lg);background:var(--glass-ground);
  box-shadow:inset 0 0 0 1px var(--glass-edge),inset 0 1px 0 rgb(233 239 244 / .07),0 40px 90px -50px rgb(0 0 0 / .7);
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(1.2);backdrop-filter:blur(var(--glass-blur)) saturate(1.2)}
@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.glass{background:rgb(16 31 43 / .92)}}
.glass[data-spotlight]::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;opacity:0;
  background:radial-gradient(28rem circle at var(--mx,50%) var(--my,50%),rgb(233 239 244 / .07),transparent 65%);
  transition:opacity .5s var(--ease-out)}
.glass[data-spotlight]:hover::before{opacity:1}

/* ---------- Entrances ----------
   Content is visible by default: without JavaScript, with reduced motion, and if site.js never runs (the
   inline script in <head> adds .enter-failsafe after 3 s). Otherwise each [data-enter] waits until it first
   scrolls into view (site.js adds .is-in); what is on screen at load enters as the page opens.
   Five movements, each with a job; transforms, opacity and clip-path only; --d delays, --i staggers lines.
   · rise: a heading's lines lift out of their own masks, the way the menu's words arrive;
   · wipe: a panel or photo opens upward from its lower edge (--wipe-r: its corner radius, default --radius-lg);
   · draw: a line (a neon underline, the horizon) draws out from --from;
   · fade: supporting copy settles up as it appears;
   · unmask: a cover photo opens from a rounded window to the full frame as it settles (a case study's cover).
     When the page arrives by a view transition the cover is already flying into place, so it starts open. */
.rise__line{display:block;overflow:hidden;padding-bottom:.12em;margin-bottom:-.12em}
.rise__line>span{display:block}
@media (prefers-reduced-motion:no-preference){
  .js:not(.enter-failsafe) [data-enter="rise"] .rise__line>span{transform:translateY(106%);
    transition:transform 1.15s var(--ease-enter) calc(var(--d,0s) + var(--i,0) * 90ms)}
  .js:not(.enter-failsafe) [data-enter="rise"].is-in .rise__line>span{transform:none}
  .js:not(.enter-failsafe) [data-enter="wipe"]{clip-path:inset(100% 0 0 0 round var(--wipe-r,var(--radius-lg)));
    transition:clip-path 1.2s var(--ease-enter) var(--d,0s)}
  .js:not(.enter-failsafe) [data-enter="wipe"].is-in{clip-path:inset(0 0 0 0 round var(--wipe-r,var(--radius-lg)))}
  .js:not(.enter-failsafe) [data-enter="unmask"]{clip-path:inset(9% 6% round var(--radius-lg));
    transition:clip-path 1.6s var(--ease-enter) var(--d,0s)}
  .js:not(.enter-failsafe) [data-enter="unmask"] img{scale:1.14;transition:scale 2s var(--ease-enter) var(--d,0s)}
  .js:not(.enter-failsafe) [data-enter="unmask"].is-in{clip-path:inset(0 round 0)}
  .js:not(.enter-failsafe) [data-enter="unmask"].is-in img{scale:1}
  :root:active-view-transition [data-enter="unmask"],:root:active-view-transition [data-enter="unmask"] img{clip-path:none;scale:1;transition:none}
  .js:not(.enter-failsafe) [data-enter="fade"]{opacity:0;translate:0 1.25rem;
    transition:opacity 1s var(--ease-out) var(--d,0s),translate 1.2s var(--ease-enter) var(--d,0s)}
  .js:not(.enter-failsafe) [data-enter="fade"].is-in{opacity:1;translate:0 0}
  .js:not(.enter-failsafe) [data-enter="draw"]{scale:0 1;transform-origin:var(--from,0 50%);
    transition:scale 1.5s var(--ease-enter) var(--d,0s)}
  .js:not(.enter-failsafe) [data-enter="draw"].is-in{scale:1 1}
}

/* ---------- Page transitions ----------
   Going from page to page cross-fades while the header holds still, where the browser supports it.
   The opt-in, @view-transition{navigation:auto}, is an inline <style> in each page's head, not here: the browser
   decides as the new page first renders, and on a cold cache this file could still be on its way (measured with
   the cache off: 4 of 6 transitions skipped with the rule here, none of 6 with it inline). */
@media (prefers-reduced-motion:no-preference){
  ::view-transition-old(root){animation:.3s cubic-bezier(.7,0,.84,0) both vt-out}
  ::view-transition-new(root){animation:.65s cubic-bezier(.16,1,.3,1) .08s both vt-in}
}
@keyframes vt-out{to{opacity:0}}
@keyframes vt-in{from{opacity:0;translate:0 .75rem}}
.site-header{view-transition-name:site-header}

/* Photos that travel between pages: a project's photo on the homepage or the Projects page becomes the cover of
   its case study, and the next project's photo at the foot of a case study becomes the cover of the next one.
   Each carries view-transition-name (work-<project>) and view-transition-class: work, and grows in place of the
   plain cross-fade, cropped as it goes. A cover's shade and name (class cover-layer) are lifted above the
   travelling photo and fade in over it as it lands, instead of appearing once it has. */
@media (prefers-reduced-motion:no-preference){
  ::view-transition-group(*.work){animation-duration:.8s;animation-timing-function:cubic-bezier(.16,1,.3,1);overflow:clip}
  ::view-transition-old(*.work),::view-transition-new(*.work){height:100%;object-fit:cover;animation-duration:.8s}
  ::view-transition-new(*.cover-layer){animation:.6s cubic-bezier(.22,1,.36,1) .3s both vt-appear}
  ::view-transition-old(*.cover-layer){animation:.2s linear both vt-out}
}
@keyframes vt-appear{from{opacity:0}}

/* a small pull toward the pointer for the main buttons of the inner pages and the footer (site.js sets translate) */
.btn-book[data-magnetic]{transition:background-color var(--dur-state) var(--ease-out),box-shadow var(--dur-state) var(--ease-out),
  transform var(--dur-fast) var(--ease-out),translate .7s var(--ease-enter)}

/* ---------- Layout ---------- */
.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gutter)}
.wrap--wide{max-width:var(--maxw-wide)}
.section{padding-block:var(--section-y)}
.grid{display:grid;grid-template-columns:repeat(12,1fr);gap:clamp(1rem,2vw,1.6rem)}
.stack>*+*{margin-top:1.1em}
.measure{max-width:38ch}
.lead{font-size:var(--fs-lead);line-height:1.5;color:var(--text-dim)}
.eyebrow{font-family:var(--display);font-weight:500;font-size:var(--fs-sm);color:var(--text-dim)}
/* in the accessibility tree and the outline, not on screen */
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}

.skip{position:absolute;left:-999px;top:0;background:var(--text);color:var(--ink);
  padding:.7rem 1rem;border-radius:0 0 var(--radius-sm) 0;z-index:100}
.skip:focus{left:0}

/* ---------- Buttons (never gradient) ---------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;
  min-height:48px;padding:.85rem 1.5rem;border-radius:999px;
  font-family:var(--display);font-weight:500;font-size:1rem;letter-spacing:.01em;
  cursor:pointer;border:1px solid transparent;transition:transform .3s var(--ease-out),background-color .3s var(--ease-out),border-color .3s var(--ease-out);
}
.btn--primary{background:var(--text);color:var(--ink)}
.btn--primary:hover{transform:translateY(-2px)}
.btn--ghost{border-color:var(--hair-strong);color:var(--text)}
.btn--ghost:hover{border-color:var(--text);transform:translateY(-2px)}

/* ---------- Header ----------
   Three zones on a grid with equal outer tracks, so the logo stays on the
   viewport axis however wide the button or the toggle become.
   States (set in site.js): top = transparent over the hero · compact = ink bar
   and smaller logo once the page moves · hidden = scrolling down past the hero.
   Every state change is transform or opacity: no layout shift. */
.site-header{position:fixed;inset:0 0 auto 0;z-index:70;height:var(--bar-h);pointer-events:none;
  transition:transform .42s var(--ease-out)}
.is-locked .site-header{right:var(--sbw,0px)}
.site-header::before,.site-header::after{content:"";position:absolute;left:0;right:0;opacity:0;
  transition:opacity var(--dur-state) var(--ease-out)}
.site-header::before{top:0;height:var(--bar-h-c);background:var(--ink)}   /* solid: nothing ghosts behind the logo */
.site-header::after{top:calc(var(--bar-h-c) - 1px);height:1px;background:var(--hair)}
.site-header.is-compact::before,.site-header.is-compact::after{opacity:1}
.menu-open .site-header::after{opacity:0}
.site-header.is-hidden{transform:translateY(-100%)}
.site-header__bar{position:relative;height:var(--bar-h);display:grid;
  grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);align-items:center;column-gap:.75rem;
  padding-inline:var(--gutter);transition:transform .42s var(--ease-out)}
.site-header.is-compact .site-header__bar{transform:translateY(calc((var(--bar-h-c) - var(--bar-h)) / 2))}
.site-header__start{justify-self:start;display:flex}
.site-header__end{justify-self:end;display:flex}
.site-header a,.site-header button{pointer-events:auto}
.site-header.is-instant,.site-header.is-instant *,
.site-header.is-instant::before,.site-header.is-instant::after{transition:none!important}
@media (prefers-reduced-motion:reduce){
  .site-header,.site-header__bar,.brand{transition-duration:.01ms}
}

.brand{display:block;border-radius:6px;transition:transform .42s var(--ease-out)}
.brand__logo{display:block;width:auto;height:calc(var(--logo-h) * 1px);
  transform:translate(var(--logo-nudge-x),var(--logo-nudge-y))}
.site-header.is-compact .brand{transform:scale(calc(var(--logo-h-c) / var(--logo-h)))}

/* "Book now": one of three header elements, so it carries weight.
   The gradient (single definition) traces the lower half of the pill at rest,
   like the bottom arc of the logo ring, and closes the outline on hover and focus. */
.btn-book{position:relative;display:inline-flex;align-items:center;justify-content:center;
  height:46px;padding-inline:1.3rem;border-radius:999px;white-space:nowrap;
  font-family:var(--display);font-weight:500;font-size:1rem;letter-spacing:.012em;color:var(--text);
  background-color:rgba(10,20,28,.35);box-shadow:inset 0 0 0 1px var(--hair-strong);
  transition:background-color var(--dur-state) var(--ease-out),box-shadow var(--dur-state) var(--ease-out),transform var(--dur-fast) var(--ease-out)}
.btn-book::after{content:"";position:absolute;inset:0;padding:1px;border-radius:inherit;pointer-events:none;
  background:var(--gradient);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;
  mask:linear-gradient(#000 0 0) content-box exclude,linear-gradient(#000 0 0);
  clip-path:inset(50% 0 0 0);transition:clip-path .6s var(--ease-out)}
.btn-book:hover{background-color:rgba(233,239,244,.07);box-shadow:inset 0 0 0 1px transparent}
.btn-book:hover::after,.btn-book:focus-visible::after{clip-path:inset(0)}
.btn-book:active{transform:scale(.965);background-color:rgba(233,239,244,.13);transition-duration:90ms}
.btn-book:focus-visible{outline-offset:4px}
/* phones: a smaller pill keeps the logo dominant and its clear space intact; the touch target stays 44px */
@media (max-width:767px){
  .btn-book{height:40px;padding-inline:.75rem;font-size:.875rem}
  .btn-book::before{content:"";position:absolute;inset:-2px 0}
}
@media (max-width:359px){.btn-book{padding-inline:.65rem;font-size:.8125rem}}
@media (prefers-reduced-motion:reduce){.btn-book::after{transition-duration:.01ms}}
/* Book now and See our work wear the site's neon outline (see "Neon") in place of the half-traced one */
.btn-neon{isolation:isolate}
.btn-neon::after{display:none}
.btn-neon .neon-glow{transition:opacity var(--dur-state) var(--ease-out)}
.btn-neon:hover .neon-glow,.btn-neon:focus-visible .neon-glow{opacity:1}

/* Menu toggle: drawn, not an icon-font glyph. Closed = two strokes; open = the strokes
   cross while the logo's own ring (measured arcs and gaps, brand/arc-geometry.json) winds in
   around them. One set of CSS transitions, so a click mid-morph reverses from where it is. */
.menu-toggle{position:relative;display:inline-grid;place-items:center;width:48px;height:48px;margin-right:-13px;
  padding:0;border:0;border-radius:50%;background:none;color:var(--text);cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.mt{display:block;overflow:visible}
.mt__bar{fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;
  transform-box:view-box;transform-origin:24px 24px;
  transition:transform .3s var(--ease-morph),stroke-dasharray .3s var(--ease-morph),stroke-dashoffset .3s var(--ease-morph)}
.mt__bar--1{transform:translateY(-4px) rotate(0deg);stroke-dasharray:22 22;stroke-dashoffset:0}
.mt__bar--2{transform:translateY(4px) rotate(0deg);stroke-dasharray:14 22;stroke-dashoffset:-8}
.menu-toggle[aria-expanded="false"]:hover .mt__bar--2,.menu-toggle--nojs:hover .mt__bar--2{stroke-dasharray:22 22;stroke-dashoffset:0}
.mt__ring{transform-box:view-box;transform-origin:24px 24px;transform:rotate(-120deg);
  transition:transform .26s var(--ease-morph)}
.mt__arc{fill:none;stroke:currentColor;stroke-width:1.1;stroke-dasharray:0 1;
  transition:stroke-dasharray .26s var(--ease-morph)}
[aria-expanded="true"] .mt__bar,.is-x .mt__bar{transition-duration:.46s}
[aria-expanded="true"] .mt__bar--1,.is-x .mt__bar--1{transform:translateY(0) rotate(45deg);stroke-dasharray:15 22;stroke-dashoffset:-3.5}
[aria-expanded="true"] .mt__bar--2,.is-x .mt__bar--2{transform:translateY(0) rotate(-45deg);stroke-dasharray:15 22;stroke-dashoffset:-3.5}
[aria-expanded="true"] .mt__ring,.is-x .mt__ring{transform:rotate(0deg);transition:transform .64s var(--ease-morph) .06s}
[aria-expanded="true"] .mt__arc,.is-x .mt__arc{stroke-dasharray:1 0;transition:stroke-dasharray .64s var(--ease-morph) .06s}
.js .menu-toggle--nojs,.no-js .menu-toggle--js{display:none}
@media (prefers-reduced-motion:reduce){
  .mt__bar,.mt__ring,.mt__arc{transition-duration:.01ms!important;transition-delay:0s!important}
}

/* ---------- Menu overlay ----------
   The whole navigation lives here, so it is a designed surface: the site's
   largest type, case studies, and contact details without a page load.
   Open: panel lands softly, words rise out of their lines in sequence.
   Close: faster and different, everything fades together, panel leaves upward. */
.menu{position:fixed;inset:0;z-index:60;visibility:hidden;transition:visibility 0s linear .44s}
.menu[data-open="true"]{visibility:visible;transition-delay:0s}
.is-locked .menu{right:var(--sbw,0px)}
.menu__panel{position:absolute;inset:0;background-color:var(--ink);transform:translateY(-101%);
  transition:transform .36s var(--ease-exit) .06s}
.menu[data-open="true"] .menu__panel{transform:none;transition:transform .72s var(--ease-enter)}
.menu__inner{position:relative;height:100%;overflow-y:auto;overscroll-behavior:contain;
  display:grid;grid-template-columns:minmax(0,1fr);align-content:start;row-gap:clamp(1.75rem,5vh,3rem);
  padding:calc(var(--bar-h) + .25rem) var(--gutter) clamp(1.75rem,5vh,3.5rem)}

.menu__nav{transition:opacity .16s cubic-bezier(.4,0,1,1)}
.menu:not([data-open="true"]) .menu__nav{opacity:0}
.menu__list{--menu-fs:clamp(2.6rem,min(20vw,9.3svh),4.5rem);
  font-family:var(--display);font-weight:300;font-size:var(--menu-fs);line-height:1;letter-spacing:-.03em}
.menu__item{display:block}
.menu__link{display:inline-block;vertical-align:top;color:var(--text);padding-bottom:.08em;
  background:var(--gradient) no-repeat 0 100%/0 max(2px,.024em);
  transition:background-size .55s var(--ease-out),color .3s var(--ease-out)}
.menu__link:hover,.menu__link:focus-visible,.menu__link[aria-current]{background-size:100% max(2px,.024em)}
.menu__link:focus-visible{outline-offset:.12em}
.menu__list:has(.menu__link:hover) .menu__link:not(:hover){color:var(--text-dim)}
.menu__mask{display:block;overflow:hidden;padding-bottom:.2em;margin-bottom:-.2em}
.menu__word{display:block;transform:translateY(125%);transition:transform 0s linear .44s}
.menu[data-open="true"] .menu__word{transform:none;
  transition:transform .86s var(--ease-enter) calc(.1s + var(--i,0) * .055s)}

.menu__contact{display:flex;flex-wrap:wrap;gap:1.25rem 3rem;font-size:var(--fs-sm);line-height:1.5;
  opacity:0;transform:translateY(.6rem);
  transition:opacity .16s cubic-bezier(.4,0,1,1),transform 0s linear .44s}
.menu[data-open="true"] .menu__contact{opacity:1;transform:none;
  transition:opacity .5s var(--ease-out) .5s,transform .7s var(--ease-enter) .5s}
.menu__group{display:grid;gap:.3rem;align-content:start;justify-items:start}
.menu__label{font-family:var(--display);font-weight:500;color:var(--text-faint);margin-bottom:.15rem}
.menu__contact a{color:var(--text);background:var(--gradient) no-repeat 0 100%/0 1px;padding-bottom:1px;
  transition:background-size .4s var(--ease-out)}
.menu__contact a:hover,.menu__contact a:focus-visible{background-size:100% 1px}
.menu__close{display:none}

@media (min-width:768px){
  .menu__list{--menu-fs:clamp(4rem,min(9.6vw,12.8svh),11.5rem)}
  .menu__inner{align-content:safe end}
}
@media (min-width:1024px){
  .menu__inner{grid-template-columns:minmax(0,1fr) auto;column-gap:4vw;align-items:end}
  .menu__contact{flex-direction:column;padding-bottom:.5rem}
}
@media (prefers-reduced-motion:reduce){
  .menu__panel,.menu[data-open="true"] .menu__panel{transform:none;transition:opacity .2s linear}
  .menu:not([data-open="true"]) .menu__panel{opacity:0}
  .menu__word,.menu__contact,
  .menu[data-open="true"] .menu__word,.menu[data-open="true"] .menu__contact{transform:none;transition:opacity .2s linear}
}
/* Without JS: the toggle is a link to #site-menu, and a close link sits where the toggle was. */
.no-js .menu:target{visibility:visible;z-index:80}
.no-js .menu:target .menu__panel,.no-js .menu:target .menu__word,
.no-js .menu:target .menu__contact{transform:none;opacity:1}
.no-js .menu:target .menu__nav{opacity:1}
.no-js .menu__close{display:inline-grid;position:absolute;top:calc(var(--bar-h) / 2 - 24px);right:var(--gutter)}

/* Grain: one static noise tile, blended so it dithers gradients without shifting the ground colour. */
.grain{position:absolute;inset:0;pointer-events:none;opacity:.5;mix-blend-mode:overlay;background-size:220px 220px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='table' tableValues='1 1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

/* ---------- Hero ----------
   Centred, calm. The header's height is reserved at the top. The text block sits
   at 1.1 : 0.9 in what is left: the lit arc rises above the headline, and the arc plus
   the text together read centred (slightly high) at that split.
   Line breaks are set by hand per breakpoint; trailing punctuation hangs so the letters
   sit on the axis. The text paints on first frame (no entrance animation): it is the LCP.
   The arc never reaches the header. Its radius is --arc-k times the headline size, capped at 26svh
   on short screens, and the space above the text is never less than --arc-room: the arc's visible
   glow above its origin (1.3 radii) less the half line down to the origin, plus a 1.5rem gap under
   the header. Only when a screen is too short for that does the hero grow past it.
   A flex column, not grid rows: with only a min-height, grid scales every fr row from the largest
   minimum, which stretched the space below the text too and made the hero taller than needed. */
.hero{--arc-k:2.1;
  --arc-r:min(calc(var(--fs-hero) * var(--arc-k)),26svh);   /* the arc's centreline radius */
  --arc-room:calc(var(--arc-r) * 1.3 - var(--fs-hero) * .52 + 1.5rem);
  position:relative;isolation:isolate;overflow:clip;min-height:100vh;min-height:100svh;
  display:flex;flex-direction:column;align-items:center;
  padding:var(--bar-h) var(--gutter) 0;text-align:center;background-color:var(--ink)}
.hero::before{content:"";flex:1.1 1 0;min-height:max(1.25rem,var(--arc-room))}
.hero::after{content:"";flex:.9 1 0;min-height:2.5rem}
.hero__grain{z-index:-1}
.hero__head{position:relative}

/* ---------- Hero light field ----------
   One origin: the centre of the headline. Every layer is placed from it, so the
   composition reads as one light seen from one point. Back to front:
     ink ground (the hero's background) · edge glows · hairline rings · the logo's arc, lit
   then the grain (.hero__grain) and the text. Colours: only the three stops of --gradient
   and brand white. Animated from this still frame (see "Light field motion" below). Everything
   is inline (gradients, inline SVG, masks as data URIs), so it renders the same from a file://
   page, from a server, and with no JavaScript. */
.field{--arc-bright:18deg;                   /* where the light is brightest: 0deg = top, clockwise */
  position:absolute;left:50%;top:50%;width:0;height:0;z-index:-2;pointer-events:none}
/* two-line headline on phones: the origin sits on the first line's centre (still half a line down),
   and the arc is a little larger for the narrower text */
@media (max-width:599px){.hero{--arc-k:2.4}.field{top:25%}}

/* glows and rings share a wrapper centred on the origin. The light falls away before the
   section boundary through a static ink gradient laid over the same band (.field__fade):
   over an ink ground that is the same result as masking the light, without re-masking
   moving layers every frame. The page below continues on the same ink, no hard edge. */
.field__lights{position:absolute;left:-120vw;top:-130svh;width:240vw;height:260svh}
.field__fade{position:absolute;left:-120vw;top:-130svh;width:240vw;height:260svh;
  background:linear-gradient(to bottom,rgb(10 20 28 / 0) calc(50% + 34svh),var(--ink) calc(50% + 48svh))}

/* Edge glows: the gradient pulled apart into its stops, each a light source outside the frame,
   seen only as falloff. Soft stops approximate (1 - t)^2.2; no blur filters. They add as light
   (screen). Khaki sits inside the firebrick light's falloff: dim khaki alone over navy reads
   olive, khaki meeting firebrick reads as warm light, which is the gradient's own right half. */
.field__glow{--gain:1;--peak:calc(var(--a) * var(--gain));
  position:absolute;left:50%;top:50%;width:calc(var(--r) * 2);height:calc(var(--r) * 2);
  margin:calc(var(--r) * -1) 0 0 calc(var(--r) * -1);transform:translate(var(--x),var(--y));mix-blend-mode:screen;
  background:radial-gradient(closest-side,
    rgb(var(--c) / var(--peak)) 0%,rgb(var(--c) / calc(var(--peak) * .78)) 10%,rgb(var(--c) / calc(var(--peak) * .57)) 20%,
    rgb(var(--c) / calc(var(--peak) * .40)) 30%,rgb(var(--c) / calc(var(--peak) * .26)) 40%,rgb(var(--c) / calc(var(--peak) * .16)) 50%,
    rgb(var(--c) / calc(var(--peak) * .09)) 60%,rgb(var(--c) / calc(var(--peak) * .045)) 70%,rgb(var(--c) / calc(var(--peak) * .018)) 80%,
    rgb(var(--c) / calc(var(--peak) * .005)) 90%,rgb(var(--c) / 0) 100%)}
.field__glow--sky{--c:var(--grad-a-rgb);--a:.5;--r:52vmax;--x:-58vw;--y:-34svh}
.field__glow--fire{--c:var(--grad-c-rgb);--a:.55;--r:50vmax;--x:56vw;--y:2svh}
.field__glow--khaki{--c:var(--grad-b-rgb);--a:.25;--r:34vmax;--x:50vw;--y:26svh}
@media (max-width:599px){
  .field__glow--sky{--a:.45;--r:60vmax;--x:-62vw;--y:-40svh}
  .field__glow--fire{--a:.55;--r:50vmax;--x:62vw;--y:40svh}
  .field__glow--khaki{--a:.3;--r:36vmax;--x:58vw;--y:52svh}
  .field__fade{background:linear-gradient(to bottom,rgb(10 20 28 / 0) calc(50% + 42svh),var(--ink) calc(50% + 54svh))}
}

/* Rings: hairlines on the same origin, radii in units of the arc (they scale with it).
   Quiet inside the text, gathering toward the edges where the glows are. The quiet zone is
   baked into each circle's stroke-opacity (a radial fade on concentric circles depends only on
   radius: 0 at 1.8, .15 at 2.3, .6 at 3.2, 1 at 4.2 arc radii), so no mask has to be
   recomposited while the rings breathe. */
.field__rings{position:absolute;left:50%;top:50%;width:calc(var(--arc-r) * 22);height:calc(var(--arc-r) * 22);
  transform:translate(-50%,-50%)}

/* The arc: the logo's ring (measured, brand/arc-geometry.json) as three stacked layers, a core
   over two softer blooms. Each layer is the shape as a mask with the light inside it; the light
   is a conic gradient brightest at --arc-bright and falling away both ways, so the arc reads as
   lit, not filled. The mask shapes are inline data URIs (generated from the measured geometry):
   separate mask files would not load for a page opened directly from disk. */
.field__arc{
  --mask-arc-core:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%22-1.8 -1.8 3.6 3.6%22%3E%3Cdefs%3E%3CradialGradient id=%22g%22 gradientUnits=%22userSpaceOnUse%22 cx=%220%22 cy=%220%22 r=%221.03626%22%3E%3Cstop offset=%220.93001%22 stop-color=%22%23fff%22 stop-opacity=%220.5%22/%3E%3Cstop offset=%221%22 stop-color=%22%23fff%22 stop-opacity=%221%22/%3E%3C/radialGradient%3E%3C/defs%3E%3Cg fill=%22url(%23g)%22%3E%3Cpath d=%22M-0.95206 0.40918A1.03626 1.03626 0 0 1 0.74805 -0.71713L0.70041 -0.66197A0.96373 0.96373 0 0 0 -0.8909 0.36753Z%22/%3E%3Cpath d=%22M0.84562 -0.59898A1.03626 1.03626 0 1 1 -0.89371 0.52453L-0.83264 0.48527A0.96373 0.96373 0 1 0 0.79704 -0.54177Z%22/%3E%3C/g%3E%3C/svg%3E");
  --mask-bloom-1:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%22-1.8 -1.8 3.6 3.6%22%3E%3Cdefs%3E%3CradialGradient id=%22g%22 gradientUnits=%22userSpaceOnUse%22 cx=%220%22 cy=%220%22 r=%221.29012%22%3E%3Cstop offset=%220.60646%22 stop-color=%22%23fff%22 stop-opacity=%220%22/%3E%3Cstop offset=%220.70484%22 stop-color=%22%23fff%22 stop-opacity=%220.35%22/%3E%3Cstop offset=%220.80323%22 stop-color=%22%23fff%22 stop-opacity=%221%22/%3E%3Cstop offset=%220.90161%22 stop-color=%22%23fff%22 stop-opacity=%220.35%22/%3E%3Cstop offset=%221%22 stop-color=%22%23fff%22 stop-opacity=%220%22/%3E%3C/radialGradient%3E%3C/defs%3E%3Cpath fill=%22url(%23g)%22 fill-rule=%22evenodd%22 d=%22M1.29012 0A1.29012 1.29012 0 1 1 -1.29012 0A1.29012 1.29012 0 1 1 1.29012 0ZM0.78241 0A0.78241 0.78241 0 1 0 -0.78241 0A0.78241 0.78241 0 1 0 0.78241 0Z%22/%3E%3C/svg%3E");
  --mask-bloom-2:url("data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%22-1.8 -1.8 3.6 3.6%22%3E%3Cdefs%3E%3CradialGradient id=%22g%22 gradientUnits=%22userSpaceOnUse%22 cx=%220%22 cy=%220%22 r=%221.76157%22%3E%3Cstop offset=%220.30004%22 stop-color=%22%23fff%22 stop-opacity=%220%22/%3E%3Cstop offset=%220.44415%22 stop-color=%22%23fff%22 stop-opacity=%220.22%22/%3E%3Cstop offset=%220.58826%22 stop-color=%22%23fff%22 stop-opacity=%221%22/%3E%3Cstop offset=%220.72551%22 stop-color=%22%23fff%22 stop-opacity=%220.3%22/%3E%3Cstop offset=%220.86275%22 stop-color=%22%23fff%22 stop-opacity=%220.08%22/%3E%3Cstop offset=%221%22 stop-color=%22%23fff%22 stop-opacity=%220%22/%3E%3C/radialGradient%3E%3C/defs%3E%3Cpath fill=%22url(%23g)%22 fill-rule=%22evenodd%22 d=%22M1.76157 0A1.76157 1.76157 0 1 1 -1.76157 0A1.76157 1.76157 0 1 1 1.76157 0ZM0.52855 0A0.52855 0.52855 0 1 0 -0.52855 0A0.52855 0.52855 0 1 0 0.52855 0Z%22/%3E%3C/svg%3E");
  /* where the arc is lit: 75deg either side of the bright point, dark by the headline's midline */
  --mask-window:conic-gradient(from calc(var(--arc-bright) - 180deg),transparent 105deg,rgb(0 0 0 / .45) 128deg,
    rgb(0 0 0 / .9) 155deg,#000 180deg,rgb(0 0 0 / .9) 205deg,rgb(0 0 0 / .45) 232deg,transparent 255deg);
  position:absolute;left:50%;top:50%;width:calc(var(--arc-r) * 3.6);height:calc(var(--arc-r) * 3.6);
  transform:translate(-50%,-50%)}
/* every layer is its shape (ring or bloom) intersected with the lit window; both masks stay still while the
   site's neon loop turns inside (see "Neon"), so the colours flow along the arc through the lit part */
.field__layer{position:absolute;inset:0;
  -webkit-mask-size:100% 100%;mask-size:100% 100%;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-composite:source-in;mask-composite:intersect}
/* the core's turning light is a disc just larger than the ring (outer radius 1.036 arc radii), so only
   that much is recomposited per frame. A disc rather than a clip-path square: a straight clip edge was the
   likely source of a hairline of light seen across the glow on a real GPU (not reproducible headless). */
.field__layer--core{-webkit-mask-image:var(--mask-arc-core),var(--mask-window);mask-image:var(--mask-arc-core),var(--mask-window)}
.field__layer--core>.field__light{inset:calc(50% - var(--arc-r) * 1.1)}
.field__layer--bloom-1{opacity:.55;-webkit-mask-image:var(--mask-bloom-1),var(--mask-window);mask-image:var(--mask-bloom-1),var(--mask-window)}
.field__layer--bloom-2{opacity:.22;-webkit-mask-image:var(--mask-bloom-2),var(--mask-window);mask-image:var(--mask-bloom-2),var(--mask-window)}
/* the neon's glow: a blurred copy of the lit core, on a surface just big enough for ring and blur */
.field__neon{position:absolute;inset:calc(50% - var(--arc-r) * 1.25)}
.field__neon>.field__layer--core{-webkit-mask-size:144% 144%;mask-size:144% 144%;
  -webkit-mask-position:50% 50%;mask-position:50% 50%}
.field__light{--neon-loops:4;position:absolute;inset:0;border-radius:50%}
.field__ring-set{position:absolute;inset:0;width:100%;height:100%;max-width:none;overflow:visible}

/* ---------- Light field motion ----------
   Ambient and continuous: nothing starts, stops or restarts. Transform and opacity only
   (no animated gradients, masks, filters or paths), so the compositor does all the work.
   Durations are unrelated (13, 16, 19, 22, 23, 26, 41, 47, 53 s), so the
   composition never returns to the same arrangement, and it never flickers.
   · The light flows along the arc as the site's neon: the colour loop turns inside the lit window
     (see the layers above and "Neon"), four loops round the ring, one passing every --neon-cycle.
     The window itself stays put at the top of the arc, so the light no longer swings down beside
     the headline.
   · Rings breathe in brightness, three sets at different rates. (Scaling them was measured
     at 15% late frames at 1920x1080: rings this large re-rasterise as they scale. Opacity does not.)
   · Glows drift on slow loops and swing ±15% in brightness around the approved level, out of
     step, so they are never all at full together. --gain lifts each gradient by 1/.87, so
     the middle of the swing is exactly the approved light.
   The first frame is the approved composition. Reduced motion keeps it exactly, and still. */
/* set 1 starts at full; sets 2 and 3 start just below full, rising, so the rings do not all fade together */
@keyframes field-breathe-1{to{opacity:.5}}
@keyframes field-breathe-2{to{opacity:.58}}
@keyframes field-breathe-3{to{opacity:.66}}
.field__ring-set--1{animation:field-breathe-1 13s cubic-bezier(.45,0,.55,1) infinite alternate}
.field__ring-set--2{animation:field-breathe-2 19s cubic-bezier(.45,0,.55,1) -35.5s infinite alternate}
.field__ring-set--3{animation:field-breathe-3 23s cubic-bezier(.45,0,.55,1) -43s infinite alternate}

@keyframes field-orbit-sky{0%,100%{translate:0 0}12.5%{translate:2.1vw -.6svh}25%{translate:3vw -2svh}37.5%{translate:2.1vw -3.4svh}
  50%{translate:0 -4svh}62.5%{translate:-2.1vw -3.4svh}75%{translate:-3vw -2svh}87.5%{translate:-2.1vw -.6svh}}
@keyframes field-orbit-fire{0%,100%{translate:0 0}12.5%{translate:-1.8vw .9svh}25%{translate:-2.5vw 3svh}37.5%{translate:-1.8vw 5.1svh}
  50%{translate:0 6svh}62.5%{translate:1.8vw 5.1svh}75%{translate:2.5vw 3svh}87.5%{translate:1.8vw .9svh}}
@keyframes field-orbit-khaki{0%,100%{translate:0 0}12.5%{translate:1.4vw -.4svh}25%{translate:2vw -1.5svh}37.5%{translate:1.4vw -2.6svh}
  50%{translate:0 -3svh}62.5%{translate:-1.4vw -2.6svh}75%{translate:-2vw -1.5svh}87.5%{translate:-1.4vw -.4svh}}
/* every glow starts mid-swing (opacity .87 x gain = the approved light): sky and khaki rising, fire falling */
@keyframes field-level{from{opacity:.74}to{opacity:1}}
.field__glow--sky{animation:field-orbit-sky 41s linear infinite,field-level 16s cubic-bezier(.45,0,.55,1) -8s infinite alternate}
.field__glow--fire{animation:field-orbit-fire 53s linear infinite,field-level 22s cubic-bezier(.45,0,.55,1) -33s infinite alternate}
.field__glow--khaki{animation:field-orbit-khaki 47s linear infinite,field-level 26s cubic-bezier(.45,0,.55,1) -13s infinite alternate}
@media (prefers-reduced-motion:no-preference){.field__glow{--gain:1.1494}}

/* paused while the tab is hidden, the hero is off-screen or the menu covers it (site.js) */
.field.is-paused *{animation-play-state:paused!important}
@media (prefers-reduced-motion:reduce){.field *{animation:none!important}}
.hero__inner{min-width:0;max-width:100%}
/* nowrap: only the hand-set breaks (<br> and .ln) may end a line; the container never decides */
/* the ink halo is invisible on the ground; where the arc's light passes behind the letters it dims the
   light right around them, which keeps the headline at 3:1 or more through the whole motion */
.hero__title{font-size:var(--fs-hero);font-weight:400;line-height:1.04;letter-spacing:-.022em;white-space:nowrap;
  text-shadow:0 0 .3em rgb(10 20 28 / .6)}
.hero__title .ln{display:inline}
/* two lines from 600px (the longer is 30.5em); on phones the lines wrap on their own, balanced.
   --text-soft, not --text-dim: with the bigger headline the arc is bigger too, and --text-dim measured 3.7:1
   under the moving light at its worst moment (1536px) */
.hero__lede{margin:clamp(1.1rem,.8rem + 1vw,1.6rem) auto 0;font-size:clamp(1rem,.85rem + .45vw,1.25rem);line-height:1.5;
  color:var(--text-soft);text-wrap:balance}
.hero__lede br{display:none}
.hang{margin-inline-end:-.27em}
.hero__cta{height:52px;margin-top:clamp(1.5rem,1.1rem + 1.2vw,2.25rem);padding-inline:1.75rem;font-size:1rem}
@media (max-width:599px){
  :root{--fs-hero:clamp(2.75rem,13.8vw,4rem)}      /* two lines ("Let's Succeed" is 5.43em); the arc scales with it */
  .hero__title .ln{display:block}
}
@media (min-width:600px){
  .hero__lede{white-space:nowrap}
  .hero__lede br.b-lg{display:inline}
}

/* ---------- Scroll text fill ----------
   [data-reveal] text starts dim and fills in word by word as it scrolls through the viewport:
   from its top at 85% of the viewport height to its bottom at 50%. site.js wraps each word
   (.rv-w, with its index --wi; the count is --wn). One number, --reveal (0 to 1), drives every
   word: word i is lit once the sweep has passed it, over a soft edge --rv-span words wide.
   Where CSS scroll-driven animations exist the browser drives --reveal in step with the scroll;
   elsewhere site.js sets it on scroll. No JavaScript, or reduced motion: full strength. */
@property --reveal{syntax:"<number>";inherits:true;initial-value:0}
[data-reveal]{--rv-dim:.22;--rv-span:8}
.rv-w{opacity:clamp(var(--rv-dim),
  calc(var(--rv-dim) + (1 - var(--rv-dim)) * (var(--reveal) * (var(--wn) + var(--rv-span)) - var(--wi)) / var(--rv-span)),1)}
@keyframes reveal-fill{from{--reveal:0}to{--reveal:1}}
@supports (animation-timeline:view()){
  [data-reveal]{animation:reveal-fill linear both;animation-timeline:view();
    animation-range:cover 15vh cover calc(100% - 50vh)}
}
@media (prefers-reduced-motion:reduce){
  [data-reveal]{animation:none}
  .rv-w{opacity:1}
}

/* ---------- Offer: what we provide ----------
   Full viewport height, like the hero. The statement sits top left and fills in as the section
   scrolls by; the services run along a lit arc tucked into the bottom-right corner.
   The arc is a quarter ellipse centred on the section's corner: --arc-rx across, --arc-ry up.
   Its light is a ring of radius --arc-ry stretched across by --arc-sx (rx / ry, set by
   site.js), so it still turns as one texture. The white core, the hover spot and the label rows
   are drawn in an SVG in CSS px on the same ellipse (site.js). */
@property --offer-label{syntax:"<length>";inherits:true;initial-value:15px}
@property --arc-rx{syntax:"<length>";inherits:true;initial-value:0px}
@property --arc-ry{syntax:"<length>";inherits:true;initial-value:0px}
.offer{--arc-ry:min(36svh,78vw);--arc-rx:min(92vw,calc(var(--arc-ry) * 1.5));--offer-label:13px;
  --fs-offer:clamp(1.55rem,1.05rem + 1.9vw,2.6rem);
  position:relative;overflow:clip;min-height:100vh;min-height:100svh;border-top:1px solid var(--hair)}
@media (min-width:600px){.offer{--arc-ry:min(34svh,34rem);--arc-rx:min(60vw,44rem,calc(var(--arc-ry) * 1.5));--offer-label:14px}}
/* side by side on landscape screens from 1024 px: the arc takes the corner below half the height */
@media (min-width:1024px) and (orientation:landscape){.offer{--arc-ry:50svh;--arc-rx:min(39vw,calc(var(--arc-ry) * 1.5));--offer-label:15px}}

.offer__grid{display:grid;grid-template-columns:minmax(0,1fr);align-items:start}
.offer__text{font-family:var(--display);font-weight:400;font-size:var(--fs-offer);line-height:1.2;
  letter-spacing:-.018em;color:var(--text);max-width:26ch}
/* hovering a service lights its words: the same gradient underline the links use */
.offer__phrase{background:var(--gradient) no-repeat 0 100%/0 max(2px,.05em);padding-bottom:.06em;
  transition:background-size .6s var(--ease-out)}
.offer__phrase.is-lit{background-size:100% max(2px,.05em)}
/* stacked (narrow screens): keeps the arc and its labels below the statement */
.offer__stage{height:max(0px,calc(var(--arc-ry) + 3.25rem - var(--section-y)))}
@media (min-width:1024px) and (orientation:landscape){
  .offer__grid{grid-template-columns:minmax(0,7fr) minmax(0,5fr);column-gap:clamp(2rem,4vw,5rem)}
  .offer__stage{display:none}   /* side by side: the arc stays right of the statement's measure */
}

.offer__arc{position:absolute;inset:0;pointer-events:none}
/* The light is the site's neon (see "Neon") on a ring texture: four loops round the ring, so the
   visible quarter always holds one whole loop, one passing every --neon-cycle. The mask is the neon's
   profile across the ring: a 3 px tube, and either side the glow the other neon gets from a live blur,
   computed here (a 3 px line blurred by --neon-glow at --neon-glow-strength; the factors are that
   Gaussian at half-σ steps), since blurring a surface this large every frame would be heavy. The mask is
   round, so the element turns as a whole and the browser draws it once. The wrapper sits on the corner
   and stretches the ring into the ellipse. */
.offer__led-wrap{position:absolute;right:0;bottom:0;width:0;height:0;transform:scaleX(var(--arc-sx,1));transform-origin:0 0}
.offer__led{--neon-loops:4;--ring:87.719%;--g:var(--neon-glow);--s:var(--neon-glow-strength);
  --neon-profile:radial-gradient(closest-side,transparent calc(var(--ring) - var(--g) * 3),
    rgb(0 0 0 / calc(var(--s) * .009)) calc(var(--ring) - var(--g) * 2.5),rgb(0 0 0 / calc(var(--s) * .029)) calc(var(--ring) - var(--g) * 2),
    rgb(0 0 0 / calc(var(--s) * .065)) calc(var(--ring) - var(--g) * 1.5),rgb(0 0 0 / calc(var(--s) * .121)) calc(var(--ring) - var(--g)),
    rgb(0 0 0 / calc(var(--s) * .175)) calc(var(--ring) - var(--g) * .5),rgb(0 0 0 / calc(var(--s) * .19)) calc(var(--ring) - 2px),
    #000 calc(var(--ring) - 1.5px),#000 calc(var(--ring) + 1.5px),
    rgb(0 0 0 / calc(var(--s) * .19)) calc(var(--ring) + 2px),rgb(0 0 0 / calc(var(--s) * .175)) calc(var(--ring) + var(--g) * .5),
    rgb(0 0 0 / calc(var(--s) * .121)) calc(var(--ring) + var(--g)),rgb(0 0 0 / calc(var(--s) * .065)) calc(var(--ring) + var(--g) * 1.5),
    rgb(0 0 0 / calc(var(--s) * .029)) calc(var(--ring) + var(--g) * 2),rgb(0 0 0 / calc(var(--s) * .009)) calc(var(--ring) + var(--g) * 2.5),
    transparent calc(var(--ring) + var(--g) * 3));
  position:absolute;left:calc(var(--arc-ry) * -1.14);top:calc(var(--arc-ry) * -1.14);
  width:calc(var(--arc-ry) * 2.28);height:calc(var(--arc-ry) * 2.28);border-radius:50%;
  -webkit-mask-image:var(--neon-profile);mask-image:var(--neon-profile)}
.offer.is-paused .offer__led{animation-play-state:paused}

/* one SVG unit = one CSS px: site.js sets the viewBox to the box, origin on the corner */
.offer__svg{position:absolute;right:0;bottom:0;width:calc(var(--arc-rx) + 4.5rem);height:calc(var(--arc-ry) + 4.5rem);
  max-width:none;overflow:visible}
.offer__core{fill:none;stroke:#fff;stroke-opacity:.42;stroke-width:1.1}
.offer__spot{fill:none;stroke:#fff;stroke-linecap:round;opacity:0;
  transition:stroke-dasharray .7s var(--ease-out),stroke-dashoffset .7s var(--ease-out),opacity .35s var(--ease-out)}
.offer__spot--halo{stroke-width:14;stroke-opacity:.16}
.offer__spot--beam{stroke-width:3.2;stroke-opacity:.95}
.offer.has-active .offer__spot{opacity:1}
.offer__svg.is-instant .offer__spot{transition:opacity .35s var(--ease-out)}

.offer__labels,.offer__probe{font-family:var(--display);font-weight:500;letter-spacing:.02em;font-size:15px}
.offer__labels{fill:var(--text-soft)}
.offer__label{pointer-events:auto;cursor:pointer}
.offer__label text{transition:fill .3s var(--ease-out)}
.offer__label:hover text,.offer__label:focus-visible text,.offer__label.is-lit text{fill:var(--text)}
.offer.has-active .offer__label:not(.is-lit):not(:focus-visible) text{fill:var(--text-dim)}
.offer__label:focus-visible{outline:none}
.offer__label:focus-visible text{text-decoration:underline;text-decoration-thickness:.08em}
.offer__dots{fill:var(--text-faint)}
.offer__probe{visibility:hidden}
/* without JavaScript nothing can fit the labels to the ellipse: the arc shows as a quarter circle,
   and the services are read in the statement itself */
.no-js .offer__svg{display:none}

/* the arc meets the section's bottom edge: it fades into the ink instead of being cut */
.offer__fade{position:absolute;left:0;right:0;bottom:0;height:calc(var(--arc-ry) * .16);pointer-events:none;
  background:linear-gradient(to bottom,rgb(10 20 28 / 0),var(--ink))}

@media (prefers-reduced-motion:reduce){
  .offer__led{animation:none}
  .offer__spot{transition:opacity .2s linear}
}

/* ---------- Section head ---------- */
.section__title{font-size:var(--fs-h2)}
.work__head{display:flex;justify-content:space-between;align-items:end;gap:1rem;margin-bottom:clamp(1.6rem,3vw,2.6rem)}

/* ---------- Projects ----------
   Four cards. With a mouse and room for a row (1024 px and up), a card widens on hover or keyboard
   focus and a panel slides out on its left, with what we did and the results; the others narrow to
   make room. On touch screens and narrower windows nothing is hidden: each card shows its photo
   with the panel beneath, in one or two columns.
   Nothing inside a card reflows while it moves. The panel's content has a fixed width, so the
   panel's edge uncovers it; the photo has a fixed size, so the frame opens around it and it is
   never rescaled. The cards' widths do change each frame: a layout animation (DESIGN.md, motion). */
.projects{--gap:clamp(.75rem,1.2vw,1rem);--pad:clamp(1.25rem,2vw,1.75rem);
  --project-h:clamp(28rem,62svh,38rem);--panel-w:clamp(17rem,24vw,23rem);
  --grow:3.7;--glide:.75s;--ease-glide:cubic-bezier(.25,.75,.2,1);--card-r:20px;
  border-top:1px solid var(--hair)}
.projects__row{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--gap)}
@media (min-width:600px){.projects__row{grid-template-columns:repeat(2,minmax(0,1fr))}}
.project{min-width:0}
/* Corners stay round at every moment. The card clips its own content (the panel) to --card-r, and the photo
   is a rounded tile of its own, clipped with clip-path: a moving photo on its own compositor layer is not
   reliably rounded by a parent's overflow and border-radius in every browser, but its own clip-path is. */
.project__card{position:relative;isolation:isolate;display:flex;flex-direction:column-reverse;height:100%;
  overflow:hidden;overflow:clip;border-radius:var(--card-r);background:var(--ink-3)}
.project__panel{flex:1 0 auto}
.project__body{display:flex;flex-direction:column;justify-content:space-between;gap:1.5rem;height:100%;padding:var(--pad)}
.project__sector{font-size:var(--fs-sm);line-height:1.45;color:var(--text-dim)}
.project__title{font-weight:300;font-size:clamp(1.75rem,1.3rem + 1vw,2.25rem);line-height:1.05;letter-spacing:-.02em}
/* the title's link covers the whole card; the focus ring goes round the card */
.project__link::after{content:"";position:absolute;inset:0;z-index:2}
@supports selector(:has(*)){
  .project__link:focus-visible{outline:none}
  .project__card:has(.project__link:focus-visible){outline:2px solid var(--grad-a);outline-offset:3px}
}
.project__text{margin-top:.75rem;font-size:var(--fs-sm);line-height:1.55;color:var(--text-dim)}
.project__stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem 1.25rem;margin-top:1.5rem;
  font-size:var(--fs-xs);line-height:1.4;color:var(--text-dim)}
.project__n{display:block;margin-bottom:.3rem;font-family:var(--display);font-weight:300;
  font-size:clamp(1.5rem,1.1rem + .8vw,1.9rem);line-height:1;letter-spacing:-.03em;font-variant-numeric:tabular-nums;color:var(--text)}
.project__note{margin-top:1rem;font-size:var(--fs-xs);line-height:1.45;color:var(--text-dim)}
.project__more{display:inline-block;margin-top:1.5rem;padding-bottom:2px;font-family:var(--display);font-weight:500;
  background:var(--gradient) no-repeat 0 100%/100% 2px}
.project__media{position:relative;aspect-ratio:4/3;overflow:hidden;overflow:clip;border-radius:var(--card-r);
  clip-path:inset(0 round var(--card-r));background:var(--ink-2)}
/* --pos (set per photo) keeps the subject in frame whatever shape the card is */
.project__media img{position:absolute;inset:0;width:100%;height:100%;max-width:none;object-fit:cover;object-position:var(--pos,50% 50%)}
/* a quiet scrim keeps the logo legible on any photograph */
.project__media::after{content:"";position:absolute;inset:0;background:linear-gradient(to top,rgb(10 20 28 / .55),rgb(10 20 28 / 0) 45%)}
.project__logo{position:absolute;left:var(--pad);bottom:var(--pad);z-index:1;white-space:nowrap;
  font-family:var(--display);font-weight:500;font-size:1.25rem;letter-spacing:-.01em;color:#fff}

/* How open each card is, 0 to 1. Animated on the row, so every card can read all four. */
@property --o1{syntax:"<number>";inherits:true;initial-value:0}
@property --o2{syntax:"<number>";inherits:true;initial-value:0}
@property --o3{syntax:"<number>";inherits:true;initial-value:0}
@property --o4{syntax:"<number>";inherits:true;initial-value:0}
@supports selector(:has(*)){
@media (min-width:1024px) and (hover:hover) and (pointer:fine){
  .projects__row{position:relative;display:block;height:var(--project-h);margin-inline:calc(var(--gap) / -2);container-type:inline-size;
    --sum:calc(4 + (var(--grow) - 1) * (var(--o1) + var(--o2) + var(--o3) + var(--o4)));
    --img-w:calc((100cqi - 4 * var(--gap)) / 4 * 1.4);
    transition:--o1 var(--glide) var(--ease-glide),--o2 var(--glide) var(--ease-glide),
               --o3 var(--glide) var(--ease-glide),--o4 var(--glide) var(--ease-glide)}
  /* open: the hovered card, or the focused one while the pointer is elsewhere */
  .projects__row:has(> .project:nth-child(1):hover),.projects__row:not(:hover):has(> .project:nth-child(1):focus-within){--o1:1}
  .projects__row:has(> .project:nth-child(2):hover),.projects__row:not(:hover):has(> .project:nth-child(2):focus-within){--o2:1}
  .projects__row:has(> .project:nth-child(3):hover),.projects__row:not(:hover):has(> .project:nth-child(3):focus-within){--o3:1}
  .projects__row:has(> .project:nth-child(4):hover),.projects__row:not(:hover):has(> .project:nth-child(4):focus-within){--o4:1}
  /* Each card's slot is its share of the row by weight: 1 closed, --grow open. The half gaps belong to the
     slots, so the pointer never falls between two cards and the row never flickers shut.
     Slots are placed with translate and sized with width, so no box's layout origin ever moves:
     the motion is smooth and none of it counts as layout shift (animating flex-grow measured 0.1 CLS per hover). */
  .projects__row>.project{position:absolute;top:0;left:0;height:100%;padding-inline:calc(var(--gap) / 2);will-change:transform;
    --w:calc(1 + (var(--grow) - 1) * var(--open));
    --card-w:calc(100cqi * var(--w) / var(--sum) - var(--gap));
    width:calc(100cqi * var(--w) / var(--sum));translate:calc(100cqi * var(--before) / var(--sum)) 0}
  .projects__row>.project:nth-child(1){--open:var(--o1);--before:0}
  .projects__row>.project:nth-child(2){--open:var(--o2);--before:calc(1 + (var(--grow) - 1) * var(--o1))}
  .projects__row>.project:nth-child(3){--open:var(--o3);--before:calc(2 + (var(--grow) - 1) * (var(--o1) + var(--o2)))}
  .projects__row>.project:nth-child(4){--open:var(--o4);--before:calc(3 + (var(--grow) - 1) * (var(--o1) + var(--o2) + var(--o3)))}

  /* The opening card, shared with the Projects page (projects.css places those cards and sets --open, --card-w
     and --img-w for each). The panel sits still at the card's left edge with a fixed width; the photo slides
     right off it, so the text is uncovered without rewrapping. The photo trims off its right side exactly as far
     as it has slid, so its own rounded clip always ends on the card's right edge: the right corners are the
     photo's, the left corners the card's, and the photo's left corners round over the panel, as in the reference. */
  :is(.projects__row,.wk-grid.is-engine) .project__card{display:block}
  :is(.projects__row,.wk-grid.is-engine) .project__panel{width:var(--panel-w);height:100%}
  :is(.projects__row,.wk-grid.is-engine) .project__media{position:absolute;inset:0;aspect-ratio:auto;translate:calc(var(--open) * var(--panel-w)) 0;
    clip-path:inset(0 calc(var(--open) * var(--panel-w)) 0 0 round var(--card-r))}
  /* fixed size, kept centred in the visible part: a resting card's width plus room to open wider mid-motion */
  :is(.projects__row,.wk-grid.is-engine) .project__media img{inset:0 auto 0 0;width:var(--img-w);will-change:transform;
    translate:calc((var(--card-w) - var(--open) * var(--panel-w) - var(--img-w)) / 2) 0}

  /* the text arrives behind the opening edge and goes at once on close; the title is simply uncovered.
     (No fade on the title: an ancestor with opacity would trap the card-wide link under the photo.) */
  :is(.projects__row,.wk-grid.is-engine) :is(.project__sector,.project__text,.project__stats,.project__note){opacity:0;transition:opacity .18s var(--ease-out)}
  :is(.projects__row,.wk-grid.is-engine) .project__more{opacity:0;background-size:0 2px;transition:opacity .18s var(--ease-out),background-size .3s var(--ease-out)}
  :is(.projects__row .project:hover,.projects__row:not(:hover) .project:focus-within,.wk-grid.is-engine .project.is-open)
    :is(.project__sector,.project__text,.project__stats,.project__note){opacity:1;transition:opacity .5s var(--ease-out) .2s}
  :is(.projects__row .project:hover,.projects__row:not(:hover) .project:focus-within,.wk-grid.is-engine .project.is-open) .project__more{
    opacity:1;background-size:100% 2px;transition:opacity .5s var(--ease-out) .2s,background-size .7s var(--ease-out) .4s}

  /* the logos step back while a card is open: the panel names the project */
  :is(.projects__row,.wk-grid.is-engine) .project__logo{transition:opacity .35s var(--ease-out)}
  :is(.projects__row:hover,.projects__row:focus-within) .project__logo,.wk-grid.is-engine .project.is-row-open .project__logo{opacity:0}
}
}
@media (prefers-reduced-motion:reduce){
  .projects__row,.wk-grid .project,.project__panel *,.project__logo{transition-duration:.01ms!important;transition-delay:0s!important}
}

/* ---------- Footer: contact ----------
   The contact hub and the site footer in one, at least one screen tall. The page signs off under the
   light it opened with: the hero's edge glows turned to rise from the bottom edge (sky left, firebrick
   and khaki right), and the logo's ring lit beside the headline (the hero's arc, flowing like every neon).
   The gradient's other appearances are the field underline on focus and the Send button's neon outline.
   .site-footer--slim is the bar alone, for the Contact page, where the page itself is the form.
   Landscape from 1024 px: the headline left, the form and the contact details right. Narrower: stacked. */
.site-footer{position:relative;isolation:isolate;overflow:hidden;overflow:clip;display:flex;flex-direction:column;
  min-height:calc(100vh - var(--bar-h-c));min-height:calc(100svh - var(--bar-h-c));
  border-top:1px solid var(--hair);background-color:var(--ink)}
.site-footer__light{position:absolute;inset:0;z-index:-2;pointer-events:none}
/* the light sources sit below the bottom edge; only their upper falloff is seen */
.site-footer__glow{--gain:1;top:100%}
.site-footer__glow--sky{--c:var(--grad-a-rgb);--a:.4;--r:46vmax;--x:-42vw;--y:10vmax}
.site-footer__glow--fire{--c:var(--grad-c-rgb);--a:.5;--r:44vmax;--x:40vw;--y:12vmax}
.site-footer__glow--khaki{--c:var(--grad-b-rgb);--a:.2;--r:28vmax;--x:26vw;--y:11vmax}
/* phones: the bar's small text sits lower in the light, so the light is a little dimmer (measured 4.4:1 before) */
@media (max-width:599px){
  .site-footer__glow--sky{--a:.32}
  .site-footer__glow--fire{--a:.4}
  .site-footer__glow--khaki{--a:.16}
}
.site-footer__grain{z-index:-1}
.site-footer__inner{flex:1 0 auto;display:flex;flex-direction:column;container-type:inline-size}
.site-footer--slim{min-height:0}

.contact{flex:1 0 auto;display:grid;grid-template-columns:minmax(0,1fr);align-content:center;
  row-gap:clamp(3rem,10vw,4.5rem);padding-block:var(--section-y)}
@media (min-width:1024px) and (orientation:landscape){
  .contact{grid-template-columns:minmax(0,1.08fr) minmax(0,1fr);column-gap:clamp(2.5rem,5vw,6rem);align-items:center}
}

/* The headline is the footer's type event: Jost Light caps, one line indented, sized to its column. */
.contact__title{font-family:var(--display);font-weight:300;font-size:clamp(3.2rem,19vw,8.5rem);font-size:min(20.5cqi,8.5rem);
  line-height:.96;letter-spacing:-.012em;text-transform:uppercase;color:var(--text)}
@media (min-width:1024px) and (orientation:landscape){.contact__title{font-size:min(12.4cqi,11.5rem)}}
.contact__ln{display:block;white-space:nowrap}
.contact__ln--in{padding-left:.62em}
/* the ring's centre, set after "Let's": its lit top level with the caps, its lit ends reaching the baseline */
.contact__mark{--arc-r:.52em;--arc-bright:18deg;position:relative;top:-.16em;display:inline-block;width:0;height:0;
  margin-left:.74em;pointer-events:none}

.contact__side{display:grid;row-gap:clamp(3rem,8vh,4.5rem);align-content:center;min-width:0}
.contact__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:clamp(1.5rem,3.5vh,2.1rem) clamp(1.25rem,2.5vw,2rem)}
.form-field{grid-column:1 / -1;min-width:0}
@media (min-width:480px){.form-field--half{grid-column:auto}}
.form-field__label{display:flex;justify-content:space-between;gap:1rem;font-family:var(--display);font-weight:500;
  font-size:var(--fs-sm);line-height:1.3;color:var(--text-dim)}
.form-field__optional{font-weight:400}
.form-field__control{position:relative}
.form-field__input{display:block;width:100%;margin:0;padding:.5rem 0 .55rem;border:0;border-bottom:1px solid var(--hair-strong);border-radius:0;
  background:transparent;color:var(--text);font-family:var(--body);font-size:1.0625rem;line-height:1.5;
  -webkit-appearance:none;appearance:none;transition:border-color .3s var(--ease-out)}
.form-field__input:focus{outline:none}
.form-field__input--area{resize:none;overflow-y:auto;min-height:calc(1.5em + 1.05rem + 1px);max-height:14rem;field-sizing:content}
/* focus draws the gradient along the line, from the left: the ink, as on every link */
.form-field__control::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:var(--gradient);
  transform:scaleX(0);transform-origin:0 50%;transition:transform .6s var(--ease-out);pointer-events:none}
.form-field__control:focus-within::after{transform:scaleX(1)}
.form-field__input:-webkit-autofill{-webkit-text-fill-color:var(--text);transition:background-color 600000s 0s}
/* errors: firebrick marks the line; the message is firebrick lifted to 6.8:1 on the ink so it can be read */
.form-field.is-invalid .form-field__input{border-bottom-color:var(--grad-c)}
.form-field__error{margin-top:.5rem;font-size:var(--fs-sm);line-height:1.4;color:#E0827E}
.form-field__error:empty{display:none}

.contact__actions{display:flex;flex-wrap:wrap;align-items:center;gap:1rem 2rem;margin-top:clamp(2rem,5vh,2.75rem)}
.contact__status{flex:1 1 14rem;font-size:var(--fs-sm);line-height:1.5;color:var(--text)}
.contact__status a{background:var(--gradient) no-repeat 0 100%/100% 1px;padding-bottom:1px}
.btn-book--send{height:52px;margin-left:auto;padding-inline:1.75rem;border:0;font-size:1rem;cursor:pointer}
.btn-book--send:disabled{opacity:.55;cursor:progress}

.contact__info{display:grid;grid-template-columns:repeat(2,max-content);gap:1.5rem clamp(2.5rem,8vw,4.5rem);
  font-size:var(--fs-sm);line-height:1.6}
.contact__group{display:grid;gap:.3rem;align-content:start;justify-items:start}
.contact__label{margin-bottom:.3rem;font-family:var(--display);font-weight:500;color:var(--text-dim)}
.contact__link{color:var(--text);background:var(--gradient) no-repeat 0 100%/0 1px;padding-bottom:1px;
  transition:background-size .4s var(--ease-out)}
.contact__link:hover,.contact__link:focus-visible{background-size:100% 1px}
@media (min-width:1024px) and (orientation:landscape){
  .contact__info{justify-content:end;text-align:right}
  .contact__group{justify-items:end}
  .contact__link{background-position:100% 100%}
}

.site-footer__bar{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:1rem 2.5rem;
  padding-block:1.4rem clamp(1.5rem,4vh,2.25rem);border-top:1px solid var(--hair);font-size:var(--fs-sm);color:var(--text-dim)}
.site-footer__brand{display:block;border-radius:4px}
.site-footer__brand img{width:auto;height:34px}
.site-footer__nav ul{display:flex;flex-wrap:wrap;gap:.5rem 1.75rem}
.site-footer__nav a{color:var(--text-dim);transition:color .25s var(--ease-out)}
.site-footer__nav a:hover,.site-footer__nav a[aria-current]{color:var(--text)}
@media (prefers-reduced-motion:reduce){
  .form-field__control::after,.contact__link{transition-duration:.01ms}
}

/* ============================================================
   About
   An editorial page in movements, all copy the client's own (the live About page): a hero that rises
   over a neon horizon; the mission told in full as the page scrolls, beside a rail that draws with it;
   the goals as a quote and a panel; the line about AI given a screen of its own; the values as four
   points on a ring, a set with no first or last; a last line into the footer.
   ============================================================ */
.ab-hero{position:relative;isolation:isolate;overflow:clip;min-height:100vh;min-height:100svh;
  display:flex;flex-direction:column;padding-top:var(--bar-h);background-color:var(--ink)}
.ab-hero__light{position:absolute;inset:0;z-index:-2;pointer-events:none;
  background:radial-gradient(48% 52% at 0% 0%,rgb(var(--grad-a-rgb) / .15),transparent 72%),
             radial-gradient(40% 50% at 100% 12%,rgb(var(--grad-c-rgb) / .1),transparent 72%)}
.ab-hero__grain{z-index:-1}
.ab-hero__top{display:grid;gap:clamp(2rem,5vh,3rem);padding-top:clamp(2rem,7vh,5rem)}
@media (min-width:1100px){.ab-hero__top{grid-template-columns:minmax(0,1fr) minmax(0,27rem);column-gap:clamp(2rem,4vw,4rem);align-items:end}}
/* sized to its own column: the longest line ("We are here to ensure") is 8.6em wide, so 11.2cqi always fits */
.ab-hero__intro{container-type:inline-size;min-width:0}
.ab-hero__title{margin-top:clamp(.9rem,2.2vh,1.4rem);font-weight:300;font-size:clamp(2.5rem,.6rem + 4.2vw,5.4rem);
  font-size:max(2.3rem,min(7rem,11.2cqi));line-height:1;letter-spacing:-.035em}
@media (min-width:768px){.ab-hero__title .rise__line>span{white-space:nowrap}}
/* the horizon: the neon drawn out from the centre, a low sunrise of the brand light standing on it */
.ab-hero__horizon{position:relative;margin-top:auto;padding-top:clamp(3rem,9vh,6rem)}
.ab-hero__horizon::before{content:"";position:absolute;left:50%;bottom:0;width:140vw;height:min(62svh,40rem);translate:-50% 0;
  pointer-events:none;z-index:-1;
  background:radial-gradient(50% 100% at 50% 100%,rgb(var(--grad-b-rgb) / .12),rgb(var(--grad-c-rgb) / .07) 38%,
    rgb(var(--grad-a-rgb) / .035) 62%,transparent 82%)}
.ab-hero__horizon .neon-line{--neon-len:560px}
.ab-hero__foot{padding-block:clamp(1.25rem,3.5vh,2.25rem) clamp(1.5rem,4vh,2.75rem)}
.ab-hero__scroll{display:inline-flex;align-items:center;gap:.9rem;min-height:44px;
  font-family:var(--display);font-weight:500;color:var(--text-dim);transition:color .3s var(--ease-out)}
.ab-hero__scroll:hover{color:var(--text)}
.ab-hero__scroll::after{content:"";width:1px;height:2.5rem;background:linear-gradient(var(--text-soft),transparent);
  transform-origin:50% 0;animation:scroll-cue 2.6s var(--ease-inout) infinite}
@keyframes scroll-cue{0%{scale:1 0;opacity:1}55%{scale:1 1;opacity:1}100%{scale:1 1;opacity:0}}
.is-paused .ab-hero__scroll::after{animation-play-state:paused}
.ab-hero__panel{padding:clamp(1.5rem,2.5vw,2.25rem)}
.panel-label{margin-bottom:.8rem;font-family:var(--display);font-weight:500;font-size:var(--fs-sm);color:var(--text-dim)}
.ab-hero__panel p:not(.panel-label),.story__panel p:not(.panel-label){line-height:1.65;color:var(--text-soft)}

/* the story: mission and goals beside a neon rail that draws down as the section scrolls by */
.story{position:relative;padding-block:var(--section-y);border-top:1px solid var(--hair)}
.story__grid{display:grid;grid-template-columns:auto minmax(0,1fr);column-gap:clamp(1.25rem,4.5vw,4.5rem)}
.story__rail{position:relative;width:var(--neon-tube)}
.story__rail .neon-line{position:absolute;inset:0;--neon-len:420px}
.story__body{min-width:0}
.story__lead{margin-top:1.25rem;max-width:25ch;font-family:var(--display);font-weight:400;
  font-size:clamp(1.9rem,1rem + 2.7vw,3.7rem);line-height:1.14;letter-spacing:-.022em;color:var(--text)}
.story__points{margin-top:clamp(3rem,10vh,6.5rem)}
.story__point{display:grid;gap:.6rem;padding-block:clamp(1.5rem,4vh,2.4rem);border-top:1px solid var(--hair)}
@media (min-width:1024px){.story__point{grid-template-columns:minmax(0,3fr) minmax(0,9fr);column-gap:3rem;align-items:baseline}}
.story__label{font-family:var(--display);font-weight:500;font-size:var(--fs-sm);color:var(--text-dim)}
.story__text{font-family:var(--display);font-weight:300;font-size:clamp(1.35rem,1rem + 1.25vw,2.15rem);line-height:1.3;
  letter-spacing:-.012em;color:var(--text)}
.story__goals{display:grid;gap:clamp(2rem,5vh,3rem);margin-top:clamp(4rem,12vh,8rem)}
@media (min-width:1024px){.story__goals{grid-template-columns:minmax(0,7fr) minmax(0,5fr);column-gap:clamp(2.5rem,5vw,5rem);align-items:end}}
.story__quote{margin:.9rem 0 0;font-family:var(--display);font-weight:300;font-size:clamp(1.9rem,1rem + 2.6vw,3.6rem);
  line-height:1.1;letter-spacing:-.028em;color:var(--text)}
.story__panel{padding:clamp(1.5rem,2.5vw,2.25rem)}
@supports (animation-timeline:view()){
  .story{view-timeline:--story block}
  .story__rail .neon-line{transform-origin:50% 0;animation:rail-draw linear both;animation-timeline:--story;animation-range:entry 20% exit 35%}
}
@keyframes rail-draw{from{scale:1 0}to{scale:1 1}}

/* the line about AI: a screen of its own, the promise underlined in neon */
.truth{position:relative;isolation:isolate;overflow:clip;padding-block:clamp(7rem,min(4rem + 9vw,26vh),15rem);border-top:1px solid var(--hair)}
.truth__light{position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(50% 60% at 92% 55%,rgb(var(--grad-c-rgb) / .11),transparent 72%),
             radial-gradient(42% 55% at 6% 40%,rgb(var(--grad-a-rgb) / .09),transparent 72%)}
.truth__text{margin-top:1.4rem;font-family:var(--display);font-weight:300;font-size:clamp(2.1rem,.9rem + 3.9vw,5rem);
  line-height:1.06;letter-spacing:-.032em;color:var(--text)}
.truth__text .rise__line{padding-bottom:.4em;margin-bottom:-.4em}
.truth__mark{position:relative;display:inline-block}
.truth__mark .neon-line{position:absolute;left:0;right:0;bottom:-.06em}

/* the values: on phones, tablets and touch screens four peers in a list; with a mouse and room, four points on
   a neon ring, the chosen one lit by a bead of light that travels round to it, its words inside the ring */
.values{position:relative;isolation:isolate;overflow:clip;padding-block:var(--section-y);border-top:1px solid var(--hair)}
.values__title{font-weight:300;font-size:clamp(2.4rem,1.1rem + 4.2vw,5.6rem);line-height:1;letter-spacing:-.035em}
.values__stage{margin-top:clamp(2.5rem,7vh,4.5rem)}
.values__ring,.values__spot,.values__core{display:none}
.value{padding-block:clamp(1.5rem,4vh,2.25rem);border-top:1px solid var(--hair)}
.value__name{padding:0;border:0;background:none;color:var(--text);font-family:var(--display);font-weight:300;
  font-size:clamp(2rem,1.2rem + 3vw,3rem);line-height:1.1;letter-spacing:-.02em;text-align:left;cursor:default}
.value__text{margin-top:.8rem;max-width:42rem;line-height:1.65;color:var(--text-soft)}
.value__big{display:none}
@media (min-width:1024px) and (hover:hover){
  .values__stage{--D:min(38rem,70svh);position:relative;width:var(--D);height:var(--D);margin:clamp(3.5rem,11vh,7rem) auto clamp(1rem,4vh,3rem)}
  .values__ring,.values__spot,.values__core{display:block}
  .values__ring{position:absolute;inset:0;border-radius:50%;isolation:isolate}
  .values__ring .neon-flow{--neon-loops:4}
  .values__core{position:absolute;inset:16%;border-radius:50%}
  .values__spot{position:absolute;inset:0;pointer-events:none;rotate:var(--spot,315deg);transition:rotate 1.1s var(--ease-enter)}
  .values__spot::before{content:"";position:absolute;left:50%;top:0;width:12px;height:12px;margin:-6px 0 0 -6px;border-radius:50%;
    background:#fff;box-shadow:0 0 10px 3px rgb(255 255 255 / .55),0 0 36px 12px rgb(var(--grad-b-rgb) / .32)}
  .values__list{position:absolute;inset:0}
  .value{position:absolute;left:50%;top:50%;width:0;height:0;padding:0;border:0}
  .value__name{position:absolute;left:0;top:0;padding:.3em .6em;border-radius:999px;white-space:nowrap;cursor:pointer;
    font-size:clamp(1.4rem,1rem + .9vw,1.9rem);color:var(--text-dim);
    transform:rotate(var(--a)) translateY(calc(var(--D) / -2 - 2.4rem)) rotate(calc(var(--a) * -1)) translate(-50%,-50%);
    transition:color .4s var(--ease-out)}
  /* where the browser has trigonometry, each name is pinned by the corner that faces the ring (exact on the
     diagonals the four values sit on), so a long name leans away from the line instead of across it */
  @supports (scale:sin(90deg)){
    .value__name{transform:rotate(var(--a)) translateY(calc(var(--D) / -2 - .5rem)) rotate(calc(var(--a) * -1))
      translate(calc(-50% + sin(var(--a)) * 70.72%),calc(-50% - cos(var(--a)) * 70.72%))}
  }
  .value.is-active .value__name,.value__name:hover{color:var(--text)}
  .value__text{position:absolute;left:0;top:0;width:calc(var(--D) * .54);margin:0;translate:-50% -50%;text-align:center;
    font-size:var(--fs-sm);opacity:0;scale:.97;pointer-events:none;transition:opacity .45s var(--ease-out),scale .9s var(--ease-enter)}
  .value.is-active .value__text{opacity:1;scale:1;transition-delay:.12s}
  .value__big{display:block;margin-bottom:.9rem;font-family:var(--display);font-weight:300;font-size:clamp(2rem,1.2rem + 1.5vw,2.9rem);
    line-height:1;letter-spacing:-.02em;color:var(--text)}
  /* without JavaScript, hovering or focusing a name still shows its words */
  .values__list:has(.value__name:is(:hover,:focus-visible)) .value:not(:has(.value__name:is(:hover,:focus-visible))) .value__text{opacity:0}
  .value:has(.value__name:is(:hover,:focus-visible)) .value__text{opacity:1;scale:1}
}
@media (prefers-reduced-motion:reduce){.values__spot,.value__text{transition-duration:.01ms!important;transition-delay:0s!important}}

.closing{padding-block:clamp(4.5rem,14vh,9rem) clamp(3.5rem,9vh,6rem);border-top:1px solid var(--hair)}
.closing__text{font-family:var(--display);font-weight:300;font-size:clamp(2.4rem,1rem + 4.6vw,6rem);line-height:1;letter-spacing:-.035em}
.closing__line{max-width:min(100%,34rem);margin-top:clamp(1.25rem,3vh,2rem)}
.closing__line .neon-line{--neon-len:480px}

/* ============================================================
   Contact
   A split screen: the ways to reach Tamon set as type on one side, and on the other a glass panel with the
   form. Labels float up out of the fields, and the field in use wears the site's neon outline.
   ============================================================ */
.ct{position:relative;isolation:isolate;overflow:clip;min-height:100vh;min-height:100svh;padding-top:var(--bar-h);background-color:var(--ink)}
.ct__light{position:absolute;inset:0;z-index:-2;pointer-events:none;
  background:radial-gradient(48% 55% at 0% 8%,rgb(var(--grad-a-rgb) / .17),transparent 72%),
             radial-gradient(44% 55% at 100% 96%,rgb(var(--grad-c-rgb) / .16),transparent 72%),
             radial-gradient(28% 34% at 86% 64%,rgb(var(--grad-b-rgb) / .07),transparent 72%)}
.ct__grain{z-index:-1}
.ct__grid{display:grid;gap:clamp(3rem,8vh,4.5rem);padding-block:clamp(2.25rem,7vh,4.5rem) clamp(3rem,8vh,5rem)}
@media (min-width:1024px){
  .ct__grid{grid-template-columns:minmax(0,5fr) minmax(0,6fr);column-gap:clamp(3rem,6vw,7rem);align-items:center;
    min-height:calc(100vh - var(--bar-h));min-height:calc(100svh - var(--bar-h))}
}
.ct__title{margin-top:1rem;font-weight:300;font-size:clamp(2.6rem,1rem + 4vw,5.6rem);line-height:1;letter-spacing:-.035em}
.ct__list{display:grid;gap:clamp(1rem,2.4vh,1.6rem);margin:clamp(2rem,5vh,3.25rem) 0 0}
.ct__item{display:grid;gap:.35rem}
.ct__item dt{font-family:var(--display);font-weight:500;font-size:var(--fs-sm);color:var(--text-dim)}
.ct__item dd{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem 1rem;margin:0}
.ct__big{padding-bottom:.08em;font-family:var(--display);font-weight:300;font-size:clamp(1.4rem,.9rem + 1.15vw,2.1rem);
  line-height:1.15;letter-spacing:-.015em;color:var(--text);overflow-wrap:anywhere}
a.ct__big{background:var(--gradient) no-repeat 0 100%/0 2px;transition:background-size .55s var(--ease-out)}
a.ct__big:hover,a.ct__big:focus-visible{background-size:100% 2px}
.ct__copy{min-height:32px;padding:.2rem .85rem;border:0;border-radius:999px;cursor:pointer;
  background:rgb(233 239 244 / .06);box-shadow:inset 0 0 0 1px var(--hair);color:var(--text-dim);
  font-family:var(--display);font-weight:500;font-size:var(--fs-xs);transition:background-color .3s var(--ease-out),color .3s var(--ease-out)}
.ct__copy:hover{background:rgb(233 239 244 / .12);color:var(--text)}
.ct__copy.is-done{color:var(--text);box-shadow:inset 0 0 0 1px rgb(233 239 244 / .35)}
.no-js .ct__copy{display:none}
.ct__item dd.ct__socials{gap:.4rem 1.6rem}
.ct__socials a{padding-bottom:2px;font-family:var(--display);font-size:clamp(1.1rem,1rem + .45vw,1.35rem);color:var(--text);
  background:var(--gradient) no-repeat 0 100%/0 1px;transition:background-size .45s var(--ease-out)}
.ct__socials a:hover,.ct__socials a:focus-visible{background-size:100% 1px}
.ct__panel{padding:clamp(1.5rem,3vw,2.75rem)}
.ct__panel-title{font-weight:400;font-size:var(--fs-h3);letter-spacing:-.012em}
.ct__form{margin-top:clamp(1.25rem,3vh,1.75rem)}
.ct__fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1rem}

/* floating labels: the label sits in the empty field and rises when the field is focused or filled */
.float-field{position:relative;isolation:isolate;border-radius:14px;background:rgb(10 20 28 / .5);
  box-shadow:inset 0 0 0 1px var(--hair);transition:box-shadow .35s var(--ease-out),background-color .35s var(--ease-out)}
.float-field:hover{box-shadow:inset 0 0 0 1px var(--hair-strong)}
.float-field:focus-within{background:rgb(10 20 28 / .72);box-shadow:inset 0 0 0 1px transparent}
.form-field--float .form-field__input{min-height:3.7rem;padding:1.65rem 1rem .55rem;border:0;border-radius:14px}
.form-field--float .form-field__input::placeholder{color:transparent}
.form-field--float .form-field__input--area{min-height:8.5rem;max-height:18rem}
.float-field__label{position:absolute;left:1rem;top:1.15rem;transform-origin:0 0;pointer-events:none;
  font-family:var(--display);font-weight:500;font-size:1rem;line-height:1.3;color:var(--text-dim);
  transition:transform .4s var(--ease-enter),color .35s var(--ease-out)}
.float-field:focus-within .float-field__label,.form-field__input:not(:placeholder-shown)~.float-field__label{transform:translateY(-.66rem) scale(.78)}
.float-field:focus-within .float-field__label{color:var(--text-soft)}
.float-field__hint{position:absolute;right:1rem;top:1.2rem;font-size:var(--fs-xs);color:var(--text-dim);pointer-events:none}
/* the field in use glows: the site's neon outline, resting (and not turning) on every other field */
.float-field .neon-ring{opacity:0;transition:opacity .5s var(--ease-out)}
.float-field:focus-within .neon-ring{opacity:1}
.float-field:not(:focus-within) .neon-flow{animation-play-state:paused}
.form-field--float.is-invalid .float-field{box-shadow:inset 0 0 0 1px var(--grad-c)}

/* service chips: optional, toggled like pills */
.chips{grid-column:1 / -1;min-width:0;margin:.5rem 0 .25rem;padding:0;border:0}
.chips__legend{display:flex;gap:.75rem;margin-bottom:.8rem;padding:0;font-family:var(--display);font-weight:500;
  font-size:var(--fs-sm);color:var(--text-dim)}
.chips__legend span{font-weight:400}
.chips__list{display:flex;flex-wrap:wrap;gap:.5rem}
.chip{position:relative;display:inline-flex}
.chip input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}
.chip span{display:inline-flex;align-items:center;gap:.55rem;min-height:40px;padding:.45rem .95rem;border-radius:999px;
  font-size:var(--fs-sm);color:var(--text-soft);box-shadow:inset 0 0 0 1px var(--hair-strong);
  transition:background-color .3s var(--ease-out),box-shadow .3s var(--ease-out),color .3s var(--ease-out),scale .2s var(--ease-out)}
.chip span::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--hair-strong);transition:background .3s var(--ease-out),scale .45s var(--ease-enter)}
.chip:hover span{box-shadow:inset 0 0 0 1px rgb(233 239 244 / .38);color:var(--text)}
.chip input:checked+span{background:rgb(233 239 244 / .09);box-shadow:inset 0 0 0 1px rgb(233 239 244 / .45);color:var(--text)}
.chip input:checked+span::before{background:var(--gradient);scale:1.35}
.chip input:active+span{scale:.97}
.chip input:focus-visible+span{outline:2px solid var(--grad-a);outline-offset:3px}
.ct__actions{display:flex;flex-wrap:wrap;align-items:center;gap:1rem 1.5rem;margin-top:1.5rem}
@media (prefers-reduced-motion:reduce){
  .float-field__label,.chip span,.chip span::before,a.ct__big,.ct__socials a{transition-duration:.01ms}
  .ab-hero__scroll::after,.story__rail .neon-line{animation:none}
}

/* ============================================================
   Next: the way on from the foot of a page (a case study's next project; from Services, the work).
   One link, the whole block: the name set large, and beside it a photo in a window smaller than the photo.
   With a mouse the window opens to the whole photo as the photo settles, the name leans in and a neon line
   draws under it. On touch screens the window opens as the block scrolls into view.
   ============================================================ */
.next{position:relative;isolation:isolate;overflow:clip;border-top:1px solid var(--hair);background-color:var(--ink)}
.next__light{position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(40% 60% at 85% 50%,rgb(var(--grad-c-rgb) / .1),transparent 72%),
             radial-gradient(36% 50% at 8% 90%,rgb(var(--grad-a-rgb) / .08),transparent 72%)}
.next__link{display:grid;grid-template-columns:minmax(0,1fr);gap:clamp(2rem,5vw,3.5rem);align-items:center;
  padding-block:clamp(4.5rem,12vh,8rem);color:var(--text)}
@media (min-width:900px){.next__link{grid-template-columns:minmax(0,7fr) minmax(0,5fr);column-gap:clamp(2rem,5vw,6rem)}}
.next__text{display:block;min-width:0}
.next__eyebrow{display:block;font-family:var(--display);font-weight:500;font-size:var(--fs-sm);color:var(--text-dim)}
.next__title{display:block;margin-top:.7rem;font-family:var(--display);font-weight:300;font-size:clamp(3rem,.8rem + 6vw,7.5rem);
  line-height:.98;letter-spacing:-.04em;overflow-wrap:anywhere;transition:translate .9s var(--ease-enter)}
.next__meta{display:block;margin-top:1rem;color:var(--text-soft)}
.next__line{max-width:min(100%,28rem);margin-top:clamp(1.5rem,3.5vh,2.25rem);transform-origin:0 50%;scale:.18 1;
  transition:scale 1s var(--ease-enter)}
.next__media{position:relative;display:block;aspect-ratio:4 / 5;max-height:78svh;border-radius:var(--radius-lg);overflow:clip;
  background-color:var(--tint,var(--ink-2));clip-path:inset(8% 11% round var(--radius-lg));transition:clip-path 1.1s var(--ease-enter)}
.next__media picture{display:block;height:100%}
.next__media img{width:100%;height:100%;max-width:none;object-fit:cover;object-position:var(--pos,50% 50%);scale:1.14;
  transition:scale 1.3s var(--ease-enter)}
@media (min-width:900px){.next__media{aspect-ratio:auto;height:min(34rem,64svh)}}
@media (hover:hover){
  .next__link:is(:hover,:focus-visible) .next__media{clip-path:inset(0 round var(--radius-lg))}
  .next__link:is(:hover,:focus-visible) .next__media img{scale:1}
  .next__link:is(:hover,:focus-visible) .next__title{translate:.06em 0}
  .next__link:is(:hover,:focus-visible) .next__line{scale:1 1}
  .next__link:focus-visible{outline-offset:-2px;border-radius:var(--radius-lg)}
}
/* touch: the window opens with the scroll ([data-scrub] in site.js stands in where CSS cannot tie it to the scroll) */
@keyframes next-open{to{clip-path:inset(0 round var(--radius-lg))}}
@keyframes next-settle{to{scale:1}}
@media (hover:none) and (prefers-reduced-motion:no-preference){
  .next__media{animation:next-open 1s linear both;animation-timeline:view();animation-range:entry 30% cover 55%}
  .next__media img{animation:next-settle 1s linear both;animation-timeline:view();animation-range:entry 30% cover 55%}
  .next__line{scale:1 1}
}
@media (prefers-reduced-motion:reduce){
  .next__media{clip-path:inset(0 round var(--radius-lg))}
  .next__media img{scale:1}
  .next__media,.next__media img,.next__title,.next__line{transition-duration:.01ms}
}
