/*
Theme Name: Joker
Theme URI: https://github.com/git4li/Joker
Description: Child theme of Twenty Twenty-Five for the Joker project. Design customisations live here: theme.json for design tokens, templates/ and parts/ for layout overrides, patterns/ for reusable sections.
Author: Joker
Template: twentytwentyfive
Version: 0.1.0
Requires at least: 6.7
Tested up to: 7.0
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: joker
Tags: full-site-editing, block-patterns, block-styles, wide-blocks
*/



/* ---------------------------------------------------------------------------
 * Header
 *
 * Figma: Header 574:3436 — 1380px bar, 30px from the top, overlaying the hero.
 * Logo 134.5x38.1, nav links 16.058px white with a 13.047px gap, active item
 * underlined by a 15px bar. CTA is a white pill with #0B1528 text and arrow.
 * ------------------------------------------------------------------------ */

:root {
	--joker-header-max: 1380px;
	--joker-header-gutter: 30px;
	--joker-nav-gap: 13.047px;
	--joker-panel-bg: #1a2c4f;
}


/* ---------------------------------------------------------------------------
 * About company
 *
 * Figma: Group 3 574:3437 — eyebrow at the far left, statement heading offset
 * to 292px, mission and vision beneath it, then a media row.
 *
 * The media row reproduces the design's clipping container (574:3448): a
 * 154.3px window with 439.86x282.76 items placed below it. Rather than leave
 * them permanently hidden, the items rise into the window on scroll.
 * ------------------------------------------------------------------------ */

.joker-about {
	padding-block: clamp( 60px, 8vw, 116px );
	padding-inline: 30px;
}

@media ( max-width: 781px ) {
	.joker-about {
		padding-inline: 20px;
	}

	

	/* Three across is unreadable on a phone; show one and let it scroll. */
	

	

	
}


.joker-marquee {
	overflow: clip;
	inline-size: 100%;
	user-select: none;
}

.joker-marquee__track {
	display: flex;
	inline-size: max-content;
	animation: joker-marquee-scroll 20s linear infinite;
}

.joker-marquee__run {
	display: flex;
	align-items: center;
	flex: none;
}

.joker-marquee__item {
	font-size: clamp( 3rem, 8.4vw, 7.55rem );
	line-height: 1.06;
	letter-spacing: -0.035em;
	color: #d3d3d3;
	white-space: nowrap;
	padding-inline: 0.16em;
}

.joker-marquee__dot {
	flex: none;
	inline-size: 20.07px;
	block-size: 20.07px;
	border-radius: 50%;
	background: var( --wp--preset--color--gold );
	margin-inline: 0.14em;
	animation: joker-marquee-dot 10s linear infinite;
}

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

