@font-face {
	font-family: Aeonik;
	src: url("Font/Aeonik-Regular.woff") format("woff");
	font-weight: normal;
	font-display: swap;
}

:root {
	/* Color */
	--color-bg: #ffffff;
	/* Slate-tinted neutrals (ref. Stripe): text and greys share one hue,
	   so the two-tone hero reads as intentional rather than disabled */
	--color-text: #0f1720;
	--color-text-muted: #5f6b7a; /* 5.4:1 on white, OK for small text */
	--color-text-soft: #6f7c8c; /* 4.25:1 on white, large text only (≥ 24px) */
	--color-line: #d4d4d4;
	--color-dtd: #003366;
	--color-wep: #77caff;
	--color-satispay: #ff3d00;
	--color-sardegna-ricerche: #b90009;
	--color-strada-nuova: #2e3943;

	/* Type scale */
	--font-family: Aeonik, Helvetica, Arial, sans-serif;
	/* Type scale by function, shared by home and case studies.
	   Desktop steps grow by ~1/3: 12 · 14 · 18 · 24 · 32 · 48 · 64
	   Mobile keeps every level distinct: 12 · 14 · 16 · 20 · 24 · 28 · 32 */
	--text-giant: clamp(72px, 15vw, 220px); /* signature section title */
	--text-display: clamp(32px, 4.4vw, 64px); /* main statements */
	--text-headline: clamp(28px, 3.2vw, 48px); /* case study intro */
	--text-title: clamp(24px, 2.2vw, 32px); /* project titles */
	--text-bridge: clamp(20px, 1.6vw, 24px); /* bridge sentences */
	--text-body: clamp(16px, 1.2vw, 18px);
	--text-small: 14px;
	--text-label: 12px;
	--tracking-tight: -0.01em; /* all text from 48px up */
	--tracking-caps: 0.08em; /* uppercase labels, 12px */
	--tracking-caps-s: 0.06em; /* uppercase small headings, 14px */

	/* Spacing scale, shared by home and case studies.
	   Small steps are fixed; large steps scale with the viewport width
	   (desktop → mobile). 16 = related items, 32 = groups, 64 = blocks. */
	/* Side margin: 24px on phones, growing to 40px at 1600px; beyond that it
	   grows with the screen, so full-width parts never exceed --content-max */
	--content-max: 1520px;
	--gutter: max(clamp(24px, 2.5vw, 40px), (100vw - var(--content-max)) / 2);
	--space-2xs: 12px; /* inline items, e.g. index · square · category */
	--space-xs: 8px;
	--space-s: 16px;
	--space-m: 32px;
	--space-l: 64px;
	--space-xl: clamp(72px, 6vw, 96px); /* between sections */
	--space-2xl: clamp(
		80px,
		8vw,
		120px
	); /* around bridge sentences, above "Work" */
	--space-3xl: clamp(
		96px,
		12vw,
		180px
	); /* between major blocks, before the footer */

	/* First screen: header + hero fill ~92% of it, so the hero's bottom line
	   (the top edge of the "Work" area) stays visible */
	--header-height: 56px;
	--hero-fill: 92;

	--line: 1px solid var(--color-line);
	/* Minimum height of anything tapped: buttons, index entries, the
	   (invisible) tap area of the header links on touch screens */
	--tap-target: 44px;

	/* Motion */
	--ease-out: cubic-bezier(0.22, 1, 0.36, 1);
	--duration-s: 0.3s;
	--duration-m: 0.6s;
	--duration-l: 1s;
	--reveal-distance: 32px;
	--transition: var(--duration-s) var(--ease-out);
	/* Every hover underline (menu, links, buttons) draws at this speed */
	--underline: 0.45s var(--ease-out);
}

@keyframes rise {
	from {
		opacity: 0;
		transform: translateY(var(--reveal-distance));
	}
}

* {
	box-sizing: border-box;
}

