/**
 * Oplus — Branded Residences, shared foundation.
 * Loaded on both the collection archive and the individual brand pages.
 *
 * WHAT LIVES HERE
 * ---------------
 * Everything the two templates hold in common: the token set, the page chrome
 * (top bar, search drawer, menu overlay, preloader), buttons, pills, forms,
 * modals and the section-backdrop system.
 *
 * Page-specific composition lives in:
 *   oplus-brand-collection.css   the /branded-residences/ archive
 *   oplus-brand-single.css       an individual brand
 *
 * Both of those load after this file and may override it.
 *
 * COLOUR
 * ------
 * Two tracks, published as custom properties by oplus_brand_skin_style():
 *
 *   --obr-accent / --obr-on-accent    the brand's own colour. Chrome only:
 *                                     rules, indices, small marks, hover tints.
 *   --obr-action / --obr-on-action    contrast-resolved in PHP against the
 *                                     surface. The ONLY thing allowed to paint
 *                                     a primary button.
 *
 * That split exists because roughly half of luxury brands are monochrome.
 * Mercedes is black; painting its CTA with its accent produces a black pill on
 * a black page. Do not "simplify" these back into one variable.
 *
 * --obr-black / --obr-panel / --obr-panel-2 may also be overridden per brand
 * when the editor picks a tinted page colour. See oplus_brand_surfaces().
 *
 * MOTION
 * ------
 * Elements marked .obr-rise and containers marked [data-obr-stagger] start
 * hidden and are revealed by GSAP. The hiding is scoped to `.obr-motion`,
 * which the script only adds once it knows the libraries loaded — so a blocked
 * CDN degrades to a plain visible page rather than a blank one.
 *
 * DIRECTION
 * ---------
 * Written logical-first (inline-start/end, margin-inline, text-align: start),
 * so the Arabic RTL build needs no mirrored stylesheet.
 */


/* -------------------------------------------------------------------------
 * 1. PAGE SHELL
 * ---------------------------------------------------------------------- */

/*
 * Tokens live on the BODY, not on .obr.
 *
 * The fixed top bar, the search drawer, the menu overlay and the preloader are
 * all siblings of <main> — they are printed by header-brand.php before the .obr
 * wrapper exists. Scoping these to .obr would leave every one of them without
 * a single variable. The brand's own accent/action pair is published on :root
 * separately by oplus_brand_inline_skin().
 */
.obr-body {
	--obr-black: #000000;
	--obr-ink-0: #ffffff;
	--obr-ink-70: rgba(255, 255, 255, 0.72);
	--obr-ink-50: rgba(255, 255, 255, 0.52);
	--obr-ink-12: rgba(255, 255, 255, 0.14);
	--obr-ink-06: rgba(255, 255, 255, 0.06);

	--obr-panel: #0a0a0a;
	--obr-panel-2: #111213;

	--obr-bar: 78px;

	--obr-r: 12px;
	--obr-r-lg: 18px;
	--obr-r-pill: 999px;

	--obr-ease: cubic-bezier(0.22, 1, 0.36, 1);
	--obr-fast: 180ms;
	--obr-mid: 340ms;
	--obr-slow: 720ms;

	background: #000;
}

.obr-single {
	background: var(--obr-black);
	color: var(--obr-ink-0);
}

.obr-single .obr-shell {
	max-width: 1280px;
}

.obr-skip {
	position: absolute;
	inset-inline-start: -9999px;
	top: 0;
	z-index: 2000;
	padding: 12px 20px;
	background: #fff;
	color: #000;
	font-weight: 600;
}

.obr-skip:focus {
	inset-inline-start: 12px;
	top: 12px;
}

/*
 * The `hidden` attribute is only display:none in the UA stylesheet, so ANY
 * author `display` declaration silently beats it. Several overlays here are
 * display:flex or display:grid, which left them in an undefined state — that
 * is why the menu button appeared to do nothing.
 *
 * One guard, applied once, rather than remembering it on every overlay.
 */
.obr-body [hidden] {
	display: none !important;
}
/* -------------------------------------------------------------------------
 * 2. MOTION PRIMITIVES
 * ---------------------------------------------------------------------- */

/*
 * NOTHING IS HIDDEN HERE. This is deliberate, and it is a correction.
 *
 * The previous version set `opacity: 0` on every .obr-rise element and relied
 * on GSAP to bring each one back. That inverts the safe default: the page ships
 * invisible and only becomes visible if a chain of third-party code succeeds.
 * When one scroll trigger silently failed to fire, the entire page stayed
 * black — no console error, nothing to find, just a black rectangle. Writing a
 * timed "failsafe" to un-hide things afterwards should have been the signal
 * that the design was wrong rather than the fix.
 *
 * Hiding is now GSAP's job alone. It uses gsap.from(), which sets the start
 * state and animates out of it as one operation, so an element is only ever
 * hidden by the same code that is already committed to revealing it. If the
 * libraries never load, or a tween throws, the content is simply there.
 *
 * The only thing left in CSS is the compositor hint.
 */
.obr-motion .obr-rise,
.obr-motion [data-obr-stagger] > * {
	will-change: transform, opacity;
}
/* -------------------------------------------------------------------------
 * 3. PRELOADER
 *
 * The curtain owns its own timeline, in CSS, and dismisses itself. It does not
 * wait for script.
 *
 * That is the point. The first version was removed by JavaScript, and this
 * module's JavaScript only runs after GSAP, ScrollTrigger and Lenis have all
 * downloaded — so on a slow connection a 1.2s intro became several seconds of
 * black screen with no way out. Now every timing below is `forwards`: the
 * curtain is gone whether or not a single byte of script arrives.
 *
 * THE DRAW
 * --------
 * Two techniques, chosen by what the theme has:
 *
 *   .obr-preload--svg   real path drawing. stroke-dashoffset runs to zero, so
 *                       the mark builds itself stroke by stroke, then the fill
 *                       arrives underneath. Requires vector paths — this is
 *                       the only honest "self-drawing" logo.
 *
 *   .obr-preload--img   a wipe uncovers the raster while a thin gold light
 *                       travels along the leading edge. Reads as drawing at
 *                       speed, works with the PNG that exists today.
 *
 * Total: 1.0s draw, 0.35s hold, 0.45s lift.
 * ---------------------------------------------------------------------- */

