/* ==========================================================================
   CONTROL. Shared components: wordmark, header, buttons, eyebrows,
   visuals, forms, footer, inner pages, carriage track.
   ========================================================================== */

/* ---- Wordmark: the period is the signature ---- */
.cp-wordmark {
	font-family: var(--cp-font-sans);
	font-weight: 700;
	letter-spacing: 0.22em;
	text-transform: uppercase;
	font-size: 1rem;
	line-height: 1;
	white-space: nowrap;
}

.cp-wordmark__dot {
	color: var(--cp-accent);
}

.cp-wordmark--footer {
	font-size: clamp(1.5rem, 4vw, 2.25rem);
}

/* ---- Header (Corentin's composition, round 11) ----
   Two pages either side of the centred lockup, the CTA as a filled box at the
   end of the right hand group. The bar is a three column grid, 1fr auto 1fr,
   so the brand sits on the page's centre line whatever the two groups weigh;
   on wide screens the nav gives up its own box and its two groups take the
   outer cells, on narrow ones it is the overlay again (below). The bar stays
   transparent: every section is dark now, so the text is white throughout
   and the tone flip below only ever has one answer to give. */
.cp-header {
	position: fixed;
	inset: 0 0 auto 0;
	z-index: 100;
	transition: background-color var(--cp-dur-ui) ease, box-shadow var(--cp-dur-ui) ease;
}

.admin-bar .cp-header {
	top: 32px;
}

@media (max-width: 782px) {
	.admin-bar .cp-header {
		top: 46px;
	}
}

.cp-header__inner {
	max-width: var(--cp-container-max);
	margin-inline: auto;
	padding-inline: var(--cp-gutter);
	height: var(--cp-header-h);
	display: grid;
	grid-template-columns: 1fr auto 1fr;
	align-items: center;
	column-gap: var(--cp-s3);
}

/* THE LOCKUP: chrome wordmark, descriptor hung under its right half in two
   stepped lowercase lines, which is the plate that opens the charte. The
   descriptor is positioned off the wordmark's box rather than flowed, so the
   grid cell is the wordmark's width and the brand stays exactly centred. */
/* THE WHOLE LOCKUP IS CENTRED, not the mark alone. The descriptor is in the
   flow now, stepped in by 54 per cent of the mark's width (computed from the
   mark's height and the file's 1567 by 789 aspect), so the brand box is the
   union of mark and descriptor and centring the box centres what the eye
   sees. His mockup does the same: mark centre 737, lockup centre 750, frame
   centre 748. The first build hung the descriptor off the box and centred
   the mark, which read as sitting to the right (Daffa, 2026-09-23). */
.cp-header__brand {
	grid-column: 2;
	grid-row: 1;
	justify-self: center;
	position: relative;
	display: inline-flex;
	flex-direction: column;
	align-items: flex-start;
	text-decoration: none;
	color: #ffffff;
}

/* The wordmark is 34px tall on a phone, under the 44px a finger needs. The
   hit area grows through a pseudo-element so the lockup itself, and the
   descriptor hung off its box, do not move by a pixel. */
.cp-header__brand::before {
	content: "";
	position: absolute;
	inset: -0.4rem -0.5rem;
}

.cp-logo {
	display: block;
	width: auto;
}

/* --cp-header-h is derived from this value and the descriptor under it so
   the charte's clear space band comes out right; see the note beside the
   token before changing either. */
.cp-header__mark {
	height: var(--cp-logo-h);
	width: auto;
	filter: drop-shadow(0 6px 14px rgba(0, 0, 0, 0.35));
}

.cp-header__desc {
	margin-top: -0.2rem;
	margin-inline-start: calc(var(--cp-logo-h) * 1.986 * 0.54);
	display: flex;
	flex-direction: column;
	font-family: var(--cp-font-display);
	/* Scales with the mark (about 15px under a 64px mark, as his mockup),
	   with a floor so the phone lockup stays legible. */
	font-size: max(0.68rem, calc(var(--cp-logo-h) * 0.235));
	line-height: 1.05;
	letter-spacing: 0.02em;
	color: var(--cp-creme);
	white-space: nowrap;
}

.cp-header__desc span + span {
	padding-inline-start: 1.1em;
}

.cp-header__nav {
	display: flex;
	align-items: center;
	gap: clamp(1rem, 3vw, 2.5rem);
}

.cp-header__group {
	display: flex;
	align-items: center;
	gap: clamp(1rem, 3vw, 2.5rem);
}

/* Display serif, at the client's request: "I find Montserrat a bit too thin
   here" (2026-08-08). Measured at 1024 the labels set narrower in Erode than
   in Montserrat, so the row gets NARROWER, not wider. A label is a unit: the
   gap clamp absorbs the squeeze rather than a label breaking into two rows. */