html {
	scroll-behavior: smooth;
	/* Stop mobile browsers from inflating text in landscape (iOS Safari
	   boosts it after reflows, e.g. while scrolling). Was in Bootstrap. */
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

body {
	margin: 0;
	background: var(--color-bg);
	color: var(--color-text);
	font-family: var(--font-family);
	font-size: var(--text-body);
	line-height: 1.5;
	-webkit-font-smoothing: antialiased;
}

a {
	color: inherit;
}

:focus-visible {
	outline: 2px solid var(--color-text);
	outline-offset: 4px;
}

/* Lines live inside the page margins and never close a box */
.wrap {
	margin: 0 var(--gutter);
}

/* Hidden visually, still read by screen readers */
.visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
	border: 0;
}

/* Scroll reveal: hidden only when JS is running, so content never stays invisible */
.js [data-reveal] {
	opacity: 0;
	transform: translateY(var(--reveal-distance));
	transition:
		opacity var(--duration-l) var(--ease-out),
		transform var(--duration-l) var(--ease-out);
}
.js [data-reveal].is-visible,
/* The copyright enters with the contact column above it: as the last
   line of the page it never gets past the reveal threshold on its own */
.js .site-footer__links.is-visible ~ .site-footer__legal[data-reveal] {
	opacity: 1;
	transform: none;
}

/* Underline that draws from the left */
.link-draw {
	text-decoration: none;
	background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px
		no-repeat;
	padding-bottom: 2px;
	transition: background-size var(--underline);
}
.link-draw:hover,
.link-draw:focus-visible {
	background-size: 100% 1px;
}

/* Button: outlined rectangle that fills dark on hover/focus; the label also
   gets an underline, so the state change doesn't rely on color alone */
.button {
	display: inline-flex;
	align-items: center;
	/* Touch-target height, label centered by the flex alignment, whatever
	   the font metrics */
	min-height: var(--tap-target);
	padding: 0 var(--space-s);
	border: 1px solid var(--color-text);
	color: var(--color-text);
	font-size: var(--text-small);
	line-height: 1.2;
	text-decoration: none;
	/* The fill fades, the text color switches in one step shortly after:
	   fading both, text and fill pass through the same grey and the label
	   blinks out for a couple of frames */
	transition:
		background-color var(--transition),
		color 0s linear calc(var(--duration-s) / 6);
}
.button:hover,
.button:focus-visible {
	background: var(--color-text);
	color: var(--color-bg);
}
/* Same draw-in underline on a label inside a larger link (button, scroll
   cue): the whole link triggers it, only the text gets underlined */
.button__label,
.hero__cue-label {
	background: linear-gradient(currentColor, currentColor) 0 100% / 0 1px
		no-repeat;
	padding-bottom: 2px;
	transition: background-size var(--underline);
}
.button:hover .button__label,
.button:focus-visible .button__label,
.hero__cue:hover .hero__cue-label,
.hero__cue:focus-visible .hero__cue-label {
	background-size: 100% 1px;
}
/* In the button the label turns light shortly after the fill starts
   (see .button): the underline starts with that color switch, otherwise
   it's partly drawn while still invisible */
.button:hover .button__label,
.button:focus-visible .button__label {
	transition-delay: calc(var(--duration-s) / 6);
}

/* Shared bits */
/* Metadata label: classifies content (category, role, breadcrumb, ©) */
.label {
	margin: 0;
	color: var(--color-text-muted);
	font-size: var(--text-label);
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
}
/* Small heading: titles the content that follows (Approach, Contact,
   Next project, case study sections) — a step above the labels */
.heading-s {
	margin: 0;
	color: var(--color-text);
	font-size: var(--text-small);
	font-weight: normal;
	line-height: 1.5;
	letter-spacing: var(--tracking-caps-s);
	text-transform: uppercase;
}
/* Header */
.site-header {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	padding: var(--space-s) 0;
	border-bottom: var(--line);
}
/* Navigation style, shared with the breadcrumb and the case study index */
.site-header a {
	font-size: var(--text-small);
	letter-spacing: var(--tracking-caps-s);
	text-transform: uppercase;
}
.site-nav {
	display: flex;
	gap: var(--space-m);
}

