/* Shared by every page: colours, type, the header.
   The site follows the device: dark by default, light when the device is set to light.
   The Workings layer of a case study is always the light board, whatever the device. */

:root{
  /* Finished (the main site) */
  --f-bg:#121212; --f-raise:#1B1B1B; --f-text:#EDEBE7; --f-strong:#fff; --f-muted:#A3A09A;
  --f-line:rgba(237,235,231,.14); --f-accent:#8EA4FF; --f-veil:18,18,18;
  /* Workings (the board) */
  --w-canvas:#EEEEEC; --w-dot:#C9C9C4; --w-ui:#FFFFFF; --w-ink:#16171A; --w-muted:#62636A; --w-line:#E2E2DF;
  --w-sel:#2F56E8; --w-dan:#E2531A; --w-note:#FFE88A; --w-ok:#1F8A52;
  /* type */
  --sans:"Hanken Grotesk","Helvetica Neue",Arial,sans-serif;
  --mono:"IBM Plex Mono",ui-monospace,Menlo,monospace;
  --uifont:"Onest","Helvetica Neue",Arial,sans-serif;
  /* motion and spacing */
  --ease:cubic-bezier(.22,1,.36,1); --gutter:clamp(16px,3vw,40px);
  /* the project title: the same size on the page curtain and on the hero, so one lands exactly on the other */
  --ttl:clamp(44px,7vw,120px); --spad:clamp(16px,2.4vw,36px);
  --bg:var(--f-bg); --fg:var(--f-text); color-scheme:dark;
}
/* light: when the device is set to light (unless the toggle says dark), or when the toggle says light */
@media (prefers-color-scheme:light){
  :root:not([data-theme="dark"]){
    --f-bg:#FAF9F8; --f-raise:#FFFFFF; --f-text:#1A1A18; --f-strong:#111; --f-muted:#6E6C66;
    --f-line:rgba(26,26,24,.14); --f-accent:#2F56E8; --f-veil:250,249,248; color-scheme:light;
  }
}
:root[data-theme="light"]{
  --f-bg:#FAF9F8; --f-raise:#FFFFFF; --f-text:#1A1A18; --f-strong:#111; --f-muted:#6E6C66;
  --f-line:rgba(26,26,24,.14); --f-accent:#2F56E8; --f-veil:250,249,248; color-scheme:light;
}

*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--fg);font-family:var(--sans);font-size:17px;line-height:1.5;-webkit-font-smoothing:antialiased;overflow-x:hidden}
button{font:inherit;color:inherit}
h1,h2,h3,p{margin:0}
a{color:inherit}
:focus-visible{outline:2px solid var(--f-accent);outline-offset:3px}
.wrap{max-width:1400px;margin:0 auto;padding-inline:var(--gutter)}