.cp-header__link {
	font-family: var(--cp-font-display);
	font-size: 0.95rem;
	font-weight: 400;
	letter-spacing: 0.02em;
	text-decoration: none;
	color: #ffffff;
	position: relative;
	padding: 0.35em 0.7em;
	border-radius: 3px;
	transition: color var(--cp-dur-ui) ease, background-color var(--cp-dur-ui) ease;
	white-space: nowrap;
}

/* THE FILLED BOX IS THE HOVER STATE, NOT THE CURRENT PAGE. His mockup paints
   one label as a dark box and the first build read that as "the page you are
   on"; on the homepage, where "Le Projet" is that page, it looked like a
   button stuck down (Daffa, 2026-09-23). So the box answers the pointer and
   the keyboard only, and the current page gets the thin rule instead. */
.cp-header__link::after {
	content: "";
	position: absolute;
	left: 0.7em;
	right: 0.7em;
	bottom: 0.15em;
	height: 1px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--cp-dur-ui) var(--cp-ease-out);
}

@media (hover: hover) {
	.cp-header__link:hover {
		background: rgba(20, 0, 6, 0.5);
	}
}

.cp-header__link:focus-visible {
	background: rgba(20, 0, 6, 0.5);
}

.cp-header__link.is-current::after {
	transform: scaleX(1);
}

/* WHITE EVERYWHERE, no tone flip. The header used to turn ink over a light
   section, and main.js still probes data-tone under it; but every section
   is dark since round 11, and the probe falls back to "light" over anything
   without the attribute (the marquee divider on the Vision page), which
   painted the row black on a burgundy ground (Daffa, 2026-09-23: "warna
   teks header nav menu terang sudah pas di semua section"). Pure white
   rather than --cp-text-light, because the header is a sibling of the dark
   sections and never inherits their token overrides; the old creme white
   measured 3.85 over the red, under AA. */
.cp-header__brand,
.cp-header__link,
.cp-lang,
.cp-header__toggle {
	color: #ffffff;
}

/* THE LANGUAGE SWITCH. One link to the other language, not a pair. Quiet by
   construction: it sits after a filled box and must not compete with it, so
   it is small, letterspaced and outlined only. Registered in the data-over
   list above, since the flip is a selector list rather than inheritance. */
.cp-lang {
	--i: 6;
	flex: 0 0 auto;
	font-size: var(--cp-fs-eyebrow);
	font-weight: 600;
	letter-spacing: 0.14em;
	text-decoration: none;
	color: #ffffff;
	line-height: 1;
	padding: 0.45em 0.6em;
	border: 1px solid currentColor;
	border-radius: 999px;
	opacity: 0.75;
	transition: opacity var(--cp-dur-ui) ease;
}

@media (hover: hover) {
	.cp-lang:hover {
		opacity: 1;
	}
}

.cp-lang:focus-visible {
	opacity: 1;
}

/* Wide screens: the nav dissolves into the grid and its two groups take the
   cells either side of the brand. SYMMETRIC ABOUT THE LOCKUP: each group
   hugs the centre with the grid's column gap, so the page before the mark
   and the page after it sit at the same distance from it, and the outer
   items go to the outer edge inside a small inset, as his row does. The
   first build spread each group evenly over its half, and with four items
   on the right against two on the left the gaps beside the mark came out
   143 and 61 (Daffa, 2026-09-23: "gak pas gap space nya antara kiri dan
   kanan"). */
@media (min-width: 64em) {
	.cp-header__inner {
		column-gap: clamp(2rem, 5.5vw, 5.5rem);
	}

	.cp-header__nav {
		display: contents;
	}

	.cp-header__group {
		grid-row: 1;
		justify-content: space-between;
		gap: var(--cp-s2);
	}

	/* The outer inset is zero at 64em, where four items on the right already
	   fill their half, and grows to 3rem by about 79em. With a fixed inset
	   the right column outgrew its 1fr at 1024 and pushed the lockup 30px
	   off centre. */
	.cp-header__group--start {
		grid-column: 1;
		padding-inline-start: clamp(0rem, (100vw - 64rem) * 0.2, 3rem);
	}

	.cp-header__group--end {
		grid-column: 3;
		padding-inline-end: clamp(0rem, (100vw - 64rem) * 0.2, 3rem);
	}
}

/* --------------------------------------------------------------------------
   Small screens: a real menu, because four of these items are pages

   DEFAULT IS OPEN, AND THE COLLAPSE HAPPENS BEFORE PAINT. The links below
   64em stay visible until cp-nav-js is on the document. The inline head
   script sets it, so the collapsed header is the first thing painted rather
   than a full row of links folding away a frame later. main.js then vouches
   for the toggle with data-nav-ready, and if that never arrives the head
   script drops cp-nav-js again. A script that fails still leaves a plain
   wrapped row, never a button that opens nothing.
   -------------------------------------------------------------------------- */