.obr-preload {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: grid;
	place-items: center;
	align-content: center;
	gap: 30px;
	background: #000;
	/*
	 * The exit is a curtain lift, not a fade.
	 *
	 * A cross-fade tells you a layer was removed. A panel travelling upward
	 * out of frame, easing as it goes, tells you a scene has started — and it
	 * hands the eye to the hero underneath rather than dissolving into it.
	 * The page is already painted behind this, so the reveal is genuine.
	 */
	animation: obr-curtain 2100ms cubic-bezier(0.76, 0, 0.24, 1) forwards;
	will-change: transform;
}

/* Script cut it short — snap out rather than finish the timeline. */
.obr-preload.is-done {
	animation: none;
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity 420ms var(--obr-ease), visibility 420ms;
}

@keyframes obr-curtain {
	0%,
	68% {
		transform: translate3d(0, 0, 0);
		visibility: visible;
	}
	99% {
		transform: translate3d(0, -101%, 0);
		visibility: visible;
	}
	100% {
		transform: translate3d(0, -101%, 0);
		visibility: hidden;
		pointer-events: none;
	}
}

/*
 * A hairline of warm light along the curtain's trailing edge, so the lift
 * reads as an object with a boundary rather than a rectangle disappearing.
 */
.obr-preload::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	bottom: 0;
	height: 1px;
	background: linear-gradient(
		to right,
		transparent,
		rgba(232, 197, 131, 0.9) 30%,
		rgba(255, 246, 226, 1) 50%,
		rgba(232, 197, 131, 0.9) 70%,
		transparent
	);
	opacity: 0;
	animation: obr-curtain-edge 2100ms cubic-bezier(0.76, 0, 0.24, 1) forwards;
}

@keyframes obr-curtain-edge {
	0%,
	64% {
		opacity: 0;
	}
	72% {
		opacity: 1;
	}
	96%,
	100% {
		opacity: 0;
	}
}

.obr-preload-stage {
	position: relative;
	display: grid;
	place-items: center;
	/*
	 * The mark exits FIRST, then the curtain lifts. Letting them go together
	 * makes the logo look like it is being dragged off screen; releasing it a
	 * beat earlier makes the lift feel like a consequence of the mark having
	 * finished its job.
	 */
	animation: obr-preload-settle 2100ms var(--obr-ease) forwards;
}

@keyframes obr-preload-settle {
	0%,
	58% {
		transform: scale(1) translate3d(0, 0, 0);
		opacity: 1;
	}
	70%,
	100% {
		transform: scale(1.09) translate3d(0, -12px, 0);
		opacity: 0;
	}
}

/* --- Raster: wipe + travelling light ---------------------------------- */