/* header: the name, with what I do beside it */
.brand{display:flex;gap:10px;align-items:baseline;text-decoration:none;font-size:17px;color:var(--f-text)}
.brand b{font-weight:600;color:var(--f-strong)}
.brand > span{color:var(--f-muted)}
.contact{font-size:15px;border:1px solid var(--f-line);background:rgba(var(--f-veil),.6);color:var(--f-text);border-radius:999px;min-height:38px;padding:0 16px;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);text-decoration:none;display:inline-flex;align-items:center}
.contact:hover{color:var(--f-bg)}
/* buttons: on hover a fill swipes up from the bottom. --sw is the fill colour, the text swaps to the page colour */
.contact,.info .go,.feat .go,#fin .tail .cta{--sw:var(--f-strong);background-image:linear-gradient(var(--sw),var(--sw));background-repeat:no-repeat;background-origin:border-box;background-position:50% 100%;background-size:100% 0;transition:background-size .45s var(--ease),color .3s var(--ease),border-color .3s}
.contact:hover,.info a.go:hover,.feat a.fp:hover .go,#fin .tail a.nxrow:hover .cta,#fin .tail a.cta:hover{background-size:100% 100%;border-color:var(--sw)}
@media (prefers-reduced-motion:reduce){ .contact,.info .go,.feat .go,#fin .tail .cta{transition:color .2s} }

/* the light/dark toggle: a circle, half filled */
.theme{width:38px;height:38px;border-radius:50%;border:1px solid var(--f-line);background:rgba(var(--f-veil),.6);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;padding:0;color:var(--f-text);transition:border-color .3s}
.theme:hover{border-color:var(--f-text)}
.theme svg{display:block;transition:transform .6s var(--ease)}
.theme:active svg{transform:rotate(180deg)}
.acts{display:flex;align-items:center;gap:8px}

/* footer */
.foot{display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;color:var(--f-muted);font-size:14px;padding:32px 0;border-top:1px solid var(--f-line)}
.foot a{color:var(--f-strong);text-decoration:none}

@media (max-width:720px){ .brand span{display:none} }
@media (prefers-reduced-motion:reduce){ *,*::before,*::after{transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important} }

/* ===== moving between pages =====
   Leaving: a curtain rises from the bottom in the colour of where you're going (with its name, for a case study).
   Arriving: the same curtain lifts off the top and the page plays its entrance underneath.
   The curtain is drawn on the page itself so it's there from the very first frame. */
html[data-cv]::after,html[data-cv]::before{position:fixed;z-index:200;pointer-events:none;transform:translateY(100%);transition:transform .75s cubic-bezier(.76,0,.24,1)}
html[data-cv]::after{content:"";inset:0;background:var(--cv,#121212)}
html[data-cv]::before{content:attr(data-cv-title);z-index:201;inset:0;display:flex;align-items:flex-end;padding:0 calc(100vw - min(100vw,1400px) + var(--gutter) + var(--spad)) clamp(28px,6vh,64px) calc(var(--gutter) + var(--spad));color:#fff;font-family:var(--sans);font-weight:300;font-size:var(--ttl);letter-spacing:-.035em;line-height:.95;transition-delay:.06s}
html[data-cv="below"]::after,html[data-cv="below"]::before{transition:none}
html[data-cv="in"]::after,html[data-cv="in"]::before{transform:none}
html[data-cv="up"]::after,html[data-cv="up"]::before{transform:translateY(-100%)}
html[data-cv="up"]::before{transition-delay:0s}
/* arriving on a project: the panel shrinks into the hero and the title slides onto the hero's own title, then the panel fades to show the image */
html[data-cv]::after{clip-path:inset(0 0 0 0)}
html[data-cv="land"]::after{transform:none;clip-path:var(--cv-clip);transition:clip-path .9s cubic-bezier(.76,0,.24,1)}
html[data-cv="land"]::before{transform:translate(var(--cv-dx),var(--cv-dy));transition:transform .9s cubic-bezier(.76,0,.24,1)}
html[data-cv="done"]::after{transform:none;clip-path:var(--cv-clip);opacity:0;transition:opacity .6s ease}
html[data-cv="bye"]::after{transform:none;clip-path:var(--cv-clip);opacity:0;transition:opacity .25s ease}
html[data-cv="bye"]::before{display:none}
html[data-cv="done"]::before{transform:translate(var(--cv-dx),var(--cv-dy));transition:none}

/* while the curtain is fully down, the page underneath takes its colour too, so the switch between pages never shows anything else */
html[data-cv-bg],html[data-cv-bg] body{background:var(--cv)}

/* things that rise into place as they come into view */
.js [data-reveal]{opacity:0;transform:translateY(28px);transition:opacity .9s var(--ease),transform 1.1s var(--ease)}
.js [data-reveal].seen{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){ html[data-cv]::after,html[data-cv]::before{display:none} .js [data-reveal]{opacity:1;transform:none} }
/* a group whose children rise in one after another */
.js [data-reveal="kids"]{opacity:1;transform:none}
.js [data-reveal="kids"] > *{opacity:0;transform:translateY(24px);transition:opacity .8s var(--ease),transform 1s var(--ease)}
.js [data-reveal="kids"].seen > *{opacity:1;transform:none}
.js [data-reveal="kids"] > :nth-child(2){transition-delay:.08s}
.js [data-reveal="kids"] > :nth-child(3){transition-delay:.16s}
.js [data-reveal="kids"] > :nth-child(4){transition-delay:.24s}
@media (prefers-reduced-motion:reduce){ .js [data-reveal="kids"] > *{opacity:1;transform:none} }

/* the header bar: clear at the top of the page, then a frosted panel slides in behind it once you scroll */
.top::before{content:"";position:absolute;inset:0;pointer-events:none;background:color-mix(in srgb,var(--f-bg) 35%,transparent);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);border-bottom:1px solid color-mix(in srgb,var(--f-line) 30%,transparent);opacity:0;transform:translateY(-6px);transition:opacity .4s var(--ease),transform .5s var(--ease)}
.top.stuck::before{opacity:1;transform:none}
.top > .wrap{position:relative}

/* the contact panel: drops in from the top with the address, a copy button and an email button */
.cpanel{position:fixed;inset:0;z-index:150}
.cpanel[hidden]{display:none}
.cpanel .cp-veil{position:absolute;inset:0;background:rgba(var(--f-veil),.55);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);opacity:0;transition:opacity .45s var(--ease)}
.cpanel .cp-in{position:absolute;left:0;right:0;top:0;background:var(--f-bg);border-bottom:1px solid var(--f-line);box-shadow:0 30px 60px -30px rgba(0,0,0,.35);transform:translateY(-100%);transition:transform .55s var(--ease)}
.cpanel .cp-in .wrap{position:relative;padding-top:calc(env(safe-area-inset-top,0px) + clamp(72px,10vh,104px));padding-bottom:clamp(36px,6vh,64px)}
.cpanel.on .cp-veil{opacity:1}
.cpanel.on .cp-in{transform:none}
.cp-k{color:var(--f-muted);font-size:15px}
.cp-mail{display:inline-block;margin-top:2px;margin-left:-.055em;font-weight:300;font-size:clamp(22px,5vw,72px);letter-spacing:-.03em;line-height:1.05;color:var(--f-strong);text-decoration:none;white-space:nowrap}
@media (max-width:560px){ .cp-mail{font-size:6.4vw} }
.cp-mail:hover{text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:.12em}
.cp-acts{display:flex;flex-wrap:wrap;gap:10px;margin-top:28px}
.cp-acts .contact{cursor:pointer;font-family:inherit}
.cp-x{position:absolute;right:var(--gutter);top:calc(env(safe-area-inset-top,0px) + 16px);font-size:15px;color:var(--f-muted);background:none;border:0;padding:8px 0;cursor:pointer}
.cp-x:hover{color:var(--f-strong)}
@media (prefers-reduced-motion:reduce){ .cpanel .cp-in,.cpanel .cp-veil{transition:none} }
