/*!
 * FLYSTACK — theme styles
 *
 * ORDERED IN LAYERS. Later layers intentionally override earlier ones, so
 * DO NOT append new rules to the end of this file — add them to the layer
 * they belong to. Two bugs came from ignoring this: a `display: flex`
 * declaration on the menu toggle overrode an earlier desktop hide and put a
 * burger on 1440px screens, and repeated appends made it impossible to tell
 * which of several competing rules was winning.
 *
 *   0  Design tokens          — custom properties only, no selectors
 *   1  Base / resets          — element defaults, parent-theme corrections
 *   2  Utilities              — .fs-* helpers applied via Elementor classes
 *   3  Components             — switcher, social rail, footer, a11y widget
 *   4  Header (desktop)       — layout, nav spacing, logo alignment
 *   5  Responsive             — tablet and mobile, menu sheet, burger morph
 *   6  Visibility overrides   — MUST REMAIN LAST
 *
 * Values marked "measured" were taken from computed styles on
 * www.flystackdroneshows.com, not estimated. Keep them that way.
 */


/* ==========================================================================
   Brand typeface  [Layer 0: Design tokens]

   The live site runs on Montserrat with exactly one exception: the FLYSTACK
   wordmark, which it sets in a second family via `class="font-codeNext"`.
   Without it "FLYSTACK DRONE SHOWS" rendered 396px wide against live's 377px
   at the same size and tracking — the give-away that the glyphs, not the
   metrics, were wrong.

   Self-hosted from the live site's own woff2 files (see flystack-fonts.php),
   so there is no third-party request and no layout shift from a late swap.
   ========================================================================== */

@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 100; src: url("../fonts/flystack-brand-100.woff2") format("woff2"); }
@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 200; src: url("../fonts/flystack-brand-200.woff2") format("woff2"); }
@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 300; src: url("../fonts/flystack-brand-300.woff2") format("woff2"); }
@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 400; src: url("../fonts/flystack-brand-400.woff2") format("woff2"); }
@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 500; src: url("../fonts/flystack-brand-500.woff2") format("woff2"); }
@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 600; src: url("../fonts/flystack-brand-600.woff2") format("woff2"); }
@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 700; src: url("../fonts/flystack-brand-700.woff2") format("woff2"); }
@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 800; src: url("../fonts/flystack-brand-800.woff2") format("woff2"); }
@font-face { font-family: "FLYSTACK Brand"; font-style: normal; font-display: swap; font-weight: 900; src: url("../fonts/flystack-brand-900.woff2") format("woff2"); }

/* ==========================================================================
   FLYSTACK — brand design tokens
   Values sampled from the live Next.js site (www.flystackdroneshows.com).
   Change a token here and it propagates everywhere, including Elementor
   widgets, because the Elementor Global Colors are mapped to these in the kit.
   ========================================================================== */

:root {
	/* --- Core palette (Tailwind "stone" scale, as used on the live site) --- */
	--fs-black:        #000000;
	--fs-bg:           #0c0a09; /* stone-950 — page background            */
	--fs-surface:      #292524; /* stone-800 — cards, header, footer      */
	--fs-surface-alt:  #1c1917; /* stone-900 — subtle raised panels       */
	--fs-text:         #fafaf9; /* stone-50  — primary text               */
	--fs-text-soft:    #e7e5e4; /* stone-200 — secondary text             */
	--fs-muted:        #a8a29e; /* stone-400 — captions, meta             */
	--fs-muted-dark:   #6d6c6b; /* dividers, disabled                     */

	/* --- Accent --- */
	--fs-accent:       #fb923c; /* orange-400 — the FLYSTACK orange       */
	--fs-accent-hover: #f97316; /* orange-500                             */
	--fs-accent-soft:  rgba(251, 146, 60, 0.14);

	/* --- Alpha helpers (used heavily on the live site over video) --- */
	--fs-white-60:     rgba(255, 255, 255, 0.6);
	--fs-white-40:     rgba(255, 255, 255, 0.4);
	--fs-white-20:     rgba(255, 255, 255, 0.2);
	--fs-white-10:     rgba(255, 255, 255, 0.1);

	/* --- Typography --- */
	--fs-font: "Montserrat", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
	/* The wordmark only — never body copy. */
	--fs-font-brand: "FLYSTACK Brand", "Montserrat", ui-sans-serif, system-ui, sans-serif;
	--fs-fw-light: 300;
	--fs-fw-regular: 400;
	--fs-fw-medium: 500;
	--fs-fw-semibold: 600;
	--fs-fw-bold: 700;
	--fs-fw-black: 800;

	/* Fluid type scale — clamp() so headings breathe on large screens */
	--fs-size-display: clamp(2.75rem, 8vw, 7rem);
	--fs-size-h1:      clamp(2.25rem, 5.5vw, 4.5rem);
	--fs-size-h2:      clamp(1.75rem, 4vw, 3.25rem);
	--fs-size-h3:      clamp(1.375rem, 2.5vw, 2rem);
	--fs-size-h4:      clamp(1.125rem, 1.6vw, 1.375rem);
	--fs-size-body:    clamp(0.9375rem, 1.05vw, 1.0625rem);
	--fs-size-small:   0.875rem;
	--fs-size-eyebrow: 0.8125rem;

	/* --- Layout --- */
	--fs-container: 1280px;
	--fs-gutter: clamp(1.25rem, 4vw, 4rem);
	--fs-section-y: clamp(4rem, 9vw, 9rem);
	--fs-radius: 14px;
	--fs-radius-lg: 22px;

	/* --- Motion --- */
	--fs-ease: cubic-bezier(0.22, 1, 0.36, 1);
	--fs-dur: 0.45s;
}

/* ==========================================================================
   Admin bar compensation

   The Theme Builder header is position:fixed at top:0, so WordPress's 32px
   admin bar sits on top of it for logged-in users. That is a real layout bug
   for editors, not just a measuring nuisance — it hides the nav.

   WordPress exposes the bar height as a custom property; fall back to the
   documented 32px / 46px values on older releases.
   ========================================================================== */

body.admin-bar .elementor-location-header > .e-con,
body.admin-bar .elementor-location-header > .elementor-element,
body.admin-bar .elementor-location-header .e-con.e-parent {
	top: var(--wp-admin--admin-bar--height, 32px) !important;
}

@media screen and (max-width: 782px) {
	body.admin-bar .elementor-location-header > .e-con,
	body.admin-bar .elementor-location-header > .elementor-element,
	body.admin-bar .elementor-location-header .e-con.e-parent {
		top: var(--wp-admin--admin-bar--height, 46px) !important;
	}
}

/* ==========================================================================
   Font smoothing — hello-elementor-reset-override

   Hello Elementor's reset.css sets `body { -webkit-font-smoothing: antialiased }`.
   On macOS that thins every glyph, so Montserrat 400 in the nav rendered
   visibly lighter than the live site, which leaves smoothing at `auto`
   (subpixel). Matching the original rendering.

   `html body` is used purely to outrank the parent theme's `body` rule,
   which loads after this stylesheet.
   ========================================================================== */

html body,
html body input,
html body button,
html body select,
html body textarea {
	-webkit-font-smoothing: auto;
	-moz-osx-font-smoothing: auto;
}

/* ==========================================================================
   Base
   ========================================================================== */

body {
	background-color: var(--fs-bg);
	color: var(--fs-text);
	font-family: var(--fs-font);
	font-weight: var(--fs-fw-regular);
	font-size: var(--fs-size-body);
	line-height: 1.7;
	/* Deliberately NOT -webkit-font-smoothing: antialiased.
	   The live site leaves this at `auto` (subpixel). Forcing `antialiased`
	   thins every glyph on macOS, which made Montserrat 400 in the nav read
	   noticeably lighter than the original. Matching the live rendering. */
	text-rendering: optimizeLegibility;
	overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6 {
	font-family: var(--fs-font);
	color: var(--fs-text);
	line-height: 1.08;
	letter-spacing: -0.01em;
	margin-block: 0 0.5em;
}

h1 { font-size: var(--fs-size-h1); font-weight: var(--fs-fw-bold); }
h2 { font-size: var(--fs-size-h2); font-weight: var(--fs-fw-bold); }
h3 { font-size: var(--fs-size-h3); font-weight: var(--fs-fw-semibold); }
h4 { font-size: var(--fs-size-h4); font-weight: var(--fs-fw-bold); }

p { margin-block: 0 1.1em; }
p:last-child { margin-bottom: 0; }

a { color: inherit; text-decoration: none; transition: color var(--fs-dur) var(--fs-ease); }
a:hover { color: var(--fs-accent); }

img, video { max-width: 100%; height: auto; display: block; }

::selection { background: var(--fs-accent); color: var(--fs-black); }

/* Visible focus ring — the live site has none, this is an accessibility fix. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
	outline: 2px solid var(--fs-accent);
	outline-offset: 3px;
	border-radius: 4px;
}

/* ==========================================================================
   Reusable brand utilities
   Apply these as Elementor "CSS Classes" on any section/widget.
   ========================================================================== */

/* Small uppercase label that sits above a heading ("about us", "pricing"…). */
.fs-eyebrow {
	font-size: var(--fs-size-eyebrow);
	font-weight: var(--fs-fw-semibold);
	letter-spacing: 0.22em;
	text-transform: uppercase;
	color: var(--fs-accent);
	display: block;
	margin-bottom: 1rem;
}

/* The live site authors headings in sentence case and uppercases them in CSS.
   Keep that split: content stays readable in the WP editor and in exports. */
.fs-upper { text-transform: uppercase; }

.fs-display {
	font-size: var(--fs-size-display);
	font-weight: var(--fs-fw-bold);
	text-transform: uppercase;
	line-height: 0.95;
	letter-spacing: -0.02em;
}

.fs-muted { color: var(--fs-muted); }
.fs-accent { color: var(--fs-accent); }

.fs-container {
	max-width: var(--fs-container);
	margin-inline: auto;
	padding-inline: var(--fs-gutter);
}

.fs-section { padding-block: var(--fs-section-y); }
.fs-section--black { background: var(--fs-black); }
.fs-section--surface { background: var(--fs-surface); }

/* Card surface used by tech cards, project cards, blog cards. */
.fs-card {
	background: var(--fs-surface);
	border: 1px solid var(--fs-white-10);
	border-radius: var(--fs-radius);
	padding: clamp(1.5rem, 2.5vw, 2.25rem);
	transition: transform var(--fs-dur) var(--fs-ease),
	            border-color var(--fs-dur) var(--fs-ease);
}
.fs-card:hover { transform: translateY(-6px); border-color: var(--fs-accent); }

/* Primary CTA ("Book now"). */
.fs-btn,
.elementor-button.fs-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	background: var(--fs-accent);
	color: var(--fs-black);
	font-weight: var(--fs-fw-semibold);
	font-size: var(--fs-size-small);
	letter-spacing: 0.04em;
	padding: 0.9rem 1.9rem;
	border: 1px solid var(--fs-accent);
	border-radius: 999px;
	transition: background var(--fs-dur) var(--fs-ease),
	            color var(--fs-dur) var(--fs-ease);
}
.fs-btn:hover { background: var(--fs-accent-hover); border-color: var(--fs-accent-hover); color: var(--fs-black); }

.fs-btn--ghost {
	background: transparent;
	color: var(--fs-text);
	border-color: var(--fs-white-40);
}
.fs-btn--ghost:hover { background: var(--fs-text); color: var(--fs-black); border-color: var(--fs-text); }

/* Full-bleed background video wrapper (hero). */
.fs-video-bg {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	z-index: 0;
	pointer-events: none;
}
.fs-video-overlay::before {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(180deg, rgba(12,10,9,0.35) 0%, rgba(12,10,9,0.15) 45%, rgba(12,10,9,0.9) 100%);
	z-index: 1;
}

/* Respect users who ask for less motion. */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ==========================================================================
   Hero headline entrance

   The live site animates the h1 with JS from an inline start state of
   `opacity:0; transform:translateX(-40px)`. Elementor's built-in fadeInLeft
   uses animate.css, which travels translate3d(-100%,0,0) — the element's full
   width (~656px here) — so it reads as a completely different effect.
   This reproduces the real 40px nudge as a pure CSS keyframe: no JS, no
   scroll listener, and it cannot desync from the video behind it.
   ========================================================================== */

@keyframes fsSlideInLeft {
	from { opacity: 0; transform: translateX(-40px); }
	to   { opacity: 1; transform: translateX(0); }
}

/* Superseded by the shared .fs-reveal-left system — kept as a comment so the
   original 0.9s/0.25s timing is recoverable if the hero needs to differ from
   the rest of the site.
   .fs-hero-title { animation: fsSlideInLeft 0.9s cubic-bezier(0.22,1,0.36,1) 0.25s both; } */

/* Hero is above the fold, so it reveals on load with a slight delay rather
   than waiting for a scroll intersection. */
.fs-js .fs-hero-title {
	/* Live: transition {delay: 0.4} with no duration, so Framer's 0.3s
	   tween default applies — shorter and later than the other reveals. */
	transition-duration: 0.3s;
	transition-delay: 400ms;
}

@media (prefers-reduced-motion: reduce) {
	.fs-hero-title,
	.fs-hero-title .elementor-heading-title {
		animation: none;
		opacity: 1;
		transform: none;
	}
}

/* ==========================================================================
   Language switcher

   Matches the live site: a single 32px circular flag for the active language,
   revealing the rest on hover or focus. Keyboard accessible, which the
   original is not.
   ========================================================================== */

.fs-lang { position: relative; display: inline-flex; align-items: center; }

.fs-lang__toggle {
	appearance: none;
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
	line-height: 0;
	border-radius: 50%;
}

.fs-lang__flag {
	width: 32px;
	height: 32px;
	border-radius: 50%;
	object-fit: cover;
	display: block;
	overflow: hidden;
}

/*
 * The panel is shadcn's DropdownMenuContent, which is what live uses:
 *
 *     z-50 min-w-[4rem] overflow-hidden rounded-md border bg-popover p-1
 *     text-popover-foreground shadow-md            (sideOffset 4, align center)
 *
 * and each row is DropdownMenuItem:
 *
 *     flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm
 *     focus:bg-accent focus:text-accent-foreground
 *
 * with --radius 0.5rem, so rounded-md is 6px and rounded-sm is 4px, and
 * --popover / --border / --accent resolve to #0C0A09 / #292524 / #292524.
 * The earlier panel here was a 190px card with full language names; live is a
 * narrow list of two-letter codes beside 32px flags.
 */
.fs-lang__list {
	position: absolute;
	top: calc(100% + 4px);          /* sideOffset={4} */
	left: 50%;                      /* align="center" */
	transform: translateX(-50%) scale(0.95);
	margin: 0;
	padding: 4px;                   /* p-1 */
	list-style: none;
	min-width: 4rem;                /* min-w-[4rem] */
	overflow: hidden;
	background: #0c0a09;            /* bg-popover */
	border: 1px solid #292524;      /* border */
	border-radius: 6px;             /* rounded-md */
	color: #fafaf9;                 /* text-popover-foreground */
	box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
	            0 2px 4px -2px rgba(0, 0, 0, 0.1);   /* shadow-md */
	opacity: 0;
	visibility: hidden;
	/* fade-in-0 zoom-in-95 slide-in-from-top-2, at tailwindcss-animate's
	   default 150ms. */
	transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
	z-index: 50;
}

/*
 * Click, not hover. Radix's dropdown opens on click and stays open until
 * something dismisses it; opening on hover put the panel in front of whatever
 * the pointer was travelling towards.
 */
.fs-lang:focus-within .fs-lang__list {
	opacity: 1;
	visibility: visible;
	transform: translateX(-50%) scale(1);
}

.fs-lang__list a {
	position: relative;
	display: flex;
	align-items: center;
	gap: 8px;                       /* gap-2 */
	padding: 6px 8px;               /* py-1.5 px-2 */
	border-radius: 4px;             /* rounded-sm */
	color: inherit;
	font-size: 14px;                /* text-sm */
	line-height: 20px;
	white-space: nowrap;
	transition: background-color 0.15s ease, color 0.15s ease;
}

.fs-lang__list a:hover,
.fs-lang__list a:focus-visible {
	background: #292524;            /* focus:bg-accent */
	color: #fafaf9;                 /* focus:text-accent-foreground */
}

/* fs-lang-specificity — Elementor's image rules outrank the base .fs-lang__flag
   declarations, so the flag rendered square. Pinned here at the widget level. */
.elementor-widget-shortcode .fs-lang { display: inline-flex; align-items: center; line-height: 0; }

.elementor-widget-shortcode .fs-lang__flag,
.elementor .fs-lang__flag,
.fs-lang img.fs-lang__flag {
	width: 32px !important;
	height: 32px !important;
	border-radius: 50% !important;
	object-fit: cover !important;
	display: block !important;
	max-width: none !important;
}

/* The shortcode widget adds its own block spacing, which pushed the flag
   below the optical centre of the 72px header. */
.elementor-widget-shortcode:has(.fs-lang) .elementor-widget-container { line-height: 0; }
.elementor-widget-shortcode:has(.fs-lang) { display: flex; align-items: center; }

/* fs-book-btn-nowrap — the 1px tracking that matches the live button pushed
   "Book now" past its column width, wrapping it onto two lines. */
.fs-book-btn .elementor-button,
.fs-book-btn .elementor-button-text {
	white-space: nowrap;
}

/* ==========================================================================
   Footer column grid

   Elementor lays containers out with flex, where percentage widths must be
   hand-balanced against the gap — get it wrong by a few pixels and the last
   column silently wraps. Grid tracks account for the gap themselves, so this
   cannot drift when a column's content changes.
   ========================================================================== */

.fs-footer-grid {
	display: grid !important;
	grid-template-columns: 1.4fr 1fr 1fr 1.3fr;
	gap: 40px 32px;
	align-items: start;
	width: 100%;
}

.fs-footer-grid > .e-con,
.fs-footer-grid > .elementor-element {
	width: auto !important;
	max-width: none !important;
	flex: none !important;
}

@media (max-width: 1024px) {
		.fs-footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 640px) {
	.fs-footer-grid { grid-template-columns: 1fr; gap: 32px; }

	/* Mobile order: Brand, Office, Company, Services.
	   The brand block keeps the top spot so the footer still opens with the
	   logo; the remaining three reverse so contact details come before the
	   link lists — on a phone people are usually after the address or number.
	   Source order stays Brand > Services > Company > Office, which is what
	   screen readers follow and what the desktop grid reads left to right. */
	.fs-footer-grid > *:nth-child(1) { order: 1; } /* Brand    */
	.fs-footer-grid > *:nth-child(2) { order: 4; } /* Services */
	.fs-footer-grid > *:nth-child(3) { order: 3; } /* Company  */
	.fs-footer-grid > *:nth-child(4) { order: 2; } /* Office   */
}



/* SVG flags need the same circular crop the img version had. */
.fs-lang svg.fs-lang__flag,
.elementor-widget-shortcode .fs-lang svg.fs-lang__flag {
	width: 32px !important;
	height: 32px !important;
	border-radius: 50% !important;
	display: block !important;
	overflow: hidden;
	background: #292524;
}
/* Same 32px circle in the list as in the trigger — live reuses the very
   same `w-8 aspect-square rounded-full` wrapper for both. */
.fs-lang__list svg.fs-lang__flag { width: 32px !important; height: 32px !important; }

/* ==========================================================================
   Hero social rail — fs-hero-social

   Live spec: .absolute.w-20.h-full.top-0.right-0 flex column, centred,
   gap 24px, icons 24x24 at rgba(255,255,255,0.6).
   ========================================================================== */

.elementor-widget.fs-hero-social {
	position: absolute;
	top: 0;
	right: 0;
	width: 80px;
	height: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
	z-index: 5;
	pointer-events: none;
}

.fs-hero-social .elementor-widget-container,
.fs-hero-social .elementor-social-icons-wrapper {
	display: flex !important;
	flex-direction: column !important;
	gap: 24px;
	pointer-events: auto;
}

.fs-hero-social .elementor-social-icon {
	background: none !important;
	width: 24px !important;
	height: 24px !important;
	padding: 0 !important;
	margin: 0 !important;
	color: rgba(255, 255, 255, 0.6);
	transition: color 0.3s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.3s ease;
}

/* Hover: each icon takes its own brand colour, read from the live site's
   Tailwind classes (hover:text-pink-500, hover:text-[#25D366], ...).

   Elementor writes `fill` straight onto the svg through an element-ID
   selector (.elementor-element-xxxx .elementor-social-icon svg), which
   outranks anything set on the anchor — so changing `color` alone did
   nothing. The fill has to be overridden per network. */
/* Live only recolours these — `hover:text-<brand> transition-all` and nothing
   else. The 3px slide that used to live here was not on the original. */