.obr-preload-draw {
	position: relative;
	display: block;
	/* The wipe. inset() from the inline-end side, so it uncovers from the
	   start edge — and mirrors for RTL without a second keyframe set. */
	clip-path: inset(0 100% 0 0);
	animation: obr-preload-wipe 1000ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

[dir="rtl"] .obr-preload-draw {
	clip-path: inset(0 0 0 100%);
	animation-name: obr-preload-wipe-rtl;
}

@keyframes obr-preload-wipe {
	to {
		clip-path: inset(0 0 0 0);
	}
}

@keyframes obr-preload-wipe-rtl {
	to {
		clip-path: inset(0 0 0 0);
	}
}

.obr-preload-draw img {
	display: block;
	max-width: min(420px, 74vw);
	max-height: 180px;
	width: auto;
	object-fit: contain;
}

/*
 * The pen. A narrow warm bar that rides the wipe edge, brightest at its centre
 * so it reads as a light source rather than a rectangle. It is what sells the
 * illusion — the wipe alone looks like a curtain, the wipe plus a leading
 * light looks like something being made.
 */
.obr-preload-pen {
	position: absolute;
	inset-block: -6%;
	inset-inline-start: 0;
	width: 2px;
	background: linear-gradient(
		to bottom,
		transparent,
		#e8c583 18%,
		#fff6e2 50%,
		#e8c583 82%,
		transparent
	);
	box-shadow: 0 0 18px 3px rgba(232, 197, 131, 0.55);
	animation: obr-preload-pen 1000ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

@keyframes obr-preload-pen {
	0% {
		inset-inline-start: 0;
		opacity: 0;
	}
	12% {
		opacity: 1;
	}
	88% {
		opacity: 1;
	}
	100% {
		inset-inline-start: 100%;
		opacity: 0;
	}
}

/* --- Vector: genuine path drawing -------------------------------------- */

.obr-preload-svg {
	display: block;
	width: min(420px, 74vw);
}

.obr-preload-svg svg {
	display: block;
	width: 100%;
	height: auto;
	overflow: visible;
}

/*
 * Each drawable element is given its own length and delay by the script, as
 * --obr-len and --obr-delay. Strokes run first and the fill fades in behind
 * them, which is what makes a solid logo look hand-drawn rather than wiped.
 */
.obr-preload-svg [data-obr-draw] {
	stroke: #e8c583;
	stroke-width: 1;
	fill-opacity: 0;
	stroke-dasharray: var(--obr-len, 1000);
	stroke-dashoffset: var(--obr-len, 1000);
	animation:
		obr-preload-stroke 900ms cubic-bezier(0.65, 0, 0.35, 1) var(--obr-delay, 0ms) forwards,
		obr-preload-fill 480ms ease-out calc(var(--obr-delay, 0ms) + 620ms) forwards;
}

@keyframes obr-preload-stroke {
	to {
		stroke-dashoffset: 0;
	}
}

@keyframes obr-preload-fill {
	to {
		fill-opacity: 1;
		stroke-opacity: 0;
	}
}

/* --- Wordmark fallback -------------------------------------------------- */

.obr-preload-word {
	display: block;
	font-size: clamp(0.9375rem, 0.85rem + 0.55vw, 1.375rem);
	font-weight: 600;
	letter-spacing: 0.32em;
	text-transform: uppercase;
	color: #fff;
	text-align: center;
	clip-path: inset(0 100% 0 0);
	animation: obr-preload-wipe 1000ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

/* --- Progress rule ------------------------------------------------------ */

.obr-preload-bar {
	display: block;
	width: 132px;
	height: 1px;
	background: rgba(255, 255, 255, 0.14);
	overflow: hidden;
}

.obr-preload-bar i {
	display: block;
	width: 100%;
	height: 100%;
	background: linear-gradient(to right, #b8863b, #e8c583, #b8863b);
	transform-origin: left center;
	animation: obr-preload-bar 1350ms cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

[dir="rtl"] .obr-preload-bar i {
	transform-origin: right center;
}

@keyframes obr-preload-bar {
	from {
		transform: scaleX(0);
	}
	to {
		transform: scaleX(1);
	}
}

/*
 * An intro is decoration. Anyone who has asked for less motion gets the page,
 * not the performance.
 */
@media (prefers-reduced-motion: reduce) {
	.obr-preload {
		display: none;
	}
}

/* -------------------------------------------------------------------------
 * 4. TOP BAR
 * ---------------------------------------------------------------------- */

.obr-topbar {
	position: fixed;
	inset-inline: 0;
	top: 0;
	z-index: 900;
	height: var(--obr-bar);
	display: flex;
	align-items: center;
	transition: background-color 400ms var(--obr-ease),
		backdrop-filter 400ms var(--obr-ease),
		transform 400ms var(--obr-ease);
}

/* Solid only once the hero is behind us — over the film it must be invisible. */
.obr-topbar.is-stuck {
	background: rgba(0, 0, 0, 0.72);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
}

/* Hide on scroll down, show on scroll up. Reading room back when wanted. */
.obr-topbar.is-hidden {
	transform: translateY(-100%);
}

/*
 * Flex, not a three-column grid.
 *
 * The grid was `1fr auto 1fr` and depended on a centre child existing. Once the
 * section wordmark was removed there were only two children, so the tools took
 * the middle track and drifted into the centre of the bar. space-between holds
 * the ends apart whether the bar carries two items or three.
 */
.obr-topbar-inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 20px;
	width: 100%;
	max-width: 1440px;
	margin-inline: auto;
	padding-inline: clamp(18px, 3vw, 40px);
}

.obr-topbar-home {
	justify-self: start;
	display: inline-flex;
	align-items: center;
	text-decoration: none;
}

/*
 * The Branded Residences lockup, not the corporate logo.
 *
 * Three lines deep — wordmark, rule, section name, Arabic — so it needs real
 * height to stay legible. It was set far too small and read as a smudge.
 *
 * The white treatment is a filter rather than a second asset: the supplied
 * file has charcoal type that disappears on a black bar, and
 * `brightness(0) invert(1)` flattens any artwork to pure white while keeping
 * its alpha. One file serves both surfaces, and swapping the logo later needs
 * no new export.
 */
.obr-topbar-logo,
.obr-topbar-home img,
.obr-topbar-logo--svg svg {
	height: clamp(52px, 5.4vw, 74px);
	width: auto;
	max-width: min(300px, 52vw);
	object-fit: contain;
	object-position: left center;
	filter: brightness(0) invert(1);
	opacity: 0.96;
	transition: opacity var(--obr-fast) var(--obr-ease);
}

[dir="rtl"] .obr-topbar-logo,
[dir="rtl"] .obr-topbar-home img {
	object-position: right center;
}

.obr-topbar-home:hover .obr-topbar-logo,
.obr-topbar-home:hover img {
	opacity: 1;
}

.obr-topbar-logo--svg {
	display: inline-flex;
	align-items: center;
}

.obr-topbar-wordmark {
	color: #fff;
	font-size: 1.25rem;
	font-weight: 700;
	letter-spacing: 0.16em;
}

.obr-topbar-brand {
	justify-self: center;
	display: inline-flex;
	align-items: center;
	text-decoration: none;
}

.obr-topbar-brand img {
	height: clamp(34px, 4vw, 48px);
	width: auto;
	max-width: min(300px, 34vw);
	object-fit: contain;
}

.obr-topbar-brandtext {
	justify-self: center;
	color: #fff;
	font-size: 0.9375rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

.obr-topbar-tools {
	justify-self: end;
	display: flex;
	align-items: center;
	gap: 6px;
}

.obr-iconbtn {
	display: grid;
	place-items: center;
	width: 46px;
	height: 46px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: #fff;
	cursor: pointer;
	transition: background-color var(--obr-fast) var(--obr-ease);
}

.obr-iconbtn:hover {
	background: rgba(255, 255, 255, 0.1);
}

.obr-iconbtn:focus-visible {
	outline: 2px solid #fff;
	outline-offset: 2px;
}

.obr-burger-lines {
	display: block;
	width: 24px;
	height: 12px;
	position: relative;
}

.obr-burger-lines i {
	position: absolute;
	inset-inline: 0;
	height: 2px;
	background: currentColor;
	transition: transform 320ms var(--obr-ease), opacity 200ms linear;
}

.obr-burger-lines i:first-child {
	top: 0;
}

.obr-burger-lines i:last-child {
	bottom: 0;
}

.obr-burger[aria-expanded="true"] .obr-burger-lines i:first-child {
	transform: translateY(5px) rotate(45deg);
}

.obr-burger[aria-expanded="true"] .obr-burger-lines i:last-child {
	transform: translateY(-5px) rotate(-45deg);
}

@media (max-width: 900px) {
	/*
	 * The centre slot goes on a phone.
	 *
	 * A three-column bar needs roughly 700px to hold a logo, a brand mark and
	 * two controls without them touching. Below that the Oplus logo and the
	 * centred wordmark overlapped — visible in testing as two pieces of text
	 * printed on top of each other. Both the image and the text variant have to
	 * be hidden; the first pass only hid the image, which is why the archive
	 * still collided while the brand page looked fine.
	 */
	.obr-topbar-brand,
	.obr-topbar-brandtext {
		display: none;
	}

	.obr-topbar-inner {
		grid-template-columns: 1fr auto;
	}
}

@media (max-width: 760px) {
	.obr-body {
		--obr-bar: 68px;
	}

	.obr-topbar-logo,
	.obr-topbar-home img,
	.obr-topbar-logo--svg svg {
		height: 44px;
		max-width: 58vw;
	}
}

@media (max-width: 400px) {
	.obr-topbar-logo,
	.obr-topbar-home img,
	.obr-topbar-logo--svg svg {
		height: 38px;
		max-width: 54vw;
	}
}
/* -------------------------------------------------------------------------
 * 5. SEARCH DRAWER
 * ---------------------------------------------------------------------- */

.obr-search {
	position: fixed;
	inset-inline: 0;
	top: var(--obr-bar);
	z-index: 890;
	padding: 22px clamp(18px, 3vw, 40px);
	background: rgba(0, 0, 0, 0.9);
	backdrop-filter: blur(16px);
	-webkit-backdrop-filter: blur(16px);
	border-bottom: 1px solid var(--obr-ink-12);
}

.obr-search form {
	display: flex;
	gap: 10px;
	max-width: 700px;
	margin-inline: auto;
}

.obr-search input {
	flex: 1;
	height: 48px;
	padding-inline: 16px;
	border: 1px solid var(--obr-ink-12);
	border-radius: 8px;
	background: rgba(255, 255, 255, 0.05);
	color: #fff;
	font: inherit;
}

.obr-search input:focus {
	outline: 2px solid var(--obr-action);
	outline-offset: 1px;
}
/* -------------------------------------------------------------------------
 * 6. MENU OVERLAY
 * ---------------------------------------------------------------------- */

/*
 * The first build stacked every item — parents and children alike — right
 * aligned in one narrow column. With a real menu (six parents, thirteen
 * children) that produces a wall of ragged text pinned to the screen edge.
 *
 * This version reads as an index instead: parents are columns, children sit
 * under their parent as a quiet list, and everything is start-aligned inside
 * a proper measure. Multi-column collapses to one on narrow screens.
 */

.obr-menu {
	position: fixed;
	inset: 0;
	z-index: 880;
	display: flex;
	background: rgba(6, 6, 7, 0.96);
	backdrop-filter: blur(28px) saturate(120%);
	-webkit-backdrop-filter: blur(28px) saturate(120%);
}

.obr-menu-inner {
	display: flex;
	flex-direction: column;
	gap: clamp(28px, 4vh, 56px);
	width: 100%;
	max-width: 1440px;
	margin-inline: auto;
	padding: calc(var(--obr-bar) + clamp(24px, 5vh, 64px))
		clamp(20px, 4vw, 64px)
		clamp(28px, 5vh, 56px);
	overflow-y: auto;
	overscroll-behavior: contain;
}

.obr-menu-nav {
	flex: 1;
	min-height: 0;
}

.obr-menu-list {
	margin: 0;
	padding: 0;
	list-style: none;
	text-align: start;

	/* Columns rather than one tall list. The browser balances the fill, so a
	   menu of any length stays inside one screen without a hand-built grid. */
	columns: 3 240px;
	column-gap: clamp(24px, 4vw, 64px);
}

/* A parent and its children must never be split across a column break. */
.obr-menu-list > li {
	break-inside: avoid;
	-webkit-column-break-inside: avoid;
	page-break-inside: avoid;
	margin-bottom: 26px;
}

.obr-menu-list > li > a {
	display: block;
	padding-bottom: 8px;
	color: #fff;
	font-size: clamp(1rem, 0.94rem + 0.28vw, 1.1875rem);
	font-weight: 700;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	text-decoration: none;
	border-bottom: 1px solid var(--obr-ink-12);
	transition: border-color var(--obr-fast) var(--obr-ease),
		color var(--obr-fast) var(--obr-ease);
}

.obr-menu-list > li > a:hover,
.obr-menu-list > li > a:focus-visible {
	border-bottom-color: var(--obr-accent);
}

/* Children are always visible — a hover-to-open submenu inside a full-screen
   overlay is a trap on touch and a nuisance with a keyboard. */
.obr-menu-list .sub-menu {
	margin: 12px 0 0;
	padding: 0;
	list-style: none;
}

.obr-menu-list .sub-menu li {
	margin-bottom: 2px;
}

.obr-menu-list .sub-menu a {
	position: relative;
	display: block;
	padding: 5px 0 5px 0;
	color: var(--obr-ink-50);
	font-size: 0.9375rem;
	font-weight: 400;
	letter-spacing: 0.01em;
	text-transform: none;
	text-decoration: none;
	transition: color var(--obr-fast) var(--obr-ease),
		padding-inline-start var(--obr-fast) var(--obr-ease);
}

.obr-menu-list .sub-menu a:hover,
.obr-menu-list .sub-menu a:focus-visible {
	color: #fff;
	padding-inline-start: 10px;
}

.obr-menu-list .sub-menu a::before {
	content: "";
	position: absolute;
	inset-inline-start: 0;
	top: 50%;
	width: 0;
	height: 1px;
	background: var(--obr-accent);
	transform: translateY(-50%);
	transition: width var(--obr-fast) var(--obr-ease);
}

.obr-menu-list .sub-menu a:hover::before,
.obr-menu-list .sub-menu a:focus-visible::before {
	width: 5px;
}

.obr-menu-list a:focus-visible {
	outline: 2px solid var(--obr-action);
	outline-offset: 3px;
}

.obr-menu-foot {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 18px;
	padding-top: clamp(20px, 3vh, 32px);
	border-top: 1px solid var(--obr-ink-12);
}

.obr-menu-cta {
	order: 3;
	/* Clears the site's fixed WhatsApp/call buttons on the inline-end edge. */
	margin-inline-end: 74px;
}

.obr-menu-phone {
	color: var(--obr-ink-70);
	font-size: 1.0625rem;
	font-weight: 700;
	letter-spacing: 0.02em;
	text-decoration: none;
	font-variant-numeric: tabular-nums;
}

.obr-menu-phone:hover {
	color: #fff;
}

.obr-menu-lang {
	font-size: 0.875rem;
}

.obr-menu-lang a {
	color: var(--obr-ink-50);
	text-decoration: none;
}

.obr-menu-lang a:hover {
	color: #fff;
}

@media (max-width: 900px) {
	.obr-menu-list {
		columns: 2 200px;
	}
}

@media (max-width: 600px) {
	.obr-menu-list {
		columns: 1;
	}

	.obr-menu-list > li {
		margin-bottom: 20px;
	}

	.obr-menu-foot {
		flex-direction: column;
		align-items: stretch;
	}

	.obr-menu-cta {
		order: -1;
		margin-inline-end: 0;
	}
}
/* -------------------------------------------------------------------------
 * 10. FORMS
 * ---------------------------------------------------------------------- */

.obr-form-row {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-bottom: 18px;
}

.obr-form-row label {
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var(--obr-ink-50);
}

/* Underline fields, as in the reference — lighter than boxed inputs on a
   dark surface, where four hard rectangles read as a form to fill in rather
   than a conversation to start. */
.obr-form-row input,
.obr-form-row textarea {
	width: 100%;
	padding: 10px 2px;
	border: 0;
	border-bottom: 1px solid var(--obr-ink-12);
	border-radius: 0;
	background: transparent;
	color: #fff;
	font: inherit;
	font-size: 1rem;
	transition: border-color var(--obr-fast) var(--obr-ease);
}

.obr-form-row input:hover,
.obr-form-row textarea:hover {
	border-bottom-color: var(--obr-ink-50);
}

.obr-form-row input:focus,
.obr-form-row textarea:focus {
	outline: none;
	border-bottom-color: var(--obr-action);
	box-shadow: 0 1px 0 0 var(--obr-action);
}

.obr-form-row input:focus-visible,
.obr-form-row textarea:focus-visible {
	outline: 2px solid var(--obr-action);
	outline-offset: 4px;
}

.obr-form-row textarea {
	resize: vertical;
	min-height: 70px;
}

.obr-form button[type="submit"] {
	margin-top: 8px;
	border-radius: 4px;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	font-size: 0.8125rem;
}

.obr-form-consent {
	margin: 14px 0 0;
	font-size: 0.75rem;
	line-height: 1.6;
	color: var(--obr-ink-50);
}

.obr-form-notice {
	margin: 0 0 18px;
	padding: 12px 16px;
	border-radius: 8px;
	font-size: 0.875rem;
	line-height: 1.5;
}

.obr-form-notice--ok {
	background: rgba(var(--obr-accent-rgb), 0.2);
	border: 1px solid rgba(var(--obr-accent-rgb), 0.5);
	color: #fff;
}

.obr-form-notice--error {
	background: rgba(220, 53, 69, 0.16);
	border: 1px solid rgba(220, 53, 69, 0.45);
	color: #fff;
}

/* Off-screen rather than display:none — some bots skip hidden fields. */
.obr-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}
/* -------------------------------------------------------------------------
 * 11. OVERLAYS
 * ---------------------------------------------------------------------- */

.obr-modal,
.obr-lightbox {
	position: fixed;
	inset: 0;
	z-index: 950;
	display: grid;
	place-items: center;
	padding: clamp(16px, 4vw, 48px);
}

.obr-modal-scrim,
.obr-lightbox-scrim {
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, 0.72);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
}

.obr-modal-card {
	position: relative;
	z-index: 1;
	width: min(560px, 100%);
	max-height: 90svh;
	overflow-y: auto;
	padding: clamp(28px, 4vw, 48px);
	border: 1px solid var(--obr-ink-12);
	border-radius: var(--obr-r-lg);
	background: rgba(10, 10, 10, 0.96);
}

.obr-modal-title {
	margin: 0 0 26px;
	font-size: clamp(1.25rem, 1.05rem + 0.9vw, 1.75rem);
	font-weight: 400;
	letter-spacing: 0.02em;
	text-transform: uppercase;
	color: var(--obr-ink-70);
}

.obr-modal-title strong {
	color: #fff;
	font-weight: 700;
}

.obr-modal-close {
	position: absolute;
	z-index: 2;
	top: 14px;
	inset-inline-end: 14px;
	display: grid;
	place-items: center;
	width: 40px;
	height: 40px;
	border: 1px solid var(--obr-ink-12);
	border-radius: 50%;
	background: rgba(0, 0, 0, 0.4);
	color: #fff;
	font-size: 1.5rem;
	line-height: 1;
	cursor: pointer;
	transition: background-color var(--obr-fast) var(--obr-ease);
}

.obr-modal-close:hover {
	background: rgba(255, 255, 255, 0.14);
}

.obr-lightbox .obr-modal-close {
	top: clamp(16px, 3vw, 32px);
	inset-inline-end: clamp(16px, 3vw, 32px);
}

.obr-modal-facts {
	display: flex;
	flex-wrap: wrap;
	gap: 20px;
	margin-top: 28px;
	padding-top: 22px;
	border-top: 1px solid var(--obr-ink-12);
}

.obr-modal-facts > div {
	display: flex;
	flex-direction: column;
	gap: 3px;
}

.obr-modal-facts span {
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--obr-ink-50);
}

.obr-modal-facts strong {
	font-size: 1rem;
	color: #fff;
}

.obr-lightbox img {
	position: relative;
	z-index: 1;
	max-width: 100%;
	max-height: 90svh;
	object-fit: contain;
	border-radius: var(--obr-r);
}

.obr-film-frame {
	position: relative;
	z-index: 1;
	width: min(1100px, 100%);
	aspect-ratio: 16 / 9;
	border-radius: var(--obr-r);
	overflow: hidden;
	background: #000;
}

.obr-film-frame iframe {
	width: 100%;
	height: 100%;
	border: 0;
}

/* Locks the page while an overlay owns the screen. */
.obr-locked {
	overflow: hidden;
}

/* -------------------------------------------------------------------------
 * 5. WRAPPER BASE
 * ---------------------------------------------------------------------- */

/*
 * `.obr` wraps the page content inside <main>. The token block above lives on
 * <body> because the chrome sits outside this wrapper; what belongs here is
 * everything scoped to the content itself.
 *
 * Both templates are dark now, so the aliases below point at the dark family
 * rather than carrying a second light palette that nothing uses.
 */
.obr {
	--obr-ink: var(--obr-ink-0);
	--obr-ink-72: var(--obr-ink-70);
	--obr-ink-muted: var(--obr-ink-50);
	--obr-surface: var(--obr-black);
	--obr-surface-2: var(--obr-panel);
	--obr-surface-deep: var(--obr-panel-2);

	--obr-shell: 1280px;
	--obr-gap: 28px;

	color: var(--obr-ink);
	background: var(--obr-surface);
	font-feature-settings: "kern" 1, "liga" 1;
	-webkit-font-smoothing: antialiased;
}

.obr *,
.obr *::before,
.obr *::after {
	box-sizing: border-box;
}

/*
 * Zero-specificity image default.
 *
 * Written as `.obr img` this rule was (0,1,1) and quietly beat every
 * single-class rule that tried to size an image — `.obr-chero-frame`,
 * `.obr-card-bg` and the rest are all (0,1,0). Their `height: 100%` lost to
 * this `height: auto`, so full-bleed images fell back to their intrinsic
 * aspect: the hero showed a band of photo with black beneath it on tall
 * screens, and cards with differently-shaped images came out uneven.
 *
 * :where() contributes nothing to specificity, so this is now a true default
 * that any class can override.
 */
:where(.obr) :where(img) {
	max-width: 100%;
	height: auto;
}

.obr .screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	border: 0;
	white-space: nowrap;
}

.obr-shell {
	width: 100%;
	max-width: var(--obr-shell);
	margin-inline: auto;
	padding-inline: 24px;
}

@media (max-width: 600px) {
	.obr-shell {
		padding-inline: 18px;

	}
}

/* -------------------------------------------------------------------------
 * 2. TYPE
 * ---------------------------------------------------------------------- */

.obr-section-title {
	margin: 0 0 14px;
	font-size: clamp(1.5rem, 1.15rem + 1.5vw, 2.25rem);
	line-height: 1.18;
	font-weight: 700;
	letter-spacing: -0.015em;
	color: var(--obr-ink);
}

.obr-section-lead {
	margin: 0 0 28px;
	max-width: 62ch;
	font-size: 1rem;
	line-height: 1.65;
	color: var(--obr-ink-muted);
}

.obr-eyebrow {
	margin: 0 0 12px;
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	opacity: 0.75;
}

.obr-crumbs {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	align-items: center;
	margin-bottom: 22px;
	font-size: 0.8125rem;
	color: var(--obr-ink-muted);
}

.obr-crumbs a {
	color: inherit;
	text-decoration: none;
	border-bottom: 1px solid transparent;
	transition: border-color var(--obr-fast) var(--obr-ease);
}

.obr-crumbs a:hover,
.obr-crumbs a:focus-visible {
	border-bottom-color: currentColor;
}

.obr-empty {
	padding: 32px;
	border: 1px dashed var(--obr-ink-12);
	border-radius: var(--obr-r);
	color: var(--obr-ink-muted);
	text-align: center;
}

/* -------------------------------------------------------------------------
 * 3. BUTTONS  —  all four variants read from the skin
 * ---------------------------------------------------------------------- */

.obr-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	min-height: 46px;
	padding: 0 22px;
	border: 1px solid transparent;
	border-radius: var(--obr-r-pill);
	font-size: 0.9375rem;
	font-weight: 600;
	line-height: 1;
	text-decoration: none;
	cursor: pointer;
	transition: transform var(--obr-fast) var(--obr-ease),
		background-color var(--obr-fast) var(--obr-ease),
		border-color var(--obr-fast) var(--obr-ease),
		color var(--obr-fast) var(--obr-ease);
}