/* Hero: two-column grid with a vertical guide in the middle */
.hero {
	display: grid;
	grid-template-columns: 1fr 1fr;
	/* Header + hero take ~92% of the screen: "Work" sits below the fold,
	   but the hero's bottom line is visible, hinting at what follows.
	   Also capped at 75% of the width, so tall portrait tablets don't get
	   a mostly empty hero (wide screens are unaffected) */
	min-height: min(calc(var(--hero-fill) * 1vh - var(--header-height)), 75vw);
	min-height: min(calc(var(--hero-fill) * 1svh - var(--header-height)), 75vw);
	border-bottom: var(--line);
}
/* Diagonal balance: statement top-left, aside bottom-right */
.hero__intro {
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
	gap: var(--space-l);
	padding: var(--space-l) var(--space-m) var(--space-l) 0;
	border-right: var(--line);
}
/* Hero entrance on load, staggered */
.hero__statement,
.hero__cue,
.hero__aside {
	animation: rise var(--duration-l) var(--ease-out) both;
}
.hero__aside {
	animation-delay: 0.2s;
}
.hero__cue {
	animation-delay: 0.4s;
}
/* Two columns: the statement always sits on three lines, each ending on
   its soft part. The size follows the column too: 9.2% of its width keeps
   the longest line (10.6em) inside it, so no line ever wraps */
.hero__intro {
	container-type: inline-size;
}
.hero__line {
	display: block;
	white-space: nowrap;
}
.hero__statement {
	margin: 0;
	font-size: min(var(--text-display), 9.2cqi);
	font-weight: normal;
	line-height: 1.1;
	letter-spacing: var(--tracking-tight);
}
/* Two-tone emphasis: key facts in black, connective text softer (hero
   statement, footer statement) */
.hero__statement .soft,
.site-footer__cta .soft {
	color: var(--color-text-soft);
}
/* Scroll cue: previews what's below, in the label style with a short rule */
.hero__cue {
	align-self: flex-start;
	margin-top: auto;
	padding-top: var(--space-s);
	border-top: 1px solid var(--color-text);
	font-size: var(--text-label);
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
	text-decoration: none;
}
/* Arrow on hover/focus: it slides out downwards while an identical copy
   (its text-shadow, 1.5em above) slides in from the top, clipped to the
   arrow's own box so the label never moves */
.hero__cue-arrow {
	display: inline-block;
	overflow: hidden;
	height: 1.5em;
	line-height: 1.5;
	vertical-align: top;
}
.hero__cue-arrow::before {
	content: "↓";
	display: block;
	text-shadow: 0 -1.5em 0 currentColor;
	transition: transform var(--duration-m) var(--ease-out);
}
.hero__cue:hover .hero__cue-arrow::before,
.hero__cue:focus-visible .hero__cue-arrow::before {
	transform: translateY(1.5em);
}
.hero__aside {
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	padding: var(--space-l) 0 var(--space-l) var(--space-m);
}
.hero__aside p {
	margin: 0;
	max-width: 36ch;
}
.hero__aside .heading-s {
	margin-bottom: var(--space-s);
}

/* Section heading */
.section-head {
	display: flex;
	justify-content: space-between;
	align-items: flex-start;
	padding-top: var(--space-2xl);
	border-bottom: var(--line);
}
.section-head__title {
	margin: 0;
	padding-bottom: var(--space-m);
	font-size: var(--text-giant);
	font-weight: normal;
	line-height: 0.95;
	letter-spacing: -0.03em;
}
/* Desktop: large one-line statements ("Work", "Let's work together.")
   enter letter by letter, each rising from below the text, which clips
   them. Letters stay inline and move with relative offsets, so the words
   keep their kerning. The trigger ([data-letters] → .is-visible) is in
   reveal.js. Per element: where letters start (--letters-from) and
   the delay between them (--letters-step) */