.fs-hero-social .elementor-social-icon-instagram:hover svg,
.fs-hero-social .elementor-social-icon-instagram:focus-visible svg { fill: #ec4899 !important; }
.fs-hero-social .elementor-social-icon-whatsapp:hover svg,
.fs-hero-social .elementor-social-icon-whatsapp:focus-visible svg { fill: #25d366 !important; }
.fs-hero-social .elementor-social-icon-facebook:hover svg,
.fs-hero-social .elementor-social-icon-facebook:focus-visible svg { fill: #1877f2 !important; }
.fs-hero-social .elementor-social-icon-youtube:hover svg,
.fs-hero-social .elementor-social-icon-youtube:focus-visible svg { fill: #ff0000 !important; }
.fs-hero-social .elementor-social-icon-linkedin:hover svg,
.fs-hero-social .elementor-social-icon-linkedin:focus-visible svg { fill: #0077b5 !important; }
.fs-hero-social .elementor-social-icon-x-twitter:hover svg,
.fs-hero-social .elementor-social-icon-x-twitter:focus-visible svg { fill: #ffffff !important; }
.fs-hero-social .elementor-social-icon-tiktok:hover svg,
.fs-hero-social .elementor-social-icon-tiktok:focus-visible svg { fill: #ffffff !important; }

.fs-hero-social .elementor-social-icon svg { width: 24px; height: 24px; }

@media (max-width: 767px) {
	.elementor-widget.fs-hero-social { width: 56px; }
	.fs-hero-social .elementor-social-icons-wrapper { gap: 18px; }
	.fs-hero-social .elementor-social-icon,
	.fs-hero-social .elementor-social-icon svg { width: 20px !important; height: 20px !important; }
}

/* ==========================================================================
   Language switcher — click as well as hover

   Touch devices have no hover, so the flag needs a real click/tap toggle.
   Hover is kept for pointer devices via the media query below.
   ========================================================================== */

.fs-lang.is-open .fs-lang__list {
	opacity: 1;
	visibility: visible;
	transform: translateX(-50%) scale(1);
}

/* ==========================================================================
   Accessibility widget — fs-a11y-brand

   Pojo/Ally ships a fixed blue launcher that clashes with the palette.
   Restyled to the FLYSTACK orange. Selectors cover both the legacy
   pojo-a11y markup and the newer Ally (ea11y) widget.
   ========================================================================== */

#pojo-a11y-toggle-button,
.pojo-a11y-toggle-button,
.ea11y-widget-toggle button,
button[class*="ea11y"][class*="toggle"],
#ally-widget-toggle {
	background-color: var(--fs-accent, #fb923c) !important;
	color: #000 !important;
	border-color: var(--fs-accent, #fb923c) !important;
	box-shadow: 0 6px 20px rgba(251, 146, 60, 0.35) !important;
	transition: background-color 0.3s ease, transform 0.3s ease !important;
}

#pojo-a11y-toggle-button:hover,
.pojo-a11y-toggle-button:hover,
.ea11y-widget-toggle button:hover,
#ally-widget-toggle:hover {
	background-color: #f97316 !important;
	transform: scale(1.06);
}

#pojo-a11y-toggle-button svg,
.ea11y-widget-toggle button svg,
#ally-widget-toggle svg {
	fill: #000 !important;
	color: #000 !important;
}

/* Panel chrome, so the opened tray matches the site rather than default blue. */
#pojo-a11y-sidebar .pojo-a11y-toolbar-title,
.ea11y-widget-panel__header {
	background-color: var(--fs-accent, #fb923c) !important;
	color: #000 !important;
}

#pojo-a11y-sidebar .pojo-a11y-toolbar-items a:hover,
#pojo-a11y-sidebar .pojo-a11y-toolbar-items a:focus {
	color: var(--fs-accent, #fb923c) !important;
}

/* ==========================================================================
   Bare-button reset  [Layer 2: Base]

   hello-elementor's reset.css carries

       [type=button]:hover, [type=submit]:hover, button:hover
           { background-color: #c36; color: #fff }

   which is specificity (0,1,1) — higher than a single class — so every
   unstyled <button> in our components flashed a magenta pill on hover: the
   drone-count arrows, the scale numbers, the carousel arrows. Wrapping the
   element part in :where() drops this back to (0,2,0): high enough to beat
   the reset, low enough that each component's own :hover rule still wins.
   ========================================================================== */

:where(button, [type="button"], [type="submit"])[class*="fs-"]:hover,
:where(button, [type="button"], [type="submit"])[class*="fs-"]:focus {
	background-color: transparent;
	color: inherit;
	text-decoration: none;
}

/* ==========================================================================
   Link hover colour  [Layer 2: Base]

   Elementor's kit styles every `a:hover` with the global accent colour. That
   selector is (0,1,1) — higher than a single class — so any custom link that
   only declared `color` in its base rule silently turned orange on hover. On
   the two orange pills that meant the label became the same colour as its own
   background and the button read as an empty capsule.

   None of these change colour on hover on the live site, so each restates the
   colour it already has. Kept together rather than scattered so the next
   custom link has an obvious place to be added.
   ========================================================================== */

.fs-faq__button:hover,
.fs-faq__button:focus-visible,
.fs-factors__more:hover,
.fs-factors__more:focus-visible,
.fs-btn-outline:hover,
.fs-btn-outline:focus-visible,
.fs-project__card:hover,
.fs-project__card:focus-visible {
	color: var(--fs-text, #fafaf9);
}

.fs-factors__link:hover,
.fs-factors__link:focus-visible {
	color: #ffffff;
}

.fs-btn-solid:hover,
.fs-btn-solid:focus-visible {
	color: var(--fs-text, #fafaf9);
}

/* The same reset also carries `white-space: nowrap` on every <button>, which
   is fine for its own short pill buttons and wrong for anything with a
   sentence in it — the FAQ questions ran straight off the side of the phone
   rather than wrapping. Same :where() trick, same reasoning. */
:where(button, [type="button"], [type="submit"])[class*="fs-"] {
	white-space: normal;
}

/* ==========================================================================
   Scroll reveals — fs-reveal  [Layer 3: Components]

   Copied from the live site's initial inline states, which are the only part
   of a JS-driven animation that is readable from the DOM:

     headings / eyebrows   opacity:0; transform:scale(0.8)
     body + bullet rows    opacity:0; transform:translateX(-40px)
     hero headline         opacity:0; transform:translateX(-40px)

   Duration and easing ARE readable, just not from CSS: the live site animates
   with Framer Motion, and its React fiber still carries the props. Read off
   the running page:

     eyebrow / heading   initial {opacity:0, scale:0.8}   duration 0.5
     bullet rows         initial {opacity:0, x:-40px}     duration 0.5, no stagger
     hero headline       initial {opacity:0, x:-40px}     delay 0.4 (default 0.3s)
     stat cells          initial {opacity:0, scale:0.6}   duration 0.5,
                                                          delay 0 / .1 / .2 / .3

   Framer's default easing for a tween is easeOut = cubic-bezier(0,0,.58,1).
   Every value below is that measurement, not an approximation of the feel.

   Elements start hidden ONLY once the observer has claimed them (html.fs-js),
   so if JavaScript fails the content still renders.
   ========================================================================== */

.fs-js .fs-reveal-scale,
.fs-js .fs-reveal-left,
.fs-js .fs-reveal-slide,
.fs-js .fs-reveal-up,
.fs-js .fs-reveal-pop,
.fs-js .fs-reveal-card,
.fs-js .fs-reveal-fade {
	opacity: 0;
	transition: opacity 0.5s cubic-bezier(0, 0, 0.58, 1),
	            transform 0.5s cubic-bezier(0, 0, 0.58, 1);
}

/* will-change ONLY while the element is still waiting to reveal.
   It used to sit on the base rule, which left ~20 elements permanently
   promoted to their own compositor layers long after they had finished
   animating — layers that cost memory and are re-composited on every frame
   the page paints. Browsers promote automatically for the duration of a
   transition; the hint is only worth giving ahead of one that has not run. */
.fs-js .fs-reveal-scale:not(.is-in),
.fs-js .fs-reveal-left:not(.is-in),
.fs-js .fs-reveal-slide:not(.is-in),
.fs-js .fs-reveal-up:not(.is-in),
.fs-js .fs-reveal-pop:not(.is-in),
.fs-js .fs-reveal-card:not(.is-in) {
	will-change: opacity, transform;
}

/* Opacity only — for elements whose transform is already driven by something
   else, like the drone heading's scroll-linked scale. */
.fs-js .fs-reveal-fade  { transform: none; }
.fs-js .fs-reveal-scale { transform: scale(0.8); }
.fs-js .fs-reveal-pop   { transform: scale(0.6); }
/* Feature cards: scale 0.9 over 0.6s, no stagger — the odd one out, so it
   overrides the shared 0.5s duration rather than sharing it. */
.fs-js .fs-reveal-card  { transform: scale(0.9); transition-duration: 0.6s; }
.fs-js .fs-reveal-left  { transform: translateX(-40px); }
/* FAQ rows: translateX(-60px) over 0.6s — a longer throw and a longer
   duration than the -40px/0.5s rows elsewhere, both read off the fiber. */
.fs-js .fs-reveal-slide { transform: translateX(-60px); transition-duration: 0.6s; }
.fs-js .fs-reveal-up    { transform: translateY(30px); }

.fs-js .fs-reveal-scale.is-in,
.fs-js .fs-reveal-left.is-in,
.fs-js .fs-reveal-slide.is-in,
.fs-js .fs-reveal-up.is-in,
.fs-js .fs-reveal-pop.is-in,
.fs-js .fs-reveal-card.is-in {
	opacity: 1;
	transform: none;
}

/* No transform reset here — the element's transform belongs to its own logic. */
.fs-js .fs-reveal-fade.is-in { opacity: 1; }

/* The bullet rows do NOT stagger on the live site — all three carry the same
   duration 0.5 with no delay. An earlier 120/240ms stagger here was invented;
   it read well but did not match. */

/* The stat cells DO stagger: 0 / 0.1 / 0.2 / 0.3. */
.fs-js .fs-stat:nth-child(2) { transition-delay: 100ms; }
.fs-js .fs-stat:nth-child(3) { transition-delay: 200ms; }
.fs-js .fs-stat:nth-child(4) { transition-delay: 300ms; }

@media (prefers-reduced-motion: reduce) {
	.fs-js .fs-reveal-scale,
	.fs-js .fs-reveal-left,
	.fs-js .fs-reveal-slide,
	.fs-js .fs-reveal-up,
	.fs-js .fs-reveal-pop,
	.fs-js .fs-reveal-card {
		opacity: 1 !important;
		transform: none !important;
		transition: none !important;
	}
	.fs-js .fs-reveal-fade { opacity: 1 !important; transition: none !important; }
}

/* ==========================================================================
   Welcome bullets — fs-welcome-list  [Layer 3: Components]

   Live spec: .flex.items-start.justify-center.gap-3 per row, lucide
   square-check-big at 22px stroked #FB923C, text 18px/28px left-aligned,
   rows 12px apart. items-start keeps the icon aligned to the first line of
   text rather than centring against a wrapped block.
   ========================================================================== */

.fs-welcome-eyebrow .elementor-heading-title {
	/* live: margin 24px 0 40px */
	margin: 24px 0 40px !important;
}

.fs-welcome-title .elementor-heading-title {
	/* live: padding 16px 0, letter-spacing normal */
	padding: 16px 0 !important;
	margin: 0 !important;
	letter-spacing: normal !important;
}

.fs-welcome-list {
	display: flex;
	flex-direction: column;
	gap: 12px;
	/* Live rhythm is symmetrical: 40px from the eyebrow down to the heading
	   (its margin-bottom) and 40px from the heading down to the first bullet.
	   Without this the second gap collapsed to 0 and the block read
	   top-heavy. */
	/* Live UL is py-10: 40px above the first bullet and 40px below the last,
	   before the stats grid adds its own 40px on top of that — 80px in total
	   between the last bullet and the first stat.
	   PADDING, not margin: as margin it would collapse against the grid's
	   own 40px margin-top and the pair would render as a single 40px gap. */
	padding-block: 40px;
	margin-block: 0;
	/* Live row is 808px: icon box 38 + gap 12 + text 758. The icon BOX is
	   38 wide even though the glyph draws at 22 — that extra width is what
	   places the text at x=356 rather than 348. */
	max-width: 808px;
	margin-inline: auto;
}

.fs-welcome__row {
	display: flex;
	align-items: flex-start;
	justify-content: center;
	gap: 12px;
	text-align: left;
}

.fs-welcome__icon {
	/* 38px box, 22px glyph — matches the live icon's footprint so the text
	   column starts at the same x. */
	flex: 0 0 38px;
	width: 38px;
	height: 22px;
	overflow: visible;
	color: var(--fs-accent, #fb923c);
	stroke: var(--fs-accent, #fb923c);
	/* mt-1 on the live site — nudges the box down onto the text baseline. */
	margin-top: 4px;
}

.fs-welcome__row span {
	flex: 1 1 auto;
	color: #fafaf9;
}

@media (max-width: 767px) {
	.fs-welcome-list { gap: 14px; }
	.fs-welcome__row { justify-content: flex-start; }
}

/* --------------------------------------------------------------------------
   Eyebrow hairline

   Live markup wraps the eyebrow text in a relatively-positioned inline span
   carrying `after:w-1/3 after:h-[0.5px] after:right-1/2 after:bottom-0
   after:bg-white/60 pb-2`.

   Reproduced with the same mechanism rather than a measured offset. The rule
   is positioned against the containing block Chrome builds for an abs-pos
   child of a multi-line inline box — the span from the first fragment's left
   edge to the last fragment's right edge — which is why the line sits left of
   where "centred" would put it. Hard-coding 97px at a 50% offset would match
   at 1420px and drift at every other width; percentages against the same box
   track it automatically.
   -------------------------------------------------------------------------- */

.fs-eyebrow-rule {
	position: relative;
	padding-bottom: 8px;
}

/* The wordmark, wherever it appears in running text. */
.fs-brand {
	font-family: var(--fs-font-brand);
}

.fs-eyebrow-rule::after {
	content: '';
	position: absolute;
	right: 50%;
	bottom: 0;
	width: 33.3333%;
	height: 0.5px;
	background: rgba(255, 255, 255, 0.6);
}

/* ==========================================================================
   GP4 scroll viewer — fs-drone  [Layer 3: Components]

   A node-for-node mirror of the live section. Each wrapper earns its place:

     .fs-drone        pt-8, pure black          — the section
       __center       text-center
         __hold       sticky top 0, min-h 320px — present on live; cannot
                                                  actually stick, see below
           __col      flex column
             __runway min-height 200vh          — THE SCROLL TARGET
               __abs  absolute inset 0
                 __pin sticky top 0, 100vh      — what actually pins
                   h3            the heading, z 20
                   __stage       the canvas, underneath

   __hold is sticky on live but never moves: its containing block is exactly
   its own height, so there is no room to offset into. Reproduced faithfully
   rather than "cleaned up" — giving it room changes where the next section
   meets the canvas.

   The runway's 200vh is the mechanic: one screen of scrolling maps to 0..1,
   and that number drives the model and the heading. Shrink it and the drone
   spins faster. Behaviour lives in drone-viewer.js.
   ========================================================================== */

.fs-drone {
	position: relative;
	width: 100%;
	padding-top: 32px;          /* live: pt-8 */
	background: #000;           /* live: bg-black, not the page --fs-bg */
	overflow: visible;
}

.fs-drone__center {
	width: 100%;
	text-align: center;
}

.fs-drone__hold {
	position: sticky;
	top: 0;
	width: 100%;
	min-height: 320px;
	overflow: visible;
}

.fs-drone__col {
	display: flex;
	flex-direction: column;
	width: 100%;
	height: 100%;
}

.fs-drone__runway {
	width: 100%;
	height: 100%;
	min-height: 200vh;
	overflow: visible;
}

.fs-drone__abs {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
}

.fs-drone__pin {
	position: sticky;
	top: 0;
	width: 100%;
	height: 100vh;
}

.fs-drone__title {
	position: sticky;
	top: 64px;                  /* live: top-16 */
	display: block;
	height: 100vh;
	margin: 0;
	z-index: 20;
	overflow: hidden;
	transform-origin: top;      /* live: origin-top */
	/* t=0 values, so the heading is right before the module loads. */
	transform: scale(1);
	padding-top: 60px;
	font-family: var(--fs-font);
	font-size: 48px;            /* live: md:text-5xl */
	font-weight: 400;           /* live: font-normal — the bold is on the span */
	/* leading-none. NOT 1.2: with origin-top scaling and a growing padding,
	   the extra half-leading pushes the text down by a few px more at every
	   scroll position, which reads as the title drifting out of sync. */
	line-height: 1;
	text-transform: uppercase;
	text-align: center;
	color: var(--fs-text, #fafaf9);
}

.fs-drone__title > span {
	position: relative;
	font-weight: 700;
	padding: 0 16px;
	/* Live tracking is normal; the base heading rule applies -0.01em. */
	letter-spacing: normal;
}

.fs-drone__title em {
	font-style: normal;
	color: var(--fs-accent, #fb923c);
}

.fs-drone__stage {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

.fs-drone__canvas {
	display: block;
	width: 100%;
	height: 100%;
	/* The canvas overlaps the feature cards by 160px (see .fs-tech-cards) and
	   there is nothing to interact with in the scene, so it must not sit
	   between the cursor and the cards. */
	pointer-events: none;
}

/* --------------------------------------------------------------------------
   Feature cards under the viewer

   Live pulls this block UP into the runway rather than stacking it below:
   `-mt-40` on the wrapper, i.e. margin-top: -160px, so the cards begin 160px
   before the 200vh runway ends and rise over the pinned canvas as the scroll
   finishes. It is deliberate on live, not a rounding artefact — the class is
   right there in the markup, alongside `pb-20`.

   Elementor's own container adds 110px of top padding on top of that, which
   is why the gap read as roughly 300px too large. Both are corrected here.
   -------------------------------------------------------------------------- */

.fs-tech-cards {
	position: relative;
	z-index: 30;
	/* -160px is live's own -mt-40. The extra 20px cancels the flex gap
	   Elementor puts between top-level sections, which live has no
	   equivalent of — without it the cards land 20px low. */
	margin-top: calc(-160px - 20px);
}

.fs-tech-cards > .e-con-inner {
	padding-top: 0;
	padding-bottom: 80px;        /* live: pb-20 */
}

/* Elementor gives every container 10px of default padding; the row and the
   cards inside it stack to 20px, pushing the icons below where live's grid
   starts. Live's grid has none. */
.fs-tech-cards .e-con { padding-top: 0; }

/* If the model cannot load, don't leave two blank screens behind. */
.fs-drone.is-failed .fs-drone__runway { min-height: 100vh; }
.fs-drone.is-failed .fs-drone__stage  { display: none; }

@media (max-width: 767px) {
	.fs-drone__title { font-size: 36px; }   /* live: text-4xl */
}

@media (prefers-reduced-motion: reduce) {
	/* Keep the model, drop the runway: it renders at t=0 and stays put. */
	.fs-drone__runway { min-height: 100vh; }
}

/* ==========================================================================
   Projects — fs-projects / fs-carousel  [Layer 3: Components]

   Measured from live at 1420px:

     section   #000, padding 80px vertical / 64px horizontal (40px below md)
     eyebrow   15px / 300 / uppercase / letter-spacing 4.8px / padding-bottom 40
     heading   48px / 700 / #FB923C / uppercase
     intro     18px / 200 / letter-spacing .05em / padding 16 top, 40 bottom
     viewport  1143px wide, cards 370px tall, radius 32px
     slides    basis 1/3, 16px gutter (-ml-4 on the track, pl-4 per slide)
     scale     the centred card is 1, every other card 0.8
     arrows    31px circles, 1px #FB923C on #0C0A09
     caption   p-4, gradient transparent -> black, 20px/700 title + 20px/400 sub

   The starfield sits behind everything with a 60% black veil over it, which
   is why the stars read as barely-there specks rather than a night sky.
   ========================================================================== */

.fs-projects {
	position: relative;
	width: 100%;
	background: #000;
	padding: 80px 64px;         /* live: py-20 md:px-16 */
	overflow: hidden;
	isolation: isolate;
}

.fs-projects__stars,
.fs-projects__veil {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
}

.fs-projects__stars { z-index: 0; }

/* live: an absolutely positioned bg-black/60 over the canvas */
.fs-projects__veil {
	z-index: 1;
	background: rgba(0, 0, 0, 0.6);
}

.fs-projects__inner {
	position: relative;
	z-index: 2;
	width: 100%;
}

.fs-projects__eyebrow {
	margin: 0;
	padding-bottom: 40px;
	font-size: 15px;
	font-weight: 300;
	line-height: 1.5;
	text-transform: uppercase;
	letter-spacing: 4.8px;      /* live: tracking-[0.3rem] */
	text-align: center;
	/* Alpha colour, not opacity — .fs-reveal-fade animates opacity to 1. */
	color: rgba(250, 250, 249, 0.8);
}

.fs-projects__title {
	margin: 0;
	font-size: 48px;
	font-weight: 700;
	line-height: 1;
	text-transform: uppercase;
	letter-spacing: normal;
	text-align: center;
	color: var(--fs-accent, #fb923c);
}

.fs-projects__intro {
	margin: 0;
	padding: 16px 0 40px;
	font-size: 18px;
	font-weight: 200;
	letter-spacing: 0.05em;
	text-align: center;
	color: var(--fs-text, #fafaf9);
}

/* --- carousel ----------------------------------------------------------- */

/* Live's wrapper spans the full content box and insets the viewport with
   padding (40 left / 64 right), then hangs the arrows outside it absolutely —
   48px clear of the viewport edge on both sides. Laying the arrows out in
   flow instead made the viewport 86px wider than live's and the cards
   correspondingly oversized. */
.fs-carousel {
	position: relative;
	margin-top: 40px;
	padding-left: 40px;         /* live: md:px-10 */
	padding-right: 64px;        /* live: md:pe-16 */
	padding-bottom: 40px;
}

.fs-carousel__viewport {
	overflow: hidden;
	width: 100%;
}

.fs-carousel__track {
	display: flex;
	margin-left: -16px;          /* live: -ml-4, paired with pl-4 per slide */
	will-change: transform;
	transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1);
}

.fs-project {
	flex: 0 0 33.3333%;
	min-width: 0;
	padding-left: 16px;
	box-sizing: border-box;
}

.fs-project__card {
	position: relative;
	display: block;
	/* Live's card is not a fixed height — it holds a 4:5 portrait ratio at
	   every viewport (measured 0.802 at both 1420 and 1512 wide) and lets the
	   height follow the slide width. Building it as a fixed 370px box made it
	   landscape, which is what was cropping the taller covers. */
	aspect-ratio: 4 / 5;
	height: auto;
	max-width: 600px;
	margin-inline: auto;
	border-radius: 32px;
	overflow: hidden;
	text-decoration: none;
	background: var(--fs-surface, #292524);
	/* Off-centre cards sit back at 0.8; the centred one comes forward. */
	transform: scale(0.8);
	transition: transform 0.5s cubic-bezier(0.25, 1, 0.5, 1);
}

.fs-project.is-active .fs-project__card { transform: scale(1); }

/* The card is filled edge to edge, anchored to the TOP of the photo.
   These are drone-show frames: the figure is always in the sky, in the upper
   part of the image, and the lower part is crowd, stage or ground. Cropping
   from the bottom keeps the subject; centring the crop (the browser default)
   cut the top off the portrait covers, which is what made the cards look
   like they were losing the shot.

   Scoped to .fs-projects on purpose: Elementor ships
   `.elementor img { height: auto }` at specificity (0,1,1), which outranks a
   lone class — with `.fs-project__img` alone the image kept its intrinsic
   height and sat at the top of the card instead of filling it. */
.fs-project__media {
	position: absolute;
	inset: 0;
	display: block;
	overflow: hidden;
}

.fs-projects .fs-project__img {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 0;
}

/* Two gradients doing two different jobs.

   The source paints ONE, full-card, `from-transparent to-black`, held at
   `opacity-0` until `group-hover`. Copied literally that leaves the title
   sitting on bare photograph at rest, and on the brighter covers — ART IS
   ALIVE, the Untold frames — it is genuinely hard to read.

   So: a permanent scrim under the caption only, and the source's full-card
   gradient still fading in on hover over the top of it. Same treatment, and
   the same 45%/0.85 numbers, as the Projects archive cards, so the two places a
   visitor sees a project cover behave alike.

   `transition-all` with no duration is Tailwind's 150ms default, not the 500ms
   the surrounding card uses. */
.fs-project__veil {
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	height: 45%;
	background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.85) 100%);
}

.fs-project__veil::after {
	content: '';
	position: absolute;
	inset: -122.222% 0 0;   /* 45% tall element, so -122.2% regains the full card */
	background: linear-gradient(to bottom, transparent, #000);
	opacity: 0;
	transition: opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-project__card:hover .fs-project__veil::after,
.fs-project__card:focus-visible .fs-project__veil::after {
	opacity: 1;
}

.fs-project__caption {
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	margin: 0;
	padding: 16px;
	font-size: 20px;
	line-height: 1.35;
	text-align: left;
	color: var(--fs-text, #fafaf9);
	transition: padding-bottom 0.5s ease;
}

.fs-project__card:hover .fs-project__caption { padding-bottom: 24px; }

.fs-project__name { font-weight: 700; }
.fs-project__sub  { font-weight: 400; }

/* 32px, from shadcn's carousel: `absolute h-8 w-8 rounded-full`. An earlier
   pass had these at 30px, measured by eye rather than read off the component. */
.fs-carousel__arrow {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 2;
	width: 32px;
	height: 32px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: 1px solid var(--fs-accent, #fb923c);
	border-radius: 9999px;
	background: var(--fs-bg, #0c0a09);
	color: var(--fs-text, #fafaf9);
	cursor: pointer;
	padding: 0;
	transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
	            background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Live: `hover:bg-accent hover:text-accent-foreground` — accent in the dark
   theme is #292524, foreground stays #FAFAF9. It does not fill orange. */
.fs-carousel__arrow:hover,
.fs-carousel__arrow:focus-visible {
	background: #292524;
	color: var(--fs-text, #fafaf9);
}

.fs-carousel__arrow[disabled] { opacity: 0.4; cursor: default; }

/* 48px outside the viewport: the wrapper's own padding is 40 left / 64 right,
   so the offsets are measured back from those edges. */
/* Live hangs each arrow 16px clear of the viewport edge. These offsets are
   measured against the wrapper's own 40/64 padding, and were re-nudged by 2px
   when the arrows went from 32 to live's real 30px. */
.fs-carousel__arrow--prev { left: -6px; }
.fs-carousel__arrow--next { right: 18px; }

/* --- the pill button --------------------------------------------------- */

.fs-projects__more { text-align: center; }

.fs-btn-outline {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 0 24px;
	height: 50px;
	border: 1px solid var(--fs-accent, #fb923c);
	border-radius: 999px;
	background: transparent;
	color: var(--fs-text, #fafaf9);
	font-size: 18px;
	font-weight: 500;
	text-decoration: none;
	transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Live: `hover:bg-black/60 hover:scale-110` — it darkens and grows, it does
   not fill orange, and the label colour never changes. Filling it orange with
   black text was invented. */
.fs-btn-outline:hover,
.fs-btn-outline:focus-visible {
	background: rgba(0, 0, 0, 0.6);
	color: var(--fs-text, #fafaf9);
	transform: scale(1.1);
}

@media (max-width: 1023px) {
	.fs-project { flex-basis: 100%; }
	.fs-project__card { transform: scale(1); max-width: 384px; }
	.fs-carousel__viewport { display: flex; justify-content: center; }
}

@media (max-width: 767px) {
	.fs-projects { padding: 64px 40px; }   /* live: px-10 */
	.fs-projects__title { font-size: 36px; }
	/* Live's wrapper paddings are md:-prefixed, so below 768 the viewport runs
	   full width — which leaves nowhere outside for the arrows to hang. Bring
	   them inside rather than off the edge of the screen. */
	.fs-carousel { padding-left: 0; padding-right: 0; }
	.fs-carousel__arrow--prev { left: 0; }
	.fs-carousel__arrow--next { right: 0; }
}

@media (prefers-reduced-motion: reduce) {
	.fs-carousel__track,
	.fs-project__card { transition: none; }
}

/* ==========================================================================
   Process timeline — fs-process  [Layer 3: Components]

   Vertical, as on live. A 240px orange bar sticks 80px below the top of the
   viewport and travels down a centre rail while four steps pass it; each step
   goes grey -> white as the bar reaches its dot.

   Measured from live at 1420px:
     wrapper  max-width 800, centred
     eyebrow  15 / 300 / uppercase / ls 4.8 / padding-top 80
     heading  48 / 700 / uppercase / margin-bottom 80
     bar      sticky top 80, 4x240, linear-gradient(transparent 5%, #FB923C)
     steps    margin-top -80, grid 320 + 320, gutter 160
     label    sticky top 256, 36 / 700 / uppercase, padding 40 0, mb 16
     dot      sticky top 256, 20x20, 4px border in the page background
     when     24 / 700 / uppercase, padding-bottom 8; sub 14 / 400 block
     state    #6D6C6B -> #FFFFFF, transition all .2s ease-in-out

   The dot's border is the trick worth keeping: it is drawn in the page
   background colour, so it punches a clean gap through the bar passing behind
   it instead of sitting on top of a continuous line.
   ========================================================================== */

.fs-process {
	position: relative;
	width: 100%;
	max-width: 800px;
	margin-inline: auto;
}

/* The rail's containing block: head + steps only. Live keeps the Fast-Line
   block outside the timeline wrapper so the bar stops with the last step. */
.fs-process__flow {
	position: relative;
}

/* Sits above the rail and masks the bar behind the title.
   The 80px padding-bottom is load-bearing, not spacing for its own sake: the
   gradient is opaque for its top half and fades out over the bottom, so the
   block's height decides where the bar becomes visible. Without the padding
   the fade ended too high and the bar appeared alongside the heading instead
   of starting cleanly below it. Live's head measures 351px:
   143 eyebrow + 48 title + 80 title margin + 80 padding. */
.fs-process__head {
	position: relative;
	z-index: 10;
	padding-bottom: 80px;
	background: linear-gradient( to bottom, var(--fs-bg, #0c0a09) 50%, transparent );
}

.fs-process__eyebrow {
	margin: 0;
	padding: 80px 0 40px;
	font-size: 15px;
	font-weight: 300;
	line-height: 1.5;
	text-transform: uppercase;
	letter-spacing: 4.8px;
	text-align: center;
	/* Live dims this with opacity-80. Expressed as an alpha colour instead:
	   the element also carries .fs-reveal-fade, and the reveal system animates
	   `opacity` to 1 — so a design rule written as opacity is silently undone
	   the moment the element reveals. */
	color: rgba(250, 250, 249, 0.8);
}

.fs-process__title {
	margin: 0 0 80px;
	font-size: 48px;
	font-weight: 700;
	line-height: 1;
	text-transform: uppercase;
	letter-spacing: normal;
	text-align: center;
	color: var(--fs-text, #fafaf9);
	/* Live: text-shadow: #ffffff 0 0 6px — a tight white glow. Easy to miss
	   against a white heading on black, but it is what gives the title its
	   slight bloom. */
	text-shadow: 0 0 6px #ffffff;
}

.fs-process__track {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	z-index: 0;
	pointer-events: none;
}

.fs-process__bar {
	position: sticky;
	top: 80px;
	display: block;
	width: 4px;
	height: 240px;
	margin-left: 50%;
	transform: translateX(-50%);
	border-radius: 999px;
	background: linear-gradient( to bottom, transparent 5%, var(--fs-accent, #fb923c) );
}

.fs-process__steps {
	position: relative;
	z-index: 1;
	margin: -80px 0 0;
	padding: 0;
	list-style: none;
}

.fs-step__grid {
	position: relative;
	display: grid;
	grid-template-columns: 320px 320px;
	column-gap: 160px;
	color: #6d6c6b;
	transition: color 0.2s ease-in-out;
}

.fs-step.is-active .fs-step__grid { color: #ffffff; }

.fs-step__label {
	position: sticky;
	top: 256px;
	display: block;
	width: 100%;
	padding: 40px 0;
	margin-bottom: 16px;
	font-size: 36px;
	font-weight: 700;
	line-height: 40px;
	text-transform: uppercase;
	text-align: left;
	color: inherit;
}

.fs-step__rail {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	padding-bottom: 32px;
}

.fs-step__dot {
	position: sticky;
	top: 256px;
	display: block;
	width: 20px;
	height: 20px;
	margin-left: 50%;
	transform: translateX(-50%) translateY(48px);
	border-radius: 999px;
	border: 4px solid var(--fs-bg, #0c0a09);
	background: #6d6c6b;
	transition: background-color 0.2s ease-in-out;
}

.fs-step.is-active .fs-step__dot { background: #ffffff; }

.fs-step__body { padding: 40px 0; }

.fs-step__when {
	margin: 0;
	padding-bottom: 8px;
	font-size: 24px;
	font-weight: 700;
	line-height: 32px;
	text-transform: uppercase;
	letter-spacing: normal;
	color: inherit;
}

.fs-step__sub {
	display: block;
	font-size: 14px;
	font-weight: 400;
	line-height: 20px;
}

.fs-step__desc {
	margin: 0;
	color: inherit;
}

/* --- Fast-Line block --------------------------------------------------- */

.fs-process__fast {
	position: relative;
	z-index: 1;
	max-width: 512px;
	margin-inline: auto;
	text-align: center;
	padding-bottom: 80px;
}

.fs-process__fasttitle {
	margin: 96px 0 0;
	padding-bottom: 16px;
	font-size: 24px;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: normal;
	color: var(--fs-accent, #fb923c);
}

.fs-process__fastdesc {
	margin: 0;
	padding-bottom: 24px;
	color: var(--fs-text, #fafaf9);
}

/* The Fast-Line CTA. Despite the name this is NOT solid on live — it is
   `bg-transparent border border-primary h-9 text-base` at 124x42 with
   `hover:text-accent-foreground hover:bg-black/60`, so only the backdrop
   changes on hover. It shipped here as a solid orange pill with black text,
   which was never live's design. Class name kept so the section markup does
   not have to move. */
.fs-btn-solid {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	height: 42px;
	padding: 0 20px;
	border: 1px solid var(--fs-accent, #fb923c);
	border-radius: 9999px;
	background: transparent;
	color: var(--fs-text, #fafaf9);
	font-size: 16px;
	font-weight: 500;
	text-decoration: none;
	transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-btn-solid:hover,
.fs-btn-solid:focus-visible {
	background: rgba(0, 0, 0, 0.6);
	color: var(--fs-text, #fafaf9);
}

@media (max-width: 767px) {
	/* Live drops to a single column and moves the rail to the left edge.
	   Both the bar and the dot keep -translate-x-1/2 at every breakpoint —
	   only the `left` changes (left-0 below sm, sm:left-1/2 above). Dropping
	   the translate from the bar alone left its centre 2px right of the dots'
	   centre, which reads as the line running off-centre through them. */
	.fs-step__grid { grid-template-columns: 1fr; column-gap: 0; padding-left: 32px; }
	.fs-process__bar { margin-left: 0; transform: translateX(-50%); }
	.fs-step__dot   { margin-left: 0; transform: translateX(-50%) translateY(48px); }
	.fs-process__title { font-size: 36px; }
	.fs-step__label { font-size: 28px; padding: 24px 0 0; margin-bottom: 0; position: static; }
	.fs-step__body  { padding: 8px 0 32px; }
}

@media (prefers-reduced-motion: reduce) {
	.fs-step__grid,
	.fs-step__dot { transition: none; }
}

/* ==========================================================================
   Our clients — fs-clients  [Layer 3: Components]

   Measured from live at 1420px:
     section   #000, padding 64 (24/48 below md), overflow hidden
     container max-width 1000, overflow hidden, relative
     eyebrow   14px / 300 / uppercase / letter-spacing 1.4px
     strip     height 80, margin-top 56
     track     flex, gap 64, 25s linear infinite, ~53px/s
     masks     56px, #000 -> transparent at 30%, both edges, z 30

   The loop is two identical sets, each with a trailing gap of its own, so
   translateX(-50%) advances exactly one set. Live hard-codes -1328px, which
   is one set's width at its specific logo sizes — correct today, wrong the
   moment a logo changes.
   ========================================================================== */

.fs-clients {
	width: 100%;
	padding: 64px;
	background: #000;
	overflow: hidden;
}

.fs-clients__inner {
	position: relative;
	width: 100%;
	max-width: 1000px;
	margin-inline: auto;
	overflow: hidden;
}

.fs-clients__eyebrow {
	margin: 0;
	font-size: 14px;
	font-weight: 300;
	line-height: 20px;
	text-transform: uppercase;
	letter-spacing: 1.4px;
	text-align: center;
	color: var(--fs-text, #fafaf9);
}

.fs-clients__strip {
	position: relative;
	width: 100%;
	height: 80px;
	margin-top: 56px;
}

.fs-clients__track {
	position: absolute;
	top: 0;
	left: 0;
	display: flex;
	height: 100%;
	animation: fs-marquee 25s linear infinite;
}

.fs-clients__set {
	display: flex;
	align-items: center;
	gap: 64px;
	/* The trailing gap belongs to the set, not to the track. That is what
	   makes -50% land exactly one set along instead of half a gap short. */
	padding-right: 64px;
	flex: 0 0 auto;
}

/* Scoped to .fs-clients to outrank Elementor's `.elementor img { height: auto }`
   at (0,1,1). Unscoped, the logos rendered at natural size and one set came
   out 21,576px wide — which the marquee then dutifully timed at 407 seconds. */
.fs-clients .fs-clients__logo {
	display: block;
	width: auto;
	max-width: 160px;
	height: 80px;
	object-fit: contain;
	flex: 0 0 auto;
}

/* live: scale-75 on the municipal crests — 80 x 0.75 = 60. */
.fs-clients .fs-clients__logo--crest { height: 60px; }

@keyframes fs-marquee {
	from { transform: translateX(0); }
	to   { transform: translateX(-50%); }
}

.fs-clients__mask {
	position: absolute;
	top: 0;
	width: 56px;
	height: 100%;
	z-index: 30;
	pointer-events: none;
}

.fs-clients__mask--start {
	left: 0;
	background: linear-gradient( to right, #000 30%, transparent );
}

.fs-clients__mask--end {
	right: 0;
	background: linear-gradient( to left, #000 30%, transparent );
}

@media (max-width: 767px) {
	.fs-clients { padding: 48px 24px 32px; }   /* live: px-6 py-12 pb-8 */
}

@media (prefers-reduced-motion: reduce) {
	.fs-clients__track { animation: none; }
}

/* ==========================================================================
   Pricing — fs-pricing  [Layer 3: Components]

   Measured from live at 1420px:
     card     1px #FB923C, radius 64, padding 64, transition all .5s
     eyebrow  15 / 300 / uppercase / ls 4.8 / padding-bottom 40
     heading  36 / 400, text-shadow #ffffff 0 0 10px
     panel    grid, two 403px columns
     icon     40x40 circle, 1px white, margin-bottom 24
     label    20 / 700 / uppercase / ls 4.8 / #FB923C
     desc     16 / #A8A29E, padding-top 16
     stepper  24px, gap 12, margin-top 16
     scale    six stops over 320px, 16 / #FAFAF9
     ticks    4x1px rgba(255,255,255,.4)
     thumb    32x32, 4px #414141, page-background fill
   ========================================================================== */

.fs-pricing {
	width: 100%;
	/* Live wraps the card in `.container`, whose real rule is
	     width:100%; margin-inline:auto; padding-inline:2rem
	     @media (min-width:1000px){ max-width:1000px }
	   The 32px inline padding applies at EVERY width, which is what keeps the
	   card off the edge of a phone. Without it ours went full-bleed and both
	   the title and the description broke later than live's. Desktop is
	   unaffected: min(936, 1440-64) is still 936. */
	padding: 80px 32px 40px;    /* live: pt-20 pb-10 + container padding */
	background: #000;
	overflow: hidden;
}

.fs-pricing__card {
	width: 100%;
	max-width: 936px;
	margin-inline: auto;
	padding: 64px;
	border: 1px solid var(--fs-accent, #fb923c);
	border-radius: 64px;
	transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
	overflow: hidden;
}

/* Live holds the card at 0.95 until it is roughly a third of the way up the
   viewport, then releases it to full size — a threshold rather than a scrub,
   with the 0.5s transition above doing the easing. See projects.js. */
.fs-pricing__card.is-small {
	transform: scale(0.95);
}

/* Live puts z-30 on the head block so it sits above the absolutely-positioned
   video stage (z-0); without it the black video paints over the centred text. */
.fs-pricing__eyebrow,
.fs-pricing__title {
	position: relative;
	z-index: 30;
}

.fs-pricing__eyebrow {
	margin: 0;
	padding-bottom: 40px;
	font-size: 15px;
	font-weight: 300;
	text-transform: uppercase;
	letter-spacing: 4.8px;
	line-height: 22.5px;
	text-align: center;
	color: rgba(250, 250, 249, 0.8);
	/* live wraps the head in `sm:px-6`, so the text column is 760 not 808.
	   Without it the title broke a word later than live's did. */
	padding-inline: 24px;
}

.fs-pricing__title {
	margin: 0;
	padding-bottom: 24px;
	font-size: 36px;
	font-weight: 400;
	line-height: 40px;
	text-align: center;
	padding-inline: 24px;
	color: var(--fs-text, #fafaf9);
	text-shadow: 0 0 10px #ffffff;   /* live uses 10px here, 6px on the process title */
}

.fs-pricing__panel {
	position: relative;
	display: grid;
	grid-template-columns: 1fr 1fr;
	align-items: center;
	margin-top: 80px;
}

.fs-pricing__controls {
	display: flex;
	justify-content: flex-end;
	gap: 0;
	height: 100%;
}

/* Live: `lg:pe-28 w-full flex flex-col justify-between items-start h-full` —
   381px wide with 112px inline-end padding, so the text column is 269px and
   the stepper is pushed to the foot of the 320px row. */
.fs-pricing__info {
	flex: 1 1 auto;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	height: 100%;
	padding-inline-end: 112px;
}

.fs-pricing__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	margin-bottom: 24px;
	border: 1px solid #fff;
	border-radius: 999px;
	color: var(--fs-accent, #fb923c);
}

.fs-pricing__label {
	margin: 0;
	font-size: 20px;
	font-weight: 700;
	line-height: 28px;
	text-transform: uppercase;
	letter-spacing: 4.8px;
	color: var(--fs-accent, #fb923c);
}

.fs-pricing__desc {
	margin: 0;
	padding-top: 16px;
	font-size: 16px;
	line-height: 24px;
	color: var(--fs-muted, #a8a29e);
}

.fs-pricing__stepper {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-top: auto;
	padding: 4px 8px;
	font-size: 24px;
	line-height: 32px;
	color: var(--fs-text, #fafaf9);
}

.fs-pricing__step {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 24px;
	height: 24px;
	padding: 4px;
	border: 0;
	border-radius: 999px;
	background: none;
	overflow: hidden;
	cursor: pointer;
}

/* Live draws the caret hollow — transparent fill, 20-unit white stroke on a
   256x512 viewBox — and fills it solid white on hover over 150ms. Disabled
   swaps the stroke to the muted grey and drops the pointer. */
.fs-pricing__step svg {
	display: block;
	width: 100%;
	height: 100%;
	fill: transparent;
	stroke: #ffffff;
	stroke-width: 20;
	transition: fill 0.15s cubic-bezier(0.4, 0, 0.2, 1),
	            stroke 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-pricing__step:hover:not([disabled]) svg,
.fs-pricing__step:focus-visible:not([disabled]) svg { fill: #ffffff; }

.fs-pricing__step[disabled] { cursor: default; }
.fs-pricing__step[disabled] svg { stroke: var(--fs-muted, #a8a29e); fill: transparent; }

/* --- the slider ---------------------------------------------------------- */

.fs-pricing__slider {
	position: relative;
	flex: 0 0 22px;
	display: flex;
	justify-content: flex-start;
	width: 22px;
	height: 320px;
	user-select: none;
	-webkit-user-select: none;
}

/* Numbers and ticks share one column-reverse / space-between stack hung 48px
   to the left of the rail — that is what spaces the four ticks evenly inside
   each gap without a second scale to keep in sync. */
.fs-pricing__scale {
	position: absolute;
	top: 0;
	left: -48px;
	display: flex;
	flex-direction: column-reverse;
	justify-content: space-between;
	align-items: flex-end;
	width: 32px;
	height: 100%;
	margin: 0;
	padding: 0;
	list-style: none;
	text-align: right;
}

.fs-pricing__stop {
	padding: 0;
	border: 0;
	background: none;
	font-size: 16px;
	line-height: 24px;
	color: var(--fs-text, #fafaf9);
	cursor: pointer;
	transition: color 0.2s ease;
}

/* Live's numbers carry `cursor-pointer` and nothing else — no hover colour,
   and the current one is not marked either; the handle is the only indicator. */

.fs-pricing__tick {
	display: block;
	width: 4px;
	height: 1px;
	background: rgba(255, 255, 255, 0.4);
}

.fs-pricing__rail {
	position: relative;
	width: 16px;
	height: 100%;
	background: none;
	cursor: pointer;
	touch-action: none;             /* let the thumb be dragged, not the page */
}

/* Radix splits this in two: a clipped track holding the filled range, and the
   thumb as a sibling so it is not cut off by the track's overflow. */
.fs-pricing__track {
	position: absolute;
	inset: 0;
	overflow: hidden;
	border-radius: 999px;
	background: #121212;
}

.fs-pricing__range {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	top: 100%;                      /* JS moves the top edge; 100% = empty */
	background: var(--fs-accent, #fb923c);
}

.fs-pricing__rail:focus-visible {
	outline: 2px solid var(--fs-accent, #fb923c);
	outline-offset: 4px;
}

.fs-pricing__thumb {
	position: absolute;
	left: 50%;
	bottom: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	margin-left: -16px;
	border: 4px solid #414141;
	border-radius: 999px;
	background: var(--fs-bg, #0c0a09);
	box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
	overflow: hidden;
	z-index: 1;
	cursor: grab;
	/* Live puts no transition on the handle's position — it tracks the pointer
	   frame for frame. Easing it made dragging feel like it lagged behind. */
}

.fs-pricing__rail.is-dragging .fs-pricing__thumb { cursor: grabbing; }

/* Live: `w-10 h-10 object-center object-cover` on a 40px square inside the
   32px thumb (24px of content after the 4px border), so the mark is cropped
   rather than shrunk. `.elementor img { height: auto }` outranks a bare class,
   hence the scoped selector. */
.fs-pricing .fs-pricing__thumb img {
	display: block;
	width: 100%;
	max-width: none;
	height: 40px;
	object-fit: cover;
	object-position: center;
	pointer-events: none;
	-webkit-user-drag: none;
}

/* Live renders the clip at 907x907 inside a 403px column, so it bleeds well
   past the cell on both sides and the card's overflow:hidden crops it. That
   overscale is why the formation reads large and fills the right of the card
   rather than sitting in a neat box. */
/* Out of flow on purpose. In flow, a 907px-tall clip set the row height and
   pushed the card to 1749px against live's 1285 — live's grid row stays 320px
   because the clip overflows it rather than sizing it. The 112px offset is
   measured: live's video sits at x418 inside a card whose content starts at
   x306. */
/* Anchored to the right-hand column, not to a fixed 112px: live's clip lives
   inside the second grid cell, so its offset tracks the panel's midpoint. At
   1440 `50% - 291` resolves to the measured 112px; at narrower widths it keeps
   the same relationship instead of sliding out of the card. */
.fs-pricing__stage {
	position: absolute;
	top: 50%;
	left: calc(50% - 291px);
	transform: translateY(-50%);
	width: 907px;
	height: 907px;
	z-index: 0;
	pointer-events: none;
}

.fs-pricing .fs-pricing__video {
	display: block;
	width: 907px;
	max-width: none;
	height: 907px;
	object-fit: cover;
	pointer-events: none;
}

/* The controls sit above the oversized clip — live gives its slider column
   z-50 for exactly this reason. */
.fs-pricing__controls { position: relative; z-index: 10; }

/* --- cost factors -------------------------------------------------------- */

.fs-pricing__factors {
	position: relative;
	z-index: 30;
	margin-top: 112px;
}

.fs-factors__title {
	margin: 0;
	padding: 0 16px 24px;
	font-size: 18px;
	font-weight: 700;
	line-height: 28px;
	text-transform: uppercase;
	letter-spacing: normal;
	text-align: center;
	color: var(--fs-accent, #fb923c);
}

.fs-factors__list {
	margin: 24px 0 0;
	padding: 0;
	list-style: none;
	width: 100%;
}

.fs-factors__item { width: 100%; text-align: center; }
.fs-factors__item + .fs-factors__item { margin-top: 16px; }

/* Elementor's own `hr` rule zeroes the inline margins, which left the 50%
   rule hugging the left edge instead of centred — hence the extra class. */
.fs-factors__list .fs-factors__rule {
	max-width: 50%;
	margin: 0 auto;
	border: 0;
	border-top: 1px solid rgba(255, 255, 255, 0.2);
}

.fs-factors__link {
	display: block;
	padding-top: 16px;
	font-size: 16px;
	font-weight: 300;
	line-height: 24px;
	color: #fff;
	text-decoration: none;
	transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-factors__link:hover,
.fs-factors__link:focus-visible { transform: scale(1.25); }

/* "Read more" pill — live: flex justify-center, margin-top 64, orange button
   20px / 500, radius 9999, padding 0 28, height 40. */
.fs-factors__cta {
	display: flex;
	justify-content: center;
	margin-top: 64px;
}

.fs-factors__more {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	height: 40px;
	padding: 0 28px;
	border-radius: 9999px;
	background: var(--fs-accent, #fb923c);
	color: var(--fs-text, #fafaf9);
	font-size: 20px;
	font-weight: 500;
	line-height: 1;
	white-space: nowrap;
	text-decoration: none;
	box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
	            color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-factors__more:hover,
.fs-factors__more:focus-visible { background: rgba(251, 146, 60, 0.9); }

/* --- the phone-only control ------------------------------------------------
   Live replaces the whole left column below sm with

     flex sm:hidden w-full items-start justify-center gap-1 mt-6 mb-10
     -translate-x-16 z-30 relative

   holding a vertical caret stack (`flex-col text-2xl p-1 px-2 text-primary`)
   and a `relative pt-10 pb-10` paragraph whose description is absolutely
   positioned 66px down. The -64px nudge is live's: the row is centred first,
   then pulled left because the description overhangs to the right.
   -------------------------------------------------------------------------- */

.fs-pricing__mobile {
	display: none;
	width: 100%;
	align-items: flex-start;
	justify-content: center;
	gap: 4px;
	margin: 24px 0 40px;
	transform: translateX(-64px);
	position: relative;
	z-index: 30;
}

.fs-pricing__mstack {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0;
	margin-top: 10px;
	padding: 4px 8px;
	font-size: 24px;
	line-height: 32px;
	color: var(--fs-accent, #fb923c);
	z-index: 10;
}

/* Solid carets, unlike the hollow left/right pair on desktop.

   `color` has to be restated: hello-elementor's reset sets `color: #c36` on
   every bare <button> at (0,0,1), and since the button never inherits from
   .fs-pricing__mstack the carets rendered magenta. */
.fs-pricing__caret {
	width: 24px;
	height: 24px;
	padding: 0;
	overflow: visible;
	color: var(--fs-accent, #fb923c);
}

.fs-pricing__caret svg { fill: currentColor; stroke: none; }
.fs-pricing__caret:hover:not([disabled]) svg { fill: currentColor; }
.fs-pricing__caret[disabled] { color: var(--fs-muted, #a8a29e); }
.fs-pricing__caret[disabled] svg { fill: currentColor; stroke: none; }

/* Tapping the count steps to the next value. A real <button> for keyboard and
   screen-reader users; the resets are because hello-elementor's reset styles
   every bare button with a border, a magenta colour and its own font. */
.fs-pricing__cycle {
	font: inherit;
	color: inherit;
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
	line-height: inherit;
}

.fs-pricing__count {
	color: var(--fs-accent, #fb923c);
}

.fs-pricing__munit {
	position: relative;
	margin: 0;
	padding: 40px 0;
}

.fs-pricing__munit-word {
	font-size: 20px;
	line-height: 28px;
	color: #ffffff;
}

.fs-pricing__mdesc {
	position: absolute;
	top: 0;
	left: 0;
	margin-top: 66px;
	min-width: max-content;
	font-size: 12px;
	line-height: 16px;
	color: var(--fs-muted, #a8a29e);
}

/* --- below lg: live's slider is `lg:block hidden`, so it does not exist on
   tablet either. The info column loses the 112px reserve it kept for it. --- */
@media (max-width: 1023px) {
	.fs-pricing__slider { display: none; }
	.fs-pricing__info { padding-inline-end: 0; }
}

/* --- 640-767: card padding drops from md:p-16 to sm:p-8 --- */
@media (max-width: 767px) and (min-width: 640px) {
	.fs-pricing__card { padding: 32px; }
}

/* --- below sm: single column, clip on top, compact control below --- */
@media (max-width: 639px) {
	.fs-pricing__card { padding: 32px 16px; }
	.fs-pricing__eyebrow,
	.fs-pricing__title { padding-inline: 0; }
	.fs-pricing__title { font-size: 24px; line-height: 32px; }
	.fs-pricing__panel { grid-template-columns: 1fr; }
	.fs-pricing__controls { order: 2; height: auto; }
	.fs-pricing__info { display: none; }
	.fs-pricing__mobile { display: flex; }
	/* `sm:mt-28` — no top margin at all below the breakpoint. */
	.fs-pricing__factors { margin-top: 0; }
}

@media (max-width: 767px) {
	/* No padding override here: live's wrapper is `pb-10 pt-20` with no
	   responsive prefix, and the container's 32px inline padding applies at
	   every width. A flat `48px 0` was letting the card run edge to edge. */
	/* Radius stays 64px at every width on live — only the padding changes. */
	.fs-pricing__panel { grid-template-columns: 1fr; }
	.fs-pricing__controls { justify-content: center; height: auto; }
	/* Live's clip is `order-1 sm:order-2`: on a phone it sits ABOVE the
	   control, not beside it. */
	.fs-pricing__stage {
		order: 1;
		position: static;
		transform: none;
		width: 100%;
		left: auto;
		top: auto;
	}
	/* Phone only: pull the clip in.

	   Two separate gaps were adding up. The 80px head padding is one; the
	   other is inside the mp4 itself — the clips are square (1080x1080) with the
	   formation floating in the middle, so a 1:1 box renders a band of dead
	   black above and below the drones.

	   How far it is safe to crop was measured, not guessed: per-frame
	   cropdetect over all 178 frames of each clip gives the vertical extent of
	   lit pixels as a share of frame height —

	       50   32.8% - 53.7%        300  20.4% - 66.9%
	       100  28.7% - 57.8%        400  17.2% - 70.0%
	       200  25.9% - 60.4%        500  14.1% - 79.4%

	   so the union across every clip and every frame is 14.1% - 79.4%, whose
	   midpoint is 47%. The clip box is a flat 300px tall here. Note that at
	   300 against a 292px column the box is TALLER than it is wide, so
	   object-fit:cover scales the square source to 300x300 and crops 8px
	   horizontally rather than trimming any dead frame off the top and bottom
	   — the full height of every formation is visible, with the original black
	   bands around it. object-position's 47% is therefore doing nothing
	   vertically at this size; it is kept so the crop reappears correctly if
	   the box is ever shortened below the column width again.

	   Desktop and tablet keep live's spacing untouched. */
	/* Half of the 40px this block already carried; live's own value is the
	   80px head padding, which desktop and tablet keep. */
	.fs-pricing__panel { margin-top: 20px; }
	.fs-pricing__stage { height: 300px; overflow: hidden; }
	.fs-pricing .fs-pricing__video {
		width: 100%;
		height: 100%;
		aspect-ratio: auto;
		object-fit: cover;
		object-position: 50% 47%;
	}
	.fs-pricing__mobile { margin-top: 0; margin-bottom: 24px; }
	.fs-factors__cta { margin-top: 40px; }
}

@media (prefers-reduced-motion: reduce) {
	.fs-pricing__step svg,
	.fs-factors__more,
	.fs-factors__link { transition: none; }
	.fs-factors__link:hover { transform: none; }
}


/* ==========================================================================
   FAQ — fs-faq  [Layer 3: Components]

   Live's #faq is a `.container` (max-width 1000, padding-inline 32) with an
   80px top margin, an inner block padded 64 on the sides and 64 at the foot,
   and a Radix single-open accordion inside. Every number below is measured,
   not eyeballed:

     eyebrow  15/300 uppercase ls 4.8, centred, pb 24, .8 alpha   h 46.5
     heading  48/700 lh 48 #FB923C centred, pb 24                 h 72
     button   158.75 x 42 pill, its <a> carrying margin-bottom 64
     rows     0.5px #6B7280, radius 32, padding-inline 24, 24 apart, h 61
     rule     margin-top 80, 1px #292524

   The 0.5px border is deliberate — `border-[0.5px]` on live. It renders as a
   hairline on 2x screens and rounds to 1 device pixel on 1x, which is exactly
   what live does; forcing 1px made the rows visibly heavier side by side.
   ========================================================================== */

.fs-faq {
	max-width: 1000px;
	margin: 80px auto 0;
	padding: 0 32px;
	color: var(--fs-text, #fafaf9);
}

.fs-faq__inner {
	width: 100%;
	padding: 0 64px 64px;
}

.fs-faq__eyebrow {
	margin: 0;
	padding-bottom: 24px;
	font-size: 15px;
	font-weight: 300;
	line-height: 22.5px;
	letter-spacing: 4.8px;
	text-transform: uppercase;
	text-align: center;
	/* Live sets opacity .8 on the element. Using alpha on the colour instead:
	   the reveal animates opacity to 1 and would silently wipe it out. */
	color: rgba(250, 250, 249, 0.8);
}

.fs-faq__title {
	margin: 0;
	padding-bottom: 24px;
	font-size: 48px;
	font-weight: 700;
	line-height: 48px;
	/* Live's heading tracks at `normal`. Ours is an <h2> for SEO, and the
	   global heading rule gives every h1-h6 -0.01em, which pulled the words
	   ~5px tighter than live's <h4> across the line. */
	letter-spacing: normal;
	text-align: center;
	color: var(--fs-accent, #fb923c);
}

.fs-faq__cta {
	display: flex;
	justify-content: center;
	margin-bottom: 64px;
}

.fs-faq__button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	height: 42px;
	padding: 0 24px;
	border: 1px solid var(--fs-accent, #fb923c);
	border-radius: 9999px;
	background: transparent;
	color: var(--fs-text, #fafaf9);
	font-size: 20px;
	font-weight: 500;
	line-height: 28px;
	white-space: nowrap;
	text-decoration: none;
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
	            color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
	            border-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Scoped: something in the Elementor stack zeroes box-shadow on links, so the
   bare-class version of this never rendered. Live carries Tailwind's `shadow`. */
.fs-faq .fs-faq__button {
	box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
}

.fs-faq__button:hover,
.fs-faq__button:focus-visible { background: var(--fs-accent, #fb923c); }

/* --- the accordion ------------------------------------------------------- */

.fs-faq__list { display: block; }

.fs-faq__item {
	border: 0.5px solid #6b7280;
	border-radius: 32px;
	padding: 0 24px;
}

.fs-faq__item + .fs-faq__item { margin-top: 24px; }

.fs-faq__head {
	display: flex;
	margin: 0;
	font-size: inherit;
	font-weight: inherit;
}

.fs-faq__trigger {
	display: flex;
	border-radius: 0;
	flex: 1;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
	width: 100%;
	padding: 16px 0;
	border: 0;
	background: none;
	color: inherit;
	font-family: inherit;
	font-size: 20px;
	font-weight: 500;
	line-height: 28px;
	text-align: left;
	cursor: pointer;
	transition: all 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-faq__trigger:hover .fs-faq__question,
.fs-faq__trigger:focus-visible .fs-faq__question { text-decoration: underline; }

/* A flex item's default min-width:auto is its content width, so the question
   refused to shrink and ran straight out of the row on narrow screens. Live
   has no wrapper element here — the text is an anonymous box inside the
   button — which is why it wraps there without help. */
.fs-faq__question { min-width: 0; }

.fs-faq__chevron {
	flex: 0 0 auto;
	width: 16px;
	height: 16px;
	color: var(--fs-muted, #a8a29e);
	transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-faq__trigger[aria-expanded="true"] .fs-faq__chevron { transform: rotate(180deg); }

/* Height is driven from JS (there is no CSS length for "auto"); live animates
   the same property over the same 200ms ease-out via Radix's accordion-down. */
.fs-faq__panel {
	overflow: hidden;
	height: 0;
	transition: height 0.2s ease-out;
}

.fs-faq__panel[hidden] { display: none; }

.fs-faq__answer {
	padding-bottom: 16px;
	font-size: 16px;
	line-height: 24px;
	color: var(--fs-text, #fafaf9);
}

/* Scoped: Elementor zeroes `hr` margins with a selector that outranks a bare
   class, which pulled the rule up flush against the last row. */
.fs-faq .fs-faq__rule {
	margin: 80px 0 0;
	border: 0;
	border-top: 1px solid #292524;
}

/* Measured against live at a 500px viewport: the FAQ has NO responsive type or
   spacing at all. The heading stays 48/48, the trigger stays 20/28, the rows
   keep radius 32 and 24px of inline padding, and the rule keeps its 80px top
   margin — identical to 1440. The only thing that does move is the inner
   block's side padding, which is `md:px-16 sm:px-6` with no base value:

       >= 768   64px
       640-767  24px
       < 640     0

   Everything that used to live here — 32px heading, 17px trigger, radius 24,
   48px margins — was invented, and made the section read a size smaller than
   live on every phone. */
@media (max-width: 767px) and (min-width: 640px) {
	.fs-faq__inner { padding: 0 24px 64px; }
}

@media (max-width: 639px) {
	.fs-faq__inner { padding: 0 0 64px; }
}

@media (prefers-reduced-motion: reduce) {
	.fs-faq__panel,
	.fs-faq__chevron,
	.fs-faq__button { transition: none; }
}


/* ==========================================================================
   Blog — fs-blog  [Layer 3: Components]

   Live's #blog is a `.container` with `mb-20`. The card is the interesting
   part: the text block is pulled 80px UP over the bottom of the image and
   scaled to 0.95, and a gradient fades the image into the page background
   behind it, so the panel appears to float on the photo.
   ========================================================================== */

.fs-blog {
	width: 100%;
	max-width: 1000px;
	margin: 0 auto 80px;
	padding: 0 32px;
	color: var(--fs-text, #fafaf9);
}

.fs-blog__eyebrow {
	margin: 0;
	padding-bottom: 24px;
	font-size: 15px;
	font-weight: 300;
	line-height: 22.5px;
	letter-spacing: 4.8px;
	text-transform: uppercase;
	text-align: center;
	color: rgba(250, 250, 249, 0.8);
}

.fs-blog__heading {
	margin: 0;
	padding-bottom: 24px;
	font-size: 48px;
	font-weight: 700;
	line-height: 48px;
	letter-spacing: normal;      /* the global h1-h6 rule tracks -0.01em */
	text-transform: uppercase;
	text-align: center;
	color: var(--fs-accent, #fb923c);
}

.fs-blog__stand {
	margin: 0;
	padding-bottom: 64px;
	font-size: 20px;
	line-height: 28px;
	text-align: center;
}

.fs-blog__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 24px;
	max-width: 512px;            /* live: max-w-lg below the lg breakpoint */
	margin-inline: auto;
}

@media (min-width: 1024px) {
	.fs-blog__grid {
		grid-template-columns: repeat(3, 1fr);
		max-width: none;
	}
}

.fs-blog__card {
	border-radius: 24px;
	transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* The blog card carries a reveal class as well as its own hover, and the two
   fight over `transform`. `.fs-js .fs-reveal-card.is-in { transform: none }` is
   (0,3,0) and beat `.fs-blog__card:hover` at (0,2,0) — so once a card had
   revealed, its hover did nothing at all, and the transition it did inherit was
   the reveal's 0.6s rather than the source's 300ms.

   Qualifying the hover with the same classes settles both: the source is
   `hover:scale-105 transition-all duration-300`. */
.fs-blog__card:hover { transform: scale(1.05); }

.fs-js .fs-blog__card.fs-reveal-card.is-in {
	transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-js .fs-blog__card.fs-reveal-card.is-in:hover {
	transform: scale(1.05);
}

.fs-blog__link {
	display: block;
	color: inherit;
	text-decoration: none;
	cursor: pointer;
}

.fs-blog__media {
	position: relative;
	display: block;
}

/* `.elementor img { height: auto }` is (0,1,1) and outranks a single class,
   which is what flattened the project cards twice — scope it. */
.fs-blog .fs-blog__img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 5 / 4;
	border-radius: 12px;
	object-fit: cover;
}

.fs-blog__img--top    { object-position: 50% 0%; }
.fs-blog__img--center { object-position: 50% 50%; }
.fs-blog__img--bottom { object-position: 50% 100%; }

/* Fades the photo into the page so the panel below reads as floating. */
.fs-blog__fade {
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 30%;
	background: linear-gradient(to bottom, transparent, var(--fs-bg, #0c0a09));
	pointer-events: none;
}

.fs-blog__body {
	position: relative;
	z-index: 10;
	display: block;
	margin-top: -80px;
	transform: scale(0.95);
}

.fs-blog__meta {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-bottom: 8px;
}

.fs-blog__date {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 4px 12px;
	border: 1px solid #292524;
	border-radius: 9999px;
	background: var(--fs-bg, #0c0a09);
	font-size: 14px;
	font-weight: 600;
	line-height: 20px;
}

.fs-blog__box {
	display: block;
	padding: 0 16px 16px;
	border: 1px solid #292524;
	border-radius: 12px;
	background: var(--fs-bg, #0c0a09);
}

.fs-blog__title {
	display: block;
	padding-top: 16px;
	font-size: 20px;
	font-weight: 700;
	line-height: 28px;
}

.fs-blog__excerpt {
	display: -webkit-box;
	-webkit-line-clamp: 3;
	-webkit-box-orient: vertical;
	overflow: hidden;
	padding-top: 8px;
	font-size: 16px;
	line-height: 24px;
}

/* Live's "Read more" is not a line of text — it is the same solid orange pill
   as the header CTA: `bg-primary text-primary-foreground shadow
   hover:bg-primary/90 h-9 px-4 py-2 rounded-full text-sm font-medium`.
   It measures 34px tall on the card only because the whole text block carries
   scale(.95); the real box is h-9 / 36. */
.fs-blog__moreWrap {
	display: block;
	padding-top: 8px;
}

.fs-blog__more {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 8px 16px;           /* 20 line-height + 16 = live's h-9 / 36 */
	border-radius: 9999px;
	background: var(--fs-accent, #fb923c);
	color: var(--fs-text, #fafaf9);
	font-size: 14px;
	font-weight: 500;
	line-height: 20px;
	white-space: nowrap;
	box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
	transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-blog__link:hover .fs-blog__more { background: rgba(251, 146, 60, 0.9); }

/* ==========================================================================
   Contact — fs-contact  [Layer 3: Components]

   Live: a `bg-[#020204] border-b border-white pt-10` band holding a
   `.container pb-20`, then `sm:p-16 py-16 px-0`, then a flex row that stacks
   below sm with a 96px gap. Logo left (max-width 240, the image itself
   scale-150), copy right.
   ========================================================================== */

/* The rule above the footer.
   Live sets `border-b border-white` — solid #fff — which on a near-black page
   reads as a hard bright line rather than a separator. Taken down to 25% white
   in two steps at FLYSTACK's request: 50% first, then halved again.

   Deliberate divergence from live, applied to every band that carries this
   border so they cannot drift apart. There are four:
   the homepage contact band, the Projects archive, the single project page and
   the Contact page. */
.fs-contact {
	width: 100%;
	padding-top: 40px;
	background: #020204;
	border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}

.fs-contact__inner {
	width: 100%;
	max-width: 1000px;
	margin-inline: auto;
	padding: 0 32px 80px;
}

.fs-contact__pad { padding: 64px 0; }

@media (min-width: 640px) {
	.fs-contact__pad { padding: 64px; }
}

.fs-contact__row {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 96px;
}

@media (min-width: 640px) {
	.fs-contact__row { flex-direction: row; }
}

.fs-contact__logo {
	position: relative;
	z-index: 10;
	width: 100%;
	max-width: 240px;
	height: auto;
}

.fs-contact .fs-contact__logo img {
	display: block;
	width: 100%;
	height: auto;
	transform: scale(1.5);
}

.fs-contact__copy {
	position: relative;
	z-index: 20;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
}

.fs-contact__title {
	margin: 0;
	padding-bottom: 24px;
	font-size: 30px;
	font-weight: 400;
	line-height: 36px;
	letter-spacing: normal;
	text-transform: uppercase;
	text-align: left;
	color: var(--fs-text, #fafaf9);
	/* Live glows this heading exactly like the pricing title. The paragraph
	   underneath has no shadow at all — checked, it is text-shadow: none. */
	text-shadow: 0 0 10px #ffffff;
}

@media (min-width: 640px) {
	.fs-contact__title { font-size: 48px; line-height: 48px; }
}

.fs-contact__text {
	margin: 0;
	padding-bottom: 16px;
	font-size: 16px;
	line-height: 24px;
}

/* `border bg-background shadow-sm hover:bg-accent hover:text-accent-foreground
   h-9 rounded-full border-primary text-xl p-6` — 152 x 50. */
.fs-contact__cta {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 10px 24px;          /* 28 line-height + 20 + 2 border = live's 50 */
	border: 1px solid var(--fs-accent, #fb923c);
	border-radius: 9999px;
	background: var(--fs-bg, #0c0a09);
	color: var(--fs-text, #fafaf9);
	font-size: 20px;
	font-weight: 500;
	line-height: 28px;
	text-decoration: none;
	white-space: nowrap;
	box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
	transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
	            background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-contact__cta:hover,
.fs-contact__cta:focus-visible {
	background: #292524;
	color: var(--fs-text, #fafaf9);
}

@media (prefers-reduced-motion: reduce) {
	.fs-blog__card { transition: none; }
	.fs-blog__card:hover { transform: none; }
}

/* ==========================================================================
   Stats grid — fs-stats  [Layer 3: Components]

   Live spec, measured at 1420px inside the same 808px content box as the
   welcome copy:

     grid   md:grid-cols-4 grid-cols-2, gap 40px, margin-top 40px
     cell   max-width 144px, centred in its 172px column,
            flex column, align + justify centre, gap 16px (0 below md)
     icon   80x80, #FB923C — stroked on the drone, filled on the other three
     value  24px / 700 / lh 32 / #FAFAF9   (20px below md)
     label  16px / 400 / lh 24 / #FAFAF9   (14px below md)

   Value and label share one <p>, split by a <br>, exactly as on live — that
   is what keeps the two lines locked to the same 24px rhythm.
   ========================================================================== */

.fs-stats {
	display: grid;
	grid-template-columns: repeat(4, 1fr);
	gap: 40px;
	margin-top: 40px;
	max-width: 808px;
	margin-inline: auto;
}

.fs-stat {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 16px;
	width: 100%;
	max-width: 144px;
	margin-inline: auto;
	text-align: center;
}

.fs-stat__icon {
	display: block;
	width: 80px;
	height: 80px;
	color: var(--fs-accent, #fb923c);
}

/* The drone glyph is drawn with strokes; the other three are solid shapes.
   Setting both on the wrapper would fill the drone's circles. */
.fs-stat__icon--stroke { fill: none; stroke: currentColor; }
.fs-stat__icon--fill   { fill: currentColor; stroke: none; }

.fs-stat p {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	font-weight: 400;
	color: #fafaf9;
}

.fs-stat__value {
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	color: #fafaf9;
}

@media (max-width: 767px) {
	.fs-stats { grid-template-columns: repeat(2, 1fr); }
	.fs-stat  { gap: 0; }
	.fs-stat p { font-size: 14px; }
	.fs-stat__value { font-size: 20px; }
}

/* ==========================================================================
   Header bar

   Live's bar is `fixed top-0 left-0 w-full z-50 bg-background` with
   `transition-all duration-500`. Two things follow, and both were wrong here.

   1. `fixed` carries no responsive prefix, so live's bar is pinned at EVERY
      width. Ours was only fixed from tablet up; on a phone it scrolled away
      with the page.
   2. It is TRANSPARENT at the top of the page and solid #0C0A09 once
      scrolled. This note previously claimed solid-at-every-position and
      called the transparent-at-top behaviour invented — that was wrong twice
      over. The readings behind it (rgba(12,10,9,0.996) at 600, 1200, 1500)
      were all taken while scrolled, so they only ever measured the second
      half of the behaviour. A settled render at scrollY 0, on every page and
      every width, reports `bg-transparent` / rgba(0,0,0,0).

      So `body.fs-scrolled` drives it again, which is what the inline script
      in functions.php has been maintaining all along.

      It matters most on the About page, where the hero's star field runs to
      y=0 and is meant to show through the bar.
   ========================================================================== */

.elementor-location-header > .e-con,
.elementor-location-header .e-con.e-parent {
	position: fixed !important;
	top: 0;
	left: 0;
	width: 100%;
	background-color: transparent !important;
	transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

body.fs-scrolled .elementor-location-header > .e-con,
body.fs-scrolled .elementor-location-header .e-con.e-parent {
	background-color: #0c0a09 !important;
}

/* The open mobile drawer needs a ground of its own regardless of scroll —
   the panel below the bar is solid, and a transparent bar above it would
   leave the logo and burger floating over whatever they happen to cover. */
.elementor-location-header:has(.elementor-menu-toggle.elementor-active) > .e-con,
.elementor-location-header:has(.elementor-menu-toggle.elementor-active) .e-con.e-parent {
	background-color: #0c0a09 !important;
}

/* Live's header CTA is a SOLID orange pill, not an outline — re-measured at
   scrollY 0, 600 and 3000 and identical at all three, so it does not react to
   scroll either. Its Tailwind is:

       bg-primary text-primary-foreground shadow hover:bg-primary/90
       h-9 px-4 py-2 rounded-full text-sm font-medium
       transition-all duration-500

   i.e. #FB923C on #FAFAF9, 14/500, no tracking, padding 8/16, 104 x 36.
   An earlier note here recorded it as a 2px outline at 165x40 — that was
   wrong, and the outline is what shipped. !important throughout because
   Elementor's per-widget CSS carries an ID-level selector. */
.fs-book-btn .elementor-button {
	box-sizing: border-box;
	height: 36px;
	padding: 8px 16px !important;
	border: 0 !important;
	border-radius: 9999px !important;
	background-color: var(--fs-accent, #fb923c) !important;
	color: var(--fs-text, #fafaf9) !important;
	font-size: 14px !important;
	font-weight: 500 !important;
	letter-spacing: normal !important;
	box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
	transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1) !important;
}

/* hover:bg-primary/90 — the label keeps its colour. */
.fs-book-btn .elementor-button:hover,
.fs-book-btn .elementor-button:focus-visible {
	background-color: rgba(251, 146, 60, 0.9) !important;
	color: var(--fs-text, #fafaf9) !important;
}

/* ==========================================================================
   Header vertical centring — fs-header-vcenter

   The flag, CTA and burger have different intrinsic heights (32 / 42 / 36),
   so without an explicit cross-axis rule at every level they settle on
   slightly different baselines inside the 72px bar.
   ========================================================================== */

.elementor-location-header > .e-con,
.elementor-location-header .e-con.e-parent,
.elementor-location-header > .e-con > .e-con,
.elementor-location-header .e-con.e-parent > .e-con {
	align-items: center !important;
}

.elementor-location-header .elementor-widget-shortcode,
.elementor-location-header .elementor-widget-button,
.elementor-location-header .elementor-widget-nav-menu,
.elementor-location-header .elementor-widget-theme-site-logo,
.elementor-location-header .elementor-widget-image {
	display: flex !important;
	align-items: center !important;
	align-self: center !important;
	margin-block: 0 !important;
}

.elementor-location-header .elementor-widget-container,
.elementor-location-header .fs-lang,
.elementor-location-header .elementor-menu-toggle {
	display: flex !important;
	align-items: center !important;
}

/* The button's own line-height was pushing it off centre. */
.elementor-location-header .fs-book-btn .elementor-button {
	display: inline-flex;
	align-items: center;
	line-height: 1;
}

/* ==========================================================================
   Nav spacing + header padding

   Two corrections here.

   1. flex-wrap must go on the <ul>, not the <nav>. .elementor-nav-menu--main
      is the nav element; the flex container is .elementor-nav-menu inside it.
      Setting nowrap on the nav did nothing, so CONTACT kept dropping to a
      second row at ~1100px.

   2. The live header padding is responsive, not a fixed 64px:
        px-6      -> 24px  below 768
        md:px-16  -> 64px  768-1023
        lg:px-10  -> 40px  1024-1279
        xl:px-16  -> 64px  1280 and up
      Mirroring that gives back 48px of nav room exactly where it was tight.
   ========================================================================== */

@media (min-width: 1025px) {
	.elementor-location-header .elementor-nav-menu--main .elementor-nav-menu {
		flex-wrap: nowrap !important;
	}
	.elementor-location-header .elementor-nav-menu--main .elementor-item {
		white-space: nowrap;
		padding-inline: clamp(8px, 1.4vw, 20px) !important;
	}

	/* Give the nav column the slack it needs; the flanking columns only ever
	   hold a logo and a fixed-width CTA. */
	.elementor-location-header > .e-con > .e-con:nth-child(2),
	.elementor-location-header .e-con.e-parent > .e-con:nth-child(2) {
		width: auto !important;
		flex: 1 1 auto !important;
	}
	.elementor-location-header > .e-con > .e-con:nth-child(1),
	.elementor-location-header > .e-con > .e-con:nth-child(3),
	.elementor-location-header .e-con.e-parent > .e-con:nth-child(1),
	.elementor-location-header .e-con.e-parent > .e-con:nth-child(3) {
		flex: 0 0 auto !important;
	}
}

/* Between the breakpoint and 1280px the row is genuinely tight: at 1100px
   there are ~711px for the nav and 40px gaps would need ~720. Tighter padding
   and a slightly smaller label keep all seven items on one line without the
   flag riding over CONTACT. */
@media (min-width: 1025px) and (max-width: 1279px) {
	.elementor-location-header .elementor-nav-menu--main .elementor-item {
		font-size: 15px !important;
		padding-inline: 8px !important;
	}
}

/* The nav may shrink; the logo and CTA may not. min-width:0 lets a flex item
   go below its content width, which it will not do by default. */
@media (min-width: 1025px) {
	.elementor-location-header > .e-con > .e-con:nth-child(2),
	.elementor-location-header .e-con.e-parent > .e-con:nth-child(2) {
		min-width: 0 !important;
	}
	.elementor-location-header > .e-con > .e-con:nth-child(3),
	.elementor-location-header .e-con.e-parent > .e-con:nth-child(3) {
		flex-shrink: 0 !important;
	}
}

/* Live's responsive horizontal padding. */
.elementor-location-header > .e-con,
.elementor-location-header .e-con.e-parent {
	padding-inline: 24px !important;
}
@media (min-width: 768px) {
	.elementor-location-header > .e-con,
	.elementor-location-header .e-con.e-parent { padding-inline: 64px !important; }
}
@media (min-width: 1024px) and (max-width: 1279px) {
	.elementor-location-header > .e-con,
	.elementor-location-header .e-con.e-parent { padding-inline: 40px !important; }
}
@media (min-width: 1280px) {
	.elementor-location-header > .e-con,
	.elementor-location-header .e-con.e-parent { padding-inline: 64px !important; }
}

/* ==========================================================================
   Logo alignment

   The logo column was centring its image, pushing the mark ~42px past the
   header's padding edge. Live sits it flush against the padding: x=64 at
   1440px, x=40 in the 1024-1279 range.
   ========================================================================== */

.elementor-location-header > .e-con > .e-con:first-child,
.elementor-location-header .e-con.e-parent > .e-con:first-child {
	justify-content: flex-start !important;
	align-items: center !important;
	padding-inline: 0 !important;
}

.elementor-location-header .elementor-widget-theme-site-logo,
.elementor-location-header .elementor-widget-theme-site-logo .elementor-widget-container,
.elementor-location-header .elementor-widget-image {
	text-align: left !important;
	padding-inline: 0 !important;
	margin-inline: 0 !important;
}

.elementor-location-header .elementor-widget-theme-site-logo img,
.elementor-location-header .elementor-widget-image img {
	margin-inline: 0 !important;
}

/* The logo column is wider than the logo (185px vs 80px) and centres its
   child, putting the mark (185-80)/2 = 52.5px past the padding edge.
   An auto margin on the opposite side beats justify-content regardless of
   which selector Elementor used to centre it, so this holds without having
   to out-specify the generated element-ID rule. */
.elementor-location-header > .e-con > .e-con:first-child > .elementor-widget,
.elementor-location-header .e-con.e-parent > .e-con:first-child > .elementor-widget,
.elementor-location-header .elementor-widget-theme-site-logo {
	margin-right: auto !important;
	margin-left: 0 !important;
}

/* Mirror on the right-hand column so the CTA stays flush to the padding edge
   rather than centring in its own column. */
.elementor-location-header > .e-con > .e-con:last-child,
.elementor-location-header .e-con.e-parent > .e-con:last-child {
	justify-content: flex-end !important;
}

/* ==========================================================================
   Mobile header — fs-mobile-header

   The desktop layout is three columns (logo / nav / CTA). Below the tablet
   breakpoint those must collapse to a single row: logo left, then flag and
   hamburger right. Without this the burger lands centred under the logo and
   the CTA drops to a third line.
   ========================================================================== */

@media (max-width: 1024px) {
	.elementor-location-header > .e-con,
	.elementor-location-header .e-con.e-parent {
		flex-direction: row !important;
		flex-wrap: nowrap !important;
		align-items: center !important;
		justify-content: space-between !important;
		/* padding-inline is owned by the responsive block above — live's
		   24 / 64 / 40 / 64 ladder. A flat 20px here silently overrode it. */
		gap: 12px !important;
	}

	.elementor-location-header > .e-con > .e-con {
		width: auto !important;
		flex: 0 0 auto !important;
	}

	/* Nav column shrinks to just the toggle. */
	.elementor-location-header .elementor-widget-nav-menu { width: auto !important; }
	.elementor-location-header .elementor-menu-toggle { margin-inline-start: auto; }

	/* Drawer panel spans the viewport under the bar. */
	.elementor-location-header .elementor-nav-menu--dropdown {
		background-color: #0c0a09 !important;
		border-top: 1px solid rgba(255, 255, 255, 0.12);
	}
	.elementor-location-header .elementor-nav-menu--dropdown a {
		font-size: 16px !important;
		padding: 14px 20px !important;
	}
}

/* Nothing to shrink at 600px any more: the CTA is 104x36 at every width, the
   same as live, and the side padding ladder already drops to 24px below 768. */

/* ==========================================================================
   Mobile drawer state — fs-drawer-state

   Elementor's "improved asset loading" only enqueues widget-nav-menu.min.css
   when its asset loader knows the widget is on the page. Because the layout
   is written straight into _elementor_data over REST, that registration never
   happens, so the stylesheet that hides the dropdown is missing and the
   drawer renders permanently open under the bar — which is why the mobile
   header looked three rows tall.

   Declaring the collapsed/expanded states here makes the header independent
   of whether Elementor decided to ship that file.
   ========================================================================== */

.elementor-location-header .elementor-nav-menu--dropdown {
	display: none;
}

.elementor-location-header .elementor-menu-toggle.elementor-active + .elementor-nav-menu--dropdown,
.elementor-location-header .elementor-menu-toggle[aria-expanded="true"] + .elementor-nav-menu--dropdown,
.elementor-location-header .elementor-nav-menu__container.elementor-active {
	display: block;
	position: absolute;
	top: 100%;
	left: 0;
	right: 0;
	width: 100%;
	background: #0c0a09;
	border-top: 1px solid rgba(255, 255, 255, 0.12);
	box-shadow: 0 20px 40px rgba(0, 0, 0, 0.6);
	z-index: 99;
}

/* Above the breakpoint the horizontal menu shows and the toggle is hidden. */
@media (min-width: 1025px) {
	.elementor-location-header .elementor-menu-toggle { display: none !important; }
	.elementor-location-header .elementor-nav-menu--main { display: flex !important; }
}

/* Below it, the reverse. */
@media (max-width: 1024px) {
	.elementor-location-header .elementor-nav-menu--main:not(.elementor-nav-menu--dropdown) { display: none !important; }
	.elementor-location-header .elementor-menu-toggle { display: flex !important; }
	.elementor-location-header > .e-con,
	.elementor-location-header .e-con.e-parent { position: relative; }
}

/* ==========================================================================
   Burger to the right — fs-burger-right

   The nav column sits between logo and CTA in source order, which put the
   toggle in the middle of the mobile bar. Reordering visually only, so the
   desktop grid and the DOM/tab order stay as they are.

   Order: logo · flag + Book now · burger
   ========================================================================== */

@media (max-width: 1024px) {
	.elementor-location-header > .e-con > .e-con:nth-child(1),
	.elementor-location-header .e-con.e-parent > .e-con:nth-child(1) { order: 1; }

	/* nav / burger column moves to the end */
	.elementor-location-header > .e-con > .e-con:nth-child(2),
	.elementor-location-header .e-con.e-parent > .e-con:nth-child(2) { order: 3; }

	/* flag + CTA sit before it */
	.elementor-location-header > .e-con > .e-con:nth-child(3),
	.elementor-location-header .e-con.e-parent > .e-con:nth-child(3) { order: 2; margin-inline-start: auto; }

	.elementor-location-header .elementor-menu-toggle { margin-inline-start: 4px; }
}

/* ==========================================================================
   Mobile menu sheet — fs-menu-sheet

   The live site uses a Radix sheet: a fixed panel sliding in from the right at
   roughly 75vw, full height, over a dimmed page. Not a full-width overlay and
   not Elementor's default push-down dropdown.
   Measured: panel 374px at a 500px viewport, 24px padding (p-6), links 16px/400
   uppercase #FAFAF9 spaced 16px apart (space-y-4).
   ========================================================================== */

@media (max-width: 1024px) {
	.elementor-location-header .elementor-nav-menu--dropdown {
		/* Elementor's kit CSS targets this via element-ID selectors, which
		   outrank a two-class rule — every geometry property needs !important
		   or the panel keeps Elementor's in-flow full-width box. */
		display: block !important;
		position: fixed !important;
		top: 0 !important;
		right: 0 !important;
		bottom: 0 !important;
		left: auto !important;
		width: min(75vw, 374px) !important;
		height: 100dvh !important;
		max-height: none !important;
		padding: 24px !important;
		background: #0c0a09 !important;
		border-top: 0;
		border-left: 1px solid rgba(255, 255, 255, 0.1);
		box-shadow: -18px 0 48px rgba(0, 0, 0, 0.6);
		overflow-y: auto;
		z-index: 9998 !important;

		/* Off-canvas until opened. visibility keeps it out of the tab order.
		   !important because Elementor's own dropdown animation sets a
		   scaleY(0) transform that otherwise wins and collapses the panel. */
		transform: translateX(100%) !important;
		visibility: hidden !important;
		transition: transform 0.5s cubic-bezier(0.32, 0.72, 0, 1),
		            visibility 0.5s;
	}

	body.fs-menu-open .elementor-location-header .elementor-nav-menu--dropdown {
		transform: translateX(0) !important;
		visibility: visible !important;
	}

	/* Panel title, mirroring the live sheet header. */
	.elementor-location-header .elementor-nav-menu--dropdown::before {
		content: "FLYSTACK Drone Shows";
		display: block;
		font-size: 20px;
		font-weight: 700;
		color: #fafaf9;
		padding-bottom: 16px;
		margin-bottom: 24px;
		border-bottom: 1px solid rgba(255, 255, 255, 0.15);
	}

	.elementor-location-header .elementor-nav-menu--dropdown a {
		font-size: 16px !important;
		font-weight: 400 !important;
		text-transform: uppercase;
		color: #fafaf9 !important;
		padding: 8px 0 !important;
		border: 0 !important;
	}
	.elementor-location-header .elementor-nav-menu--dropdown li { margin-bottom: 8px; }
	.elementor-location-header .elementor-nav-menu--dropdown a:hover { color: #fb923c !important; }

	/* Dimmed page behind the sheet. */
	body.fs-menu-open::after {
		content: "";
		position: fixed;
		inset: 0;
		background: rgba(0, 0, 0, 0.6);
		z-index: 9997;
		animation: fsFade 0.4s ease both;
	}
	@keyframes fsFade { from { opacity: 0 } to { opacity: 1 } }

	/* Toggle stays clickable above the sheet so it can close it. */
	.elementor-location-header .elementor-menu-toggle { position: relative; z-index: 9999; }

	body.fs-menu-open { overflow: hidden; }
}

/* ==========================================================================
   Menu stacking — fs-menu-stacking

   The header bar is position:fixed with z-index:99, which makes it a stacking
   context. The sheet lives inside it, so its z-index:9998 is resolved WITHIN
   that context — against the header's 99, not against the page. The overlay
   (body::after, z-index 9997) is a sibling of the header at page level, so it
   painted over the entire header including the sheet.

   Raising the header above the overlay while the menu is open fixes it
   without having to move the panel out of the header markup.
   ========================================================================== */

body.fs-menu-open .elementor-location-header,
body.fs-menu-open .elementor-location-header > .e-con,
body.fs-menu-open .elementor-location-header .e-con.e-parent {
	z-index: 10000 !important;
}

/* ==========================================================================
   Burger -> X — fs-toggle-morph

   Three bars: the outer two rotate 45 deg into the cross, the middle one fades
   and collapses. Pure CSS, no JS beyond the existing open/close class.

   Elementor ships two SVG icons and swaps them in widget-nav-menu.min.css,
   which never loads for REST-written layouts. Rather than re-declare that
   swap, the "open" SVG is repurposed as the middle bar (its fill is cleared
   so the glyph itself does not draw) and ::before / ::after supply the outer
   two. That keeps the whole thing to one element and no extra markup.
   ========================================================================== */

.elementor-location-header .elementor-menu-toggle {
	position: relative;
	width: 28px;
	height: 20px;
	padding: 0 !important;
	border: 0;
	background: none !important;
	display: flex !important;
	align-items: center;
	justify-content: center;
	cursor: pointer;
}

/* Elementor's close icon is unused — the bars morph instead. */
.elementor-location-header .elementor-menu-toggle .elementor-menu-toggle__icon--close,
.elementor-location-header .elementor-menu-toggle i {
	display: none !important;
}

/* Middle bar: the open-icon SVG, stripped of its glyph. */
.elementor-location-header .elementor-menu-toggle .elementor-menu-toggle__icon--open,
.elementor-location-header .elementor-menu-toggle svg:first-of-type {
	display: block !important;
	width: 28px !important;
	height: 2px !important;
	background: #fafaf9;
	border-radius: 2px;
	fill: transparent !important;
	overflow: hidden;
	transition: opacity 0.25s ease, transform 0.35s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Outer bars. */
.elementor-location-header .elementor-menu-toggle::before,
.elementor-location-header .elementor-menu-toggle::after {
	content: "";
	position: absolute;
	left: 0;
	width: 28px;
	height: 2px;
	background: #fafaf9;
	border-radius: 2px;
	transition: transform 0.35s cubic-bezier(0.22, 1, 0.36, 1),
	            top 0.25s ease, bottom 0.25s ease;
}

.elementor-location-header .elementor-menu-toggle::before { top: 1px; }
.elementor-location-header .elementor-menu-toggle::after  { bottom: 1px; }

/* Open state: middle fades, outer two cross. */
body.fs-menu-open .elementor-location-header .elementor-menu-toggle .elementor-menu-toggle__icon--open,
body.fs-menu-open .elementor-location-header .elementor-menu-toggle svg:first-of-type {
	opacity: 0;
	transform: scaleX(0.2);
}

body.fs-menu-open .elementor-location-header .elementor-menu-toggle::before {
	top: 50%;
	transform: translateY(-50%) rotate(45deg);
}

body.fs-menu-open .elementor-location-header .elementor-menu-toggle::after {
	bottom: 50%;
	transform: translateY(50%) rotate(-45deg);
}

/* All three bars share the hover colour. Setting it only on ::before and
   ::after left the middle bar white, giving an orange/white/orange stripe. */
.elementor-location-header .elementor-menu-toggle:hover::before,
.elementor-location-header .elementor-menu-toggle:hover::after,
.elementor-location-header .elementor-menu-toggle:hover .elementor-menu-toggle__icon--open,
.elementor-location-header .elementor-menu-toggle:hover svg:first-of-type {
	background: #fb923c;
}

/* ==========================================================================
   Toggle visibility — must come LAST

   The burger morph block above sets `display: flex !important` on
   .elementor-menu-toggle with no media query. Because it appears after the
   earlier min-width:1025px hide and carries the same specificity, it was
   winning at every width and the burger showed on desktop too.

   These two rules are deliberately at the end of the file so they resolve
   last. Anything added below this point must not restate the toggle's
   display property.
   ========================================================================== */

@media (min-width: 1025px) {
	.elementor-location-header .elementor-menu-toggle,
	.elementor-location-header div.elementor-menu-toggle {
		display: none !important;
	}
	.elementor-location-header .elementor-nav-menu--main:not(.elementor-nav-menu--dropdown) {
		display: flex !important;
	}
	/* Sheet stays out of the way entirely above the breakpoint. */
	.elementor-location-header .elementor-nav-menu--dropdown {
		display: none !important;
	}
}

@media (max-width: 1024px) {
	.elementor-location-header .elementor-menu-toggle,
	.elementor-location-header div.elementor-menu-toggle {
		display: flex !important;
	}
}


/* ==========================================================================
   ABOUT US — hero

   Live: `.w-full.relative.overflow-hidden` holding an absolutely positioned
   cover image and a `.container.relative.z-10.py-40` content column.

   The height is content-driven on live (580px at 500px wide is just
   160 + 52 + 112 + 96 + 160), so nothing here pins one. A fixed height would
   break as soon as a translation wraps to a different number of lines.
   ========================================================================== */

.fs-abt-hero {
	position: relative;
	width: 100%;
	overflow: hidden;

	/* z-index 0 rather than auto, so this is a stacking context.

	   `.fs-abt-hero__inner` carries live's `z-10`. With the hero at
	   `z-index: auto` that 10 leaks into the ROOT stacking context, where it
	   outranks the sections below — including the mission drone, which hangs
	   ~370px up into this hero. Closing the context here keeps the hero's
	   internal layering internal. */
	z-index: 0;
}

.fs-abt-hero__bg {
	position: absolute;
	z-index: 0;
	inset: 0;
}

.fs-abt-hero__bg img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Live's `.container`: full width, 2rem inline padding at every size, capped
   at 1000px from 1000px up. Confirmed by reading the rule out of live's own
   stylesheet rather than inferring it from Tailwind defaults, which cap at
   1536px and would have made this 500px too wide on a desktop. */
.fs-abt-hero__inner {
	position: relative;
	z-index: 10;
	width: 100%;
	margin-inline: auto;
	padding: 160px 32px;
}

@media (min-width: 1000px) {
	.fs-abt-hero__inner {
		max-width: 1000px;
	}
}

.fs-abt-hero__eyebrow {
	margin: 0;
	padding: 0 0 32px;
	font-size: 14px;
	font-weight: 300;
	line-height: 20px;
	letter-spacing: 1.4px;
	text-transform: uppercase;
	color: #fafaf9;
}

/* letter-spacing is restated because the theme sets -0.01em on every heading
   globally, which showed up here as -0.48px of tightening live does not have. */
.fs-abt-hero__title {
	margin: 0;
	padding: 0 0 40px;
	font-size: 30px;
	line-height: 36px;
	font-weight: 700;
	letter-spacing: normal;
	text-transform: uppercase;
	text-align: start;
	color: #fafaf9;
}

@media (min-width: 640px) {
	.fs-abt-hero__title {
		font-size: 48px;
		line-height: 48px;
	}
}

.fs-abt-hero__accent {
	color: #fb923c;
}

.fs-abt-hero__text {
	margin: 0;
	padding: 0;
	padding-inline-end: 40px;
	max-width: 672px;
	font-size: 16px;
	font-weight: 400;
	line-height: 24px;
	color: #fafaf9;
}

@media (min-width: 768px) {
	.fs-abt-hero__text {
		width: 50%;
	}
}


/* ==========================================================================
   Header CTA — the sm: variant

   CORRECTION to the note further up this file, which claims the live button
   is a solid orange pill at every width and calls the 2px outline "wrong".
   That note was written from measurements taken in a 500px-wide window and
   generalised to the whole range. The button's full class list, read from a
   settled render at 390 and again at 1440, is:

       bg-primary text-primary-foreground shadow hover:bg-primary/90
       h-9 px-4 py-2 rounded-full text-sm font-medium
       sm:p-[10px_35px] sm:h-[40px] sm:font-semibold sm:tracking-[1px]
       sm:text-[16px] sm:bg-transparent sm:border-2 sm:border-primary
       sm:hover:bg-primary

   So BOTH forms are real and the switch is at 640px:

       below 640   solid #FB923C, 14/500, padding 8/16, 104 x 36
       640 and up  transparent, 2px #FB923C border, 16/600, tracking 1px,
                   padding 10/35, 165 x 40, and hover FILLS with #FB923C

   The block above already produces the small form. This adds the large one.
   ========================================================================== */

/*
 * ...and the switch is at 640px AND at scrollY 200. The whole override list
 * lives inside `scrollYNumber < 200 && "..."`, so the outline is the
 * top-of-page form and the solid pill is what the bar settles into once the
 * background comes in. Reading the `sm:` prefixes without the surrounding
 * condition is how this shipped as an outline at every scroll position.
 */
@media (min-width: 640px) {
	body:not(.fs-scrolled) .fs-book-btn .elementor-button {
		height: 40px;
		padding: 10px 35px !important;
		border: 2px solid var(--fs-accent, #fb923c) !important;
		background-color: transparent !important;
		color: var(--fs-text, #fafaf9) !important;
		font-size: 16px !important;
		font-weight: 600 !important;
		letter-spacing: 1px !important;
		box-shadow: none;
	}

	/* sm:hover:bg-primary — the outline fills rather than dimming. */
	body:not(.fs-scrolled) .fs-book-btn .elementor-button:hover,
	body:not(.fs-scrolled) .fs-book-btn .elementor-button:focus-visible {
		background-color: var(--fs-accent, #fb923c) !important;
		color: var(--fs-text, #fafaf9) !important;
	}
}


/* ==========================================================================
   ABOUT US — mission

   Live: `.container` > `.grid.sm:grid-cols-2.grid-cols-1.gap-x-24.gap-8
   .md:py-20.pb-20.pt-0` holding three bordered cards and one image column.

   Measured in settled renders at 390 / 834 / 1440:

       grid columns   1               2 (337)        2 (420)
       column gap     96              96             96
       row gap        32              32             32
       padding-block  0 / 80          80 / 80        80 / 80
       card 1 margin  40px top        0              0

   Source order is card 1, art, card 2, card 3; the visual order flips the
   first two below 640 so the drone leads on a phone.
   ========================================================================== */

.fs-abt-mission {
	width: 100%;
	margin-inline: auto;
	padding-inline: 32px;

	/* Raised above the hero, whose content layer is z-10 inside a stacking
	   context pinned at 0. The drone hangs ~370px up out of this section and
	   into that hero, so without an explicit level the two sections' layering
	   depends on Elementor's band markup rather than on anything stated here.

	   Note for anyone chasing a similar ghost: during this build the drone
	   appeared to be invisible at desktop and it was NOT a z-index fault.
	   Hit-testing found the image on top the whole time; the automation
	   screenshots were showing a stale first frame, and any scroll or style
	   mutation "fixed" it. Verify against a scrolled screenshot before
	   changing stacking rules. */
	position: relative;
	z-index: 1;
}

@media (min-width: 1000px) {
	.fs-abt-mission {
		max-width: 1000px;
	}
}

.fs-abt-mission__grid {
	display: grid;
	grid-template-columns: 1fr;
	column-gap: 96px;
	row-gap: 32px;
	padding-block: 0 80px;
}

@media (min-width: 640px) {
	.fs-abt-mission__grid {
		grid-template-columns: 1fr 1fr;
	}
}

/* py-20 arrives at md, not at sm — the two-column switch and the vertical
   padding are on different breakpoints on live, so 640-767 is two columns
   with no top padding. */
@media (min-width: 768px) {
	.fs-abt-mission__grid {
		padding-block: 80px;
	}
}

.fs-abt-mission__card {
	border: 1px solid rgba(255, 255, 255, 0.2);
	border-radius: 12px;
	padding: 16px;
}

.fs-abt-mission__card--first {
	order: 2;
	margin-top: 40px;
}

@media (min-width: 640px) {
	.fs-abt-mission__card--first {
		order: 1;
	}
}

@media (min-width: 768px) {
	.fs-abt-mission__card--first {
		margin-top: 0;
	}
}

.fs-abt-mission__card--second { order: 3; }
.fs-abt-mission__card--third  { order: 4; }

.fs-abt-mission__title {
	margin: 0;
	padding: 0 0 16px;
	font-size: 18px;
	line-height: 28px;
	font-weight: 700;
	letter-spacing: normal;
	text-transform: uppercase;
	color: #fb923c;
}

.fs-abt-mission__body {
	margin: 0;
	padding: 0;
	font-size: 16px;
	line-height: 24px;
	color: #fafaf9;
}

/* The art column.

   Tailwind composes transforms as translate → rotate → skew → scale, so
   `rotate-12` with `-scale-x-100` is rotate(12deg) scaleX(-1), and the sm
   variant swaps in scale(-1.5, 1.5). Writing them in the other order gives a
   visibly different mirror axis, which is why they are spelled out here
   rather than left to a shorthand. */
.fs-abt-mission__art {
	position: relative;
	order: 1;
	margin-top: -160px;
	transform: rotate(12deg) scaleX(-1);
}

@media (min-width: 640px) {
	.fs-abt-mission__art {
		order: 2;
		margin-top: 0;
		transform: rotate(12deg) scale(-1.5, 1.5);
	}
}

.fs-abt-mission__art img {
	display: block;
	width: 100%;
	height: auto;
	max-width: 100%;
	margin-bottom: -80px;
	animation: fs-line-float 6s ease-in-out infinite;

	/* The image runs a continuous transform animation, so give it its own
	   compositing layer rather than repainting the section every frame. */
	will-change: transform;
}

/* From sm the drone leaves the flow and hangs from the bottom of its cell,
   with 160px of padding above it, so it overhangs the row upward instead of
   stretching it. */
@media (min-width: 640px) {
	.fs-abt-mission__art img {
		position: absolute;
		left: 0;
		bottom: 0;
		padding-top: 160px;
		margin-bottom: 0;
	}
}

@keyframes fs-line-float {
	0%   { transform: translate(0); }
	50%  { transform: translateY(10px); }
	100% { transform: translate(0); }
}

@media (prefers-reduced-motion: reduce) {
	.fs-abt-mission__art img {
		animation: none;
	}
}


/* ==========================================================================
   ABOUT US — band clipping

   Live wraps the whole page in `bg-background border-b border-white
   overflow-hidden`, and that one wrapper is what stops the mission drone —
   mirrored and scaled 1.5, so it reaches 7px past the right edge at 1440 —
   from adding a horizontal scrollbar.

   Here the sections are sibling Elementor containers, and it turns out no new
   rule is needed at all: the theme already sets `overflow: hidden auto` on
   `body`, and because `html` is `overflow: visible` the browser propagates
   that to the viewport, so the document never scrolls sideways.

   Recording the two attempts that did NOT work, because both look correct:

     - `overflow-x: clip` on each band. CSS Overflow resolves the other axis
       to `auto` when one axis is `clip`, so the band clipped VERTICALLY too
       and the drone — which hangs ~370px up into the hero — vanished.
     - `overflow-x: clip` on the Elementor page wrapper. Same disappearance,
       even though the drone sits well inside that wrapper's box vertically.

   In both cases the symptom is a completely invisible drone rather than a
   cropped one, which reads like a broken image URL and is worth recognising
   quickly if a later section overhangs its band the same way.
   ========================================================================== */


/* ==========================================================================
   ABOUT US — advantages

   Live: `w-full md:grid md:grid-cols-2 grid-cols-1 grid-rows-2 md:grid-rows-1`
   wrapping a full-bleed photograph and a black copy panel.

   Only `md:grid` turns the grid on, so below 768 this is an ordinary block
   container and the two halves just stack — `grid-cols-1` and `grid-rows-2`
   in live's class list never take effect and are not reproduced.

   Measured at 390 / 834 / 1440: section 390x904 / 834x680 / 1440x400, photo
   column 390x400 / 417x680 / 720x400, panel padding 32 / 64 / 64.
   ========================================================================== */

.fs-abt-adv {
	width: 100%;
}

@media (min-width: 768px) {
	.fs-abt-adv {
		display: grid;
		grid-template-columns: 1fr 1fr;
		grid-template-rows: 1fr;
	}
}

.fs-abt-adv__media {
	position: relative;
	width: 100%;
	height: 100%;
	min-height: 400px;
}

/* object-position 50% 0% — the crop is anchored to the TOP, not the centre,
   which is what keeps the drone formation in frame as the column gets
   taller at tablet width. */
.fs-abt-adv__media img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 0%;
}

.fs-abt-adv__panel {
	width: 100%;
	height: 100%;
	padding: 32px;
	background-color: #000000;
}

@media (min-width: 640px) {
	.fs-abt-adv__panel {
		padding: 64px;
	}
}

/* Live writes this heading in literal capitals with text-transform none. It
   is written in sentence case here and uppercased in CSS instead, so a
   translation can carry its own capitalisation rules — visually identical. */
.fs-abt-adv__title {
	margin: 0;
	padding: 0 0 32px;
	font-size: 36px;
	line-height: 40px;
	font-weight: 700;
	letter-spacing: normal;
	text-transform: uppercase;
	color: #fafaf9;
}

.fs-abt-adv__title span {
	font-weight: 100;
	color: #fb923c;
}

.fs-abt-adv__row {
	display: flex;
	gap: 8px;
}

/* space-y-4: the gap is a top margin on every row but the first. */
.fs-abt-adv__row + .fs-abt-adv__row {
	margin-top: 16px;
}

.fs-abt-adv__icon {
	flex: 0 0 24px;
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 8px;
	margin: 0;
	padding: 0;
	color: #fb923c;
}

/* 24 wide, 22 tall: live sets the height with an attribute and the width with
   `w-6`, so the glyph box is deliberately not square. */
.fs-abt-adv__glyph {
	flex: none;
	width: 24px;
	height: 22px;
}

.fs-abt-adv__row p:last-child {
	margin: 0;
	padding: 0;
	font-size: 16px;
	line-height: 24px;
	color: #fafaf9;
}


/* ==========================================================================
   ABOUT US — story

   Live keeps four visually distinct blocks inside ONE
   `.container.overflow-hidden`: the Target Audience diagram, the standfirst
   and its CTA, the team grid, and the client logos. They are one section here
   for the same reason — a single place that owns the 32px inline padding and
   the 1000px cap.

   Measured at 390 / 834 / 1440(1728):
     container   390x2737 / 834x2358 / 1000x2555, padding-inline 32
     diagram     326x338 / 770x798 / 936x970 — pure 523:542 aspect ratio
     standfirst  padding-top 128 at every width, max-width 768
     team        padding-block 80, cards 240 / 257 / 312
     clients     padding 64 / 0 / 112, margin-block 40, row gap 32
   ========================================================================== */

.fs-abt-story {
	width: 100%;
	margin-inline: auto;
	padding-inline: 32px;
	overflow: hidden;
}

@media (min-width: 1000px) {
	.fs-abt-story {
		max-width: 1000px;
	}
}

/* ---- Target Audience diagram ---- */

.fs-abt-story__audience {
	position: relative;
}

.fs-abt-story__audience img {
	display: block;
	width: 100%;
	height: auto;
}

/* The connector line, overlaid on the same viewBox as the diagram it sits on
   top of, so the two stay registered at every width without any arithmetic. */
.fs-abt-lines {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	pointer-events: none;
}

/* 1px below sm and 0.2px above, matching live's `stroke-[1px]
   sm:stroke-[0.2px]`. These are USER units, not device pixels — at desktop
   the diagram is scaled about 1.8x, so 0.2 lands just under half a pixel and
   reads as a hairline, which is the intent. */
.fs-abt-lines__path {
	stroke-width: 1px;
}

@media (min-width: 640px) {
	.fs-abt-lines__path {
		stroke-width: 0.2px;
	}
}

/* The glowing head of the line — an addition, not something live has.

   The core is a plain white dot at r=2.2, smaller than the diagram's own
   junction dots (~r=3.9) so it reads as the tip of the line rather than a
   sixth category node. The glow is two stacked drop-shadows: a tight white
   one that keeps the dot looking lit rather than blurred, and a wider brand
   orange one that gives it colour without tinting the core.

   Blur radii here are USER units — the diagram is scaled about 1.8x at
   desktop, so 2 and 5 land near 3.6px and 9px on screen.

   Opacity is driven from the script, which hides the tip at both ends of the
   range: there is no line yet at the start, and at the end the head lands on
   one of the diagram's own dots where a second one would look doubled. */
.fs-abt-lines__tip {
	opacity: 0;
	filter: drop-shadow(0 0 2px #ffffff)
	        drop-shadow(0 0 5px rgba(251, 146, 60, 0.95));
	transition: opacity 0.25s ease;
}

@media (prefers-reduced-motion: reduce) {
	.fs-abt-lines__tip {
		display: none;
	}
}

/* ---- Standfirst and CTA ---- */

.fs-abt-story__lead {
	max-width: 768px;
	margin: 0 auto;
	padding: 128px 0 0;
	font-size: 16px;
	line-height: 24px;
	text-align: center;
	color: #fb923c;
}

.fs-abt-story__cta {
	display: flex;
	justify-content: center;
	padding-top: 40px;
}

/* A WHITE pill, not the orange one used elsewhere on the site, and not the
   outlined one in the header: black label on solid white, dropping to 80%
   opacity on hover (live's `hover:bg-white/80`). */
.fs-abt-story__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	box-sizing: border-box;
	height: 40px;
	padding: 20px 24px;
	border: 0;
	border-radius: 9999px;
	background-color: #ffffff;
	color: #000000;
	font-size: 14px;
	font-weight: 500;
	letter-spacing: normal;
	line-height: 1;
	white-space: nowrap;
	text-decoration: none;
	box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
	transition: background-color 0.15s ease;
}

.fs-abt-story__btn:hover,
.fs-abt-story__btn:focus-visible {
	background-color: rgba(255, 255, 255, 0.8);
	color: #000000;
	text-decoration: none;
}

/* Scoped, because Elementor zeroes `hr` margins with a selector that outranks
   a bare class — the same trap the factors rule and the FAQ rule both hit. */
.fs-abt-story .fs-abt-story__rule {
	height: 0;
	margin: 0;
	border: 0;
	border-top: 1px solid #292524;
}

.fs-abt-story .fs-abt-story__rule--lead {
	margin-top: 80px;
}

/* ---- Team ---- */

.fs-abt-team {
	padding-block: 80px;
	text-align: center;
}

.fs-abt-team__eyebrow {
	margin: 0 0 40px;
	padding: 0;
	font-size: 18px;
	line-height: 28px;
	font-weight: 200;
	letter-spacing: normal;
	text-transform: uppercase;
	color: #fafaf9;
}

/* A list, where live uses bare divs. Five people are a list, and the markup
   costs nothing visually once the bullets and padding are off. */
.fs-abt-team__grid {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0;
	margin: 0;
	padding: 0;
	list-style: none;
}

.fs-abt-team__card {
	position: relative;
	width: 240px;
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 768px) {
	.fs-abt-team__card {
		width: 33.3333%;
	}
}

.fs-abt-team__photo {
	display: block;
	width: 100%;
	height: auto;
}

/* Absolute with no left/right and no width, so it shrink-wraps its longest
   line exactly as live's does — the overlay is a different width on every
   card and that is not a bug. */
.fs-abt-team__label {
	position: absolute;
	top: 0;
	bottom: 0;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	padding: 20px;
	text-align: start;
}

.fs-abt-team__name {
	margin: 0;
	padding: 0;
	font-size: 36px;
	line-height: 40px;
	font-weight: 700;
	letter-spacing: normal;
	color: #fafaf9;
}

.fs-abt-team__role {
	margin: 0;
	padding: 0;
	font-size: 18px;
	line-height: 16px;
	font-weight: 700;
	letter-spacing: normal;
	color: #fafaf9;
}

/* The role is the only thing on this page keyed to lg, not md or sm. */
@media (min-width: 1024px) {
	.fs-abt-team__role {
		font-size: 24px;
		line-height: 28px;
	}
}

/* ---- Clients ---- */

.fs-abt-clients {
	padding: 64px 0 112px;
	margin-block: 40px;
}

.fs-abt-clients__eyebrow {
	margin: 0;
	padding: 0 0 16px;
	font-size: 14px;
	line-height: 20px;
	font-weight: 300;
	letter-spacing: 1.4px;
	text-transform: uppercase;
	text-align: center;
	color: #fafaf9;
}

.fs-abt-clients__row {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 32px;
	padding-top: 40px;
}

/* Three caps, matching live's max-w-28 / max-w-12 / max-w-8. Height is left
   to the intrinsic ratio so the wordmarks and the crests both sit on the row
   centre line without distortion.

   Scoped to the row on purpose. Elementor ships `.elementor img
   { max-width: 100% }` at (0,1,1), which outranks a bare class at (0,1,0) —
   every logo rendered at its full natural size and the strip came out 2377px
   tall. Adding the parent class takes this to (0,2,0) and it wins without
   needing !important. */
.fs-abt-clients__row .fs-abt-clients__logo {
	max-width: 112px;
	width: auto;
	height: auto;
	object-fit: contain;
	filter: grayscale(1);
	transition: filter 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-abt-clients__row .fs-abt-clients__logo--round { max-width: 48px; }
.fs-abt-clients__row .fs-abt-clients__logo--crest { max-width: 32px; }

.fs-abt-clients__row .fs-abt-clients__logo:hover {
	filter: grayscale(0);
}


/* ==========================================================================
   ABOUT US — testimonials and the closing CTA card

   Live: a `bg-black` block holding `container pb-20` > `pt-20`, the heading,
   the quote grid, then a light card 80px below it.

   Measured at 1440: block 1062 tall, container 1000 capped, grid 936x518 in
   three 306.664px columns 8px apart, cards radius 24 / padding 16 / 1px
   #292524, names 18/400 uppercase, quotes 16/24 with 16px above.

   The columns are CSS multi-column rather than live's three duplicated sets
   of markup — see the note on fs_section_voices() in flystack-about.php for
   why, and for the testimonial live drops at desktop.
   ========================================================================== */

.fs-abt-voices {
	width: 100%;
	background-color: #000000;
}

.fs-abt-voices__inner {
	width: 100%;
	margin-inline: auto;
	padding: 80px 32px;
}

@media (min-width: 1000px) {
	.fs-abt-voices__inner {
		max-width: 1000px;
	}
}

.fs-abt-voices__title {
	margin: 0;
	padding: 0 0 64px;
	font-size: 36px;
	line-height: 40px;
	font-weight: 700;
	letter-spacing: normal;
	text-transform: uppercase;
	text-align: center;
	color: #fafaf9;
}

.fs-abt-voices__grid {
	position: relative;
}

/* One column below 640, two to 1023, three above — the breakpoints live uses
   on its grid, expressed as column COUNT so a single copy of each quote can
   flow through them. */
.fs-abt-voices__cols {
	columns: 1;
	column-gap: 8px;
}

@media (min-width: 640px) {
	.fs-abt-voices__cols {
		columns: 2;
	}
}

@media (min-width: 1024px) {
	.fs-abt-voices__cols {
		columns: 3;
	}
}

/* break-inside on the card AND display:inline-block on nothing else: a
   multi-column card that splits across a column boundary loses its border on
   one side, which reads as a rendering fault rather than a layout choice. */
.fs-abt-voices__card {
	break-inside: avoid;
	-webkit-column-break-inside: avoid;
	margin: 0 0 8px;
	padding: 16px;
	border: 1px solid #292524;
	border-radius: 24px;
}

/* font-style is restated because WordPress themes conventionally italicise
   <figcaption>, and hello-elementor is no exception — the names came out
   slanted while the quotes beside them did not. */
.fs-abt-voices__name {
	margin: 0;
	padding: 0;
	font-style: normal;
	font-size: 18px;
	line-height: 28px;
	font-weight: 400;
	letter-spacing: normal;
	text-transform: uppercase;
	color: #fafaf9;
}

.fs-abt-voices__quote {
	margin: 0;
	padding: 16px 0 0;
	font-size: 16px;
	line-height: 24px;
	text-align: start;
	color: #fafaf9;
	quotes: none;
}

.fs-abt-voices__fade {
	position: absolute;
	bottom: 0;
	left: 0;
	width: 100%;
	height: 160px;
	pointer-events: none;
	background: linear-gradient(to top, #000000 20%, transparent);
}

/* ---- The closing CTA card ---- */

/* Inverted out of the black section: near-white ground, warm-black text. */
.fs-abt-cta {
	box-sizing: border-box;
	width: 100%;
	max-width: 672px;
	margin: 80px auto 0;
	padding: 24px;
	border-radius: 24px;
	background-color: #fafaf9;
	color: #292524;
}

.fs-abt-cta__head {
	display: flex;
	justify-content: space-between;
	gap: 24px;
	width: 100%;
}

.fs-abt-cta__title {
	margin: 0;
	padding: 0;
	font-size: 18px;
	line-height: 28px;
	font-weight: 700;
	letter-spacing: normal;
	text-transform: uppercase;
	color: #292524;
}

/* Scoped to the row, for the same reason the client logos are: Elementor
   ships `.elementor img { border-radius: 0 }` at (0,1,1), which beat a bare
   class and rendered this as a hard-cornered square. */
.fs-abt-cta__head .fs-abt-cta__mark {
	flex: none;
	width: 56px;
	height: 56px;
	border-radius: 50%;
	object-fit: cover;
}

/* space-y-6 between the two rows. */
.fs-abt-cta__foot {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 40px;
	width: 100%;
	margin-top: 24px;
}

@media (min-width: 640px) {
	.fs-abt-cta__foot {
		flex-direction: row;
		justify-content: space-between;
		align-items: flex-end;
	}
}

.fs-abt-cta__text {
	margin: 0;
	padding: 0;
	font-size: 16px;
	line-height: 24px;
	color: #292524;
}

/* An outlined pill again, but a third variant: orange 1px hairline on the
   light card, dark label, 18/500. Not the header's 2px, not the story
   block's solid white.

   Height is set explicitly rather than left to padding. Live's class list
   asks for both `h-9` and `py-5`, which is contradictory — it lands on 42px
   in the browser, while reproducing the padding alone gave 60. 42 with the
   vertical padding dropped reproduces live's box exactly; the horizontal 24
   still sets the 148px width. */
.fs-abt-cta__btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	flex: none;
	box-sizing: border-box;
	height: 42px;
	padding: 0 24px;
	border: 1px solid #fb923c;
	border-radius: 9999px;
	background-color: transparent;
	color: #292524;
	font-size: 18px;
	font-weight: 500;
	line-height: 1;
	letter-spacing: normal;
	white-space: nowrap;
	text-decoration: none;
	transition: background-color 0.15s ease, color 0.15s ease;
}

.fs-abt-cta__btn:hover,
.fs-abt-cta__btn:focus-visible {
	background-color: rgba(12, 10, 9, 0.2);
	color: #292524;
	text-decoration: none;
}


/* ==========================================================================
   PROJECTS — archive

   Measured from live at 1420. The grid there is client-rendered, so none of
   this is visible in the page source and it had to be read from a live tab.

   Live paints the same 31 cards twice — a flex stack below 640 and a grid
   above it. One list through CSS multi-column reproduces the 2 / 3 / 4 column
   result without repeating every project title in the markup.
   ========================================================================== */

.fs-pj {
	position: relative;
	padding-top: 160px;
	text-align: center;
	border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}

/* The line-work sits behind the content at a fifth opacity, pulled up 80px and
   capped at one screen so it never tiles down the whole archive.

   Live uses `-z-10` here and we cannot. A negative z-index paints in the
   nearest ANCESTOR STACKING CONTEXT's negative layer, and on live the nearest
   one is the root, where "behind everything" still means in front of the page
   background. Here the section sits inside an Elementor band that paints an
   opaque #0C0A09 background of its own, so -10 put the artwork behind that
   band and it vanished completely — the file loaded, the element measured
   1420x886, and nothing was visible.

   Layering it at 0 against content at 1 keeps the same result without
   depending on what an ancestor happens to paint. */
.fs-pj {
	isolation: isolate;
}

.fs-pj__backdrop {
	position: absolute;
	z-index: 0;
	top: -80px;
	left: 0;
	display: block;
	width: 100%;
	height: 100%;
	max-height: 100vh;
	opacity: 0.2;
	pointer-events: none;
}

.fs-pj__inner {
	position: relative;
	z-index: 1;
}

.fs-pj__backdrop img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* px-16 with md:px-8 — wider gutters on PHONES than on desktop, which reads
   like a mistake and is not: live's grid is a single column below 640, so the
   generous inline padding is what keeps the cards off the screen edge. */
.fs-pj__inner {
	padding-inline: 64px;
}

@media (min-width: 768px) {
	.fs-pj__inner {
		padding-inline: 32px;
	}
}

.fs-pj__head {
	padding-block: 40px;
}

.fs-pj__eyebrow {
	margin: 0;
	padding: 0 0 32px;
	font-size: 14px;
	font-weight: 300;
	letter-spacing: 12.8px;
	text-transform: uppercase;
	color: #fafaf9;
}

.fs-pj__h1 {
	margin: 0;
	padding: 0 0 40px;
	font-size: 36px;
	line-height: 40px;
	font-weight: 700;
	letter-spacing: normal;
	text-transform: uppercase;
	color: #fb923c;
}

@media (min-width: 640px) {
	.fs-pj__h1 {
		font-size: 60px;
		line-height: 60px;
	}
}

.fs-pj__sub {
	margin: 0;
	padding: 0;
	font-size: 16px;
	line-height: 24px;
	color: #fafaf9;
}

/* ---- The grid ---- */

/* Flex columns filled by script, NOT CSS `columns`.

   CSS multi-column was the obvious choice and produces the wrong reading
   order: it fills each column top to bottom, so the first four projects end
   up stacked in column one instead of running left to right across the top
   row. With 31 hand-ordered projects that reads as a shuffled grid.

   A plain CSS grid would fix the order but lose the masonry — rows align to
   the tallest card and the varying photo heights leave gaps.

   So the markup carries ONE flat list in the correct order, which is what
   search engines and screen readers get, and projects.js deals it round-robin
   into as many columns as the breakpoint calls for. Without JavaScript the
   list simply stays a single column, still in order. */
.fs-pj__grid {
	display: flex;
	align-items: flex-start;
	gap: 16px;
	margin-top: 80px;
	padding-bottom: 80px;
}

.fs-pj__col {
	display: flex;
	flex: 1 1 0;
	min-width: 0;
	flex-direction: column;
	gap: 16px;
}

/* Before the script runs the cards are direct children of the grid, so the
   grid must not try to lay them out side by side. */
.fs-pj__grid:not(.is-dealt) {
	flex-direction: column;
}

.fs-pj__card {
	display: block;
	text-decoration: none;
}

.fs-pj__frame {
	position: relative;
	display: block;
	overflow: hidden;
	border-radius: 16px;
	max-height: 700px;
	cursor: pointer;
	transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-pj__card:hover .fs-pj__frame,
.fs-pj__card:focus-visible .fs-pj__frame {
	transform: scale(1.03);
}

/* `50% 0` — top edge, horizontally centred. Was `left top`, which kept the sky
   but pushed a wide frame's subject off to the right of the card. The drones
   sit top-centre in almost every one of these photographs. */
.fs-pj__frame .fs-pj__img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 16px;
	object-fit: cover;
	object-position: 50% 0;
}

.fs-pj__label {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: flex-end;
	padding: 16px;
	text-align: left;
	transition: padding 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-pj__card:hover .fs-pj__label,
.fs-pj__card:focus-visible .fs-pj__label {
	padding-bottom: 24px;
}

/* A band under the title, not a wash over the whole card.

   Live ramps `from-transparent to-black` across the FULL card height, which
   means everything below the midpoint is progressively dimmed and the
   photograph loses its lower half. FLYSTACK asked for the image to stay clean
   and the gradient to sit only behind the caption, so this is a deliberate
   departure from live: the scrim starts at 55% of the card and is fully
   transparent above that line.

   Kept at 0.85 rather than solid black so the image still reads through
   behind the text. */
.fs-pj__scrim {
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	height: 45%;
	background: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.85) 100%);
}

.fs-pj__title {
	position: relative;
	z-index: 10;
	display: block;
	font-size: 20px;
	line-height: 28px;
	font-weight: 700;
	color: #fafaf9;
}

/* ---- Closing CTA ---- */

.fs-pj__cta {
	display: flex;
	flex-direction: column;
	justify-content: center;
	width: 100%;
	margin-inline: auto;
	margin-bottom: 80px;
	padding-inline: 32px;
}

@media (min-width: 1000px) {
	.fs-pj__cta { max-width: 1000px; }
}

.fs-pj__cta-title {
	margin: 0;
	padding-inline: 24px;
	font-size: 30px;
	line-height: 36px;
	font-weight: 700;
	letter-spacing: normal;
	text-transform: uppercase;
	color: #fafaf9;
}

@media (min-width: 640px) {
	.fs-pj__cta-title { font-size: 48px; line-height: 48px; }
}

.fs-pj__cta-text {
	margin: 0;
	padding-top: 24px;
	font-size: 18px;
	line-height: 28px;
	color: #fafaf9;
}

.fs-pj__cta-row {
	display: flex;
	gap: 16px;
	justify-content: center;
	margin-block: 32px;
}

.fs-pj__cta-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	height: 40px;
	padding: 0 35px;
	border: 2px solid #fb923c;
	border-radius: 9999px;
	background-color: transparent;
	color: #fafaf9;
	font-size: 16px;
	font-weight: 600;
	letter-spacing: 1px;
	line-height: 1;
	white-space: nowrap;
	text-decoration: none;
	transition: background-color 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}

.fs-pj__cta-btn:hover,
.fs-pj__cta-btn:focus-visible {
	background-color: #fb923c;
	color: #fafaf9;
	text-decoration: none;
}


/* Rotating hero heading on the Projects archive.

   All five phrases are in the markup; only one is shown at a time. Stacking
   them means the heading reserves the height of the tallest, so the grid below
   does not jump as the words change — live's does not jump either.

   Timing: live's cadence measured between 2.1s and 3.0s per phrase, which is
   not a constant, so this uses a steady 3s. The crossfade is ours; live's exact
   transition was not resolvable without frame-accurate capture. */
.fs-pj__h1[data-fs-rotate] {
	display: grid;
	justify-items: center;
}

.fs-pj__h1[data-fs-rotate] .fs-pj__phrase {
	grid-area: 1 / 1;
	opacity: 0;
	transform: translateY(8px);
	transition: opacity 0.5s ease, transform 0.5s ease;
}

.fs-pj__h1[data-fs-rotate] .fs-pj__phrase.is-on {
	opacity: 1;
	transform: none;
}

/* Without JavaScript the first phrase must still be readable, so the stack
   collapses to just that one rather than showing five on top of each other. */
.no-js .fs-pj__h1[data-fs-rotate] .fs-pj__phrase:not(.is-on) {
	display: none;
}

@media (prefers-reduced-motion: reduce) {
	.fs-pj__h1[data-fs-rotate] .fs-pj__phrase {
		transition: none;
	}
}


/* ==========================================================================
   SINGLE PROJECT

   Live renders this page LIGHT — `bg-secondary-foreground text-secondary`,
   #FAFAF9 on #292524 — and it is the only light page on the site.

   FLYSTACK asked for it dark, in line with everything else. So this is a
   deliberate divergence: same layout, same spacing, same type scale, inverted
   palette. The two colours simply swap, and every rule below that named a light
   ground now names the dark one.

   The 80px header strip goes with it. It existed only because a transparent
   white nav is invisible over a near-white page; over #0C0A09 the site's normal
   header behaviour is correct again.
   ========================================================================== */

.fs-single {
	position: relative;
	display: block;
	/* No top padding: the hero runs to y=0 and the header sits over it, the same
	   way it sits over the homepage video. The 80px that used to be here was
	   clearing a header that is transparent until scrolled anyway. */
	padding-block: 0 160px;
	background-color: #0c0a09;
	color: #fafaf9;
	border-bottom: 1px solid rgba(255, 255, 255, 0.25);
	/* clip, not hidden: `overflow-x: hidden` would make this a scroll container
	   and break `position: sticky` for anything inside it. */
	overflow-x: clip;
}

/* Without a cover there is nothing for the header to sit over, so the page needs
   its top spacing back. */
.fs-single:not(:has(.fs-single__hero)) {
	padding-top: 80px;
}

/* Kept in the markup but no longer painted: the page is dark now, so the strip
   would be a black band over a black page. */
.fs-single__headerbg {
	display: none;
}

.fs-single__inner {
	width: 100%;
	margin-inline: auto;
	padding-inline: 32px;
}

@media (min-width: 1000px) {
	.fs-single__inner { max-width: 1000px; }
}

.fs-single__cover {
	margin-bottom: 40px;
}

/* ---- Hero: full-bleed cover with the title over it ---- */

/* Pulled out to the viewport edges rather than moved in the template —
   `margin-left: calc(50% - 50vw)` widens the block without disturbing the flow
   of anything around it, and works wherever it happens to sit.

   100vw rather than 100%: with a visible scrollbar 100vw is the wider of the
   two, and matching the negative margin to it keeps the left and right edges
   equal. `overflow-x: clip` on the section stops the overhang becoming a
   horizontal scrollbar. */
.fs-single__hero {
	position: relative;
	width: 100vw;
	max-width: 100vw;
	margin-left: calc(50% - 50vw);
	margin-right: calc(50% - 50vw);
	margin-bottom: 48px;
	overflow: hidden;
}

/* Around 60% of the viewport, and never at a silly proportion.
   `min(60vh, 62vw)` lets the height rule on a normal desktop and hands over to
   the width on anything tall and narrow, where a straight 60vh would be a
   letterbox standing on its end. The floor stops it collapsing on a short
   laptop window.

   80vh was the first attempt and was too much: it filled the screen and pushed
   everything about the project below the fold. */
.fs-single .fs-single__cover {
	display: block;
	width: 100%;
	height: min(60vh, 62vw);
	min-height: 320px;
	padding: 0;
	border: 0;
	background: none;
	cursor: pointer;
	line-height: 0;
}

/* Biased to the top, but NOT pinned to it.

   The rule everywhere else on the site is `50% 0`, and at card size that is
   right: the box is wide and shallow next to the photograph, so the top edge is
   most of the picture. This hero is 2.38:1 against covers that are often square
   — petrolul.webp is 1440x1459 — and at `50% 0` it showed the top 42%, which on
   a night shot is empty sky with the formation cropped off below.

   `50% 25%` starts the window a quarter of the way down, which is where the
   drones actually sit: above the crowd and the stage, below the empty top of
   the frame.

   No radius at full bleed: a rounded corner needs an edge to sit against, and
   at the viewport edge there isn't one. */
.fs-single__cover .fs-single__cover-img {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: 0;
	object-fit: cover;
	object-position: 50% 25%;
}

/* The scrim is on the hero, not the button, so hovering the image to open the
   lightbox does not fade the title's backing out from under it. Weighted to the
   bottom, where the title sits, and kept off the top two-thirds so the
   formation stays as bright as it is everywhere else on the site. */
/* The scrim resolves into the PAGE colour, not into black.

   It used to end at `rgba(0,0,0,.85)`, and the page behind is #0C0A09 — near
   black but not black. The two never met, so the bottom of every hero showed a
   darker band with a hard seam where the image stopped. Ending on #0C0A09 makes
   the photograph fade into the page instead of onto a strip of ink.

   Kept off the top third so the formation stays as bright as it is everywhere
   else; the slight wash at the very top is only there to hold the nav. */
.fs-single__hero::after {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: linear-gradient(
		to bottom,
		rgba(12, 10, 9, 0.35) 0%,
		rgba(12, 10, 9, 0) 22%,
		rgba(12, 10, 9, 0) 45%,
		rgba(12, 10, 9, 0.55) 82%,
		#0c0a09 100%
	);
}

.fs-single .fs-single__title--over {
	position: absolute;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 2;
	/* Aligned to the same 1000px measure as the body copy below, so the title
	   sits on the text column rather than on the viewport edge. */
	width: 100%;
	max-width: 1064px;   /* 1000 measure + the 32px gutter either side */
	margin: 0 auto;
	/* 40px sat the title right on the bottom edge of the photograph. It needs
	   room under it to read as placed rather than dropped. */
	padding: 0 32px 72px;
	box-sizing: border-box;
	pointer-events: none;
	/* White over the photograph, not the orange the title uses further down the
	   page — orange on a lit drone frame competes with the formation itself.
	   Two shadows: a soft white glow to lift it off a dark sky, and a black one
	   underneath so it still reads if the crop lands on something bright. */
	color: #fff;
	text-shadow:
		0 0 18px rgba(255, 255, 255, 0.35),
		0 2px 24px rgba(0, 0, 0, 0.7);
}

@media (max-width: 640px) {
	.fs-single .fs-single__title--over {
		padding-bottom: 44px;
	}
}

.fs-single__title {
	margin: 0;
	padding: 0 0 24px;
	font-size: 48px;
	line-height: 48px;
	font-weight: 700;
	letter-spacing: normal;
	color: #fb923c;
}

/* ---- Project body copy ----

   Ported from the source's `blog-content.css`, which styles exactly this: rich
   text a person typed into an editor, on a project page. Its own values are
   written for a light page (gray-800 body, gray-900 headings, blue-600 links,
   gray-50 quote panels), so the SCALE and SPACING are kept and the COLOURS are
   the site's own.

   The point of doing it now rather than when the first project gets a write-up
   is that whatever marketing types — headings, lists, a quote, an image — has
   somewhere to land. Nothing here needs revisiting when content arrives. */
.fs-single__body {
	margin-bottom: 64px;
	font-size: 16px;
	line-height: 1.625;         /* leading-relaxed */
	color: #fafaf9;
}

.fs-single__body > *:first-child { margin-top: 0; }
.fs-single__body > *:last-child  { margin-bottom: 0; }

.fs-single__body h1 { margin: 32px 0 16px; font-size: 36px; line-height: 1.2; font-weight: 700; }
.fs-single__body h2 { margin: 24px 0 12px; font-size: 30px; line-height: 1.25; font-weight: 600; }
.fs-single__body h3 { margin: 20px 0 8px;  font-size: 24px; line-height: 1.3;  font-weight: 600; }
.fs-single__body h4 { margin: 16px 0 8px;  font-size: 20px; line-height: 1.35; font-weight: 600; }
.fs-single__body h5 { margin: 12px 0 8px;  font-size: 18px; line-height: 1.4;  font-weight: 600; }
.fs-single__body h6 { margin: 12px 0 8px;  font-size: 16px; line-height: 1.5;  font-weight: 600; }

.fs-single__body h1,
.fs-single__body h2,
.fs-single__body h3,
.fs-single__body h4,
.fs-single__body h5,
.fs-single__body h6 {
	color: #fafaf9;
	letter-spacing: normal;
	text-transform: none;       /* the site uppercases headings; prose should not be shouted */
}

.fs-single__body p { margin: 0 0 16px; }

.fs-single__body a {
	color: #fb923c;             /* the source uses blue-600; ours is the brand */
	text-decoration: underline;
	text-underline-offset: 2px;
}

.fs-single__body a:hover { color: #fdba74; }

.fs-single__body strong { font-weight: 600; color: #fff; }
.fs-single__body em { font-style: italic; }

.fs-single__body ul { margin: 0 0 16px; padding-left: 24px; list-style: disc; }
.fs-single__body ol { margin: 0 0 16px; padding-left: 24px; list-style: decimal; }
.fs-single__body li { margin-bottom: 6px; line-height: 1.625; }
.fs-single__body li > ul,
.fs-single__body li > ol { margin: 8px 0 0 24px; }

.fs-single__body blockquote {
	margin: 0 0 16px;
	padding: 12px 20px;
	border-left: 4px solid #fb923c;    /* source: border-gray-300 on a grey panel */
	background: rgba(250, 250, 249, 0.05);
	border-radius: 0 8px 8px 0;
	font-style: italic;
	color: rgba(250, 250, 249, 0.85);
}

.fs-single__body code {
	padding: 2px 6px;
	border-radius: 4px;
	background: rgba(250, 250, 249, 0.08);
	color: #fdba74;
	font-size: 14px;
	font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.fs-single__body pre {
	margin: 0 0 16px;
	padding: 16px;
	border-radius: 8px;
	background: #1c1917;
	color: #fafaf9;
	overflow-x: auto;
}

.fs-single__body pre code { padding: 0; background: none; color: inherit; }

/* Full width of the measure, and never cropped — same reasoning as the gallery:
   these will be drone photographs. */
.fs-single__body img {
	display: block;
	width: 100%;
	height: auto;
	margin: 24px 0;
	border-radius: 12px;
}

.fs-single__body figure { margin: 24px 0; }

.fs-single__body figcaption {
	margin-top: 8px;
	font-size: 14px;
	font-style: normal;         /* hello-elementor italicises these */
	color: rgba(250, 250, 249, 0.6);
	text-align: center;
}

.fs-single__body hr {
	margin: 32px 0;
	border: 0;
	border-top: 1px solid rgba(250, 250, 249, 0.2);
}

.fs-single__body table {
	width: 100%;
	margin: 0 0 16px;
	border-collapse: collapse;
}

.fs-single__body th,
.fs-single__body td {
	padding: 8px 16px;
	border: 1px solid rgba(250, 250, 249, 0.2);
	text-align: left;
}

.fs-single__body th {
	background: rgba(250, 250, 249, 0.08);
	font-weight: 600;
}

.fs-single__body tr:nth-child(even) td {
	background: rgba(250, 250, 249, 0.03);
}

/* An embedded video keeps its shape rather than being letterboxed by a fixed
   height, which is what Elementor's own oembed wrapper would otherwise do. */
.fs-single__body iframe {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;
	height: auto;
	margin: 24px 0;
	border: 0;
	border-radius: 12px;
}

/* Live uses `bg-background/5` — its dark colour at 5% over a light ground.
   Inverted here: the light colour at 5% over the dark ground, which lands in
   the same place visually, a panel just separated from the page behind it. */
.fs-single__details {
	margin-bottom: 64px;
	padding: 32px;
	border-radius: 16px;
	background-color: rgba(250, 250, 249, 0.05);
}

.fs-single__h2 {
	margin: 0 0 24px;
	padding: 0;
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	letter-spacing: normal;
	color: #fb923c;
}

.fs-single__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 24px;
}

@media (min-width: 768px) {
	.fs-single__grid { grid-template-columns: 1fr 1fr; }
}

.fs-single__label {
	margin: 0 0 8px;
	padding: 0;
	font-size: 16px;
	line-height: 24px;
	font-weight: 600;
	color: #fafaf9;
}

.fs-single__value {
	margin: 0;
	padding: 0;
	font-size: 16px;
	line-height: 24px;
	color: rgba(250, 250, 249, 0.8);
}

/* ---- Gallery ---- */

.fs-single__gallery {
	margin-bottom: 64px;
}

/* A grid rather than live's carousel. Every shot is reachable without
   operating a control, which is better for both search engines and anyone
   using a keyboard; live hides most of its gallery behind arrows. */
.fs-single__shots {
	display: grid;
	grid-template-columns: 1fr;
	gap: 16px;
	margin: 0;
	padding: 0;
	list-style: none;
}

@media (min-width: 640px) { .fs-single__shots { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1024px) { .fs-single__shots { grid-template-columns: repeat(3, 1fr); } }

.fs-single__shot {
	margin: 0;
	padding: 0;
	list-style: none;
}

/* NOT cropped.

   These were `aspect-ratio: 4/3` with `object-fit: cover`, which on a set of
   frames shot in portrait, landscape and square cut straight through the
   drones — the one thing in the photograph anyone is looking at.

   So each shot keeps its own proportions and the grid becomes masonry instead.
   The aspect ratio comes from the attachment metadata and is set inline on the
   button, so the space is reserved before the image loads and the column does
   not jump as it arrives. */
.fs-single__shots .fs-single__shot-img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 16px;
}

/* Masonry: JS deals the shots round-robin into columns so reading order still
   runs left to right across the top row. Same approach as the archive grid —
   CSS multi-column fills each column top to bottom instead, which scrambles
   the order (see §5). Until it runs, the plain grid above is a fine fallback. */
.fs-single__shots.is-dealt {
	display: flex;
	align-items: flex-start;
	gap: 16px;
}

.fs-single__shots.is-dealt .fs-single__shot-col {
	display: flex;
	flex: 1 1 0;
	min-width: 0;
	flex-direction: column;
	gap: 16px;
}

/* ---- Related ---- */

.fs-single__rel-grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 16px;
}

@media (min-width: 640px) { .fs-single__rel-grid { grid-template-columns: repeat(3, 1fr); } }

/* The related cards reuse .fs-pj__card from the archive, which is written for
   a dark ground — its title is #FAFAF9. That used to matter because this page
   was light; it is dark now, and the colour is restated anyway so the card does
   not depend on which page it lands on. */
.fs-single__rel-grid .fs-pj__title {
	color: #fafaf9;
}

/* 4:5 portrait, not live's `aspect-video`.

   Live's 16:9 was throwing away most of these covers — they are shot square or
   portrait, so a landscape box crops hard on both the sky and the ground and
   what survives is a thin strip through the middle.

   4:5 is also what the homepage carousel cards use, so a project cover now has
   the same shape in all three places it appears. The equal ratio still solves
   the original problem: a landscape cover beside a portrait one used to leave
   the three cards at three different heights. */
.fs-single__rel-grid .fs-pj__frame,
.fs-single__rel-grid .fs-pj__media {
	aspect-ratio: 4 / 5;
	height: auto;
}

.fs-single__rel-grid .fs-pj__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 0;
}


/* ==========================================================================
   Contact page
   Measured from https://www.flystackdroneshows.com/contact at 1420 and at the
   mobile layout. Live's own Tailwind values are quoted next to each rule so the
   next person does not have to re-measure to know what is deliberate.

   Two selectors carry more weight than they look like they need. Hello
   Elementor and Elementor's own base sheet both style bare `input`, `select`,
   `textarea` and `img` at (0,1,1); anything here written as a bare class would
   lose. Every control rule is therefore scoped to `.fs-ct`, which puts it at
   (0,2,0) and settles it.
   ========================================================================== */

.fs-ct {
	background: #0c0a09;
	padding-bottom: 160px;          /* pb-40 */
	border-bottom: 1px solid rgba(255, 255, 255, 0.25);  /* live: border-white, down to 25% — see note */
	/* Live's body is 16/24. Elementor's global typography here is 15.12/25.704,
	   and the difference shows up as a 7px-per-row shortfall in the form: the
	   label sits in a line box sized by the PARENT's strut, not by its own
	   14px. Setting the section back to live's body metrics fixes every
	   inherited measurement at once. */
	font-size: 16px;
	line-height: 24px;
}

.fs-ct-inner {
	max-width: 1000px;              /* .container */
	margin: 0 auto;
	padding: 160px 32px 0;          /* pt-40, container px */
	text-align: center;
	box-sizing: border-box;
}

.fs-ct .fs-ct-title {
	margin: 0;
	font-size: 48px;                /* text-5xl */
	line-height: 48px;
	font-weight: 700;
	color: #fb923c;                 /* text-primary */
}

.fs-ct .fs-ct-sub {
	margin: 0 auto;
	padding: 16px 0;                /* py-4 */
	max-width: 672px;               /* max-w-2xl */
	font-size: 24px;                /* text-2xl */
	line-height: 32px;
	font-weight: 500;
	color: rgba(255, 255, 255, 0.6);
}

.fs-ct .fs-ct-lead {
	margin: 0 0 40px;               /* mb-10 */
	padding-top: 24px;              /* pt-6 */
	font-size: 18px;                /* text-lg */
	line-height: 28px;
	color: #fafaf9;
}

/* ---- Book Now card ---- */

.fs-ct-card {
	max-width: 768px;               /* max-w-3xl */
	margin: 0 auto;
	padding: 32px;                  /* p-8 */
	background: rgba(0, 0, 0, 0.4); /* bg-black/40 */
	border-radius: 32px;            /* rounded-[32px] */
	box-sizing: border-box;
}

.fs-ct .fs-ct-card-title {
	margin: 0;
	padding-bottom: 16px;           /* pb-4 */
	font-size: 30px;                /* text-3xl */
	line-height: 36px;
	font-weight: 700;
	color: #fafaf9;
}

.fs-ct .fs-ct-card-desc {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: #fafaf9;
}

.fs-ct .fs-ct-card-desc .font-semibold {
	font-weight: 600;
}

.fs-ct-form {
	display: flex;
	flex-direction: column;
	gap: 24px;                      /* space-y-6 */
	margin-top: 32px;               /* mt-8 */
	text-align: start;              /* text-start */
}

/* inline-block, not block. Live's label is an inline element, so its row is
   24px tall (the parent's strut) rather than the label's own 17px, and every
   field row measures 68px instead of 61px. */
.fs-ct .fs-ct-label {
	display: inline-block;
	font-size: 14px;                /* text-sm */
	line-height: 17px;              /* leading-none, as it lands */
	font-weight: 500;
	color: #fafaf9;
}

/* Controls. h-9 is a fixed 36px on live, not padding-derived, so it is set
   here as a height and the padding is left to do only horizontal work. */
.fs-ct .fs-ct-input {
	display: block;
	width: 100%;
	height: 36px;
	margin-top: 8px;                /* space-y-2 */
	padding: 4px 12px;
	font-family: inherit;
	font-size: 14px;
	line-height: 20px;
	color: #fafaf9;
	background: transparent;
	border: 1px solid #292524;      /* border-input */
	border-radius: 6px;             /* rounded-md */
	box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); /* shadow-sm */
	box-sizing: border-box;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
	-webkit-appearance: none;
	appearance: none;
}

.fs-ct .fs-ct-input::placeholder {
	color: #a8a29e;                 /* muted-foreground */
	opacity: 1;
}

.fs-ct .fs-ct-input:focus,
.fs-ct .fs-ct-input:focus-visible {
	outline: none;
	border-color: #fb923c;
	box-shadow: 0 0 0 1px #fb923c;  /* focus-visible:ring-1 ring-ring */
}

.fs-ct .fs-ct-textarea {
	height: auto;
	min-height: 60px;               /* min-h-[60px] */
	padding: 8px 12px;
	resize: vertical;
}

/* Event date. Live shows a button reading "Pick a date" with a calendar glyph;
   the control here starts as text so that placeholder survives, and promotes
   itself to type="date" on focus so the user still gets the OS picker. */
.fs-ct-datewrap,
.fs-ct-selectwrap {
	position: relative;
}

.fs-ct-datewrap .fs-ct-glyph {
	position: absolute;
	left: 16px;
	top: 50%;
	margin-top: 4px;                /* the control's own 8px top margin */
	transform: translateY(-50%);
	color: #a8a29e;
	pointer-events: none;
}

.fs-ct .fs-ct-date {
	padding-left: 40px;             /* 16 icon inset + 16 glyph + 8 gap */
	color: #a8a29e;
}

.fs-ct .fs-ct-date:focus,
.fs-ct .fs-ct-date[type="date"] {
	color: #fafaf9;
}

/* The drawn glyph stands in for the browser's own indicator, and the whole
   field opens the picker on click, so the native control is hidden rather than
   shown twice. */
.fs-ct .fs-ct-date::-webkit-calendar-picker-indicator {
	opacity: 0;
	position: absolute;
	right: 0;
	width: 100%;
	height: 100%;
	cursor: pointer;
}

.fs-ct .fs-ct-date {
	cursor: pointer;
}

/* Event type. */
.fs-ct .fs-ct-select {
	padding-right: 36px;
	cursor: pointer;
}

.fs-ct .fs-ct-select option {
	background: #0c0a09;
	color: #fafaf9;
}

.fs-ct-selectwrap .fs-ct-glyph {
	position: absolute;
	right: 12px;
	top: 50%;
	margin-top: 4px;
	transform: translateY(-50%);
	opacity: 0.5;
	pointer-events: none;
}

.fs-ct-submitrow {
	margin: 0;
}

.fs-ct .fs-ct-submit {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 36px;
	margin-top: 8px;
	padding: 8px 16px;
	font-family: inherit;
	font-size: 14px;
	line-height: 20px;
	font-weight: 500;
	/* text-primary-foreground, which the source defines as
	   `--primary-foreground: 60 9.1% 97.8%` — near-white, not the dark ink the
	   orange bar reads as in a screenshot. */
	color: #fafaf9;
	background: #fb923c;
	border: 0;
	border-radius: 6px;
	cursor: pointer;
	transition: background-color 0.15s ease;
}

.fs-ct .fs-ct-submit:hover {
	background: rgba(251, 146, 60, 0.9);
}

.fs-ct .fs-ct-disclaimer {
	margin: 0;                      /* the form's 24px gap already spaces it */
	font-size: 12px;                /* text-xs */
	line-height: 16px;
	color: rgba(255, 255, 255, 0.6);
}

/* ---- Where to find us ---- */

.fs-ct-find {
	display: grid;
	grid-template-columns: 1fr;     /* grid-cols-1 */
	gap: 40px;                      /* gap-10 */
	padding-top: 64px;              /* pt-16 */
	text-align: start;
}

.fs-ct .fs-ct-find-title {
	margin: 0;
	font-size: 36px;                /* text-4xl */
	line-height: 40px;
	font-weight: 700;
	color: #fafaf9;
}

/* The element selector is load-bearing. `.fs-ct .fs-ct-find-text p` below is
   (0,2,1) and would otherwise win over a (0,2,0) class rule here, quietly
   dropping this paragraph from 18/28 back to the body's 16/24 — an 8px error
   that propagates all the way to the section height. */
.fs-ct .fs-ct-find-text p.fs-ct-find-desc {
	margin: 0;
	padding: 24px 0 16px;           /* pt-6 pb-4 */
	font-size: 18px;                /* text-lg */
	line-height: 28px;
	color: #fafaf9;
}

.fs-ct .fs-ct-find-text p {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	color: #fafaf9;
}

.fs-ct .fs-ct-key {
	font-weight: 700;
	color: #fb923c;
}

.fs-ct .fs-ct-day {
	font-weight: 700;
}

.fs-ct .fs-ct-reach {
	color: rgba(250, 250, 249, 0.6);
}

.fs-ct-reach-line {
	display: flex;
	align-items: center;
	gap: 8px;
	color: #fff;
}

.fs-ct-reach-mail {
	padding-top: 8px;               /* pt-2 */
	padding-bottom: 4px;            /* pb-1 */
}

.fs-ct-reach-line a {
	color: inherit;
	text-decoration: none;
}

.fs-ct-reach-line:hover a {
	text-decoration: underline;
}

.fs-ct .fs-ct-reach-icon {
	color: #fb923c;
	margin-top: 4px;                /* mt-1 */
	flex: 0 0 auto;
}

.fs-ct-social {
	display: flex;
	align-items: center;
	gap: 16px;                      /* gap-4 */
	margin-top: 32px;               /* mt-8 */
}

.fs-ct-social a {
	display: inline-flex;
	color: #fafaf9;
	transition: color 0.3s ease;
}

.fs-ct-social a:hover {
	color: var(--fs-hover, #fb923c);
}

.fs-ct-social svg {
	width: 26px;
	height: 26px;
	display: block;
}

/* The map fills its grid cell on desktop and is a fixed band on mobile, which
   is live's `md:h-auto h-80`. The explicit min-height matters: the frame is
   deferred, and a cell with no intrinsic height would collapse before it
   loads. */
.fs-ct-map {
	position: relative;
	height: 320px;
	min-height: 320px;
	overflow: hidden;
	background: #0c0a09;
}

/* Absolute rather than height:100%. On desktop the wrapper takes its height
   from the grid row, and a percentage height against a parent whose own height
   is auto is the single most common way an embedded map silently collapses to
   zero. inset:0 does not care how the parent got its height. */
.fs-ct .fs-ct-map-canvas {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	background: #0c0a09;
}

/* Leaflet's own chrome, toned down to the page. */
.fs-ct .leaflet-control-attribution {
	background: rgba(12, 10, 9, 0.7);
	color: rgba(250, 250, 249, 0.6);
	font-size: 10px;
}

.fs-ct .leaflet-control-attribution a {
	color: rgba(250, 250, 249, 0.8);
}

.fs-ct .leaflet-bar a {
	background: #1c1917;
	color: #fafaf9;
	border-bottom-color: #292524;
}

.fs-ct .leaflet-bar a:hover {
	background: #292524;
	color: #fb923c;
}

/* ---- md: 768 ---- */

@media (min-width: 768px) {
	.fs-ct-find {
		grid-template-columns: 1fr 1fr; /* md:grid-cols-2 */
	}

	.fs-ct-map {
		height: auto;                   /* md:h-auto */
	}
}

/* ---- Contact form: states the source had as a toast library ----
   Sonner drew the success message as a floating toast. A line inside the form,
   next to the button that caused it, is where a visitor is already looking —
   and it is one fewer dependency. */

.fs-ct .fs-ct-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.fs-ct .fs-ct-error {
	margin: 6px 0 0;
	font-size: 12px;
	line-height: 16px;
	color: #f87171;
}

.fs-ct .fs-ct-input.is-invalid {
	border-color: #f87171;
}

.fs-ct .fs-ct-status {
	margin: 0;
	padding: 12px 16px;
	font-size: 14px;
	line-height: 20px;
	border-radius: 6px;
	border: 1px solid transparent;
}

.fs-ct .fs-ct-status.is-ok {
	color: #86efac;
	background: rgba(34, 197, 94, 0.1);
	border-color: rgba(34, 197, 94, 0.35);
}

.fs-ct .fs-ct-status.is-error {
	color: #fca5a5;
	background: rgba(248, 113, 113, 0.1);
	border-color: rgba(248, 113, 113, 0.35);
}

.fs-ct .fs-ct-submit[disabled] {
	opacity: 0.7;
	cursor: default;
}

/* ==========================================================================
   Booking dialog
   The Next site opens a Radix Dialog holding the same BookForm from five
   different triggers: the header "Book now", the contact band, the timeline,
   the About page and the Projects page. Measured from its Tailwind classes:
   max-w-3xl, p-0, border-none, bg-black, rounded-3xl, overflow-hidden,
   max-h-[90vh], with the form scrolling inside.
   ========================================================================== */

.fs-book {
	position: fixed;
	inset: 0;
	z-index: 100000;               /* above the fixed header */
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 16px;
}

.fs-book[hidden] {
	display: none;
}

.fs-book__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, 0.8);
	animation: fs-book-fade 0.2s ease;
}

.fs-book__panel {
	position: relative;
	width: 100%;
	max-width: 768px;              /* max-w-3xl */
	max-height: 90vh;              /* max-h-[90vh] */
	background: #000;
	border-radius: 24px;           /* rounded-3xl */
	overflow: hidden;
	animation: fs-book-rise 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}

.fs-book__scroll {
	max-height: 90vh;
	overflow-y: auto;
	overscroll-behavior: contain;
}

/* The card inside the dialog is already black, so its own panel background
   would read as a second box drawn on top of the first. */
.fs-book .fs-ct-card {
	max-width: none;
	background: transparent;
	border-radius: 0;
}

.fs-book__close {
	position: absolute;
	top: 14px;
	right: 14px;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	padding: 0;
	color: #a8a29e;
	background: transparent;
	border: 0;
	border-radius: 999px;
	cursor: pointer;
	transition: color 0.15s ease, background-color 0.15s ease;
}

.fs-book__close:hover {
	color: #fafaf9;
	background: rgba(255, 255, 255, 0.08);
}

body.fs-book-open {
	overflow: hidden;
}

@keyframes fs-book-fade {
	from { opacity: 0; }
	to   { opacity: 1; }
}

@keyframes fs-book-rise {
	from { opacity: 0; transform: translateY(12px) scale(0.98); }
	to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
	.fs-book__backdrop,
	.fs-book__panel {
		animation: none;
	}
}

/* ==========================================================================
   Event-date calendar
   react-day-picker inside a shadcn popover, rebuilt in vanilla JS. Sizes and
   colours come from the source's calendar.tsx class list and the dark tokens
   in globals.css: popover #0C0A09, border/accent #292524, muted #A8A29E,
   primary #FB923C. Cells are h-8 w-8 (32px), head cells 0.8rem, nav 28px.
   ========================================================================== */

.fs-cal {
	position: fixed;                /* placed against the viewport by JS */
	z-index: 100010;                /* above the booking dialog */
	padding: 12px;                  /* p-3 */
	background: #0c0a09;            /* --popover */
	border: 1px solid #292524;      /* --border */
	border-radius: 6px;             /* rounded-md */
	box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -2px rgba(0, 0, 0, 0.5);
}

.fs-cal__caption {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	padding-top: 4px;
	height: 28px;
}

.fs-cal .fs-cal__label {
	font-size: 14px;                /* text-sm */
	line-height: 20px;
	font-weight: 500;
	color: #fafaf9;
	text-transform: capitalize;     /* Intl gives lowercase months in some locales */
}

.fs-cal .fs-cal__nav {
	position: absolute;
	top: 4px;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 28px;                    /* h-7 w-7 */
	height: 28px;
	padding: 0;
	color: #fafaf9;
	background: transparent;
	border: 1px solid #292524;
	border-radius: 6px;
	opacity: 0.5;
	cursor: pointer;
	transition: opacity 0.15s ease;
}

.fs-cal .fs-cal__nav:hover {
	opacity: 1;
}

.fs-cal__nav--prev { left: 4px; }
.fs-cal__nav--next { right: 4px; }

.fs-cal__row {
	display: flex;
	margin-top: 8px;                /* mt-2 */
}

.fs-cal__row--head {
	margin-top: 8px;
}

.fs-cal .fs-cal__head {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 32px;                    /* w-8 */
	font-size: 12.8px;              /* text-[0.8rem] */
	font-weight: 400;
	color: #a8a29e;                 /* --muted-foreground */
}

.fs-cal .fs-cal__day {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 32px;                    /* h-8 w-8 */
	height: 32px;
	padding: 0;
	font-family: inherit;
	font-size: 14px;
	font-weight: 400;
	color: #fafaf9;
	background: transparent;
	border: 0;
	border-radius: 6px;
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease;
}

.fs-cal .fs-cal__day:hover:not(.is-disabled) {
	background: #292524;            /* ghost hover = accent */
}

.fs-cal .fs-cal__day.is-today {
	background: #292524;            /* --accent */
	color: #fafaf9;
}

.fs-cal .fs-cal__day.is-selected,
.fs-cal .fs-cal__day.is-selected:hover {
	background: #fb923c;            /* --primary */
	color: #fafaf9;                 /* --primary-foreground */
}

.fs-cal .fs-cal__day.is-outside {
	color: #a8a29e;
	opacity: 0.5;
}

.fs-cal .fs-cal__day.is-disabled {
	color: #a8a29e;
	opacity: 0.5;
	cursor: default;
}

/* The field is driven by the calendar now, so a text caret would be a lie. */
.fs-ct .fs-ct-date[readonly] {
	cursor: pointer;
}

/* Inside the dialog the popover must escape the scrolling area's clipping. */
.fs-book .fs-ct-datewrap {
	position: relative;
}

/* ==========================================================================
   Legal pages — Privacy Policy, Terms, Cookie Policy
   All three share one shape in the source: `container pt-28`, an h1 in the
   primary colour, then `my-6 space-y-4` holding h4 headings with paragraphs
   and lists. The headings are h2 here rather than h4: an h4 straight after the
   h1 skips two levels, and these are the pages most likely to be read by a
   crawler and least likely to be read by a person.
   ========================================================================== */

.fs-legal {
	background: #0c0a09;
}

.fs-legal__inner {
	max-width: 1000px;              /* .container */
	margin: 0 auto;
	padding: 112px 32px 96px;       /* pt-28; the bottom is ours, see below */
	box-sizing: border-box;
	color: #fafaf9;
	font-size: 16px;
	line-height: 24px;
}

/* The source ends the container flush against the footer. That reads as a
   mistake rather than a decision on a page that is nothing but text, so there
   is 96px here. It is the one divergence on these pages. */

.fs-legal .fs-legal__title {
	margin: 0 0 24px;
	font-size: 48px;                /* sm:text-5xl */
	line-height: 1.1;
	font-weight: 700;
	color: #fb923c;
}

.fs-legal .fs-legal__updated {
	margin: 0 0 8px;                /* pb-2 */
	color: #a8a29e;
}

.fs-legal__inner > p {
	margin: 0 0 16px;
}

.fs-legal__body {
	margin: 24px 0;                 /* my-6 */
}

.fs-legal .fs-legal__h {
	margin: 32px 0 16px;
	font-size: 30px;                /* text-3xl */
	line-height: 36px;
	font-weight: 700;
	color: #fafaf9;
}

.fs-legal__body p {
	margin: 0 0 16px;               /* space-y-4 */
	color: #fafaf9;
}

.fs-legal .fs-legal__list {
	margin: 0 0 16px;
	padding-left: 24px;
	list-style: disc;
}

.fs-legal .fs-legal__list li {
	margin-bottom: 8px;
	color: #fafaf9;
}

.fs-legal a {
	color: #fb923c;
	text-decoration: none;
}

.fs-legal a:hover {
	text-decoration: underline;
}

.fs-legal .fs-legal__thx {
	margin-top: 32px;
}

@media (max-width: 640px) {
	.fs-legal .fs-legal__title {
		font-size: 36px;            /* text-4xl */
	}

	.fs-legal .fs-legal__h {
		font-size: 24px;
		line-height: 30px;
	}
}

/* ==========================================================================
   Hero heading — the tablet band
   The source is `md:text-6xl text-5xl`, so it switches at 768: 60px above,
   48px below. Elementor's own tablet breakpoint is 1024, so its generated CSS
   was holding the heading at 48px all the way from 768 to 1024 — a 250px-wide
   band where live shows 60px and we showed 48px.

   Overriding here rather than moving Elementor's breakpoint: that setting is
   global, and every other widget on the site is already built against it.
   ========================================================================== */

@media (min-width: 768px) and (max-width: 1024px) {
	.fs-js .elementor .fs-hero-title .elementor-heading-title,
	html .elementor .fs-hero-title .elementor-heading-title {
		font-size: 60px;
	}
}

/* ==========================================================================
   Project gallery lightbox

   Live opens a Radix dialog holding one image — no arrows, no counter — so
   reaching the fifth shot means opening and closing five times. FLYSTACK asked
   for a carousel, so this is a navigable viewer over the same images.
   ========================================================================== */

.fs-single .fs-single__cover,
.fs-single .fs-single__shot-btn {
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	background: none;
	cursor: pointer;
	line-height: 0;
}

.fs-single .fs-single__shot-btn img {
	transition: opacity 0.15s ease;
}

/* Gallery thumbnails only.
   The hero carried this too, so moving the mouse anywhere across a
   viewport-wide photograph dimmed the whole thing — a hover hint makes sense on
   a small thumbnail in a grid and reads as a glitch at that size. */
.fs-single .fs-single__shot-btn:hover img {
	opacity: 0.8;               /* live: hover:opacity-80 */
}

.fs-single .fs-single__shot-btn:focus-visible,
.fs-single .fs-single__cover:focus-visible {
	outline: 2px solid #fb923c;
	outline-offset: 3px;
}

/* Article images, wrapped into triggers by lightbox.js at run time. The button
   has to disappear completely — an article image sits in flowing prose, so any
   button chrome or stray inline-element baseline gap reads as a layout bug. */
.fs-bl-content .fs-lb-trigger {
	display: block;
	width: 100%;
	padding: 0;
	border: 0;
	background: none;
	cursor: zoom-in;
	line-height: 0;
}

.fs-bl-content .fs-lb-trigger img {
	transition: opacity 0.15s ease;
}

.fs-bl-content .fs-lb-trigger:hover img {
	opacity: 0.88;
}

.fs-bl-content .fs-lb-trigger:focus-visible {
	outline: 2px solid #fb923c;
	outline-offset: 3px;
}

.fs-lb {
	position: fixed;
	inset: 0;
	z-index: 100020;            /* above the booking dialog */
	display: none;
	align-items: center;
	justify-content: center;
}

.fs-lb.is-open {
	display: flex;
}

.fs-lb__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, 0.9);
}

.fs-lb__stage {
	position: relative;
	margin: 0;
	max-width: 95vw;            /* live: max-w-[95vw] max-h-[95vh] */
	max-height: 95vh;
	display: flex;
	align-items: center;
	justify-content: center;
}

.fs-lb .fs-lb__img {
	display: block;
	max-width: 95vw;
	max-height: 95vh;
	width: auto;
	height: auto;
	object-fit: contain;
	border-radius: 8px;
}

.fs-lb__close,
.fs-lb__nav {
	position: absolute;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;                /* a comfortable touch target */
	height: 44px;
	padding: 0;
	color: #fafaf9;
	background: rgba(12, 10, 9, 0.6);
	border: 1px solid rgba(250, 250, 249, 0.2);
	border-radius: 999px;
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease;
}

.fs-lb__close:hover,
.fs-lb__nav:hover {
	background: #292524;
	color: #fb923c;
}

.fs-lb__close { top: 20px; right: 20px; }
.fs-lb__nav--prev { left: 20px; }
.fs-lb__nav--next { right: 20px; }

.fs-lb__nav {
	top: 50%;
	transform: translateY(-50%);
}

.fs-lb__count {
	position: absolute;
	bottom: 20px;
	left: 50%;
	transform: translateX(-50%);
	margin: 0;
	padding: 6px 14px;
	font-size: 14px;
	line-height: 20px;
	color: rgba(250, 250, 249, 0.8);
	background: rgba(12, 10, 9, 0.6);
	border-radius: 999px;
}

body.fs-lb-open {
	overflow: hidden;
}

@media (max-width: 640px) {
	.fs-lb__close { top: 12px; right: 12px; }
	.fs-lb__nav--prev { left: 8px; }
	.fs-lb__nav--next { right: 8px; }
}

/* ==========================================================================
   PRICING PAGE

   Two bands, from app/[locale]/pricing/page.tsx. Tailwind values quoted beside
   each rule so the next person does not have to re-derive them.
   ========================================================================== */

.fs-pr {
	background: #000;
}

.fs-pr__inner {
	max-width: 1000px;              /* .container */
	margin: 0 auto;
	padding-inline: 32px;
	box-sizing: border-box;
}

/* ---- 1. hero + explorer ---- */

.fs-pr-top {
	position: relative;
	padding-bottom: 80px;           /* pb-20 */
}

/* `hidden md:block absolute w-1/2 h-full -translate-x-1/2`, image at
   `opacity-[0.1] scale-[1.75]`. Half the width, pulled left by half its own
   width, so it sits over the left-hand column. */
.fs-pr-top__lines {
	position: absolute;
	top: 0;
	left: 0;
	width: 50%;
	height: 100%;
	transform: translateX(-50%);
	pointer-events: none;
	overflow: hidden;
}

.fs-pr .fs-pr-top__lines img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	opacity: 0.1;
	transform: scale(1.75);
}

@media (max-width: 767px) {
	.fs-pr-top__lines { display: none; }
}

.fs-pr-top__head {
	position: relative;
	z-index: 30;
	padding-top: 160px;             /* pt-40 */
	display: grid;
	grid-template-columns: 1fr;
}

@media (min-width: 768px) {
	.fs-pr-top__head { grid-template-columns: 1fr 1fr; }   /* md:grid-cols-2 */
}

.fs-pr-top__headcol {
	position: relative;
	z-index: 30;
	text-align: center;
}

@media (min-width: 768px) {
	.fs-pr-top__headcol { text-align: start; }   /* md:text-start */
}

.fs-pr .fs-pr-top__eyebrow {
	margin: 0;
	padding-bottom: 32px;           /* pb-8 */
	font-size: 14px;                /* text-sm */
	font-weight: 300;
	letter-spacing: 12.8px;         /* tracking-[0.8rem] */
	text-transform: uppercase;
	color: #fafaf9;
}

.fs-pr .fs-pr-top__title {
	margin: 0;
	font-size: 48px;                /* sm:text-5xl */
	line-height: 1.1;
	font-weight: 700;
	text-transform: uppercase;
	color: #fb923c;
}

@media (max-width: 639px) {
	.fs-pr .fs-pr-top__title { font-size: 36px; }   /* text-4xl */
}

@media (min-width: 768px) {
	.fs-pr .fs-pr-top__title { padding-bottom: 40px; }   /* md:pb-10 */
}

.fs-pr-top__grid {
	position: relative;
	z-index: 20;
	display: grid;
	grid-template-columns: 1fr;
}

@media (min-width: 768px) {
	.fs-pr-top__grid { grid-template-columns: 1fr 1fr; }
}

/* order-2 below md, order-1 above — the explorer leads on a phone, the copy
   leads on a desktop. */
.fs-pr-top__copy {
	position: relative;
	z-index: 20;
	order: 2;
}

@media (min-width: 768px) {
	.fs-pr-top__copy {
		order: 1;
		padding-inline-end: 40px;   /* pe-10 */
	}
}

.fs-pr .fs-pr-top__lead {
	margin: 0;
	font-size: 24px;                /* text-2xl */
	line-height: 1.35;
	font-weight: 500;
	text-transform: none;
	color: #fafaf9;
}

.fs-pr-top__list {
	margin: 32px 0 0;               /* mt-8 */
	padding: 0;
	list-style: none;
	display: flex;
	flex-direction: column;
	gap: 32px;                      /* space-y-8 */
}

.fs-pr .fs-pr-top__item p {
	margin: 0;
	font-size: 16px;
	line-height: 1.5;
}

.fs-pr .fs-pr-top__name {
	font-weight: 700;
	color: #fb923c;
}

.fs-pr .fs-pr-top__text {
	font-weight: 400;
	color: #a8a29e;                 /* text-muted-foreground */
}

/* ---- the drone-count explorer ---- */

.fs-pr-explorer {
	order: 1;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	width: 100%;
	overflow: hidden;
}

@media (min-width: 768px) {
	.fs-pr-explorer {
		order: 2;
		position: sticky;
		top: 0;
		z-index: 0;
		/* Live pulls this up by 240px (`md:-mt-60`), which tucks the swarm in
		   under the title. Eased to 140 at FLYSTACK's request — the video and
		   its stepper sit a little lower, clear of the heading. */
		margin-top: -140px;
		padding-bottom: 240px;      /* md:pb-60 */
	}
}

.fs-pr-explorer__stage {
	position: relative;
	width: 100%;
	max-width: 400px;
	margin-inline: auto;
	aspect-ratio: 1 / 1;
	padding-top: 80px;              /* pt-20 */
	box-sizing: border-box;
}

@media (min-width: 1024px) {
	.fs-pr-explorer__stage { max-width: none; }   /* lg:max-w-none */
}

.fs-pr-explorer__scale {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	/* The swarm grows by count, not by zoom — see flystack_pr_counts(). */
	transition: transform 0.6s cubic-bezier(0.22, 1, 0.36, 1);
	transform-origin: center;
}

.fs-pr .fs-pr-explorer__video {
	display: block;
	width: 100%;
	height: auto;
}

.fs-pr-explorer__controls {
	display: flex;
	align-items: flex-start;
	justify-content: center;
	gap: 4px;                       /* gap-1 */
	width: 100%;
	margin-top: 24px;               /* mt-6 */
	margin-bottom: 40px;            /* mb-10 */
	transform: translateX(-64px);   /* -translate-x-16 */
}

@media (min-width: 768px) {
	.fs-pr-explorer__controls {
		transform: none;            /* md:translate-x-0 */
	}
}

@media (min-width: 1024px) {
	.fs-pr-explorer__controls { margin-bottom: 0; }   /* lg:mb-0 */
}

.fs-pr-explorer__stepper {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0;
	margin-top: 10px;               /* mt-2.5 */
	padding: 4px 8px;               /* p-1 px-2 */
	font-size: 24px;                /* text-2xl */
	color: #fb923c;
	z-index: 10;
}

.fs-pr .fs-pr-explorer__step {
	display: flex;
	padding: 0;
	border: 0;
	background: none;
	color: #fb923c;
	cursor: pointer;
	transition: color 0.15s ease;
}

.fs-pr .fs-pr-explorer__step[disabled] {
	color: #a8a29e;                 /* aria-disabled:text-muted-foreground */
	cursor: default;
}

.fs-pr .fs-pr-explorer__count {
	font-size: 24px;
	line-height: 1.1;
	color: #fb923c;
}

.fs-pr .fs-pr-explorer__labels {
	position: relative;
	margin: 0;
	padding: 40px 0;                /* pt-10 pb-10 */
}

.fs-pr .fs-pr-explorer__unit {
	font-size: 20px;                /* text-xl */
	color: #fff;
}

/* Absolutely placed 66px below the top of its paragraph, exactly as live does
   with `absolute min-w-max top-0 left-0 mt-[66px]`. */
.fs-pr .fs-pr-explorer__note {
	position: absolute;
	top: 0;
	left: 0;
	margin-top: 66px;
	min-width: max-content;
	font-size: 12px;                /* text-xs */
	line-height: 1.4;
	color: #a8a29e;
}

/* ---- 2. safety ---- */

.fs-pr-safety {
	position: relative;
	z-index: 30;
	padding: 80px 0;                /* pt-20 pb-20 */
	background: #020204;
	border-bottom: 1px solid rgba(255, 255, 255, 0.25);
}

.fs-pr-safety__head {
	display: grid;
	grid-template-columns: 1fr;
	gap: 32px;                      /* gap-8 below sm */
}

@media (min-width: 640px) {
	.fs-pr-safety__head {
		grid-template-columns: 1fr 1fr;   /* sm:grid-cols-2 */
		gap: 0;                            /* sm:gap-0 */
	}
}

.fs-pr .fs-pr-safety__figure img {
	display: block;
	width: 100%;
	height: auto;
}

.fs-pr-safety__copy {
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	align-items: flex-end;
	height: 100%;
	padding-bottom: 64px;           /* pb-16 */
	text-align: end;
}

.fs-pr .fs-pr-safety__eyebrow {
	margin: 0;
	padding-bottom: 24px;           /* pb-6 */
	font-weight: 300;
	text-transform: uppercase;
	color: #fb923c;
}

.fs-pr .fs-pr-safety__title {
	margin: 0;
	font-size: 30px;                /* text-3xl */
	line-height: 1.2;
	font-weight: 500;
	text-transform: uppercase;
	color: #fff;
}

.fs-pr-safety__cards {
	display: grid;
	grid-template-columns: 1fr;
	gap: 24px;                      /* gap-6 */
	margin: 80px 0;                 /* sm:my-20 */
}

@media (max-width: 639px) {
	.fs-pr-safety__cards { margin: 40px 0; }   /* my-10 */
}

@media (min-width: 768px) {
	.fs-pr-safety__cards { grid-template-columns: repeat(3, 1fr); }
}

.fs-pr-safety__card {
	display: flex;
	flex-direction: column;
	gap: 12px;                      /* gap-3 */
	padding: 20px;                  /* p-5 */
	border-radius: 24px;            /* rounded-3xl */
	background: #292524;            /* bg-secondary */
}

.fs-pr .fs-pr-safety__card p {
	margin: 0;
	font-size: 16px;
	line-height: 1.5;
	color: #fafaf9;
}

.fs-pr .fs-pr-safety__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 32px;                    /* w-8 */
	height: 32px;                   /* aspect-square */
	padding: 8px;                   /* p-2 */
	border-radius: 999px;
	background: rgba(251, 146, 60, 0.8);   /* bg-primary/80 */
	color: #fff;
	box-sizing: border-box;
	flex: 0 0 auto;
}

/* ==========================================================================
   REAL-TIME PAGE
   From app/[locale]/real-time/*. Tailwind values quoted beside each rule.
   ========================================================================== */

.fs-rt { background: #0c0a09; }

.fs-rt__inner {
	max-width: 1000px;
	margin: 0 auto;
	padding-inline: 32px;
	box-sizing: border-box;
}

.fs-rt .fs-rt__accent { color: #fb923c; }

/* ---- 1. hero ---- */

.fs-rt-hero {
	position: relative;
	min-height: 100vh;
	display: flex;
	align-items: center;
}

/* `absolute w-full h-screen -z-10 opacity-30` */
.fs-rt-hero__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	opacity: 0.3;
	pointer-events: none;
}

.fs-rt .fs-rt-hero__bg img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.fs-rt-hero__inner {
	position: relative;
	z-index: 1;
	width: 100%;
	padding-block: 144px;           /* py-36 */
}

.fs-rt .fs-rt-hero__title {
	margin: 0;
	padding-block: 16px;            /* py-4 */
	font-size: 48px;                /* md:text-5xl */
	line-height: 1.15;
	font-weight: 700;
	text-transform: uppercase;
	text-align: center;
	color: #fafaf9;
}

@media (max-width: 767px) { .fs-rt .fs-rt-hero__title { font-size: 36px; } }
@media (max-width: 639px) { .fs-rt .fs-rt-hero__title { font-size: 30px; } }

.fs-rt .fs-rt-hero__mark { color: #fb923c; }

.fs-rt-hero__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 40px;                      /* gap-10 */
	margin-top: 64px;               /* mt-16 */
}

@media (min-width: 1024px) {
	.fs-rt-hero__grid { grid-template-columns: 1fr 1fr; }   /* lg:grid-cols-2 */
}

/* order-2 below lg so the matrix leads on a phone — it is the thing worth
   showing first — and the copy leads on a desktop. */
.fs-rt-hero__copy {
	order: 2;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 16px;                      /* gap-4 */
	max-width: 576px;               /* max-w-xl */
	text-align: center;
}

@media (min-width: 1024px) {
	.fs-rt-hero__copy { order: 1; text-align: start; }
}

.fs-rt .fs-rt-hero__sub {
	margin: 0;
	font-size: 24px;                /* text-2xl */
	line-height: 1.3;
	font-weight: 700;
	text-transform: none;
	color: #fafaf9;
}

.fs-rt .fs-rt-hero__euro { color: #fb923c; }

.fs-rt .fs-rt-hero__desc {
	margin: 0;
	font-size: 18px;                /* text-lg */
	line-height: 1.6;
	font-weight: 400;
	color: #fafaf9;
}

/* ---- the letter matrix ---- */

.fs-rt-matrix {
	order: 1;
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 40px;                      /* gap-10 */
	width: 100%;
	max-width: 448px;               /* max-w-md */
	margin-inline: auto;
	border-inline-start: 1px solid #e5e7eb;   /* border-s border-gray-200 */
	background: rgba(255, 255, 255, 0.1);     /* bg-white/10 */
	box-sizing: border-box;
}

@media (min-width: 1024px) { .fs-rt-matrix { order: 2; } }

.fs-rt-matrix.is-failed .fs-rt-matrix__input { display: none; }

.fs-rt-matrix__input {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.fs-rt .fs-rt-matrix__label {
	padding-bottom: 16px;           /* pb-4 */
	font-size: 18px;                /* text-lg */
	text-align: center;
	color: #fafaf9;
}

.fs-rt .fs-rt-matrix__field {
	width: 128px;                   /* w-32 */
	padding: 0;
	font-family: inherit;
	font-size: 96px;                /* sm:text-8xl */
	line-height: 1;
	font-weight: 700;
	text-align: center;
	color: #fafaf9;
	background: transparent;
	border: 0;
	outline: none;
	text-transform: uppercase;
}

@media (max-width: 639px) {
	.fs-rt .fs-rt-matrix__field { font-size: 72px; }   /* text-7xl */
}

/* The square that owns the column's height: w-full max-w-sm aspect-square
   mx-auto flex items-center justify-center. */
.fs-rt-matrix__box {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	max-width: 384px;               /* max-w-sm */
	margin-inline: auto;
	aspect-ratio: 1 / 1;
}

/* The swarm itself is content-sized, not stretched: `auto` columns rather than
   1fr, so the 4px gap stays 4px and the block is 8 dots wide however wide the
   column happens to be. */
/*
 * Fixed tracks the width of a LIT dot, not `auto`.
 *
 * The source writes `grid-cols-8`, which is `repeat(8, minmax(0, 1fr))`. In a
 * shrink-to-fit box every fr resolves to the same max-content width — the lit
 * dot — so the swarm is always 8 x 20 + 7 x 4 = 188px wide whatever letter is
 * showing. With `auto` tracks each column sizes itself independently, so a
 * column holding only unlit 4px dots collapses and the whole grid shifts
 * sideways every time the letter changes. Same numbers, no jitter.
 */
.fs-rt-matrix__grid {
	display: grid;
	grid-template-columns: repeat(8, 20px);   /* sm:w-5 */
	grid-template-rows: repeat(8, 20px);
	gap: 4px;                       /* gap-1 */
	place-items: center;
}

@media (max-width: 639px) {
	.fs-rt-matrix__grid {
		grid-template-columns: repeat(8, 12px);   /* w-3 */
		grid-template-rows: repeat(8, 12px);
	}
}

/* Off: a small pale dot. On: a larger orange one. Only width changes, so the
   dot appears to fly forward rather than fade in. */
.fs-rt-dot {
	display: block;
	width: 4px;
	aspect-ratio: 1 / 1;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.6);
	transition: width 0.3s cubic-bezier(0.22, 1, 0.36, 1),
	            background-color 0.3s ease;
}

.fs-rt-dot.is-on {
	width: 20px;                    /* sm:w-5 */
	background: #fb923c;
}

@media (max-width: 639px) {
	.fs-rt-dot.is-on { width: 12px; }   /* w-3 */
}

/* ---- 2. unique ---- */

.fs-rt-unique { padding-block: 64px; }   /* mt-16 on live's inner grid */

.fs-rt-unique__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 40px;
	max-width: 576px;
	margin-inline: auto;
}

@media (min-width: 1024px) {
	.fs-rt-unique__grid {
		grid-template-columns: 1fr 1fr;
		max-width: none;            /* lg:max-w-none */
	}
}

.fs-rt-unique__copy {
	display: flex;
	flex-direction: column;
	justify-content: center;
	text-align: center;
}

@media (min-width: 1024px) { .fs-rt-unique__copy { text-align: start; } }

.fs-rt .fs-rt-unique__title {
	margin: 0;
	font-size: 30px;                /* text-3xl */
	line-height: 1.25;
	font-weight: 700;
	text-transform: none;
	color: #fafaf9;
}

.fs-rt .fs-rt-unique__desc {
	margin: 0;
	padding-top: 24px;              /* pt-6 */
	font-size: 18px;
	line-height: 1.6;
	color: #fafaf9;
}

.fs-rt .fs-rt-unique__figure img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: 16px;            /* rounded-2xl */
	box-shadow: 0 0 16px 6px rgba(255, 255, 255, 0.05);
}

/* ---- 3. tilt ---- */

.fs-rt-tilt {
	padding-block: 80px;            /* my-20 */
	perspective: 1000px;
}

.fs-rt-tilt__frame {
	position: relative;
	width: 100%;
	max-width: 512px;               /* max-w-lg */
	margin-inline: auto;
	aspect-ratio: 1 / 1;
}

.fs-rt-tilt__plane {
	position: relative;
	width: 100%;
	height: 100%;
	border-radius: 12px;
	transform-style: preserve-3d;
	will-change: transform;
}

/* inset-4 and pushed 75px toward the viewer, which is what gives the parallax
   between the picture and the words sitting flat on top of it. */
.fs-rt-tilt__face {
	position: absolute;
	inset: 16px;
	border-radius: 12px;
	background-image: url('../img/rt-tilt-1024.webp');
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
	box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.4);
	transform: translateZ(75px);
	transform-style: preserve-3d;
}

.fs-rt-tilt__copy {
	position: absolute;
	inset: 0;
	z-index: 2;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: 40px;                  /* p-10 */
	text-align: center;
	pointer-events: none;
}

.fs-rt .fs-rt-tilt__title {
	margin: 0;
	font-size: 36px;                /* sm:text-4xl */
	line-height: 1.2;
	font-weight: 700;
	text-transform: none;
	color: #fafaf9;
	text-shadow: 0 2px 18px rgba(0, 0, 0, 0.7);
}

@media (max-width: 639px) { .fs-rt .fs-rt-tilt__title { font-size: 24px; } }

.fs-rt .fs-rt-tilt__desc {
	margin: 24px 0 0;               /* mt-6 */
	font-size: 18px;
	line-height: 1.5;
	color: #fafaf9;
	text-shadow: 0 2px 18px rgba(0, 0, 0, 0.7);
}

@media (max-width: 639px) { .fs-rt .fs-rt-tilt__desc { font-size: 14px; } }

/* ---- 4. options ---- */

.fs-rt-opts {
	position: relative;
	padding-bottom: 80px;           /* pb-20 */
}

.fs-rt-opts__lines {
	position: absolute;
	inset: 0;
	z-index: 0;
	opacity: 0.1;
	pointer-events: none;
	overflow: hidden;
}

.fs-rt .fs-rt-opts__lines img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 0;
}

.fs-rt-opts > .fs-rt__inner { position: relative; z-index: 1; }

.fs-rt .fs-rt-opts__title {
	margin: 0;
	padding-bottom: 64px;           /* pb-16 */
	font-size: 48px;                /* sm:text-5xl */
	line-height: 1.15;
	font-weight: 700;
	text-align: center;
	text-transform: none;
	color: #fafaf9;
}

@media (max-width: 639px) { .fs-rt .fs-rt-opts__title { font-size: 24px; } }

.fs-rt-opts__list {
	display: flex;
	flex-direction: column;
	gap: 80px;                      /* space-y-20 below md */
}

@media (min-width: 768px) {
	.fs-rt-opts__list { gap: 40px; }   /* md:space-y-10 */
}

.fs-rt-opt {
	display: grid;
	grid-template-columns: 1fr;
	gap: 64px;                      /* gap-16 */
	align-items: center;
}

@media (min-width: 768px) {
	.fs-rt-opt { grid-template-columns: 1fr 1fr; }
	.fs-rt-opt.is-flipped .fs-rt-opt__copy { order: 2; }
	.fs-rt-opt.is-flipped .fs-rt-opt__media { order: 1; }
}

.fs-rt .fs-rt-opt__name {
	margin: 0;
	padding-bottom: 24px;           /* pb-6 */
	font-size: 30px;                /* text-3xl */
	line-height: 1.2;
	font-weight: 700;
	text-transform: none;
	color: #fb923c;
}

.fs-rt .fs-rt-opt__desc {
	margin: 0;
	font-size: 20px;                /* text-xl */
	line-height: 1.5;
	color: #fafaf9;
}

.fs-rt-opt__media {
	position: relative;
	width: 100%;
	max-width: 384px;               /* max-w-sm below md */
	margin-inline: auto;
	aspect-ratio: 1 / 1;
}

@media (min-width: 768px) {
	.fs-rt-opt__media { max-width: none; }
}

.fs-rt .fs-rt-opt__img {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	object-position: center;
	border-radius: 12px;            /* rounded-xl */
	box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5);
}

/* Two shots overlap: the first at two thirds, the second offset to the bottom
   right. */
.fs-rt-opt__media.is-pair .fs-rt-opt__img { width: 66.6667%; }

.fs-rt .fs-rt-opt__img--second {
	top: auto;
	left: auto;
	right: 0;
	bottom: 0;
	width: 66.6667%;
}

/* ==========================================================================
   Zenith Lab
   Values mapped from app/[locale]/zenith-lab/*.tsx and the shadcn primitives
   those files use. Every number below is the Tailwind class it came from, so
   nobody has to re-measure to know what is deliberate.

   Two deliberate departures, both flagged where they appear:
     1. The programme cards animate `translate` rather than `transform`, so the
        hover scale still works. Live's card animates `transform` with
        fill-mode `both`, which permanently pins the property and silently
        kills its own `hover:scale-[1.02]`.
     2. The three upload wells are real <label for> elements over real file
        inputs. Live keeps the file in React state behind a hidden input, so
        the control is unreachable by keyboard.
   ========================================================================== */

.fs-zn {
	background: #0c0a09;                    /* bg-background */
	border-bottom: 1px solid #fff;          /* border-b border-white */
	overflow: hidden;
	color: #fafaf9;
	/* Pinned for the same reason the Contact page is: Elementor's global
	   typography here is 15.12/25.704 and live's body is 16/24, and the
	   difference only surfaces through inherited line boxes. */
	font-size: 16px;
	line-height: 24px;
}

.fs-zn__accent { color: #fb923c; }

/* Tailwind's container: full width with a 2rem gutter, capped at 1000px. */
.fs-zn__inner {
	width: 100%;
	margin-inline: auto;
	padding-inline: 32px;
	box-sizing: border-box;
}

@media (min-width: 1000px) {
	.fs-zn__inner { max-width: 1000px; }
}

.fs-zn__inner--pt { padding-top: 128px; }   /* pt-32 */
.fs-zn__inner--pb { padding-bottom: 128px; }/* pb-32 */

/* `hr` inherits Tailwind's `* { border-color: var(--border) }`. */
.fs-zn .fs-zn-rule {
	height: 0;
	margin: 64px 0 0;                       /* mt-16 */
	border: 0;
	border-top: 1px solid #292524;
}

.fs-zn .fs-zn-rule--wide { margin-top: 80px; }   /* mt-20 */

/* ---- 1. hero ---- */

.fs-zn-hero {
	position: relative;
	width: 100%;
	overflow: hidden;
}

.fs-zn-hero__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
}

.fs-zn .fs-zn-hero__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: bottom;                /* object-bottom */
}

.fs-zn-hero__veil {
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, 0.6);         /* bg-black/60 */
}

.fs-zn-hero__inner {
	position: relative;
	z-index: 10;
	padding-block: 160px;                   /* py-40 */
}

.fs-zn .fs-zn-hero__title {
	margin: 0;
	padding-bottom: 16px;                   /* pb-4 */
	font-size: 48px;                        /* text-5xl */
	line-height: 1;
	font-weight: 700;
	text-transform: uppercase;
	text-align: start;
	color: #fafaf9;
}

@media (min-width: 640px) {
	.fs-zn .fs-zn-hero__title { font-size: 66px; }   /* sm:text-[66px] */
}

.fs-zn .fs-zn-hero__strap {
	margin: 0;
	padding-bottom: 32px;                   /* pb-8 */
	max-width: 512px;                       /* max-w-lg */
	font-size: 14px;                        /* text-sm */
	line-height: 20px;
	font-weight: 300;                       /* font-light */
	text-transform: uppercase;
	letter-spacing: 0.1em;                  /* tracking-widest */
	color: #fafaf9;
}

.fs-zn .fs-zn-hero__lead {
	margin: 0;
	max-width: 672px;                       /* max-w-2xl */
	padding-inline-end: 40px;               /* pe-10 */
}

@media (min-width: 768px) {
	.fs-zn .fs-zn-hero__lead { width: 50%; }  /* md:w-1/2 */
}

/* ---- the two photo panels (2. difs, 11. closing) ---- */

.fs-zn-difs { padding-block: 80px; }        /* py-20 */

.fs-zn-panel {
	position: relative;
	width: 100%;
	padding: 40px;                          /* p-10 */
	border-radius: 12px;                    /* rounded-xl */
	overflow: hidden;
}

.fs-zn-panel__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
}

.fs-zn .fs-zn-panel__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
	border-radius: 12px;
}

.fs-zn .fs-zn-fin__img { object-position: 50% 35%; }   /* object-[50%_35%] */

.fs-zn-panel__veil {
	position: absolute;
	inset: 0;
	background: rgba(0, 0, 0, 0.7);         /* bg-black/70 */
}

.fs-zn-panel__body {
	position: relative;
	z-index: 10;
}

.fs-zn .fs-zn-difs__title {
	margin: 0 0 16px;                       /* mb-4 */
	font-size: 24px;                        /* text-2xl */
	line-height: 32px;
	font-weight: 700;
	text-transform: uppercase;
	color: #fb923c;
}

/* Tailwind's preflight strips heading sizes, so live's <h3> is body copy. */
.fs-zn .fs-zn-difs__desc {
	margin: 0;
	font-size: 16px;
	line-height: 24px;
	font-weight: 400;
	color: #fff;
}

/* ---- 3. vision & objectives ---- */

.fs-zn-viz {
	display: grid;
	grid-template-columns: 1fr;
	gap: 40px;                              /* gap-10 */
	margin-bottom: 128px;                   /* mb-32 */
}

@media (min-width: 768px) {
	.fs-zn-viz { grid-template-columns: 1fr 1fr; }
}

.fs-zn .fs-zn-viz__title {
	margin: 0 0 16px;
	font-size: 30px;                        /* text-3xl */
	line-height: 36px;
	font-weight: 600;
	color: #fb923c;
}

.fs-zn .fs-zn-viz__desc { margin: 0 0 16px; }

.fs-zn-viz__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.fs-zn-viz__list > li + li { margin-top: 12px; }   /* space-y-3 */

.fs-zn-viz__list li {
	display: flex;
	gap: 12px;                              /* gap-3 */
}

.fs-zn-viz__mark {
	min-width: 12px;
	font-weight: 300;
	color: #9ca3af;                         /* text-gray-400 */
}

/* ---- 4. programme structure ---- */

.fs-zn-struct { margin-bottom: 80px; }      /* mb-20 */

.fs-zn .fs-zn-struct__title {
	margin: 0 0 40px;
	font-size: 36px;                        /* text-4xl */
	line-height: 40px;
	font-weight: 700;
	text-align: center;
}

.fs-zn-struct__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 24px;                              /* gap-6 */
}

@media (min-width: 768px) {
	.fs-zn-struct__grid { grid-template-columns: 1fr 1fr; }
}

/*
 * `translate`, not `transform`. Live writes this entrance as
 * `animation: fadeInUp .6s ease-out <delay> both`, which animates `transform`
 * and — because fill-mode `both` keeps the animated value applied forever —
 * permanently outranks its own `hover:scale-[1.02]`. Same motion, on a
 * property the hover is not competing for.
 */
.fs-zn-card {
	position: relative;
	padding: 24px;                          /* p-6 */
	border: 1px solid #262626;              /* border-neutral-800 */
	border-radius: 16px;                    /* rounded-2xl */
	background: rgba(0, 0, 0, 0.3);         /* bg-black/30 */
	-webkit-backdrop-filter: blur(4px);
	backdrop-filter: blur(4px);
	overflow: hidden;
	transition: border-color 0.5s, transform 0.5s, box-shadow 0.5s;
}

/*
 * Gated on `.fs-js`, like the rest of this theme's reveals. Live hides these
 * cards with `opacity-0` and relies on a CSS animation to bring them back — so
 * anything that stops the animation running leaves six empty boxes and no
 * programme structure on the page. Here the hidden state only exists once
 * JavaScript has confirmed it is there to undo it.
 */
.fs-js .fs-zn-card {
	opacity: 0;
	animation: fs-zn-up 0.6s ease-out both;
}

@keyframes fs-zn-up {
	from { opacity: 0; translate: 0 30px; }
	to   { opacity: 1; translate: 0 0; }
}

.fs-zn-card:hover {
	border-color: rgba(251, 146, 60, 0.4);
	transform: scale(1.02);
	box-shadow: 0 25px 50px -12px rgba(251, 146, 60, 0.2);
}

.fs-zn-card__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 24px;                    /* mb-6 */
	padding-bottom: 16px;                   /* pb-4 */
	border-bottom: 1px solid #262626;
	transition: border-color 0.3s;
}

.fs-zn-card:hover .fs-zn-card__head { border-bottom-color: rgba(251, 146, 60, 0.3); }

.fs-zn .fs-zn-card__name {
	margin: 0 40px 0 0;                     /* mr-10 */
	width: 100%;
	font-size: 18px;                        /* text-lg */
	line-height: 28px;
	font-weight: 600;
	color: #fff;
	transition: transform 0.3s;
}

.fs-zn-card:hover .fs-zn-card__name { transform: translateX(4px); }

.fs-zn-card__num {
	display: inline-block;
	flex: 0 0 auto;
	font-size: 48px;                        /* text-5xl */
	line-height: 1;
	font-weight: 300;
	color: rgba(251, 146, 60, 0.5);
	transition: color 0.3s, transform 0.3s;
}

.fs-zn-card:hover .fs-zn-card__num {
	color: #fb923c;
	transform: scale(1.1);
}

.fs-zn-card__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

.fs-zn-card__list > li + li { margin-top: 10px; }   /* space-y-2.5 */

.fs-zn-card__list li {
	display: flex;
	gap: 12px;
	font-size: 14px;
	line-height: 20px;
	color: #9ca3af;
	transition: transform 0.3s;
}

.fs-js .fs-zn-card__list li {
	opacity: 0;
	animation: fs-zn-in 0.4s ease-out both;
}

.fs-zn-card:hover .fs-zn-card__list li { transform: translateX(8px); }

@keyframes fs-zn-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}

.fs-zn-card__bullet {
	margin-top: 2px;                        /* mt-0.5 */
	color: #fb923c;
}

.fs-zn-card__accent {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 4px;                            /* h-1 */
	background: linear-gradient(to right,
		rgba(251, 146, 60, 0), rgba(251, 146, 60, 0.6), rgba(251, 146, 60, 0));
	opacity: 0;
	transition: opacity 0.5s;
}

.fs-zn-card:hover .fs-zn-card__accent { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
	.fs-js .fs-zn-card,
	.fs-js .fs-zn-card__list li { animation: none; opacity: 1; translate: none; }
}

/* ---- 5. methodology ---- */

.fs-zn-meth {
	width: 100%;
	background: #000;
	padding-block: 128px;                   /* py-32 */
}

.fs-zn .fs-zn-meth__brand {
	margin: 0;
	padding-bottom: 64px;                   /* pb-16 */
	text-align: center;
	color: #fff;
	font-size: 48px;                        /* text-5xl */
	line-height: 1;
	font-weight: 300;
}

.fs-zn-meth__brand span { font-weight: 500; }

.fs-zn-meth__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 24px;
}

@media (min-width: 768px) {
	.fs-zn-meth__grid { grid-template-columns: 1fr 1fr; }
}

.fs-zn-meth__copy { padding: 40px; }        /* p-10 */

.fs-zn .fs-zn-meth__title {
	margin: 0 0 32px;                       /* mb-8 */
	font-size: 30px;
	line-height: 36px;
	font-weight: 600;
	color: #fb923c;
}

.fs-zn-meth__list {
	margin: 0;
	padding: 0;
	list-style: decimal;
	list-style-position: inside;
	font-size: 18px;                        /* text-lg */
	line-height: 28px;
}

.fs-zn-meth__list > li + li { margin-top: 8px; }   /* space-y-2 */

.fs-zn-meth__media { position: relative; }

.fs-zn .fs-zn-meth__img {
	display: block;
	width: 100%;
	height: 100%;
	border-radius: 12px;
}

@media (min-width: 768px) {
	.fs-zn .fs-zn-meth__img {
		position: absolute;
		inset: 0;
		object-fit: cover;
	}
}

/* order-4 stacks the second photograph below its list on one column and
   restores source order the moment there are two. */
.fs-zn-meth__media--last { order: 4; }

@media (min-width: 768px) {
	.fs-zn-meth__media--last { order: 0; }
}

/* ---- 6. strategic positioning ---- */

.fs-zn .fs-zn-pos__title {
	margin: 0;
	font-size: 48px;
	line-height: 1;
	font-weight: 600;
	text-align: center;
	color: #fb923c;
}

.fs-zn .fs-zn-pos__lead {
	margin: 0 auto;
	max-width: 672px;                       /* max-w-2xl */
	padding: 24px 0 64px;                   /* py-6 pb-16 */
	text-align: center;
	opacity: 0.7;
	font-size: 18px;
	line-height: 28px;
}

.fs-zn-pos__rows {
	position: relative;
	font-size: 18px;
	line-height: 28px;
}

/* Sized and moved by zenith.js from the hovered row's own box. */
.fs-zn-pos__marker {
	position: absolute;
	top: 0;
	left: 0;
	z-index: 0;
	width: 100%;
	padding: 24px;                          /* p-6 */
	box-sizing: border-box;
	background: rgba(0, 0, 0, 0.8);         /* bg-black/80 */
	border-left: 4px solid #fb923c;         /* border-l-4 border-primary */
	transition: height 0.5s, transform 0.5s;
}

.fs-zn .fs-zn-pos__row {
	position: relative;
	z-index: 10;
	margin: 0;
	padding: 24px 40px;                     /* px-10 py-6 */
	transition: color 0.3s;
}

.fs-zn .fs-zn-pos__row:hover { color: #fff; }

.fs-zn-pos__key {
	font-weight: 700;
	color: #fb923c;
}

/* ---- 7. registration ---- */

.fs-zn-signup {
	width: 100%;
	padding-top: 80px;                      /* pt-20 */
	padding-bottom: 40px;                   /* pb-10 */
}

.fs-zn-signup__card {
	width: 100%;
	padding: 32px 24px;                     /* py-8 px-6 */
	border: 1px solid #fb923c;
	border-radius: 64px;                    /* rounded-[64px] */
	background: #000;
	transition: all 0.5s;
	box-sizing: border-box;
}

@media (min-width: 640px) { .fs-zn-signup__card { padding: 32px; } }   /* sm:p-8 */
@media (min-width: 768px) { .fs-zn-signup__card { padding: 64px; } }   /* md:p-16 */

.fs-zn-signup__head {
	position: relative;
	z-index: 30;
	margin-inline: auto;
	padding-bottom: 48px;                   /* pb-12 */
	text-align: center;
}

@media (min-width: 640px) {
	.fs-zn-signup__head { padding-inline: 24px; }   /* sm:px-6 */
}

.fs-zn .fs-zn-signup__eyebrow {
	margin: 0;
	padding-bottom: 40px;                   /* pb-10 */
	font-size: 15px;                        /* text-[15px] — no paired leading */
	font-weight: 300;
	text-transform: uppercase;
	letter-spacing: 0.3rem;
	opacity: 0.8;
}

/* `text-bold` in the source is not a Tailwind class and never resolved, so
   this heading is deliberately at normal weight. The glow is real. */
.fs-zn .fs-zn-signup__title {
	margin: 0;
	padding-bottom: 24px;                   /* pb-6 */
	font-size: 24px;                        /* text-2xl */
	line-height: 32px;
	font-weight: 400;
	text-shadow: #ffffff 0 0 10px;
}

@media (min-width: 640px) {
	.fs-zn .fs-zn-signup__title { font-size: 36px; line-height: 40px; }   /* sm:text-4xl */
}

.fs-zn .fs-zn-signup__lead {
	margin: 0;
	padding-top: 24px;                      /* pt-6 */
}

.fs-zn-signup__body {
	position: relative;
	height: 100%;
}

.fs-zn .fs-zn-signup__steps {
	margin: 0;
	padding-bottom: 40px;
	font-size: 20px;                        /* text-xl */
	line-height: 28px;
	font-weight: 700;
	color: #fb923c;
}

/* Step 1 is `md:px-2 pr-6 py-2` and steps 2-3 are `px-2 pr-6 py-2`: the first
   pill has no left padding below 768. Reproduced rather than tidied. */
.fs-zn-step {
	display: flex;
	align-items: center;
	gap: 24px;                              /* gap-6 */
	padding: 8px 24px 8px 0;
	border-radius: 9999px;
	background: rgba(0, 0, 0, 0.5);
	-webkit-backdrop-filter: blur(4px);
	backdrop-filter: blur(4px);
}

@media (min-width: 768px) {
	.fs-zn-step { padding-left: 8px; padding-right: 8px; }
}

.fs-zn-step__wrap {
	margin-top: 64px;                       /* mt-16 */
	margin-bottom: 32px;                    /* mb-8 */
}

.fs-zn-step__wrap .fs-zn-step {
	padding-left: 8px;
	padding-right: 24px;
}

.fs-zn-step__num {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 48px;
	height: 48px;
	border-radius: 9999px;
	background: #000;
	border: 1px solid #fb923c;
	color: #fff;
	font-size: 20px;
	line-height: 28px;
	font-weight: 700;
}

.fs-zn-step__title {
	font-size: 24px;                        /* text-2xl */
	line-height: 32px;
	font-weight: 700;
}

.fs-zn-boxes {
	display: grid;
	grid-template-columns: 1fr;
	gap: 16px;
	margin-top: 24px;
}

@media (min-width: 640px) {
	.fs-zn-boxes { grid-template-columns: 1fr 1fr; }
}

.fs-zn-box {
	display: flex;
	gap: 16px;
	padding: 24px;
	border: 1px solid rgba(255, 255, 255, 0.1);
	border-radius: 16px;
	background: rgba(255, 255, 255, 0.05);
	-webkit-backdrop-filter: blur(4px);
	backdrop-filter: blur(4px);
	transition: border-color 0.3s, background-color 0.3s;
}

.fs-zn-box:hover {
	border-color: rgba(251, 146, 60, 0.6);
	background: rgba(255, 255, 255, 0.1);
}

.fs-zn-box__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 40px;
	height: 40px;
	border-radius: 12px;
	background: rgba(251, 146, 60, 0.1);
	border: 1px solid rgba(251, 146, 60, 0.3);
	color: #fb923c;
	transition: background-color 0.3s;
}

.fs-zn-box:hover .fs-zn-box__icon { background: rgba(251, 146, 60, 0.2); }

.fs-zn-box__icon svg { width: 20px; height: 20px; }

.fs-zn .fs-zn-box__title {
	margin: 0 0 4px;                        /* mb-1 */
	font-size: 14px;
	line-height: 20px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;                  /* tracking-widest */
	color: #fff;
}

.fs-zn .fs-zn-box__desc {
	margin: 0;
	font-size: 14px;
	line-height: 1.625;                     /* leading-relaxed */
	color: rgba(255, 255, 255, 0.5);
}

/* ---- the application form ---- */

.fs-zn-form {
	max-width: 768px;                       /* max-w-3xl */
	margin-inline: auto;
	padding: 32px 0;                        /* p-8 px-0 */
	border-radius: 32px;                    /* rounded-[32px] */
	background: rgba(0, 0, 0, 0.4);
	box-sizing: border-box;
}

@media (min-width: 768px) {
	.fs-zn-form { padding-inline: 32px; }   /* md:px-8 */
}

.fs-zn .fs-zn-form__title {
	margin: 0;
	padding-bottom: 16px;
	font-size: 30px;                        /* text-3xl */
	line-height: 36px;
	font-weight: 700;
}

.fs-zn .fs-zn-form__intro { margin: 0; }
.fs-zn-form__strong { font-weight: 600; }

.fs-zn-form__body {
	margin-top: 32px;
	text-align: start;
}

.fs-zn-form__body > * + * { margin-top: 24px; }   /* space-y-6 */

.fs-zn-form__pair {
	display: grid;
	grid-template-columns: 1fr;
	gap: 24px;
}

@media (min-width: 640px) {
	.fs-zn-form__pair { grid-template-columns: 1fr 1fr; }
}

/* The honeypot. Off-screen rather than display:none, which some bots skip. */
.fs-zn-form__hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* Label is shadcn's: text-sm font-medium leading-none. It must be
   inline-block, not block — an inline label makes the row as tall as the
   parent's 24px strut rather than its own 17px, which is where the Contact
   page lost 7px per field. */
.fs-zn .fs-zn-form__label {
	display: inline-block;
	font-size: 14px;
	line-height: 17px;
	font-weight: 500;
	color: #fafaf9;
}

.fs-zn .fs-zn-form__input {
	display: block;
	width: 100%;
	height: 36px;                           /* h-9 */
	margin-top: 8px;                        /* space-y-2 */
	padding: 4px 12px;                      /* py-1 px-3 */
	font-family: inherit;
	font-size: 14px;
	line-height: 20px;
	color: #fafaf9;
	background: transparent;
	border: 1px solid #292524;              /* border-input */
	border-radius: 6px;                     /* rounded-md */
	box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);   /* shadow-sm */
	box-sizing: border-box;
	transition: border-color 0.15s ease, box-shadow 0.15s ease;
	-webkit-appearance: none;
	appearance: none;
}

.fs-zn .fs-zn-form__input::placeholder {
	color: #a8a29e;                         /* muted-foreground */
	opacity: 1;
}

.fs-zn .fs-zn-form__input:focus,
.fs-zn .fs-zn-form__input:focus-visible {
	outline: none;
	border-color: #fb923c;
	box-shadow: 0 0 0 1px #fb923c;          /* ring-1 ring-ring */
}

.fs-zn .fs-zn-form__input.is-invalid { border-color: #dc2626; }

.fs-zn-form__selectwrap { position: relative; }

.fs-zn .fs-zn-form__select {
	padding-right: 36px;
	cursor: pointer;
	color: #a8a29e;                         /* the placeholder option is selected */
}

.fs-zn .fs-zn-form__select.has-value { color: #fafaf9; }

.fs-zn .fs-zn-form__select option {
	background: #0c0a09;
	color: #fafaf9;
}

.fs-zn-form__caret {
	position: absolute;
	right: 12px;
	top: 50%;
	margin-top: 4px;                        /* the control's own top margin */
	transform: translateY(-50%);
	opacity: 0.5;
	pointer-events: none;
	color: #fafaf9;
}

.fs-zn-form__caret svg { width: 16px; height: 16px; display: block; }

/* FormMessage: text-[0.8rem] font-medium text-destructive. */
.fs-zn .fs-zn-form__err,
.fs-zn .fs-zn-up__err {
	margin: 0;
	font-size: 0.8rem;
	line-height: 1.4;
	font-weight: 500;
	color: #dc2626;                         /* --destructive */
}

.fs-zn .fs-zn-form__err:empty,
.fs-zn .fs-zn-up__err:empty { display: none; }

/* ---- the three upload wells ---- */

.fs-zn-form__uploads {
	display: grid;
	grid-template-columns: 1fr;
	gap: 16px;
	padding-top: 8px;                       /* pt-2 */
}

@media (min-width: 640px) {
	.fs-zn-form__uploads { grid-template-columns: 1fr 1fr 1fr; }
}

.fs-zn-up__head {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	margin-bottom: 8px;
	min-height: 2rem;                       /* min-h-[2rem] */
	gap: 8px;
}

.fs-zn-up__label {
	font-size: 14px;
	line-height: 1.25;                      /* leading-tight */
	font-weight: 500;
	color: rgba(255, 255, 255, 0.8);
}

.fs-zn-up__tag {
	flex: 0 0 auto;
	padding: 2px 8px;
	font-size: 10px;
	line-height: 16px;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	border-radius: 9999px;
	border: 1px solid rgba(255, 255, 255, 0.15);
	color: rgba(255, 255, 255, 0.3);
}

.fs-zn-up__tag.is-required {
	border-color: rgba(251, 146, 60, 0.3);
	color: #fb923c;
}

/* The real input, kept in the form and reachable by keyboard through its
   label. sr-only rather than display:none for exactly that reason. */
.fs-zn .fs-zn-up__input {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.fs-zn-up__well {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 8px;
	width: 100%;
	padding: 24px 16px;                     /* py-6 px-4 */
	border: 1px dashed rgba(255, 255, 255, 0.15);
	border-radius: 12px;
	color: rgba(255, 255, 255, 0.4);
	cursor: pointer;
	box-sizing: border-box;
	transition: border-color 0.2s, background-color 0.2s, color 0.2s;
}

.fs-zn-up__well:hover {
	border-color: rgba(251, 146, 60, 0.5);
	background: rgba(251, 146, 60, 0.05);
	color: rgba(255, 255, 255, 0.7);
}

.fs-zn-up__input:focus-visible + .fs-zn-up__well {
	outline: 2px solid #fb923c;
	outline-offset: 2px;
}

.fs-zn-up.is-error .fs-zn-up__well {
	border-color: rgba(220, 38, 38, 0.6);
	color: rgba(220, 38, 38, 0.6);
}

.fs-zn-up__wellicon svg { width: 20px; height: 20px; display: block; }
.fs-zn-up__wellcopy { font-size: 12px; line-height: 16px; }

.fs-zn-up__chip {
	display: flex;
	align-items: center;
	gap: 12px;
	padding: 12px 16px;
	border: 1px solid rgba(251, 146, 60, 0.4);
	border-radius: 12px;
	background: rgba(251, 146, 60, 0.05);
}

.fs-zn-up__chip[hidden] { display: none; }

.fs-zn-up__chipicon { flex: 0 0 auto; color: #fb923c; display: flex; }
.fs-zn-up__chipicon svg { width: 16px; height: 16px; }

.fs-zn-up__chipname {
	flex: 1 1 auto;
	min-width: 0;
	font-size: 14px;
	line-height: 20px;
	color: rgba(255, 255, 255, 0.8);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.fs-zn .fs-zn-up__clear {
	flex: 0 0 auto;
	display: flex;
	padding: 0;
	background: none;
	border: 0;
	cursor: pointer;
	color: rgba(255, 255, 255, 0.3);
	transition: color 0.2s;
}

.fs-zn .fs-zn-up__clear:hover { color: #fff; }
.fs-zn-up__clear svg { width: 16px; height: 16px; }

/* ---- consent and submit ---- */

.fs-zn-form__gdpr {
	display: grid;
	grid-template-columns: 16px 1fr;
	column-gap: 12px;
	align-items: start;
}

.fs-zn .fs-zn-form__gdpr input {
	width: 16px;
	height: 16px;
	margin: 2px 0 0;
	accent-color: #fb923c;
	cursor: pointer;
}

.fs-zn .fs-zn-form__gdpr label {
	font-size: 12px;                        /* text-xs */
	line-height: 1.625;                     /* leading-relaxed */
	font-weight: 400;
	color: rgba(255, 255, 255, 0.6);
	cursor: pointer;
}

.fs-zn .fs-zn-form__gdpr a {
	color: #fb923c;
	text-decoration: underline;
	text-underline-offset: 2px;
}

.fs-zn-form__gdpr .fs-zn-form__err { grid-column: 2; }

.fs-zn .fs-zn-form__submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 8px;
	width: 100%;
	height: 36px;                           /* h-9 */
	margin-top: 8px;                        /* mt-2 */
	padding: 8px 16px;
	font-family: inherit;
	font-size: 14px;
	line-height: 20px;
	font-weight: 500;
	white-space: nowrap;
	/* text-primary-foreground is near-white, not the dark ink the orange bar
	   reads as in a screenshot. */
	color: #fafaf9;
	background: #fb923c;
	border: 0;
	border-radius: 6px;
	box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
	cursor: pointer;
	transition: background-color 0.15s ease;
}

.fs-zn .fs-zn-form__submit:hover { background: rgba(251, 146, 60, 0.9); }

.fs-zn .fs-zn-form__submit[disabled] {
	pointer-events: none;
	opacity: 0.5;
}

.fs-zn .fs-zn-form__status {
	margin: 0;
	font-size: 14px;
	line-height: 20px;
}

.fs-zn .fs-zn-form__status:empty { display: none; }
.fs-zn .fs-zn-form__status.is-ok { color: #fb923c; }
.fs-zn .fs-zn-form__status.is-bad { color: #dc2626; }

/* ---- shared section head (8, 9, 10) ---- */

.fs-zn-head {
	margin-bottom: 64px;                    /* mb-16 */
	text-align: center;
}

.fs-zn .fs-zn-head__eyebrow {
	margin: 0 0 16px;                       /* mb-4 */
	font-size: 13px;                        /* text-[13px] */
	font-weight: 300;
	text-transform: uppercase;
	letter-spacing: 0.35rem;
	opacity: 0.6;
}

/* Conditions sets mb-8 on its eyebrow where the other two set mb-4. */
.fs-zn-cond .fs-zn-head__eyebrow { margin-bottom: 32px; }

.fs-zn .fs-zn-head__title {
	margin: 0;
	font-size: 30px;                        /* text-3xl */
	line-height: 36px;
	font-weight: 700;
}

@media (min-width: 640px) {
	.fs-zn .fs-zn-head__title { font-size: 48px; line-height: 1; }   /* sm:text-5xl */
}

.fs-zn .fs-zn-head__desc {
	margin: 32px auto 0;                    /* mt-8 */
	max-width: 576px;                       /* max-w-xl */
	font-size: 18px;
	line-height: 1.625;                     /* leading-relaxed */
	color: rgba(255, 255, 255, 0.5);
}

.fs-zn-head--onprimary .fs-zn-head__eyebrow {
	color: rgba(255, 255, 255, 0.6);
	opacity: 1;
}

.fs-zn-head--onprimary .fs-zn-head__title { color: #fff; }

.fs-zn-head__rule {
	display: block;
	width: 48px;                            /* w-12 */
	height: 1px;
	margin: 24px auto 0;                    /* mt-6 */
	background: rgba(255, 255, 255, 0.4);
}

/* ---- 8. conditions ---- */

.fs-zn-cond { padding-block: 96px; }        /* py-24 */

.fs-zn-cond__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 24px;
}

@media (min-width: 1024px) {
	.fs-zn-cond__grid { grid-template-columns: 1fr 1fr; }
}

.fs-zn-cond__panel {
	display: flex;
	flex-direction: column;
	gap: 24px;
	padding: 32px;                          /* p-8 */
	border: 1px solid rgba(255, 255, 255, 0.1);
	border-radius: 24px;                    /* rounded-3xl */
	background: rgba(255, 255, 255, 0.05);
	-webkit-backdrop-filter: blur(4px);
	backdrop-filter: blur(4px);
}

.fs-zn .fs-zn-cond__title {
	margin: 0;
	font-size: 16px;                        /* text-base */
	line-height: 24px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.3rem;
	color: #fb923c;
}

.fs-zn-cond__list {
	display: flex;
	flex-direction: column;
	gap: 16px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.fs-zn-cond__list li {
	display: flex;
	align-items: flex-start;
	gap: 16px;
}

.fs-zn-cond__icon {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 36px;                            /* w-9 */
	height: 36px;
	border-radius: 12px;
	background: rgba(251, 146, 60, 0.1);
	border: 1px solid rgba(251, 146, 60, 0.2);
	color: #fb923c;
	transition: background-color 0.2s;
}

.fs-zn-cond__list li:hover .fs-zn-cond__icon { background: rgba(251, 146, 60, 0.2); }

.fs-zn-cond__icon svg { width: 16px; height: 16px; }

.fs-zn-cond__text {
	padding-top: 6px;                       /* pt-1.5 */
	font-size: 14px;
	line-height: 1.625;
	color: rgba(255, 255, 255, 0.7);
}

.fs-zn .fs-zn-cond__prose {
	margin: 0;
	font-size: 14px;
	line-height: 1.625;
	color: rgba(255, 255, 255, 0.5);
}

.fs-zn-cond__strong {
	font-weight: 500;
	color: rgba(255, 255, 255, 0.8);
}

.fs-zn-cond__tags {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: auto;
}

.fs-zn-tag {
	padding: 6px 16px;                      /* py-1.5 px-4 */
	font-size: 12px;
	line-height: 16px;
	font-weight: 500;
	border-radius: 9999px;
	border: 1px solid rgba(255, 255, 255, 0.15);
	background: rgba(255, 255, 255, 0.05);
	color: rgba(255, 255, 255, 0.7);
	cursor: default;
	transition: border-color 0.2s, background-color 0.2s, color 0.2s;
}

.fs-zn-tag:hover {
	border-color: rgba(251, 146, 60, 0.5);
	background: rgba(251, 146, 60, 0.1);
	color: #fff;
}

/* ---- 9. important information ---- */

.fs-zn-notes {
	padding-top: 96px;                      /* py-24 */
	padding-bottom: 112px;                  /* pb-28 */
	background: #fb923c;
	color: #fff;
}

/* `container max-w-2xl`: the container's own cap gives way to 672px. */
.fs-zn-notes__inner { max-width: 672px; }

@media (min-width: 1000px) {
	.fs-zn-notes__inner { max-width: 672px; }
}

.fs-zn-notes__list {
	list-style: none;
	margin: 0;
	padding: 0;
	font-size: 18px;
	line-height: 28px;
}

.fs-zn-notes__list > li + li { margin-top: 8px; }   /* space-y-2 */

.fs-zn-notes__list li { display: flex; }
.fs-zn-notes__list li.is-sub { padding-left: 64px; }   /* pl-16 */

.fs-zn-notes__mark {
	flex: 0 0 auto;
	min-width: 32px;                        /* min-w-8 */
}

/* ---- 10. what we are looking for ---- */

.fs-zn-look { padding-block: 96px; }

.fs-zn-look__grid {
	display: grid;
	grid-template-columns: 1fr;
	gap: 48px;                              /* gap-12 */
}

@media (min-width: 1024px) {
	.fs-zn-look__grid {
		grid-template-columns: 1fr 1fr;
		gap: 64px;                          /* lg:gap-16 */
	}
}

.fs-zn .fs-zn-look__title {
	margin: 0 0 32px;                       /* mb-8 */
	font-size: 16px;
	line-height: 24px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.3rem;
	color: #fb923c;
}

.fs-zn-look__skills {
	display: flex;
	flex-direction: column;
	list-style: none;
	margin: 0;
	padding: 0;
}

.fs-zn-look__skills li {
	position: relative;
	display: flex;
	align-items: flex-start;
	gap: 20px;                              /* gap-5 */
	padding-block: 20px;                    /* py-5 */
	border-bottom: 1px solid rgba(255, 255, 255, 0.08);   /* border-white/8 */
}

.fs-zn-look__skills li:last-child { border-bottom: 0; }

/* A short rail that grows to the full height of the row on hover. */
.fs-zn-look__rail {
	position: relative;
	align-self: stretch;
	flex: 0 0 auto;
	width: 4px;                             /* w-1 */
	margin-top: 2px;                        /* mt-0.5 */
}

.fs-zn-look__rail span {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	height: 20px;                           /* h-5 */
	border-radius: 9999px;
	background: rgba(251, 146, 60, 0.3);
	transition: height 0.3s, background-color 0.3s;
}

.fs-zn-look__skills li:hover .fs-zn-look__rail span {
	height: 100%;
	background: #fb923c;
}

.fs-zn-look__skill {
	font-size: 18px;
	line-height: 1.625;
	color: rgba(255, 255, 255, 0.6);
	transition: color 0.3s;
}

.fs-zn-look__skills li:hover .fs-zn-look__skill { color: rgba(255, 255, 255, 0.9); }

.fs-zn-look__criteria {
	display: flex;
	flex-direction: column;
	gap: 8px;
	list-style: none;
	margin: 0;
	padding: 0;
}

.fs-zn-look__criteria li {
	position: relative;
	display: flex;
	align-items: flex-start;
	gap: 20px;
	padding: 20px;                          /* p-5 */
	border-radius: 16px;
	transition: background-color 0.3s;
}

.fs-zn-look__criteria li:hover { background: rgba(255, 255, 255, 0.05); }

.fs-zn-look__num {
	flex: 0 0 auto;
	margin-top: 4px;                        /* mt-1 */
	font-size: 48px;
	line-height: 1;
	font-weight: 900;                       /* font-black */
	color: rgba(255, 255, 255, 0.05);
	user-select: none;
	transition: color 0.3s;
}

.fs-zn-look__criteria li:hover .fs-zn-look__num { color: rgba(251, 146, 60, 0.2); }

.fs-zn-look__crit {
	display: block;
	padding-top: 4px;                       /* pt-1 */
}

.fs-zn-look__label {
	display: block;
	margin-bottom: 6px;                     /* mb-1.5 */
	font-size: 16px;
	line-height: 1;                         /* leading-none */
	font-weight: 600;
	color: #fff;
}

.fs-zn-look__desc {
	display: block;
	font-size: 14px;
	line-height: 1.625;
	color: rgba(255, 255, 255, 0.45);
}

/* ---- 11. closing ---- */

.fs-zn .fs-zn-fin__title {
	margin: 0 0 16px;
	font-size: 30px;                        /* text-3xl */
	line-height: 36px;
	font-weight: 700;
	text-transform: uppercase;
	color: #fb923c;
}

.fs-zn .fs-zn-fin__sub {
	margin: 0;
	padding-bottom: 16px;
	font-size: 24px;                        /* text-2xl */
	line-height: 32px;
	font-weight: 400;
	color: #fff;
}

.fs-zn-fin__list {
	margin: 0;
	padding: 0;
	list-style: disc;
	list-style-position: inside;
	font-size: 18px;
	line-height: 28px;
}

.fs-zn-fin__list > li + li { margin-top: 16px; }   /* space-y-4 */

.fs-zn .fs-zn-fin__desc {
	margin: 80px auto 0;                    /* mt-20 */
	text-align: center;
	font-size: 20px;                        /* text-xl */
	line-height: 28px;
	color: #fff;
}

.fs-zn .fs-zn-fin__sign {
	margin: 48px 0 0;                       /* mt-12 */
	text-align: center;
	font-size: 36px;                        /* text-4xl */
	line-height: 40px;
	font-weight: 700;
	color: #fff;
}

.fs-zn-fin__zenith {
	font-weight: 900;
	color: #fb923c;
}

/* ==========================================================================
   Header — the active item, and the CTA's two states

   Both re-derived from components/navigation/nav.tsx rather than from a
   screenshot, because both had been recorded wrong from screenshots before.
   ========================================================================== */

/*
 * A deliberate divergence, asked for directly: live's active nav item is
 * `underline` and nothing else, with the label staying --foreground. FLYSTACK
 * preferred the brand colour to the underline, so the active item is bold
 * accent with no rule under it. Which item counts as active is still decided
 * the way live decides it — see the path matcher in inc/i18n-chrome.php.
 */
.elementor-nav-menu .elementor-item.elementor-item-active,
.elementor-nav-menu .current-menu-item > .elementor-item,
.elementor-nav-menu--dropdown .elementor-item.elementor-item-active,
.elementor-nav-menu--dropdown .current-menu-item > .elementor-item {
	color: var(--fs-accent, #fb923c) !important;
	font-weight: 700 !important;
	text-decoration: none !important;
}



/* ==========================================================================
   The blog — listing and article

   From app/[locale]/blog/page.tsx and app/[locale]/blog/[slug]/page.tsx, plus
   that route's own blog-content.css for the prose.

   These are LIGHT pages. The listing puts white under the cards, the article
   puts #FAFAF9 under the copy, and both paint their own dark strip behind the
   fixed header — the same thing the single project template does.
   ========================================================================== */

.fs-bl,
.fs-bl-article {
	font-size: 16px;
	line-height: 24px;
}

.fs-bl__inner {
	width: 100%;
	margin-inline: auto;
	padding-inline: 32px;
	box-sizing: border-box;
}

@media (min-width: 1000px) {
	.fs-bl__inner { max-width: 1000px; }
}

/* ---- the hero ---- */

.fs-bl-hero {
	position: relative;
	width: 100%;
	padding-top: 160px;              /* pt-40 */
	background: #000;
}

/* `-top-1 -left-1`: the photograph is nudged 4px up and left. Invisible
   against black, and reproduced rather than tidied. */
.fs-bl-hero__bg {
	position: absolute;
	top: -4px;
	left: -4px;
	width: 100%;
	height: 100%;
	z-index: 0;
}

/*
 * Live writes `object-[50%,90%]`, which compiles to
 * `object-position: 50%,90%` — a comma where CSS wants a space, so the
 * declaration is invalid and the browser drops it. Live therefore renders a
 * CENTRED crop, and that is what is reproduced here. The author plainly meant
 * `50% 90%`; changing it would be a visible difference from the live page, so
 * it is recorded here for FLYSTACK to decide rather than silently fixed.
 */
.fs-bl .fs-bl-hero__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 50%;
}

.fs-bl-hero__inner {
	position: relative;
	z-index: 10;
	text-align: center;
	padding-bottom: 128px;           /* pb-32 */
}

.fs-bl .fs-bl-hero__eyebrow {
	margin: 0;
	font-family: var(--fs-font-brand);   /* font-codeNext */
	font-size: 16px;
	line-height: 24px;
	font-weight: 300;
	letter-spacing: 0.8rem;
	text-transform: uppercase;
	color: #fafaf9;
}

.fs-bl .fs-bl-hero__title {
	margin: 0;
	padding-block: 24px;             /* py-6 */
	font-size: 48px;                 /* text-5xl */
	line-height: 1;
	font-weight: 700;
	text-transform: uppercase;
	color: #fb923c;
}

.fs-bl .fs-bl-hero__desc {
	margin: 0;
	color: #fafaf9;
}

/* ---- the listing ---- */

.fs-bl-list {
	background: #fff;
	color: #292524;                  /* text-secondary */
}

.fs-bl-grid {
	display: grid;
	grid-template-columns: 1fr;
	column-gap: 40px;                /* gap-x-10, and no row gap */
	padding-bottom: 80px;            /* pb-20 */
}

@media (min-width: 640px) {
	.fs-bl-grid { grid-template-columns: 1fr 1fr; }
}

.fs-bl-grid--rec { padding-bottom: 0; }

.fs-bl .fs-bl-empty {
	padding-block: 80px;
	text-align: center;
	color: #292524;
}

/* ---- a standard card ---- */

.fs-bl-card {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	margin-bottom: 80px;             /* mb-20 sm:mb-0 */
	color: inherit;
	text-decoration: none;
	transition: transform 0.3s;
}

/* The card's click target. Sits under the two real links inside the card,
   which carry live's own `z-30`. */
.fs-bl-card__hit {
	position: absolute;
	inset: 0;
	z-index: 1;
	border-radius: inherit;
}

@media (min-width: 640px) {
	.fs-bl-card { margin-bottom: 0; }
}

.fs-bl-card:hover { transform: scale(1.05); }

/* These card rules were scoped to .fs-bl, the blog listing wrapper. The
   "Recommended articles" cards sit inside .fs-bl-article instead, so not one of
   them matched and the cards rendered completely unstyled — covers at their
   natural height, default type, no spacing. :is() keeps the specificity at
   (0,1,0), exactly what a bare .fs-bl was, so nothing else in the cascade moves. */
:is(.fs-bl, .fs-bl-article) .fs-bl-card__date {
	margin: 0;
	font-size: 12px;                 /* text-xs */
	line-height: 16px;
	color: #a8a29e;                  /* text-muted-foreground */
}

:is(.fs-bl, .fs-bl-article) .fs-bl-card__title {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 0;
	padding-top: 16px;               /* pt-4 */
	font-size: 24px;                 /* text-2xl */
	line-height: 32px;
	font-weight: 700;
}

.fs-bl-card__ext { display: inline-flex; flex: 0 0 auto; }
.fs-bl-card__ext svg { width: 16px; height: 16px; display: block; }

:is(.fs-bl, .fs-bl-article) .fs-bl-card__cover {
	display: block;
	width: 100%;
	aspect-ratio: 16 / 9;            /* aspect-video */
	object-fit: cover;
	border-radius: 24px;             /* rounded-3xl */
	margin-block: 16px;              /* my-4 */
	height: auto;
}

:is(.fs-bl, .fs-bl-article) .fs-bl-card__excerpt {
	margin: 0;
	color: rgba(41, 37, 36, 0.6);    /* text-secondary/60 */
}

/* ---- the byline ---- */

.fs-bl-by {
	display: flex;
	align-items: center;
	gap: 8px;
	padding-block: 12px;             /* py-3 */
}

:is(.fs-bl, .fs-bl-article) .fs-bl-by__label {
	margin: 0;
	font-size: 12px;
	line-height: 16px;
	color: #a8a29e;
}

.fs-bl-by__avatar {
	display: block;
	flex: 0 0 auto;
	width: 24px;
	height: 24px;
	border-radius: 9999px;
	overflow: hidden;
}

:is(.fs-bl, .fs-bl-article) .fs-bl-by__avatar img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
}

.fs-bl-by__name {
	font-size: 14px;
	line-height: 20px;
	font-weight: 500;
	color: inherit;
}

/* The underline that unwrites itself and redraws as a hairline.
   `underline ... hover:no-underline after:w-0 hover:after:w-full
   after:h-[0.5px] after:bg-black after:duration-500`. */
.fs-bl-rule {
	position: relative;
	z-index: 30;
	display: block;
	text-decoration: underline;
	color: inherit;
}

.fs-bl-rule::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 3px;
	width: 0;
	height: 0.5px;
	background: #000;
	transition: width 0.5s;
}

.fs-bl-rule:hover { text-decoration: none; }
.fs-bl-rule:hover::after { width: 100%; }

.fs-bl-read {
	display: flex;
	align-items: center;
	gap: 8px;
	margin: 32px 0 0;                /* mt-8 */
	font-weight: 500;
}

.fs-bl-read__arrow { display: inline-flex; flex: 0 0 auto; }
.fs-bl-read .fs-bl-rule::after { bottom: 4px; }

/* ---- the wide card ---- */

.fs-bl-feature {
	position: relative;
	grid-column: 1 / -1;             /* sm:col-span-2 */
	display: flex;
	flex-direction: column-reverse;
	gap: 24px;                       /* gap-6 */
	margin-block: 80px;              /* my-20 */
	padding: 32px;                   /* p-8 */
	background: #fafaf9;             /* bg-secondary-foreground */
	color: #292524;
	border-radius: 32px;             /* rounded-[32px] */
	text-decoration: none;
	transition: transform 0.3s, box-shadow 0.3s;
}

@media (min-width: 640px) {
	.fs-bl-feature { flex-direction: row; }
}

.fs-bl-feature:hover {
	transform: scale(1.05);
	box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
	            0 4px 6px -4px rgba(0, 0, 0, 0.1);   /* hover:shadow-lg */
}

.fs-bl-feature__copy { flex: 1 1 auto; min-width: 0; }

.fs-bl-feature__media {
	display: flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	min-width: 200px;
}

@media (min-width: 640px) {
	.fs-bl-feature__media { width: 50%; }
}

.fs-bl .fs-bl-feature__cover {
	display: block;
	width: 100%;
	height: 100%;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border-radius: 24px;
}

@media (min-width: 640px) {
	.fs-bl .fs-bl-feature__cover { aspect-ratio: 1 / 1; }
}

/* `-scale-x-100` on the fourth card, so its cover faces into the page. */
.fs-bl .fs-bl-feature__cover.is-flipped { transform: scaleX(-1); }

/* ---- the scrolling band ---- */

.fs-bl-marquee {
	grid-column: 1 / -1;
	display: flex;
	flex-wrap: nowrap;
	margin: 80px 0 40px;             /* my-10 mt-20 */
	overflow: hidden;
	white-space: nowrap;
	letter-spacing: -2px;
	line-height: 0.8;
	color: #000;
}

.fs-bl-marquee__row {
	display: flex;
	flex-wrap: nowrap;
	white-space: nowrap;
	font-size: 64px;
	font-weight: 600;
	text-transform: uppercase;
	animation: fs-bl-marquee var(--fs-bl-dur, 8s) linear infinite;
	will-change: transform;
}

.fs-bl-marquee__row span { display: block; margin-right: 16px; }

@keyframes fs-bl-marquee {
	from { transform: translateX(0); }
	to   { transform: translateX(var(--fs-bl-shift, -20%)); }
}

@media (prefers-reduced-motion: reduce) {
	.fs-bl-marquee__row { animation: none; }
}

/* ---- one article ---- */

.fs-bl-article {
	position: relative;
	margin-top: 80px;                /* mt-20 */
	padding-top: 80px;               /* pt-20 */
	padding-bottom: 160px;           /* pb-40 */
	background: #fafaf9;
	color: #292524;
	border-bottom: 1px solid #fff;
}

/* The dark ground the transparent header needs on a light page. */
.fs-bl-article__strip {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 80px;
	background: #0c0a09;
}

.fs-bl-article .fs-bl-article__cover {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border-radius: 24px;
	margin-bottom: 40px;             /* mb-10 */
}

.fs-bl-article .fs-bl-article__title {
	margin: 0;
	padding-bottom: 40px;            /* pb-10 */
	font-size: 48px;                 /* text-5xl */
	line-height: 1;
	font-weight: 700;
	color: #fb923c;
}

.fs-bl-article__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 16px;                       /* gap-4 */
	margin-bottom: 32px;             /* mb-8 */
	font-size: 14px;
	line-height: 20px;
	color: #a8a29e;
}

.fs-bl-article__author { display: flex; align-items: center; gap: 8px; }

.fs-bl-article .fs-bl-article__author img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
}

.fs-bl-article .fs-bl-rec__title {
	margin: 0;
	padding-top: 80px;               /* pt-20 wins over py-8 for the top */
	padding-bottom: 32px;
	font-size: 36px;                 /* text-4xl */
	line-height: 40px;
	font-weight: 700;
}

/* ---- the prose, from that route's blog-content.css ---- */

.fs-bl-content { color: #1f2937; }                     /* text-gray-800 */

.fs-bl-content p {
	margin: 0 0 16px;
	font-size: 16px;
	line-height: 1.625;                                 /* leading-relaxed */
}

.fs-bl-article .fs-bl-content h1 { margin: 32px 0 16px; font-size: 36px; line-height: 40px; font-weight: 700; color: #111827; }
.fs-bl-article .fs-bl-content h2 { margin: 24px 0 12px; font-size: 30px; line-height: 36px; font-weight: 600; color: #111827; }
.fs-bl-article .fs-bl-content h3 { margin: 20px 0 8px;  font-size: 24px; line-height: 32px; font-weight: 600; color: #111827; }
.fs-bl-article .fs-bl-content h4 { margin: 16px 0 8px;  font-size: 20px; line-height: 28px; font-weight: 600; color: #111827; }
.fs-bl-article .fs-bl-content h5 { margin: 12px 0 8px;  font-size: 18px; line-height: 28px; font-weight: 600; color: #111827; }
.fs-bl-article .fs-bl-content h6 { margin: 12px 0 8px;  font-size: 16px; line-height: 24px; font-weight: 600; color: #111827; }

.fs-bl-content a { color: #2563eb; text-decoration: underline; }
.fs-bl-content a:hover { color: #1e40af; }
.fs-bl-content strong { font-weight: 600; color: #111827; }
.fs-bl-content em { font-style: italic; }

.fs-bl-content ul { list-style: disc; padding-left: 24px; margin: 0 0 16px; }
.fs-bl-content ol { list-style: decimal; padding-left: 24px; margin: 0 0 16px; }
.fs-bl-content li { line-height: 1.625; }
.fs-bl-content li > ul,
.fs-bl-content li > ol { margin-top: 8px; margin-left: 24px; }

.fs-bl-content blockquote {
	margin: 0 0 16px;
	padding: 8px 0 8px 16px;
	border-left: 4px solid #d1d5db;
	background: #f9fafb;
	font-style: italic;
	color: #374151;
}

.fs-bl-article .fs-bl-content img {
	width: 100%;
	height: auto;
	border-radius: 8px;
	margin-block: 24px;
}

.fs-bl-content hr { margin: 32px 0; border: 0; border-top: 2px solid #e5e7eb; }

.fs-bl-content table { width: 100%; margin-bottom: 16px; border-collapse: collapse; }
.fs-bl-content th { padding: 8px 16px; background: #f3f4f6; border: 1px solid #d1d5db; text-align: left; font-weight: 600; }
.fs-bl-content td { padding: 8px 16px; border: 1px solid #d1d5db; }
.fs-bl-content table tr:nth-child(even) { background: #f9fafb; }

.fs-bl-content > *:first-child { margin-top: 0; }
.fs-bl-content > *:last-child { margin-bottom: 0; }

/* ==========================================================================
   Form success — the panel that replaces the form

   The source shows a sonner toast and leaves the filled-in form on screen. A
   toast that fades after four seconds, over a form that still looks unsent, is
   the least reassuring way to answer "did that work?" — so the card swaps to a
   single centred confirmation instead, and the way back is a button.

   Built out of pieces the rest of the site already uses: the accent ring from
   the Zenith upload wells, the outline pill from the header CTA at the top of
   the page, and the same 0.6s cubic-bezier(0.22, 1, 0.36, 1) every reveal in
   this theme runs on.
   ========================================================================== */

.fs-ct-card.is-done > .fs-ct-card-title,
.fs-ct-card.is-done > .fs-ct-card-desc,
.fs-ct-card.is-done > .fs-ct-form {
	display: none;
}

.fs-ct-done[hidden] { display: none; }

.fs-ct-done,
.fs-zn-done {
	display: flex;
	flex-direction: column;
	align-items: center;
	/* The generous vertical room is the point: the card keeps roughly the
	   height it had, so nothing below it jumps up the page. */
	padding-block: 64px;
	text-align: center;
	outline: none;
}

@media (min-width: 640px) {
	.fs-ct-done,
	.fs-zn-done { padding-block: 96px; }
}

.fs-ct-done__mark,
.fs-zn-done__mark {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 72px;
	height: 72px;
	margin-bottom: 32px;
	border-radius: 9999px;
	color: #fb923c;
	background: rgba(251, 146, 60, 0.12);
	border: 1px solid rgba(251, 146, 60, 0.35);
	animation: fs-done-mark 0.6s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.fs-ct-done__mark svg,
.fs-zn-done__mark svg {
	width: 32px;
	height: 32px;
	display: block;
	/* The tick draws itself. 48 is comfortably longer than the path, so the
	   dash starts fully offset whatever the exact length. */
	stroke-dasharray: 48;
	stroke-dashoffset: 48;
	animation: fs-done-tick 0.5s cubic-bezier(0.22, 1, 0.36, 1) 0.25s both;
}

@keyframes fs-done-mark {
	from { opacity: 0; transform: scale(0.7); }
	to   { opacity: 1; transform: scale(1); }
}

@keyframes fs-done-tick {
	to { stroke-dashoffset: 0; }
}

.fs-ct .fs-ct-done__title,
.fs-zn .fs-zn-done__title {
	margin: 0;
	max-width: 26ch;
	font-size: 24px;
	line-height: 32px;
	font-weight: 700;
	color: #fafaf9;
	animation: fs-done-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.1s both;
}

@media (min-width: 640px) {
	.fs-ct .fs-ct-done__title,
	.fs-zn .fs-zn-done__title { font-size: 30px; line-height: 36px; }
}

.fs-ct .fs-ct-done__note,
.fs-zn .fs-zn-done__note {
	margin: 16px 0 0;
	max-width: 46ch;
	font-size: 16px;
	line-height: 24px;
	color: rgba(250, 250, 249, 0.6);
	animation: fs-done-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.18s both;
}

@keyframes fs-done-rise {
	from { opacity: 0; transform: translateY(12px); }
	to   { opacity: 1; transform: translateY(0); }
}

/* The header CTA's top-of-page form: an outline that fills on hover. */
.fs-ct .fs-ct-done__again,
.fs-zn .fs-zn-done__again {
	margin-top: 32px;
	padding: 10px 28px;
	font-family: inherit;
	font-size: 14px;
	line-height: 20px;
	font-weight: 600;
	letter-spacing: 1px;
	color: #fafaf9;
	background: transparent;
	border: 2px solid #fb923c;
	border-radius: 9999px;
	cursor: pointer;
	transition: background-color 0.3s ease, color 0.3s ease;
	animation: fs-done-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.26s both;
}

.fs-ct .fs-ct-done__again:hover,
.fs-zn .fs-zn-done__again:hover,
.fs-ct .fs-ct-done__again:focus-visible,
.fs-zn .fs-zn-done__again:focus-visible {
	background: #fb923c;
	color: #fafaf9;
}

@media (prefers-reduced-motion: reduce) {
	.fs-ct-done__mark,
	.fs-zn-done__mark,
	.fs-ct-done__mark svg,
	.fs-zn-done__mark svg,
	.fs-ct-done__title,
	.fs-zn-done__title,
	.fs-ct-done__note,
	.fs-zn-done__note,
	.fs-ct-done__again,
	.fs-zn-done__again {
		animation: none;
	}
	.fs-ct-done__mark svg,
	.fs-zn-done__mark svg { stroke-dashoffset: 0; }
}

/* Zenith Lab: the form panel is the card, so it swaps its own contents. */
.fs-zn-form.is-done > .fs-zn-form__title,
.fs-zn-form.is-done > .fs-zn-form__intro,
.fs-zn-form.is-done > .fs-zn-form__body {
	display: none;
}

.fs-zn-done[hidden] { display: none; }

/*
 * The booking dialog reuses the Contact page's card inside a `.fs-ct` band, so
 * it inherits that band's 160px bottom padding. Under the form that padding is
 * invisible; under the success panel it is 160px of empty dialog below a
 * four-line confirmation. Dropped in the done state, which lets the dialog
 * shrink to the panel and sit centred in the viewport.
 */
.fs-book__scroll:has(.fs-ct-card.is-done) { padding-bottom: 0; }

/* ==========================================================================
   Cookie consent

   Live's geometry, kept: `fixed bottom-4 left-4 right-4 z-50 rounded-2xl
   bg-black border border-border text-white p-4 shadow-lg max-w-3xl mx-auto`.

   One colour changed. Live's Save button is `bg-blue-600` — a stock Tailwind
   blue on a palette that has no blue in it anywhere else, sitting next to an
   orange Accept that does the same kind of thing. It is the accent here, so
   the two primary actions look like the same button.
   ========================================================================== */

.fs-cc {
	position: fixed;
	bottom: 16px;                    /* bottom-4 */
	left: 16px;
	right: 16px;
	z-index: 50;
	display: flex;
	flex-direction: column;
	max-width: 768px;                /* max-w-3xl */
	margin-inline: auto;
	padding: 16px;                   /* p-4 */
	background: #000;
	border: 1px solid #292524;       /* border-border */
	border-radius: 16px;             /* rounded-2xl */
	color: #fff;
	box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.4),
	            0 4px 6px -4px rgba(0, 0, 0, 0.4);
	font-size: 14px;
	line-height: 20px;
	animation: fs-cc-in 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}

.fs-cc[hidden] { display: none; }
.fs-cc__view[hidden] { display: none; }

@keyframes fs-cc-in {
	from { opacity: 0; transform: translateY(16px); }
	to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
	.fs-cc { animation: none; }
}

.fs-cc .fs-cc__text {
	margin: 0;
	font-size: 14px;
	line-height: 20px;
	color: #fff;
}

@media (min-width: 768px) {
	.fs-cc .fs-cc__text { font-size: 16px; line-height: 24px; }   /* md:text-base */
}

.fs-cc .fs-cc__text a {
	color: #fb923c;                  /* text-orange-400, which is the accent */
	text-decoration: underline;
	transition: color 0.3s ease;
}

.fs-cc .fs-cc__text a:hover { color: #fdba74; }

.fs-cc .fs-cc__title {
	margin: 0 0 8px;
	font-size: 18px;                 /* text-lg */
	line-height: 28px;
	font-weight: 600;
	color: #fff;
}

.fs-cc__rows > * + * { margin-top: 12px; }   /* space-y-3 */

.fs-cc__row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 16px;
}

.fs-cc__row label { cursor: pointer; }

.fs-cc .fs-cc__row input {
	width: 16px;
	height: 16px;
	flex: 0 0 auto;
	accent-color: #fb923c;
	cursor: pointer;
}

.fs-cc .fs-cc__row input:disabled { cursor: not-allowed; opacity: 0.7; }

.fs-cc__actions {
	display: flex;
	flex-wrap: wrap;
	justify-content: flex-end;
	gap: 8px;
	margin-top: 12px;                /* mt-3, and mt-4 in the settings view */
}

.fs-cc__view[data-fs-cc-view="settings"] .fs-cc__actions { margin-top: 16px; }

.fs-cc .fs-cc__btn {
	padding: 8px 16px;
	font-family: inherit;
	font-size: 14px;
	line-height: 20px;
	color: #fff;
	border: 0;
	border-radius: 12px;             /* rounded-xl */
	cursor: pointer;
	transition: background-color 0.3s ease;
}

.fs-cc .fs-cc__btn--ghost  { background: #374151; }   /* bg-gray-700 */
.fs-cc .fs-cc__btn--ghost:hover  { background: #4b5563; }
.fs-cc .fs-cc__btn--muted  { background: #6b7280; }   /* bg-gray-500 */
.fs-cc .fs-cc__btn--muted:hover  { background: #9ca3af; }

.fs-cc .fs-cc__btn--primary {
	background: #fb923c;
	font-weight: 500;
}

.fs-cc .fs-cc__btn--primary:hover { background: #fdba74; }

/* The footer's way back into the cookie panel, matching the legal links it
   sits beside. */
.elementor-location-footer .fs-cc-link {
	display: block;
	color: rgba(250, 250, 249, 0.6);
	text-decoration: none;
	transition: color 0.3s ease;
	cursor: pointer;
}

.elementor-location-footer .fs-cc-link:hover { color: #fafaf9; }

/* An unpublished project in the portfolio grid. Only ever rendered for
   someone who can read private posts — a visitor's grid is exactly the
   published set. */
.fs-pj__card.is-private .fs-pj__frame { outline: 1px dashed rgba(251, 146, 60, 0.5); outline-offset: -1px; }

.fs-pj__private {
	position: absolute;
	top: 12px;
	left: 12px;
	z-index: 3;
	padding: 4px 10px;
	font-size: 11px;
	line-height: 16px;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: #0c0a09;
	background: #fb923c;
	border-radius: 9999px;
}