.obr-btn:hover {
	transform: translateY(-1px);
}

.obr-btn:focus-visible {
	outline: 2px solid var(--obr-accent);
	outline-offset: 3px;
}

/* The primary button. Uses the ACTION track, never the accent, so a
   monochrome brand still gets something visible against its surface. */
.obr-btn--action {
	background: var(--obr-action);
	color: var(--obr-on-action);
}

.obr-btn--action:hover {
	/* Darken by compositing rather than storing a second colour. */
	box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.14);
	color: var(--obr-on-action);
}

/* Outlined, inherits the surrounding text colour — safe on any background. */
.obr-btn--line {
	background: transparent;
	border-color: currentColor;
	color: inherit;
	opacity: 0.92;
}

.obr-btn--line:hover {
	opacity: 1;
	background: rgba(255, 255, 255, 0.08);
}

/* No chrome at all — for tertiary actions like "watch the film". */
.obr-btn--bare {
	background: transparent;
	border-color: transparent;
	color: inherit;
	padding-inline: 4px;
}

.obr-btn--bare:hover {
	color: var(--obr-action);
}

.obr-btn--accent {
	background: var(--obr-accent);
	color: var(--obr-on-accent);
}

.obr-btn--accent:hover {
	box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.12);
	color: var(--obr-on-accent);
}