@media (min-width: 1100px) and (prefers-reduced-motion: no-preference) {
	.js [data-letters] {
		overflow: clip;
	}
	.js [data-letters] .letters span {
		position: relative;
		top: var(--letters-from);
		transition: top var(--duration-m) var(--ease-out);
		transition-delay: calc(var(--i) * var(--letters-step));
	}
	.js [data-letters].is-visible .letters span {
		top: 0;
	}
	/* The letters replace the fade of the blocks they're in ("Work", the
	   footer statement column) */
	.js .section-head[data-reveal],
	.js .site-footer__cta[data-reveal] {
		opacity: 1;
		transform: none;
	}
	/* "Work": letters rise from the grey line below it (the title's bottom
	   padding is inside the clip) */
	.section-head__title {
		--letters-from: calc(1em + var(--space-m));
		--letters-step: 40ms;
	}
	/* Footer statement: 18 letters, so a shorter step keeps the whole
	   entrance about as long as "Work". The clip is extended by 0.2em
	   below so descenders (g) aren't cut once the letters are in place */
	.site-footer__cta p {
		--letters-from: 1.3em;
		--letters-step: 15ms;
		padding-bottom: 0.2em;
		margin-bottom: -0.2em;
	}
}

/* Project rows */
.project {
	border-bottom: var(--line);
}
.project__main {
	display: grid;
	grid-template-columns: 1fr 1fr;
}
.project__text {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	gap: var(--space-l);
	/* Generous top/bottom so the intro label doesn't hug the row line */
	padding: var(--space-l) var(--space-m) var(--space-l) 0;
	border-right: var(--line);
}
/* Project intro: number + color square + category, in the label style */
.project__head {
	display: flex;
	align-items: center;
	gap: var(--space-2xs);
	margin: 0 0 var(--space-m);
	font-size: var(--text-label);
	letter-spacing: var(--tracking-caps);
	text-transform: uppercase;
}
.project__category {
	display: flex;
	align-items: center;
	gap: var(--space-2xs);
	color: var(--color-text-muted);
}
/* Project color kept as the only accent: a square, like the rectangular buttons */
.project__category::before {
	content: "";
	width: 8px;
	height: 8px;
	background: var(--project-color);
}
.project__title {
	margin: 0 0 var(--space-s);
	font-size: var(--text-title);
	font-weight: normal;
	line-height: 1.15;
}
.project__description {
	margin: 0;
	max-width: 44ch;
	color: var(--color-text-muted);
}
.project__cta {
	margin-top: var(--space-m);
}
.project__media {
	margin: 0;
	padding: var(--space-m) 0 var(--space-m) var(--space-m);
}
.project__media-inner {
	overflow: hidden;
	aspect-ratio: 16 / 9;
}
.project__media img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--duration-l) var(--ease-out);
	/* Own compositing layer from the start: if Chrome creates it only when
	   the zoom begins, nearby content (the button) can blank for a frame */
	will-change: transform;
}
/* Hovering or focusing the CTA previews the project by zooming its cover */
.project:has(.project__cta:hover, .project__cta:focus-visible)
	.project__media
	img {
	transform: scale(1.04);
}

/* Facts row: three cells split by vertical lines */
/* Facts row (desktop): same two halves as the card above — role under the
   text, focus starting where the cover starts (middle line + 32px) */
.project__facts {
	display: grid;
	grid-template-columns: 1fr 1fr;
	align-items: baseline;
	margin: 0;
	padding: var(--space-s) 0;
	border-top: var(--line);
}
.project__facts div {
	display: flex;
	align-items: baseline;
	gap: var(--space-m);
}
.project__facts div + div {
	padding-left: var(--space-m);
}
.project__facts dt {
	white-space: nowrap;
}
.project__facts dd {
	margin: 0;
	font-size: var(--text-small);
}
/* Focus in two pairs: one line on desktop (joined by a dot), one pair
   per line on mobile so the break falls between pairs, not mid-word */