.cp-header__toggle {
	display: none;
	grid-column: 1;
	grid-row: 1;
	justify-self: start;
	place-items: center;
	width: var(--cp-tap);
	height: var(--cp-tap);
	margin-inline-start: -0.5rem;
	padding: 0;
	background: none;
	border: 0;
	cursor: pointer;
	color: #ffffff;
}

.cp-header__toggle-bars,
.cp-header__toggle-bars::before,
.cp-header__toggle-bars::after {
	display: block;
	width: 22px;
	height: 1.5px;
	background: currentColor;
	transition: transform var(--cp-dur-ui) var(--cp-ease-out), opacity var(--cp-dur-ui) ease;
}

.cp-header__toggle-bars {
	position: relative;
}

.cp-header__toggle-bars::before,
.cp-header__toggle-bars::after {
	content: "";
	position: absolute;
	left: 0;
}

.cp-header__toggle-bars::before { top: -6.5px; }
.cp-header__toggle-bars::after { top: 6.5px; }

.cp-header__toggle[aria-expanded="true"] .cp-header__toggle-bars {
	background: transparent;
}

.cp-header__toggle[aria-expanded="true"] .cp-header__toggle-bars::before {
	transform: translateY(6.5px) rotate(45deg);
}

.cp-header__toggle[aria-expanded="true"] .cp-header__toggle-bars::after {
	transform: translateY(-6.5px) rotate(-45deg);
}

html.cp-nav-lock,
html.cp-nav-lock body {
	overflow: hidden;
}

/* 64em, not 48: portrait tablets get the overlay too. The inline row only
   returns where it genuinely has room. */
@media (max-width: 63.9375em) {
	/* The no script fallback: the nav is a wrapped row under the bar, and the
	   bar grows to hold it. --cp-header-h stays as the floor. */
	.cp-header__inner {
		height: auto;
		min-height: var(--cp-header-h);
		row-gap: var(--cp-s2);
		padding-block: var(--cp-s2);
	}

	.cp-header__nav {
		grid-column: 1 / -1;
		grid-row: 2;
		flex-wrap: wrap;
		justify-content: center;
		gap: var(--cp-s2) var(--cp-s3);
	}

	.cp-header__group {
		display: contents;
	}

	html.cp-nav-js .cp-header__inner {
		height: var(--cp-header-h);
		padding-block: 0;
	}

	/* Only once the script is running does any of this hide. */
	html.cp-nav-js .cp-header__toggle {
		display: grid;
	}

	/* THE OVERLAY. Full screen burgundy, links set in the display face: the
	   menu is a place, not a dropdown. Solid ground on purpose, and its own
	   overflow so short landscape screens scroll INSIDE it while the page
	   behind stays locked. */
	html.cp-nav-js .cp-header__nav {
		position: fixed;
		inset: 0;
		z-index: 1;
		display: flex;
		flex-direction: column;
		align-items: flex-start;
		justify-content: center;
		gap: clamp(0.9rem, 3vh, 1.75rem);
		padding: calc(var(--cp-header-h) + var(--cp-s3)) var(--cp-gutter) var(--cp-s5);
		background: var(--cp-section-deep);
		color: #ffffff;
		overflow-y: auto;
		overscroll-behavior: contain;
		visibility: hidden;
		opacity: 0;
		transition: opacity 0.3s ease, visibility 0s linear 0.3s;
	}

	html.cp-nav-js .cp-header__nav .cp-header__link {
		padding: 0;
		font-size: clamp(2rem, 7.5vw, 3.25rem);
		line-height: 1.12;
		letter-spacing: -0.01em;
		background: none;
		opacity: 0;
		transform: translateY(16px);
		transition: opacity 0.4s ease, transform 0.45s var(--cp-ease-out);
	}

	html.cp-nav-js .cp-header__nav .cp-header__link.is-current::after {
		display: block;
		left: 0;
		right: auto;
		width: 100%;
		bottom: -0.1em;
		transform: scaleX(1);
	}

	/* The permanent CTA rides at the foot of the list, one size up. */
	html.cp-nav-js .cp-header__nav .cp-btn {
		margin-top: var(--cp-s3);
		opacity: 0;
		transform: translateY(16px);
		transition: opacity 0.4s ease, transform 0.45s var(--cp-ease-out);
	}

	html.cp-nav-js .cp-header.is-navopen .cp-header__nav {
		visibility: visible;
		opacity: 1;
		transition-delay: 0s;
	}

	/* The switch rides at the very bottom of the overlay, under the CTA. */
	html.cp-nav-js .cp-header__nav .cp-lang {
		align-self: flex-start;
		margin-top: var(--cp-s2);
		opacity: 0;
		transform: translateY(16px);
		transition: opacity 0.4s ease, transform 0.45s var(--cp-ease-out);
	}

	/* The walk-in: each item carries its own --i from the template, so the
	   stagger follows the order printed rather than a fixed child count. */
	html.cp-nav-js .cp-header.is-navopen .cp-header__nav .cp-header__link,
	html.cp-nav-js .cp-header.is-navopen .cp-header__nav .cp-btn,
	html.cp-nav-js .cp-header.is-navopen .cp-header__nav .cp-lang {
		opacity: 1;
		transform: translateY(0);
		transition-delay: calc(0.05s + var(--i, 0) * 0.06s);
	}

	.cp-header.is-navopen .cp-header__toggle { color: #ffffff; }
	.cp-header.is-navopen .cp-header__brand { position: relative; z-index: 2; }
}

@media (max-width: 63.9375em) and (prefers-reduced-motion: reduce) {
	html.cp-nav-js .cp-header__nav,
	html.cp-nav-js .cp-header__nav .cp-header__link,
	html.cp-nav-js .cp-header__nav .cp-btn,
	html.cp-nav-js .cp-header__nav .cp-lang,
	html.cp-nav-js .cp-header.is-navopen .cp-header__nav .cp-header__link,
	html.cp-nav-js .cp-header.is-navopen .cp-header__nav .cp-btn,
	html.cp-nav-js .cp-header.is-navopen .cp-header__nav .cp-lang {
		transition: none;
	}
}

@media (max-width: 29.9375em) {
	.cp-header__inner {
		column-gap: var(--cp-s2);
	}
}

/* ---- Carriage track: scroll progress as a gliding dot ---- */
.cp-track {
	position: fixed;
	right: 1.5rem;
	top: 20vh;
	height: 60vh;
	width: 1px;
	background: rgba(143, 133, 122, 0.35);
	z-index: 90;
}

.cp-track__dot {
	position: absolute;
	left: 50%;
	top: 0;
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--cp-accent);
	transform: translate(-50%, 0);
	transition: transform 0.15s linear;
}

