/*#######################################################################*/
/* Fonts – NB International (unchanged typeface, now as one family)      */
/*#######################################################################*/

@font-face {
	font-family: 'NBInternational';
	src: url('../fonts/NBInternationalRegularWebfont.woff2') format('woff2');
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: 'NBInternational';
	src: url('../fonts/nb_international_pro_medium-webfont.woff2') format('woff2'),
	     url('../fonts/nb_international_pro_medium-webfont.woff') format('woff');
	font-weight: 500;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: 'NBInternational';
	src: url('../fonts/nb_international_pro_bold-webfont.woff2') format('woff2'),
	     url('../fonts/nb_international_pro_bold-webfont.woff') format('woff');
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

/*#######################################################################*/
/* Tokens                                                                */
/*#######################################################################*/

:root{
	/* geometry — desktop values mirror the 1440×1024 Figma frame */
	--edge-x: clamp(24px, 10.42vw, 150px);   /* 150 @1440 */
	--edge-y: clamp(24px, 14.65vh, 150px);   /* 150 @1024 */
	--cv-left: 43.75vw;                      /* 630 @1440 */
	--cv-width: min(660px, 46vw);            /* 660 @1440 */

	/* set by JS (settings panel) — these are the shipping defaults */
	--intro-top: 71vh;                       /* 727 @1024 */
	--intro-gap: 140px;
	--veil-h: 130px;
	--veil-top-h: 90px;
	--veil-top-opacity: 1;
	--cue-bottom: 46px;
	--cue-opacity: 1;
	--drift: 0px;                            /* used by the “drift” cue */

	/* type */
	--fs-name: clamp(30px, 2.78vw, 40px);
	--fs-intro: clamp(24px, 2.22vw, 32px);
	--fs-heading: 22px;
	--fs-body: 16px;
	--fs-label: 15px;

	--ink: #000;
	--ink-soft: #9f9f9f;
	--paper: #fff;
}

/*#######################################################################*/
/* Base                                                                  */
/*#######################################################################*/

*, *::before, *::after{ box-sizing: border-box; }

html{
	-webkit-text-size-adjust: 100%;
	scroll-behavior: auto;
}

body{
	margin: 0;
	background: var(--paper);
	color: var(--ink);
	font-family: 'NBInternational', Helvetica, Arial, sans-serif;
	font-weight: 400;
	-moz-osx-font-smoothing: grayscale;
	-webkit-font-smoothing: antialiased;
	overflow-x: hidden;
}

a{ color: inherit; }

/* Pre-paint state: only hide things when JS is actually available, so the
   page still reads fine without JavaScript. */
.js:not([data-ready]) .identity,
.js:not([data-ready]) .cv__intro,
.js:not([data-ready]) .cue{ opacity: 0; }

/*#######################################################################*/
/* Identity (name + role)                                                */
/*#######################################################################*/

.identity{
	position: fixed;
	top: var(--edge-y);
	left: var(--edge-x);
	z-index: 4;
	margin: 0;
	max-width: calc(var(--cv-left) - var(--edge-x) - 8px);
}

.identity__name,
.identity__role{
	margin: 0;
	font-size: var(--fs-name);
	line-height: 1.2;
	letter-spacing: -0.012em;
}

.identity__name{ font-weight: 700; }

/* one step lighter than the name – NB International Pro Medium */
.identity__role{
	font-weight: 500;
	color: var(--ink-soft);
	font-size: calc(var(--fs-name) * var(--role-scale, 1));
}

/* “Zwei Zeilen”: the last word group (“&&nbsp;Researcher”) becomes a block, so
   the break sits in the same place at every font size and viewport width.
   More reliable than a max-width, which depends on the measured text. */
body[data-role-break="two"] .identity__role .wd:last-child,
body[data-role-break="two"] .identity__role > .u:last-child{ display: block; }

/* split units */
.u{
	display: inline-block;
	vertical-align: top;
}

.wd{
	display: inline-block;
	white-space: nowrap;
}

/* The mask cuts exactly on the baseline (--cut is measured from the real
   font metrics in site.js). Units that contain a descender are cut on the
   font’s descent line instead (--cut-d), so no “g” gets beheaded. */
.identity[data-mask="1"] .u{
	clip-path: inset(0 0 var(--cut, 0.22em) 0);
}

.identity[data-mask="1"] .u.dsc{
	clip-path: inset(0 0 var(--cut-d, 0.04em) 0);
}

.i{
	display: inline-block;
}

/*#######################################################################*/
/* CV                                                                    */
/*#######################################################################*/

.cv{
	position: relative;
	z-index: 1;
	padding-left: var(--cv-left);
	padding-right: var(--edge-x);
	padding-top: var(--intro-top);
	padding-bottom: max(140px, calc(var(--veil-h) + 48px));
}

.cv__col{
	max-width: var(--cv-width);
	transform: translateY(var(--drift));
}

.cv__intro{
	margin: 0 0 var(--intro-gap);
	font-size: var(--fs-intro);
	line-height: 1.2;
	font-weight: 500;
	letter-spacing: -0.006em;
	text-wrap: pretty;
}

/* intro split helpers (lines / words / mask) */
.cv__intro .ln{ display: block; }
.cv__intro[data-mask="1"] .ln{
	clip-path: inset(0 0 var(--cut, 0.2em) 0);
}

.cv__intro[data-mask="1"] .ln.dsc{
	clip-path: inset(0 0 var(--cut-d, 0.03em) 0);
}
.cv__intro .lni,
.cv__intro .wi{ display: inline-block; }
.cv__intro .w{ display: inline-block; }
.cv__intro .probe{ display: inline-block; }

.cv__heading{
	margin: 86px 0 35px;
	font-size: var(--fs-heading);
	line-height: 32px;
	font-weight: 400;
}

.cv__rest > .cv__heading:first-child{ margin-top: 0; }

.cv__row{
	display: grid;
	grid-template-columns: 149px minmax(0, 1fr);
	align-items: start;
}

.cv__row + .cv__row{ margin-top: 56px; }
.cv__heading + .cv__row{ margin-top: 0; }

.cv__label{
	font-size: var(--fs-label);
	line-height: 22.5px;
	opacity: .6;
	padding-top: 2px;
}

.cv__body{
	font-size: var(--fs-body);
	line-height: 26px;
}

.cv__body p{ margin: 0; }

/* multi-paragraph entries (Profile) */
.cv__body p + p{ margin-top: 18px; }

/* prose rows have no label, but keep the same left edge as every other entry */
.cv__row--prose .cv__body{ grid-column: 2; }

/* short divider that sets the “currently” note apart without reading as a
   new section — the section rules look different on purpose */
.cv__rule{
	width: 100px;
	height: 1px;
	border: 0;
	margin: 30px 0;
	background: currentColor;
	opacity: .22;
}

/*#######################################################################*/
/* Chips                                                                 */
/*#######################################################################*/

.chips{
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	list-style: none;
	margin: 40px 0 0;
	padding: 0;
}

.chip{
	display: inline-flex;
	align-items: center;
	gap: 7px;
	padding: 5px 14px;
	border-radius: 100px;
	font-size: 12px;
	line-height: 18px;
	text-transform: uppercase;
	letter-spacing: .05em;
	background: #f0f0f0;
}

.chip::before{
	content: '';
	width: 13px;
	height: 13px;
	flex: 0 0 auto;
	background: currentColor;
	mask: var(--chip-icon) center / contain no-repeat;
	-webkit-mask: var(--chip-icon) center / contain no-repeat;
}

/* Generic category marks rather than brand logos: the page is monochrome,
   and a hand-drawn logo is a wrong logo. Drop in official SVGs any time. */
.chip[data-kind="design"]{
	--chip-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M10 3.2 16.8 10 10 16.8 3.2 10z' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3C/svg%3E");
}

.chip[data-kind="code"]{
	--chip-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M7.6 5.4 3 10l4.6 4.6M12.4 5.4 17 10l-4.6 4.6' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.chip[data-kind="ai"]{
	--chip-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M10 2.6 11.7 8.3 17.4 10 11.7 11.7 10 17.4 8.3 11.7 2.6 10 8.3 8.3z' fill='%23000'/%3E%3C/svg%3E");
}

.chip[data-kind="research"]{
	--chip-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='8.6' cy='8.6' r='4.9' fill='none' stroke='%23000' stroke-width='1.5'/%3E%3Cpath d='M12.4 12.4 17 17' fill='none' stroke='%23000' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
}

.chip[data-kind="process"]{
	--chip-icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Ccircle cx='4.2' cy='10' r='1.8' fill='%23000'/%3E%3Ccircle cx='10' cy='10' r='1.8' fill='%23000'/%3E%3Ccircle cx='15.8' cy='10' r='1.8' fill='%23000'/%3E%3C/svg%3E");
}

body[data-chip-icons="0"] .chip::before{ display: none; }

body[data-chips="yellow"] .chip{ background: #fcff77; }

body[data-chips="outline"] .chip{
	background: none;
	box-shadow: inset 0 0 0 1px rgb(0 0 0 / .17);
}

/* :not(.chips) keeps the dash-bullet styling away from the chip list, which
   lives inside .cv__body too and would otherwise inherit content and position */
.cv__body ul:not(.chips){
	list-style: none;
	margin: 15px 0 0;
	padding-left: 16px;
	opacity: .7;
}

.cv__body ul:not(.chips) li{
	padding-left: 16px;
	margin-bottom: 12px;
	position: relative;
}

.cv__body ul:not(.chips) li:last-child{ margin-bottom: 0; }

.cv__body ul:not(.chips) li::before{
	content: "–";
	position: absolute;
	left: -16px;
	top: 0;
}

/* links */
.link{
	text-decoration: none;
	border-bottom: 1px solid currentColor;
	padding-bottom: 1px;
	transition: opacity .25s ease;
}

.link:hover{ opacity: .55; }

/*#######################################################################*/
/* Veils (fade out)                                                      */
/*#######################################################################*/

.veil{
	position: fixed;
	left: 0;
	right: 0;
	pointer-events: none;
	z-index: 3;
}

.veil--bottom{
	bottom: 0;
	height: var(--veil-h);
	transform-origin: bottom center;
	background: linear-gradient(to top,
		rgb(255 255 255 / 1)     0%,
		rgb(255 255 255 / 1)    26%,
		rgb(255 255 255 / .985) 34%,
		rgb(255 255 255 / .95)  42%,
		rgb(255 255 255 / .88)  50%,
		rgb(255 255 255 / .78)  58%,
		rgb(255 255 255 / .645) 66%,
		rgb(255 255 255 / .485) 74%,
		rgb(255 255 255 / .315) 82%,
		rgb(255 255 255 / .155) 90%,
		rgb(255 255 255 / .04)  96%,
		rgb(255 255 255 / 0)   100%);
}

.veil--top{
	top: 0;
	height: var(--veil-top-h);
	opacity: 0;
	transition: opacity .45s cubic-bezier(.4,0,.2,1);
	background: linear-gradient(to bottom,
		rgb(255 255 255 / 1)     0%,
		rgb(255 255 255 / 1)    20%,
		rgb(255 255 255 / .97)  30%,
		rgb(255 255 255 / .91)  40%,
		rgb(255 255 255 / .81)  50%,
		rgb(255 255 255 / .67)  60%,
		rgb(255 255 255 / .50)  70%,
		rgb(255 255 255 / .32)  80%,
		rgb(255 255 255 / .15)  90%,
		rgb(255 255 255 / 0)   100%);
}

html.is-scrolled .veil--top{ opacity: var(--veil-top-opacity); }
body[data-veil-top="0"] .veil--top{ display: none; }

/*#######################################################################*/
/* Scroll cue                                                            */
/*#######################################################################*/

.cue{
	position: fixed;
	bottom: var(--cue-bottom);
	left: var(--cv-left);
	z-index: 5;
	pointer-events: none;
	opacity: var(--cue-opacity);
	transition: opacity .6s cubic-bezier(.4,0,.2,1);
	color: var(--ink);
}

body[data-cue-pos="center"] .cue{ left: 50%; }
body[data-cue-pos="center"] .cue__in{ transform: translateX(-50%); }

html.cue-off .cue{ opacity: 0 !important; }
body[data-cue="none"] .cue,
body[data-cue="nudge"] .cue,
body[data-cue="drift"] .cue,
body[data-cue="breathe"] .cue{ display: none; }

.cue__in{ display: block; }

/* hairline */
.cue__line{
	display: block;
	width: 1px;
	height: 46px;
	background: currentColor;
	opacity: .28;
	transform-origin: top center;
	animation: cueLine var(--cue-dur, 2.8s) cubic-bezier(.4,0,.2,1) infinite;
}

@keyframes cueLine{
	0%   { transform: scaleY(0);   opacity: 0; }
	28%  { transform: scaleY(1);   opacity: .3; }
	62%  { transform: scaleY(1);   opacity: .3; }
	100% { transform: scaleY(1) translateY(46px); opacity: 0; }
}

/* dot */
.cue__dot{
	display: block;
	width: 5px;
	height: 5px;
	border-radius: 50%;
	background: currentColor;
	opacity: .35;
	animation: cueDot var(--cue-dur, 3.4s) cubic-bezier(.4,0,.2,1) infinite;
}

@keyframes cueDot{
	0%,100%{ transform: translateY(0);   opacity: .18; }
	50%    { transform: translateY(9px); opacity: .5; }
}

/* chevron */
.cue__chev{
	display: block;
	width: 22px;
	height: 22px;
	opacity: .32;
	animation: cueChev var(--cue-dur, 3.6s) cubic-bezier(.4,0,.2,1) infinite;
}
.cue__chev svg{ display: block; width: 100%; height: 100%; }

@keyframes cueChev{
	0%,100%{ transform: translateY(0);   opacity: .2; }
	50%    { transform: translateY(7px); opacity: .48; }
}

/* label */
.cue__label{
	display: block;
	font-size: 11px;
	line-height: 1;
	letter-spacing: .16em;
	text-transform: uppercase;
	opacity: .3;
	animation: cueLabel var(--cue-dur, 4.2s) cubic-bezier(.4,0,.2,1) infinite;
}

@keyframes cueLabel{
	0%,100%{ opacity: .18; }
	50%    { opacity: .46; }
}

/*#######################################################################*/
/* Mobile                                                                */
/*#######################################################################*/

@media only screen and (max-width: 991px){
	:root{
		--edge-x: clamp(20px, 8vw, 32px);
		--edge-y: clamp(20px, 8vw, 32px);
		--cv-left: var(--edge-x);
		--cv-width: 620px;   /* keeps the line length sane on tablets */
		--intro-top: 65.5svh;
		--intro-gap: 70px;
		--veil-h: 96px;
		--veil-top-h: 70px;
		--cue-bottom: 30px;
		--fs-name: clamp(30px, 10vw, 40px);
		--fs-intro: clamp(23px, 8.5vw, 32px);
		--fs-heading: 22px;
	}

	/* everything scrolls together */
	.identity{
		position: absolute;
		/* same content width as the CV column, so a long title wraps inside
		   the margins instead of running into the screen edge */
		max-width: calc(100% - 2 * var(--edge-x));
	}

	.cv__row{
		grid-template-columns: minmax(0, 1fr);
	}

	.cv__label{
		padding-top: 0;
		margin-bottom: 2px;
	}

	.cv__heading{ margin: 70px 0 30px; }
	.cv__row + .cv__row{ margin-top: 40px; }
}

/* short landscape viewports */
@media only screen and (max-height: 620px) and (orientation: landscape){
	:root{
		--intro-top: 58vh;
		--edge-y: 40px;
		--intro-gap: 90px;
	}
}

/*#######################################################################*/
/* Reduced motion                                                        */
/*#######################################################################*/

@media (prefers-reduced-motion: reduce){
	.cue__line, .cue__dot, .cue__chev, .cue__label{
		animation: none !important;
	}
	.cue{ opacity: .3; }
	.cv__col{ transform: none !important; }
}