.obr-btn--solid {
	background: var(--obr-ink);
	color: #fff;
}

.obr-btn--solid:hover {
	background: #000;
	color: #fff;
}

.obr-btn--ghost {
	background: transparent;
	border-color: var(--obr-ink-12);
	color: var(--obr-ink);
}

.obr-btn--ghost:hover {
	border-color: var(--obr-accent);
	color: var(--obr-accent);
}

.obr-btn--outline {
	background: transparent;
	border-color: currentColor;
	color: inherit;
}

.obr-btn--block {
	width: 100%;
}

/* -------------------------------------------------------------------------
 * 4. PILLS
 * ---------------------------------------------------------------------- */

.obr-pill {
	display: inline-flex;
	align-items: center;
	height: 26px;
	padding: 0 12px;
	border-radius: var(--obr-r-pill);
	background: rgba(var(--obr-accent-rgb), 0.12);
	color: var(--obr-accent);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.02em;
	white-space: nowrap;
}

/* Availability carries meaning, so it is not left to the brand accent. */
.obr-pill--sold-out {
	background: var(--obr-ink-06);
	color: var(--obr-ink-muted);
}

.obr-pill--final {
	background: rgba(180, 83, 9, 0.12);
	color: #9a4a08;
}

/* A pill laid over imagery: light chip, dark label, regardless of the photo. */
.obr-pill--onmedia {
	position: absolute;
	inset-block-start: 12px;
	inset-inline-start: 12px;
	background: rgba(255, 255, 255, 0.94);
	color: #111;
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
}