@media (max-width: 63.9375em) {
	.cp-track {
		display: none;
	}
}

/* ---- Buttons: pill = the period, stretched ---- */
.cp-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5em;
	min-height: 3rem;
	white-space: nowrap;
	padding: 0.75rem 1.75rem;
	border: 1px solid transparent;
	border-radius: var(--cp-radius-pill);
	font-family: var(--cp-font-sans);
	font-size: var(--cp-fs-small);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	text-decoration: none;
	cursor: pointer;
	background: var(--cp-ink);
	color: var(--cp-text-light);
	transition: background-color var(--cp-dur-ui) ease, color var(--cp-dur-ui) ease, border-color var(--cp-dur-ui) ease, transform var(--cp-dur-ui) var(--cp-ease-out);
}

.cp-btn:active {
	transform: scale(0.95);
}

@media (hover: hover) {
	.cp-btn:hover {
		background: var(--cp-ink-soft);
	}
}

.cp-btn--light {
	background: var(--cp-plaster);
	color: var(--cp-ink);
}

@media (hover: hover) {
	.cp-btn--light:hover {
		background: var(--cp-plaster-deep);
	}
}

.cp-btn--dark {
	background: var(--cp-ink);
	color: var(--cp-text-light);
}

.cp-btn--ghost {
	background: transparent;
	color: var(--cp-text-light);
	border-color: var(--cp-border-dark);
}

@media (hover: hover) {
	.cp-btn--ghost:hover {
		border-color: var(--cp-text-light);
		background: transparent;
	}
}

.cp-btn--small {
	min-height: 2.5rem;
	padding: 0.5rem 1.25rem;
	font-size: 0.75rem;
}

/* His "Rejoindre": a filled raspberry box in the display face, sentence
   case, square corners. Not a pill and not uppercase, on purpose, so it
   reads as a fifth word in the row that happens to be lit. Both header
   states and the dark sections would otherwise repaint it as the light
   pill, hence the explicit colours at every level. */
.cp-btn--cta,
.cp-header[data-over="dark"] .cp-btn--cta,
.cp-header[data-over="light"] .cp-btn--cta,
.cp-section--dark .cp-btn--cta {
	min-height: 0;
	padding: 0.5em 1.2em;
	border-radius: 3px;
	font-family: var(--cp-font-display);
	font-size: 0.95rem;
	font-weight: 500;
	letter-spacing: 0.01em;
	text-transform: none;
	background: var(--cp-cta);
	color: var(--cp-creme);
}

@media (hover: hover) {
	.cp-btn--cta:hover,
	.cp-header[data-over="dark"] .cp-btn--cta:hover,
	.cp-header[data-over="light"] .cp-btn--cta:hover {
		background: #b3204f;
		color: #ffffff;
	}
}