.focus-pair {
	/* If the line is too short, wrap between pairs, never inside one */
	white-space: nowrap;
}
/* Dot at the end of the first pair, so on a wrap it stays at line end */
.focus-pair:not(:last-child)::after {
	content: " ·" / "";
}

/* Footer */
.site-footer {
	display: grid;
	grid-template-columns: 1fr 1fr;
	margin-top: var(--space-3xl);
	border-top: var(--line);
}
.site-footer__cta {
	padding: var(--space-m) var(--space-m) var(--space-xl) 0;
	border-right: var(--line);
}
.site-footer__cta p {
	margin: 0;
	font-size: var(--text-display);
	line-height: 1.1;
	letter-spacing: var(--tracking-tight);
}
.site-footer__links {
	display: flex;
	flex-direction: column;
	gap: var(--space-xs);
	padding: var(--space-m) 0 var(--space-xl) var(--space-m);
}
.site-footer__links .heading-s {
	margin-bottom: var(--space-xs);
}
.site-footer__links a {
	align-self: flex-start;
}
.site-footer__legal {
	grid-column: 1 / -1;
	padding: var(--space-s) 0;
	border-top: var(--line);
}

@media (max-width: 767px) {
	/* Facts: label column only as wide as the longest label, so values
	   get more room and wrap on fewer lines */
	.project__facts {
		display: grid;
		grid-template-columns: max-content 1fr;
		column-gap: var(--space-m);
		row-gap: var(--space-xs);
	}
	.project__facts div {
		display: contents;
	}
	.focus-pair {
		display: block;
		white-space: normal;
	}
	.focus-pair:not(:last-child)::after {
		content: none;
	}
	.hero,
	.project__main,
	.site-footer {
		grid-template-columns: 1fr;
	}
	/* Stacked hero: height follows the content */
	.hero {
		min-height: auto;
	}
	/* "Work" follows right after on a single column */
	.hero__cue {
		display: none;
	}
	.hero__intro,
	.project__text {
		border-right: 0;
	}
	/* Hero statement: 64px above and below, like the desktop hero;
	   personal notes below get 32px, like other secondary blocks */
	.hero__intro {
		padding: var(--space-l) 0;
	}
	/* Statement sits on its bottom line, like "Work": large space above,
	   32px below */
	/* Statement: a bit more room above than "Work" gets (80px), as it
	   closes the page after the last card */
	.site-footer__cta {
		padding: calc(var(--space-2xl) + var(--space-m)) 0 var(--space-m);
		border-right: 0;
	}
	/* Single column: the last card's line already closes the projects, so
	   the footer drops its own line and gap */
	.site-footer {
		margin-top: 0;
		border-top: 0;
	}
	.hero__aside {
		padding: var(--space-m) 0;
		border-top: var(--line);
	}
	.project__main {
		display: flex;
		flex-direction: column-reverse;
	}
	.project__media {
		padding: var(--space-m) 0 0;
	}
	.project__text {
		gap: var(--space-m);
		padding: var(--space-m) 0;
	}
	/* Breathing room before every project, the first one included, so the
	   gap under "Work" matches the gap between cards */
	.project {
		margin-top: var(--space-l);
	}
	.site-footer__links {
		padding: var(--space-m) 0;
		border-top: var(--line);
	}
	.site-nav {
		gap: var(--space-s);
	}
}

/* Portrait tablets up to 899px and phones in landscape: the text column is
   taller than a 16:9 cover, leaving a gap under it; stack the card like on
   mobile (full cover on top) and list role above focus, as on mobile */