.obr-section {
	position: relative;
	isolation: isolate;
	padding: clamp(56px, 8vw, 120px) 0;
}

.obr-section + .obr-section {
	border-top: 1px solid var(--obr-ink-06);
}

/* --- Section backdrops ------------------------------------------------
 *
 * A photograph behind a section, held far enough back that the copy on top
 * never has to fight it. Three layers do that work:
 *
 *   1. the image, desaturated and darkened by a filter
 *   2. a scrim that fades to solid black at both edges, so the section melts
 *      into its neighbours instead of butting against them as a hard band
 *   3. an inset shadow around the frame, which is what makes the image read
 *      as recessed rather than pasted on
 *
 * The scrim is deliberately heavy. These images are not art-directed with
 * text overlay in mind — the same treatment has to hold up on a bright
 * daylight render and on a night shot without anyone checking each one.
 */

.obr-section--bg {
	border-top: 0 !important;
}

.obr-backdrop {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
}

/*
 * Also oversized, for the same reason as the hero layers: the script drifts
 * this between -6% and +6% on scroll, and at exactly 100% height either end of
 * that travel would expose the section background behind it. 16% of headroom
 * covers the full range with margin to spare.
 *
 * The scale() is separate — it hides the soft edge the blur-free crop leaves
 * at the frame, and GSAP animates yPercent on top of it rather than replacing it.
 */