/* Mobile first, and the reason is arithmetic rather than taste. `.cp-btn` sets
   white-space: nowrap and this variant added a fixed 2.75rem of padding on each
   side, so the pill's width was a CONSTANT 279px at every viewport - measured, it
   never moved once between 320 and 414. The waitlist form's own column is 230px at
   320 and 270px at 360, so the pill broke out of the form across that whole band
   and at 320 it pushed the page 4px wide, the only horizontal overflow on the
   site. Below 23.5em the pill goes full width and its label is allowed to wrap,
   which removes the constant instead of trying to out-pad it; above, nothing about
   the desktop pill changes. 23.5em rather than a px value on purpose: a larger
   root font makes the label wider too, so the crossover should move with it. */
.cp-btn--wide {
	display: flex;
	width: 100%;
	padding-inline: var(--cp-s2);
	white-space: normal;
}

@media (min-width: 23.5em) {
	.cp-btn--wide {
		display: inline-flex;
		width: auto;
		padding-inline: 2.75rem;
		white-space: nowrap;
	}
}

/* ---- Eyebrow + dot marker ---- */
.cp-eyebrow {
	display: flex;
	align-items: center;
	gap: 0.75em;
	font-size: var(--cp-fs-eyebrow);
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--cp-text-muted);
	margin: 0 0 var(--cp-s3);
}

.cp-eyebrow--light {
	color: var(--cp-text-light-muted);
}

.cp-dotmark {
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--cp-accent);
	flex: 0 0 auto;
}

.cp-eyebrow--light .cp-dotmark {
	background: var(--cp-accent-light);
}

/* ---- Section headings ---- */
.cp-h2 {
	font-size: var(--cp-fs-h2);
	letter-spacing: -0.01em;
	max-width: 18ch;
}

.cp-h2 .cp-line {
	display: block;
}

.cp-section-head {
	margin-bottom: clamp(2.5rem, 6vw, 4.5rem);
}

/* ---- CMS-replaceable visuals with designed placeholders ---- */

/* THE FRAME CARRIES NO COLOUR OF ITS OWN, and that is the fix for a hairline
   that outlined every plate on a dark ground. The base tint used to live here,
   under both the placeholder and any real photograph. A photograph covers it,
   but only to the edge: the plate lands on fractional pixels (533.78 x 897.67
   at 1440, measured), so the boundary pixel is part image and part whatever is
   painted behind it, and what was behind it was creme. Sampled on La Vision,
   the edge read 17 to 24 per cent creme on all four sides -- consistent across
   all three channels, which is what identified the blend -- and creme against
   this section's bourgogne ground is a 12:1 step, so it read as a drawn border.

   It only ever showed in one place. cp_visual() is used by Les Evidences, whose
   ground is beige, and by La Vision, whose ground is dark: the same hairline was
   there all along and invisible against beige.

   The tone belongs to the placeholder, so it moves there. Every tone variant
   below already paints its own opaque background on .cp-visual__ph, so nothing
   about an empty slot changes; the base is now only the fallback for a tone that
   matched no variant, which is the one case that used to render bare. */
.cp-visual {
	position: relative;
	overflow: hidden;
	border-radius: var(--cp-radius);
}

.cp-visual__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.cp-visual__ph {
	position: absolute;
	inset: 0;
	display: block;
	background: var(--cp-plaster-deep);
}

.cp-visual__ph::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: var(--cp-grain);
	opacity: 0.14;
	mix-blend-mode: overlay;
	pointer-events: none;
}

/* Last-resort placeholder compositions: an "architectural" arch of light so
   empty slots still read as interiors, never as broken images. */
.cp-visual__ph::before {
	content: "";
	position: absolute;
	left: 50%;
	bottom: 0;
	width: 56%;
	height: 78%;
	transform: translateX(-50%);
	border-radius: 999px 999px 0 0;
	pointer-events: none;
}

.cp-visual--ink .cp-visual__ph {
	background:
		radial-gradient(120% 90% at 15% 0%, rgba(241, 237, 230, 0.22) 0%, rgba(241, 237, 230, 0) 55%),
		radial-gradient(80% 60% at 85% 100%, rgba(107, 121, 80, 0.38) 0%, rgba(107, 121, 80, 0) 60%),
		linear-gradient(150deg, #3a362e 0%, #1c1a16 70%);
}

.cp-visual--ink .cp-visual__ph::before {
	background: linear-gradient(to top, rgba(241, 237, 230, 0.14), rgba(241, 237, 230, 0.02));
	box-shadow: inset 0 0 0 1px rgba(241, 237, 230, 0.08);
}

.cp-visual--plaster .cp-visual__ph::before {
	background: linear-gradient(to top, rgba(28, 26, 22, 0.16), rgba(28, 26, 22, 0.03));
	box-shadow: inset 0 0 0 1px rgba(28, 26, 22, 0.08);
}

.cp-visual--matcha .cp-visual__ph::before {
	background: linear-gradient(to top, rgba(241, 237, 230, 0.16), rgba(241, 237, 230, 0.02));
	box-shadow: inset 0 0 0 1px rgba(241, 237, 230, 0.1);
}

.cp-visual--clay .cp-visual__ph::before {
	background: linear-gradient(to top, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.04));
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}