/* Gold at the start of the cycle, crimson by the end. */
@keyframes joker-marquee-dot {
	0%   { background-color: #e9b829; }
	100% { background-color: #de103c; }
}

@media ( prefers-reduced-motion: reduce ) {
	.joker-marquee__track,
	.joker-marquee__dot {
		animation: none;
	}
}


.joker-fm {
	position: relative;
	display: grid;
	grid-template-columns: 350px 1fr 270px;
	gap: 40px;
	align-items: start;
	margin-block-start: clamp( 28px, 4vw, 56px );
}

.joker-fm__panes { position: relative; grid-column: 1; min-block-size: 262px; }

.joker-fm__pane {
	position: absolute;
	inset: 0;
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.35s ease;
	display: grid;
	gap: 18px;
}

.joker-fm__pane.is-active { opacity: 1; visibility: visible; }

.joker-fm__media { border-radius: 12px; overflow: clip; block-size: 262px; }
.joker-fm__media img, .joker-fm__media video { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }

.joker-fm__copy { color: #fff; }
.joker-fm__copy p { font-size: 1.0035rem; line-height: 1.6; margin: 0 0 14px; }

.joker-fm__more { color: #fff; font-size: 1.0035rem; text-decoration: none; border-block-end: 1px solid currentColor; }

.joker-fm__names { grid-column: 2; list-style: none; margin: 0; padding: 0; text-align: center; }

.joker-fm__name {
	background: none;
	border: 0;
	padding: 10px 0;
	cursor: pointer;
	font-family: inherit;
	font-size: clamp( 1.75rem, 3.4vw, 3.05rem );
	line-height: 1.25;
	letter-spacing: -0.03em;
	color: rgba( 255, 255, 255, 0.32 );
	transition: color 0.25s ease;
}

.joker-fm__item.is-active .joker-fm__name,
.joker-fm__name:hover,
.joker-fm__name:focus-visible { color: #fff; }

@media ( max-width: 1023px ) {
	.joker-fm { grid-template-columns: 1fr; gap: 24px; }
	.joker-fm__names { grid-column: 1; text-align: start; }

	/*
	 * Stacked, the absolutely positioned panes no longer size their container —
	 * a 262px media plus its copy overflowed the reserved height and landed on
	 * top of the name list. In flow the active pane sizes the container itself,
	 * and hover swapping is moot on touch anyway.
	 */
	.joker-fm__panes { grid-column: 1; min-block-size: 0; }

	.joker-fm__pane {
		position: static;
		display: none;
		opacity: 1;
		visibility: visible;
	}

	.joker-fm__pane.is-active { display: block; }
}

.joker-footer__visual { display: block; border-radius: 18px; overflow: clip; aspect-ratio: 822 / 628; background: var( --wp--preset--color--navy ); }
.joker-footer__visual img, .joker-footer__visual video { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }

/* Video slots — the design marks video with a play glyph.
   The wrapper class is parameterised per section (joker-card__media--video,
   joker-footer__visual--video …), so the containing block must be anchored to
   .is-video, which every video wrapper carries. Anchoring to .joker-media--video
   left the mark without a positioned ancestor, and it escaped onto the hero. */
/* Only wrappers that actually carry a play glyph need to become a containing
   block. A blanket .is-video rule overrode .joker-card__media's absolute
   positioning, so video cards stopped filling their tile while image cards
   still did. */
.is-video:has( .joker-media__play ) { position: relative; }

.joker-media__play {
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	transform: translate( -50%, -50% );
	inline-size: 68px;
	block-size: 68px;
	border: 2px solid rgba( 255, 255, 255, 0.9 );
	border-radius: 50%;
	pointer-events: none;
}

.joker-media__play::after {
	content: "";
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 54%;
	transform: translate( -50%, -50% );
	inline-size: 0;
	block-size: 0;
	border-block-start: 11px solid transparent;
	border-block-end: 11px solid transparent;
	border-inline-start: 18px solid rgba( 255, 255, 255, 0.95 );
}

/* The service cards are small; a 68px disc would dominate them. */
.joker-card__media.is-video .joker-media__play { inline-size: 46px; block-size: 46px; }
.joker-card__media.is-video .joker-media__play::after {
	border-block-start-width: 8px;
	border-block-end-width: 8px;
	border-inline-start-width: 13px;
}

/* Banner avatars — Figma ships these flattened into one bitmap, but the design
   shows three portraits overlapping behind a "+" badge. Rendered as separate
   slots so each can be swapped, or made a video, from the front page. */
.joker-avatars {
	display: flex;
	align-items: center;
	list-style: none;
	margin: 0;
	padding: 0;
	inline-size: max-content;
}

/*
 * Elementor's widget wrapper is the flex child here, so it is the one that must
 * not shrink — the circles are flex: none and would otherwise overflow it, and
 * the "+" badge would sit under the text beside it.
 */
.elementor-widget-joker-avatars { flex: none; }

.joker-avatars__item {
	inline-size: 63px;
	block-size: 63px;
	border-radius: 50%;
	overflow: clip;
	flex: none;
}

.joker-avatars__item + /*
 * Elementor's widget wrapper is the flex child here, so it is the one that must
 * not shrink — the circles are flex: none and would otherwise overflow it, and
 * the "+" badge would sit under the text beside it.
 */
.elementor-widget-joker-avatars { flex: none; }

.joker-avatars__item {
	margin-inline-start: -21px; /* the design overlaps each circle by a third */
}

.joker-avatars__media { display: block; inline-size: 100%; block-size: 100%; }
.joker-avatars__media img,
.joker-avatars__media video { inline-size: 100%; block-size: 100%; object-fit: cover; display: block; }

.joker-avatars__item--more {
	display: flex;
	align-items: center;
	justify-content: center;
	background: #fff;
}

.joker-avatars__plus { position: relative; inline-size: 18px; block-size: 18px; }

.joker-avatars__plus::before,
.joker-avatars__plus::after {
	content: "";
	position: absolute;
	inset-block-start: 50%;
	inset-inline-start: 50%;
	background: var( --wp--preset--color--contrast );
	transform: translate( -50%, -50% );
}

.joker-avatars__plus::before { inline-size: 16px; block-size: 2px; }
.joker-avatars__plus::after  { inline-size: 2px; block-size: 16px; }

@media ( max-width: 781px ) {
	/*
 * Elementor's widget wrapper is the flex child here, so it is the one that must
 * not shrink — the circles are flex: none and would otherwise overflow it, and
 * the "+" badge would sit under the text beside it.
 */
.elementor-widget-joker-avatars { flex: none; }

.joker-avatars__item { inline-size: 52px; block-size: 52px; }
	.joker-avatars__item + /*
 * Elementor's widget wrapper is the flex child here, so it is the one that must
 * not shrink — the circles are flex: none and would otherwise overflow it, and
 * the "+" badge would sit under the text beside it.
 */
.elementor-widget-joker-avatars { flex: none; }

.joker-avatars__item { margin-inline-start: -17px; }
}

/* ---------------------------------------------------------------------------
 * Elementor header
 *
 * Two details from the design that Elementor's own controls cannot express:
 * the CTA's arrow disc, and the bar under the current page. Everything else in
 * the Elementor header — colours, sizes, spacing — is set through widget
 * settings so it stays editable in the panel.
 *
 * Figma: Header 153:327.
 * ------------------------------------------------------------------------ */

.joker-el-cta .elementor-button {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	min-block-size: 48.175px;
	padding-inline: 24px 8px;
	border-radius: 30.109px;
	line-height: 1;
	text-transform: capitalize;
	white-space: nowrap;
}

/* Figma btn I574:3435;111:272 — a 34px disc holding a 12px arrow, rotated to
   point up and to the right. */
.joker-el-cta .elementor-button::after {
	content: "";
	inline-size: 34.124px;
	block-size: 34.124px;
	flex: none;
	border-radius: 50%;
	background: #fff url( "assets/icons/arrow-header.svg" ) center / 12.05px 12.05px no-repeat;
	transform: rotate( -45deg );
}

/* The Mega Menu sets aria-current itself by matching the item link against the
   current permalink, so the marker needs styling only, not logic. */
.e-n-menu-title[aria-current="page"] {
	position: relative;
}

.e-n-menu-title[aria-current="page"]::after {
	content: "";
	position: absolute;
	inset-block-end: 2px;
	inset-inline-start: 50%;
	transform: translateX( -50% );
	inline-size: 15.055px;
	block-size: 2.007px;
	border-radius: 100.364px;
	background: #fff;
}

/* ---------------------------------------------------------------------------
 * Elementor header — below the desktop breakpoint.
 *
 * The bar overlays the hero photograph, so the menu items are white. Elementor's
 * mobile dropdown gives each item a white background of its own, which leaves
 * white text on white. Restoring the navy drawer from the original design fixes
 * the contrast and keeps mobile consistent with the desktop panel.
 * ------------------------------------------------------------------------ */

@media ( max-width: 1024px ) {

	/* Scoping this to .elementor-location-header stopped it matching the drawer
	   Elementor actually renders, so it is kept deliberately simple. The
	   !important is a considered last resort: the item background is cleared
	   through the widget's own control, but the drawer colour has to beat
	   Elementor's widget stylesheet, which loads after the theme's. */
	/* Elementor stretches the drawer to the full viewport via its own
	   --stretch-width; a narrower panel tucked under the toggle reads better and
	   keeps the hero visible behind it. */
	/* Full-height drawer, as in the original design, rather than Elementor's
	   dropdown panel. It starts below the bar so the close control stays
	   reachable, and scrolls internally once Services is expanded. */
	.e-n-menu-wrapper {
		position: fixed !important;
		inset-block-start: var( --joker-bar-height, 67px ) !important;
		inset-block-end: 0 !important;
		block-size: auto !important;
		max-block-size: none !important;
		overflow-y: auto !important;
		overscroll-behavior: contain;
		z-index: 100;
		background-color: #0d1328 !important;
		border-radius: 20px 0 0 0;
		inline-size: min( 320px, 85vw ) !important;
		/* The drawer opens from the side its trigger is on, and the toggle sits
		   top right. Elementor positions this absolutely with left, right and
		   width all set, which makes an auto margin a no-op — the inset itself
		   has to be overridden. */
		inset-inline-start: auto !important;
		inset-inline-end: 0 !important;
	}

	/* Elementor stretches the dropdown content to the viewport independently of
	   the wrapper, so narrowing the drawer alone left the panel 56px wider than
	   the box holding it — which is what clipped the images and the longer
	   service names. Both have to be tied to the drawer. */
	.e-n-menu-wrapper .e-n-menu-content,
	.e-n-menu-wrapper .e-n-menu-content > .e-con,
	.e-n-menu-wrapper .e-n-menu-content .e-con-inner {
		inline-size: 100% !important;
		max-inline-size: 100% !important;
		left: 0 !important;
	}

	/* Covers the active item too: Elementor styles the current page's background
	   separately, which left "Home" as a white band in the drawer. */
	.e-n-menu-wrapper .e-n-menu-title,
	.e-n-menu-wrapper .e-n-menu-title.e-current {
		background-color: transparent !important;
		padding-block: 14px;
	}

	/* The current-page bar reads as an underline on a horizontal bar; stacked
	   in a drawer it just looks like a stray dash. */
	.e-n-menu-title[aria-current="page"]::after {
		display: none;
	}
}

/* ---------------------------------------------------------------------------
 * Mega menu columns as an accordion, in the drawer only.
 *
 * Stacked into the drawer the three columns become fourteen links in a row, so
 * each heading discloses its own list. Bound by menu-accordion.js only below
 * 1024px — the width at which the hamburger appears — so the desktop panel keeps
 * showing all three columns at once.
 * ------------------------------------------------------------------------ */

.joker-mm-acc .elementor-widget-icon-list {
	display: none;
}

.joker-mm-acc.is-open .elementor-widget-icon-list {
	display: block;
}

.joker-mm-acc .elementor-heading-title {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px;
	cursor: pointer;
}

/* Chevron, rotating to point up once the column is open. */
.joker-mm-acc .elementor-heading-title::after {
	content: "";
	inline-size: 8px;
	block-size: 8px;
	flex: none;
	border-inline-end: 2px solid currentColor;
	border-block-end: 2px solid currentColor;
	transform: rotate( 45deg ) translate( -2px, -2px );
	transition: transform 0.2s ease;
}

.joker-mm-acc.is-open .elementor-heading-title::after {
	transform: rotate( -135deg ) translate( -2px, -2px );
}

.joker-mm-acc .elementor-heading-title:focus-visible {
	outline: 2px solid #e9b829;
	outline-offset: 4px;
}

/* ---------------------------------------------------------------------------
 * Loop item — service card.
 *
 * Figma Frame 10 574:3457 fills the tile with the media and lays the label and
 * description over it. Elementor's position controls give the widget a box but
 * no height, so the card rendered empty; the media slot's presentation is
 * theme CSS already, and this is the same exception.
 * ------------------------------------------------------------------------ */

/*
 * Elementor gives every widget wrapper position:relative, so an absolute child
 * resolves against that wrapper — which has no height — rather than the card.
 * Positioning the wrapper itself is what ties the media to the tile.
 */
.e-loop-item .elementor-widget-joker-media {
	position: absolute;
	inset: 0;
	z-index: 0;
}

.e-loop-item .elementor-widget-joker-media .elementor-widget-container,
.e-loop-item .joker-loop-card__media {
	block-size: 100%;
}

.e-loop-item .joker-loop-card__media img,
.e-loop-item .joker-loop-card__media video {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	display: block;
}

/* Keeps the label and description legible over the photograph. */
.e-loop-item .joker-loop-card__media::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient( 180deg, rgba( 13, 19, 40, 0.25 ) 0%, rgba( 13, 19, 40, 0.65 ) 100% );
}

.e-loop-item .joker-loop-card__label,
.e-loop-item .joker-loop-card__desc {
	position: relative;
	z-index: 2;
}

/* ---------------------------------------------------------------- About page

   What is left here is only what Elementor Pro has no control for. Everything
   with a native equivalent — grid gaps, widget widths, image opacity and radius,
   arrow styling and placement, list markers and hide-on-mobile — is set on the
   widget so the client can change it, and the footer's one exception lives in
   that widget's own Custom CSS box rather than in this file. */

/*
 * There is no white-space control, and without one "2026" breaks across two
 * lines inside its column. Elementor resets white-space on the heading title
 * itself, so setting it on the wrapper is not enough.
 */
.joker-award__year .elementor-heading-title {
	white-space: nowrap;
}

/* Loop Grid cannot target its last item, and the design closes the list with a rule. */
.joker-awards-grid .elementor-grid-item:last-child .joker-award {
	border-bottom: 1px solid rgba( 255, 255, 255, 0.15 );
}

/*
 * The oversized gold quote mark hangs in the gutter beside the carousel. It is
 * decoration with no widget of its own, and Elementor has no pseudo-element.
 */
.joker-testi-carousel {
	position: relative;
}

.joker-testi-carousel::before {
	content: "\201C";
	position: absolute;
	top: -52px;
	left: -31px;
	color: #e9b829;
	font-family: Georgia, "Times New Roman", serif;
	font-size: 190px;
	line-height: 1;
	pointer-events: none;
}

/*
 * Elementor styles and positions the arrows through its own controls, but has
 * no width or height for the button — only icon size and padding, and padding
 * alone stretches it into an ellipse the height of the slide.
 */
.joker-testi-carousel .elementor-swiper-button {
	width: 48px;
	height: 48px;
}

@media ( max-width: 1024px ) {
	.joker-testi-carousel::before {
		top: -34px;
		left: 0;
		font-size: 120px;
	}

	.joker-testimonial__quote {
		padding-left: 46px;
	}
}

@media ( max-width: 767px ) {
	.joker-testi-carousel::before {
		top: -18px;
		font-size: 84px;
	}

	.joker-testimonial__quote {
		padding-left: 32px;
	}
}