.obr-backdrop-img {
	position: absolute;
	inset-inline: 0;
	top: -8%;
	width: 100%;
	height: 116%;
	object-fit: cover;
	filter: grayscale(0.35) brightness(0.42) contrast(1.05);
	transform: scale(1.06);
}

.obr-backdrop-scrim {
	position: absolute;
	inset: 0;
	background:
		linear-gradient(
			to bottom,
			var(--obr-black) 0%,
			rgba(0, 0, 0, 0.72) 18%,
			rgba(0, 0, 0, 0.68) 82%,
			var(--obr-black) 100%
		);
	box-shadow: inset 0 0 clamp(60px, 12vw, 160px) rgba(0, 0, 0, 0.9);
}

/* Panels sitting on a backdrop need their own surface back, or they vanish. */
.obr-section--bg .obr-amenity {
	background: rgba(10, 10, 10, 0.72);
	backdrop-filter: blur(10px);
	-webkit-backdrop-filter: blur(10px);
}

.obr-section--bg .obr-lead-form {
	background: rgba(8, 8, 9, 0.86);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
}

.obr-section--bg .obr-faq-list {
	padding-inline: clamp(0px, 2vw, 28px);
}

.obr-single .obr-section-title {
	color: #fff;
	font-size: clamp(1.5rem, 1.15rem + 1.6vw, 2.375rem);
	letter-spacing: -0.02em;
}

/* The split-weight heading in the reference: solid word, then a light one. */
.obr-section-title--split {
	text-align: center;
	font-weight: 400;
}

.obr-section-title--split strong {
	font-weight: 700;
}

.obr-section-title--split span {
	color: var(--obr-ink-50);
}

.obr-single .obr-section-lead {
	color: var(--obr-ink-50);
}

.obr-single .obr-empty {
	border-color: var(--obr-ink-12);
	color: var(--obr-ink-50);
}

/* -------------------------------------------------------------------------
 * 6. DEPTH LAYERS  —  used by both heroes
 * ---------------------------------------------------------------------- */

/* Depth, not decoration: a vignette keeps the eye off the frame edges. */
.obr-vignette {
	position: absolute;
	inset: 0;
	background: radial-gradient(
		120% 90% at 50% 45%,
		transparent 40%,
		rgba(0, 0, 0, 0.5) 100%
	);
}

/* Film grain. A pure-CSS noise field — no image request. */
.obr-grain {
	position: absolute;
	inset: -50%;
	opacity: 0.035;
	pointer-events: none;
	background-image: repeating-conic-gradient(
		#fff 0% 25%,
		transparent 0% 50%
	);
	background-size: 3px 3px;
	animation: obr-grain 900ms steps(3) infinite;
}

@keyframes obr-grain {
	0% {
		transform: translate(0, 0);
	}
	33% {
		transform: translate(-2%, 1%);
	}
	66% {
		transform: translate(1%, -2%);
	}
	100% {
		transform: translate(0, 0);
	}
}

@media (prefers-reduced-motion: reduce) {
	.obr-grain {
		animation: none;
	}
}