.cp-visual--plaster .cp-visual__ph {
	background:
		radial-gradient(100% 80% at 80% 10%, rgba(255, 255, 255, 0.55) 0%, rgba(255, 255, 255, 0) 55%),
		linear-gradient(160deg, #e7e1d8 0%, #d5cec1 100%);
}

.cp-visual--matcha .cp-visual__ph {
	background:
		radial-gradient(110% 80% at 20% 5%, rgba(241, 237, 230, 0.22) 0%, rgba(241, 237, 230, 0) 55%),
		linear-gradient(155deg, #6b7950 0%, #49543a 100%);
}

.cp-visual--clay .cp-visual__ph {
	background:
		radial-gradient(110% 80% at 75% 0%, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0) 55%),
		linear-gradient(155deg, #b0a48e 0%, #8e8271 100%);
}

/* ---- Ghost words: oversized editorial layer behind content ---- */
.cp-ghost {
	position: absolute;
	z-index: 0;
	font-family: var(--cp-font-display);
	font-style: italic;
	font-size: var(--cp-fs-ghost);
	line-height: 1;
	color: transparent;
	-webkit-text-stroke: 1px rgba(28, 26, 22, 0.1);
	white-space: nowrap;
	pointer-events: none;
	user-select: none;
}

.cp-section--dark .cp-ghost {
	-webkit-text-stroke-color: rgba(241, 237, 230, 0.08);
}

/* The loading veil styles lived here (a fixed plaster overlay plus a pulsing
   brand dot, gated on html.has-js and dismissed by a class from main.js).
   Removed along with its markup and its script.

   The lesson is worth more than the effect was: NEVER let a rule that HIDES
   content depend on a class that only JavaScript can add. The show side was
   printed by PHP, so it was guaranteed; the hide side needed a script, so it
   was not. Anything decorative that covers the page must default to absent and
   be turned on by script, never the reverse. */

/* ---- Forms ---- */
.cp-field {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	min-width: 0;
}

.cp-field__label {
	font-size: var(--cp-fs-eyebrow);
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--cp-text-light-muted);
}

.cp-field__input {
	width: 100%;
	min-height: 3rem;
	padding: 0.7rem 1rem;
	font-size: 1rem;
	/* Darkening, not lightening. See the note on .cp-waitlist__formwrap: on the
	   red ground white text has one hundredth of headroom, so a light wash inside
	   an input takes its own value below AA. */
	background: rgba(0, 0, 0, 0.08);
	border: 1px solid var(--cp-border-dark);
	border-radius: var(--cp-radius);
	color: var(--cp-text-light);
	transition: border-color var(--cp-dur-ui) ease, background-color var(--cp-dur-ui) ease;
}

.cp-field__input::placeholder {
	color: var(--cp-text-light-muted);
}

.cp-field__input:focus {
	outline: none;
	border-color: var(--cp-accent-light);
	background: rgba(241, 237, 230, 0.1);
}

.cp-field__selectwrap {
	position: relative;
}

.cp-field__selectwrap::after {
	content: "";
	position: absolute;
	right: 1rem;
	top: 50%;
	width: 7px;
	height: 7px;
	border-right: 1px solid var(--cp-text-light-muted);
	border-bottom: 1px solid var(--cp-text-light-muted);
	transform: translateY(-70%) rotate(45deg);
	pointer-events: none;
}

.cp-field__select {
	appearance: none;
	-webkit-appearance: none;
	padding-right: 2.5rem;
}

.cp-field__select option {
	color: var(--cp-ink);
	background: var(--cp-plaster);
}

.cp-fieldset {
	border: 0;
	padding: 0;
	margin: 0;
}

.cp-fieldset legend {
	padding: 0;
	margin-bottom: 0.75rem;
}

.cp-pills {
	display: flex;
	flex-wrap: wrap;
	gap: 0.75rem;
}

.cp-pill {
	position: relative;
	cursor: pointer;
}

.cp-pill input {
	position: absolute;
	opacity: 0;
	inset: 0;
	cursor: pointer;
}

.cp-pill span {
	display: inline-flex;
	align-items: center;
	min-height: 2.75rem;
	padding: 0.5rem 1.25rem;
	border: 1px solid var(--cp-border-dark);
	border-radius: var(--cp-radius-pill);
	font-size: var(--cp-fs-small);
	color: var(--cp-text-light-muted);
	transition: border-color var(--cp-dur-ui) ease, color var(--cp-dur-ui) ease, background-color var(--cp-dur-ui) ease;
}

.cp-pill input:checked + span {
	border-color: var(--cp-accent-light);
	color: var(--cp-text-light);
	background: rgba(139, 154, 109, 0.14);
}

.cp-pill input:focus-visible + span {
	outline: 2px solid var(--cp-accent-light);
	outline-offset: 3px;
}

.cp-check {
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
	cursor: pointer;
	font-size: var(--cp-fs-small);
	color: var(--cp-text-light-muted);
	line-height: 1.55;
}

/* The privacy link under a consent box. Quiet by design: it has to be findable
   without competing with the box it explains, so it carries a permanent
   underline instead of extra weight or colour. Both forms that use it sit on
   the wine ground, hence the light token. */
.cp-form__legal {
	margin: 0.6rem 0 0;
	padding-inline-start: calc(1rem + 0.75rem);
	font-size: var(--cp-fs-small);
}

.cp-form__legal--center {
	padding-inline-start: 0;
	text-align: center;
}

.cp-form__legal a {
	color: var(--cp-text-light-muted);
	text-decoration: underline;
	text-underline-offset: 0.2em;
	text-decoration-thickness: from-font;
}

@media (hover: hover) {
	.cp-form__legal a:hover {
		color: var(--cp-text-light);
	}
}

/* margin, not margin-top. Browsers ship their own margin on a checkbox, 4px on
   the left in Chrome, and setting only the top left that in place: the box sat
   4px inboard of the field and the button it is stacked under, so the form had
   three controls on two different left edges. Zeroing the shorthand puts it back
   on the column. The top offset stays, it optically centres the box against the
   first line of the label rather than against the label's box. */
.cp-check input {
	width: 1.1rem;
	height: 1.1rem;
	margin: 0.15em 0 0;
	flex: 0 0 auto;
	accent-color: var(--cp-accent);
}

.cp-form-note {
	padding: 0.75rem 1rem;
	border-radius: var(--cp-radius);
	font-size: var(--cp-fs-small);
	margin-bottom: var(--cp-s3);
}

.cp-form-note--ok {
	background: rgba(139, 154, 109, 0.16);
	border: 1px solid rgba(139, 154, 109, 0.4);
}

.cp-form-note--err {
	background: rgba(178, 106, 90, 0.14);
	border: 1px solid rgba(178, 106, 90, 0.45);
}

/* ---- Footer ---- */
/* Same ground and the same token override as .cp-section--dark, spelled out
   again because the footer is not a section. See the long note in base.css for
   why nothing here can carry a translucent text tone. */
.cp-footer {
	background: var(--cp-section-deep);
	color: var(--cp-text-light);
	padding-block: var(--cp-s6) var(--cp-s4);

	--cp-text-light: #ffffff;
	--cp-text-light-muted: var(--cp-creme);
	--cp-accent-light: rgba(255, 255, 255, 0.8);
	--cp-text: #ffffff;
	--cp-text-muted: var(--cp-text-light-muted);
	--cp-accent: var(--cp-accent-light);
	--cp-border: rgba(255, 255, 255, 0.24);
	--cp-border-dark: rgba(255, 255, 255, 0.24);
}

.cp-footer__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	gap: var(--cp-s4);
}