@media (min-width: 768px) and (max-width: 899px) and (orientation: portrait),
	(max-height: 500px) and (orientation: landscape) {
	.project__facts {
		display: grid;
		grid-template-columns: max-content 1fr;
		column-gap: var(--space-m);
		row-gap: var(--space-xs);
	}
	.project__facts div {
		display: contents;
	}
	.project__main {
		display: flex;
		flex-direction: column-reverse;
	}
	.project__media {
		padding: var(--space-m) 0 0;
	}
	/* Same rhythm as mobile portrait: 32px before the facts row, more room
	   between one project and the next */
	.project__text {
		gap: var(--space-m);
		padding: var(--space-m) 0;
		border-right: 0;
	}
	.project {
		margin-top: var(--space-l);
	}
}

/* Touch screens: header links (menu, breadcrumb) get an invisible
   tap area around them; nothing changes visually */
@media (pointer: coarse) {
	.site-header a {
		position: relative;
	}
	.site-header a::after {
		content: "";
		position: absolute;
		inset: calc((100% - var(--tap-target)) / 2) calc(var(--space-xs) * -1);
	}
}

/* Phones in landscape (short screens): hero in a single column with its
   height on the content, like on mobile portrait */
@media (max-height: 500px) and (orientation: landscape) {
	/* Type stays at the mobile portrait sizes: the large steps would
	   otherwise grow with the (wider) landscape width */
	:root {
		--text-giant: 72px;
		--text-display: 32px;
		--text-headline: 28px;
		--text-title: 24px;
		--text-bridge: 20px;
		--text-body: 16px;
	}
	/* Project cards on two columns, like desktop: a stacked full-width cover
	   would be taller than the screen. The cover fills the card height
	   (cropped at the sides), so no gap is left under it */
	.project__main {
		display: grid;
		grid-template-columns: 1fr 1fr;
	}
	.project__text {
		padding: var(--space-m) var(--space-m) var(--space-m) 0;
		border-right: var(--line);
	}
	.project__media {
		display: flex;
		padding: var(--space-m) 0 var(--space-m) var(--space-m);
	}
	.project__media-inner {
		flex: 1;
		aspect-ratio: auto;
	}
	.hero {
		grid-template-columns: 1fr;
		min-height: auto;
	}
	.hero__intro {
		padding-right: 0;
		border-right: 0;
	}
	.hero__aside {
		padding: var(--space-m) 0;
		border-top: var(--line);
	}
	.hero__cue {
		display: none;
	}
}

/* Single-column hero (mobile, phones in landscape): the statement wraps
   freely at its usual size, no fixed three lines; personal notes, now
   below it, use the full width instead of the side column's measure */
@media (max-width: 767px), (max-height: 500px) and (orientation: landscape) {
	.hero__line {
		display: inline;
		white-space: normal;
	}
	.hero__statement {
		font-size: var(--text-display);
	}
	.hero__aside p {
		max-width: none;
	}
}

/* Small phones in landscape (e.g. iPhone SE, 8): a two-column card would
   crop the cover into a tall strip; stack it instead, full uncropped cover
   (at this width a 16:9 cover still fits in the screen height) */
@media (max-height: 500px) and (max-width: 699px) and (orientation: landscape) {
	.project__main {
		display: flex;
		flex-direction: column-reverse;
	}
	.project__text {
		padding: var(--space-m) 0;
		border-right: 0;
	}
	.project__media {
		display: block;
		padding: var(--space-m) 0 0;
	}
	.project__media-inner {
		aspect-ratio: 16 / 9;
	}
}

/* Very narrow phones: keep only the role, the focus would take 3+ lines */
@media (max-width: 374px) {
	.project__facts div:has(.focus-pair) {
		display: none;
	}
}

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}
	*,
	::before,
	::after {
		animation: none !important;
		transition: none !important;
	}
	.js [data-reveal] {
		opacity: 1;
		transform: none;
	}
	.project:has(.project__cta:hover, .project__cta:focus-visible)
		.project__media
		img {
		transform: none;
	}
}