.obr-scrollcue {
	position: absolute;
	z-index: 4;
	inset-inline: 0;
	bottom: 96px;
	display: grid;
	place-items: center;
}

.obr-scrollcue i {
	display: block;
	width: 1px;
	height: 46px;
	background: linear-gradient(to bottom, transparent, var(--obr-ink-0));
	animation: obr-cue 2200ms var(--obr-ease) infinite;
	transform-origin: top center;
}

@keyframes obr-cue {
	0% {
		transform: scaleY(0);
		opacity: 0;
	}
	40% {
		transform: scaleY(1);
		opacity: 0.9;
	}
	100% {
		transform: scaleY(1) translateY(46px);
		opacity: 0;
	}
}

/* Base for the trademark note at the foot of both templates. */
.obr-legal {
	background: var(--obr-black);
}

.obr-legal p {
	margin: 0;
	max-width: 92ch;
	font-size: 0.8125rem;
	line-height: 1.75;
	color: var(--obr-ink-50);
}

/*
 * Section rhythm, shared. Page files vary the padding, not the structure.
 *
 * Tightened from a 120px ceiling. At that size a section holding two cards was
 * mostly empty black above and below it — space reads as confidence only when
 * there is something either side of it to separate.
 */
.obr-section {
	position: relative;
	isolation: isolate;
	padding: clamp(48px, 6vw, 96px) 0;
}


/* -------------------------------------------------------------------------
 * 7. PROJECT CARD  —  used by the collection rail and the brand page grid
 * ---------------------------------------------------------------------- */

.obr-project {
	position: relative;
	display: flex;
	flex-direction: column;
	border: 1px solid var(--obr-ink-12);
	border-radius: var(--obr-r-lg);
	background: var(--obr-panel);
	overflow: hidden;
	transition: transform var(--obr-mid) var(--obr-ease),
		box-shadow var(--obr-mid) var(--obr-ease);
}

.obr-project:hover {
	transform: translateY(-4px);
	box-shadow: 0 22px 50px -28px rgba(var(--obr-accent-rgb), 0.65);
}

.obr-project-media {
	display: block;
	aspect-ratio: 4 / 3;
	background: var(--obr-panel-2);
	overflow: hidden;
}

.obr-project-media img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--obr-slow) var(--obr-ease);
}

.obr-project:hover .obr-project-media img {
	transform: scale(1.05);
}

.obr-project-body {
	display: flex;
	flex-direction: column;
	flex: 1;
	padding: 18px 20px 22px;
}

.obr-project-brand {
	margin: 0 0 7px;
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

/* Lifted above the title's stretched overlay, or it is unclickable. */
.obr-project-brand a {
	position: relative;
	z-index: 2;
	color: var(--obr-accent);
	text-decoration: none;
}

.obr-project-brand a:hover {
	text-decoration: underline;
}

.obr-project-title {
	margin: 0 0 8px;
	font-size: 1.0625rem;
	font-weight: 700;
	line-height: 1.35;
	color: #fff;
}

.obr-project-title a {
	color: inherit;
	text-decoration: none;
}

.obr-project-title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.obr-project-price {
	margin: 0;
	font-size: 1.0625rem;
	font-weight: 700;
	color: var(--obr-accent);
	font-variant-numeric: tabular-nums;
}

/* -------------------------------------------------------------------------
 * 8. ATMOSPHERE  —  the dark between the scenes
 *
 * The flat sections between images read as dead black. This lays a very slow
 * drift of warm light behind them so the page feels lit rather than switched
 * off, and gives the eye a reason to keep moving.
 *
 * Deliberately CSS, not a library. A canvas or WebGL backdrop would be another
 * 40-150KB and a permanent animation frame on a page already carrying GSAP and
 * Lenis — for an effect two radial gradients produce at zero script cost. The
 * whole thing runs on the compositor: only transform and opacity animate, so
 * it never triggers layout or paint.
 * ---------------------------------------------------------------------- */

.obr-atmos {
	position: absolute;
	inset: 0;
	z-index: -1;
	overflow: hidden;
	pointer-events: none;
}

.obr-atmos::before,
.obr-atmos::after {
	content: "";
	position: absolute;
	width: 78vmax;
	height: 78vmax;
	border-radius: 50%;
	/* Built from the brand accent, so the atmosphere carries the brand rather
	   than being a generic glow. Very low alpha — this is felt, not seen. */
	background: radial-gradient(
		circle at center,
		rgba(var(--obr-accent-rgb), 0.16) 0%,
		rgba(var(--obr-accent-rgb), 0.05) 42%,
		transparent 68%
	);
	filter: blur(42px);
	will-change: transform;
}

.obr-atmos::before {
	top: -34vmax;
	inset-inline-start: -22vmax;
	animation: obr-drift-a 26s ease-in-out infinite alternate;
}

.obr-atmos::after {
	bottom: -40vmax;
	inset-inline-end: -26vmax;
	background: radial-gradient(
		circle at center,
		rgba(255, 255, 255, 0.05) 0%,
		rgba(255, 255, 255, 0.018) 44%,
		transparent 70%
	);
	animation: obr-drift-b 34s ease-in-out infinite alternate;
}

@keyframes obr-drift-a {
	from {
		transform: translate3d(0, 0, 0) scale(1);
	}
	to {
		transform: translate3d(14vmax, 9vmax, 0) scale(1.16);
	}
}

@keyframes obr-drift-b {
	from {
		transform: translate3d(0, 0, 0) scale(1.1);
	}
	to {
		transform: translate3d(-12vmax, -8vmax, 0) scale(1);
	}
}

/* A section with a photograph behind it has its own atmosphere already. */
.obr-section--bg .obr-atmos {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.obr-atmos::before,
	.obr-atmos::after {
		animation: none;
	}
}

/* The blur is expensive on low-end phones for an effect nobody will notice at
   that size. Dropped rather than degraded. */
@media (max-width: 700px) {
	.obr-atmos {
		display: none;
	}
}