.cp-footer__news {
	width: 100%;
	max-width: 34rem;
}

.cp-footer__contact {
	display: flex;
	align-items: center;
	justify-content: center;
	/* The icons now carry their own tap room, so the row gap gives back exactly
	   what each box gained. Derived from the two sizes rather than eyeballed, so
	   the glyph to glyph spacing still measures the 24px it was designed at. */
	gap: max(0px, calc(var(--cp-s3) - (var(--cp-tap) - 1.3rem)));
}

/* 2.75rem is 44px, and this was the only interactive thing on the site with no
   way to be hit comfortably: 21x21, the exact size of its own glyph, with no
   padding and no label wrapper to enlarge it the way the form checkboxes have.
   The glyph keeps its 1.3rem size - only the box around it grows. */
.cp-footer__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: var(--cp-tap);
	min-height: var(--cp-tap);
	color: var(--cp-text-light-muted);
	transition: color var(--cp-dur-ui) ease, transform var(--cp-dur-ui) ease;
}

.cp-footer__icon svg {
	width: 1.3rem;
	height: 1.3rem;
	display: block;
}

@media (hover: hover) {
	.cp-footer__icon:hover {
		color: var(--cp-text-light);
		transform: translateY(-2px);
	}
}

.cp-footer__icon:focus-visible {
	color: var(--cp-text-light);
}

.cp-footer__tag {
	margin: 0;
	font-size: var(--cp-fs-eyebrow);
	font-weight: 500;
	letter-spacing: 0.28em;
	text-transform: uppercase;
	color: var(--cp-text-light-muted);
}

.cp-footer__heading {
	font-size: var(--cp-fs-h3);
	margin-bottom: var(--cp-s1);
}

.cp-footer__sub {
	color: var(--cp-text-light-muted);
	font-size: var(--cp-fs-small);
	margin-bottom: var(--cp-s3);
}

/* Stacked on narrow screens, and the trigger was measured rather than guessed.
   Her footer rewrite lengthened both halves of this row at once: the placeholder
   gained a character ("Adresse e-mail") and the button went from "S'inscrire" to
   "NE RIEN MANQUER", 174.1px. Since the button never shrinks, the field absorbed
   all of it and fell to 148.9px at 375, leaving the placeholder 1.7px short --
   so it rendered as "Adresse e-mai".

   Padding could have bought those 1.7px, but the real number is worse than the
   symptom: 148.9px shows about fourteen characters of an address that is usually
   twenty or more, and the button was wider than the field it belonged to. Same
   reasoning as .cp-btn--wide above: remove the constant instead of out-padding
   it. 30em because the theme already breaks there, and because a row needs about
   466px before the field is comfortable once the button and gap are paid for. */
.cp-newsform__row {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	margin-bottom: var(--cp-s2);
}

@media (min-width: 30em) {
	.cp-newsform__row {
		flex-direction: row;
	}
}

.cp-newsform__row input[type="email"] {
	flex: 1 1 auto;
	min-width: 0;
	min-height: 2.75rem;
	padding: 0.5rem 1rem;
	font-size: 1rem;
	/* Darkening, not lightening. See the note on .cp-waitlist__formwrap: on the
	   red ground white text has one hundredth of headroom, so a light wash inside
	   an input takes its own value below AA. */
	background: rgba(0, 0, 0, 0.08);
	border: 1px solid var(--cp-border-dark);
	border-radius: var(--cp-radius-pill);
	color: var(--cp-text-light);
}

/* The footer newsletter block is centred throughout: the eyebrow, the heading,
   the line under it, the field and button row, and the social icons. The consent
   line was the one thing left ranged left, which read as a mistake rather than as
   a choice. Centring the flex row centres the pair, and the box keeps its
   alignment with the label's first line. */
.cp-check--footer {
	justify-content: center;
}

/* This input had no placeholder rule at all, so it fell through to the browser
   default, a neutral rgb(117,117,117). That was survivable on the near black
   footer and reads as dead on a warm ground. Matches the waiting list form. */
.cp-newsform__row input[type="email"]::placeholder {
	color: var(--cp-text-light-muted);
	opacity: 1; /* Firefox dims placeholders by default */
}

.cp-newsform__row input[type="email"]:focus {
	outline: none;
	border-color: var(--cp-accent-light);
}

.cp-newsform__row .cp-btn {
	flex: 0 0 auto;
}

.cp-footer__bar {
	width: 100%;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: var(--cp-s2) var(--cp-s3);
	padding-top: var(--cp-s3);
	border-top: 1px solid var(--cp-border-dark);
}

.cp-footer__legal {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: var(--cp-s3);
	margin: 0;
	padding: 0;
}

.cp-footer__legal a {
	font-size: var(--cp-fs-small);
	color: var(--cp-text-light-muted);
	text-decoration: none;
}

@media (hover: hover) {
	.cp-footer__legal a:hover {
		color: var(--cp-text-light);
	}
}

.cp-footer__copy {
	font-size: var(--cp-fs-eyebrow);
	color: var(--cp-text-light-muted);
	margin: 0;
}

/* ---- Inner pages (legal, journal, 404, search) ---- */
.cp-page {
	padding-top: calc(var(--cp-header-h) + var(--cp-s5));
	padding-bottom: var(--cp-s7);
	min-height: 60vh;
}

.cp-page__inner--center {
	text-align: center;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	min-height: 40vh;
}

.cp-page__title {
	font-size: var(--cp-fs-display);
	max-width: 20ch;
	margin-bottom: var(--cp-s4);
}

.cp-page__inner--center .cp-page__title {
	margin-inline: auto;
}

.cp-prose {
	max-width: 65ch;
}

.cp-prose h2 {
	font-size: var(--cp-fs-h3);
	margin-top: var(--cp-s5);
}

.cp-prose ul,
.cp-prose ol {
	padding-left: 1.25rem;
	margin: 0 0 var(--cp-s2);
}

.cp-prose li {
	margin-bottom: 0.5rem;
}

.cp-postlist {
	list-style: none;
	margin: 0;
	padding: 0;
}

.cp-postlist__item {
	border-bottom: 1px solid var(--cp-border-light);
}

.cp-postlist__link {
	display: flex;
	flex-wrap: wrap;
	gap: var(--cp-s2);
	align-items: baseline;
	padding-block: var(--cp-s3);
	text-decoration: none;
}

.cp-postlist__date {
	font-size: var(--cp-fs-eyebrow);
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--cp-text-muted);
	flex: 0 0 auto;
}

.cp-postlist__title {
	font-family: var(--cp-font-display);
	font-size: var(--cp-fs-h3);
}
