/*
 * Safiri theme styles.
 *
 * theme.json does the heavy lifting: colours, type, spacing, buttons and
 * element defaults all come from there so the Site Editor can change them.
 * This file holds only what theme.json cannot express — the floating booking
 * affordance, focus and motion handling, and a small set of utility classes
 * that patterns reuse.
 *
 * Mobile first throughout. Every media query widens; none narrows.
 */

/* ---------------------------------------------------------------------------
 * Accessibility
 * ------------------------------------------------------------------------ */

/*
 * WordPress emits its own skip link for block themes. It ships unstyled, so
 * without these rules it is invisible to sighted keyboard users.
 */
.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.skip-link:focus {
	position: fixed !important;
	top: var(--wp--preset--spacing--30);
	left: var(--wp--preset--spacing--30);
	z-index: 100;
	width: auto;
	height: auto;
	clip-path: none;
	padding: 0.75rem 1.25rem;
	background: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--base);
	border-radius: var(--wp--custom--radius--sm);
	text-decoration: none;
}

/*
 * Visible focus on keyboard navigation only. Removing focus rings entirely is
 * the single most common accessibility failure on travel sites, and it makes a
 * booking form impossible to complete without a mouse.
 */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--wp--preset--color--accent);
	outline-offset: 2px;
	border-radius: var(--wp--custom--radius--sm);
}

/* Anything that can be tapped is at least a finger wide. */
.wp-element-button,
.wp-block-button__link,
.safiri-tap {
	min-height: var(--wp--custom--control--min-height);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* A button's label must never wrap. These are pills with a min-height, so
	   a label broken over four lines does not become a taller pill -- it
	   becomes a circle with "Bo ok a trip" stacked inside it. That is what
	   happens the moment a flex row runs out of room and starts shrinking
	   the button, which a long navigation does at the first awkward width. */
	white-space: nowrap;
	flex-shrink: 0;
}

@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;
	}
}

/* ---------------------------------------------------------------------------
 * Utilities used by patterns
 * ------------------------------------------------------------------------ */

/* Small uppercase label above a heading. */
.safiri-eyebrow {
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 500;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--wp--preset--color--accent);
}

.safiri-card {
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: var(--wp--custom--radius--lg);
	overflow: hidden;
}

/* Images inside cards fill their box without distorting. */
.safiri-card img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* A setting nobody has filled in yet renders as an empty paragraph rather
   than as the name of the field. Collapse it, so a half-configured footer
   closes up instead of leaving a hole where a phone number will go.
   Scoped to paragraphs a binding produced, not every empty p on the site --
   .safiri-field is the enquiry form's own input wrapper and an empty one of
   those is a text box waiting to be typed in. */
.safiri-detail p:empty,
.safiri-detail-group p:empty {
	display: none;
}

/* And where the value had a label above it, take the label too. "PHONE" over
   a blank space is worse than no phone column at all: it reads as though the
   number failed to load rather than as though it was never entered. */
.safiri-detail:has(> p:empty) {
	display: none;
}

/* A whole column whose every value is still unset goes as well -- a "Contact"
   heading with nothing under it is the same lie in a different shape. It comes
   back on its own the moment one of the settings is filled in. */
.safiri-detail-group:not(:has(p:not(:empty))) {
	display: none;
}

/* A trip's numbers under its title: "7 days · up to 6 · from $1,850 pp".
   Bound from the trip's own settings; a trip with none set renders an empty
   paragraph, which is collapsed rather than left as a blank line. */
.safiri-trip-meta {
	font-weight: 500;
	color: var(--wp--preset--color--contrast-soft);
	letter-spacing: 0.01em;
}

.has-base-color.safiri-trip-meta {
	color: var(--wp--preset--color--base);
	opacity: 0.9;
}

.safiri-trip-meta:empty {
	display: none;
}

/* An image block nobody has chosen a picture for yet. Without this it is an
   invisible element that keeps its aspect ratio, so a team grid with three
   unset portraits is three holes and a set of captions floating in space.
   A tinted panel says "a photo goes here" and keeps the layout intact. */
.wp-block-image img:not([src]) {
	display: block;
	width: 100%;
	background:
		linear-gradient(135deg, var(--wp--preset--color--surface-alt) 0%, var(--wp--preset--color--border) 100%);
}

/* "Where to go here" is only for countries. A place has nothing under it,
   the loop renders no list, and the heading goes with it. */
.safiri-places:not(:has(.wp-block-post-template)) {
	display: none;
}

/* The trust bar is four settings. Until at least one is filled in it is a
   tinted stripe with nothing in it, so the whole band goes. */
.safiri-trust:not(:has(.safiri-detail > p:not(.safiri-eyebrow):not(:empty))) {
	display: none;
}

/* Social icons render only once they have a URL, so until the operator adds
   one the "Follow" column would be a heading over nothing. */
.safiri-follow:not(:has(.wp-block-social-link)) {
	display: none;
}

/* A quiet divider that matches the border token. */
/* Hidden where horizontal space is scarce; the floating bar covers it.
 *
 * The threshold is not the tablet breakpoint. A header holds a logo, the
 * agency's name, however many items the operator put in their menu, and this
 * button -- and an agency with seven menu items runs out of room long before
 * an agency with three. At 782px a real seven-item menu wrapped onto a second
 * row and squeezed the button until its label broke apart. Below this width
 * the floating bar is the call to action, and it is a better one on a phone
 * anyway. */
/* The doubled class is deliberate. Core gives .wp-block-buttons a display of
   its own from a stylesheet that loads after this one, and at equal
   specificity the later rule wins -- so a single class here lost, and the
   button stayed visible at exactly the widths it needed to disappear. */
.safiri-hide-mobile.safiri-hide-mobile {
	display: none;
}

@media (min-width: 1100px) {
	.safiri-hide-mobile.safiri-hide-mobile {
		display: revert;
	}
}

/* The brand keeps its logo and name on one line and gives up space last; the
   menu is what should wrap, because it can. */
.safiri-header__brand {
	flex-shrink: 0;
}

.safiri-header__nav {
	flex-wrap: wrap;
	justify-content: flex-end;
	min-width: 0;
}

/* Between phone and desktop the header becomes two rows -- brand above, menu
   below -- which reads better than one row with everything crushed into it. */
@media (max-width: 1099px) {
	.safiri-header__row {
		row-gap: var(--wp--preset--spacing--30);
	}

	.safiri-header__nav {
		justify-content: flex-start;
	}
}

.safiri-rule {
	border: 0;
	border-top: 1px solid var(--wp--preset--color--border);
	margin-block: var(--wp--preset--spacing--50);
}

/* ---------------------------------------------------------------------------
 * The floating booking affordance
 *
 * Present on every page. On phones it is a full-width bar pinned to the bottom
 * of the viewport, because a thumb reaches the bottom of a phone and not the
 * corner. From tablet up it becomes a floating pill in the corner, where it
 * does not eat vertical space on a long destination page.
 * ------------------------------------------------------------------------ */

.safiri-book {
	position: fixed;
	z-index: 50;
	inset-inline: 0;
	bottom: 0;
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom, 0px));
	background: var(--wp--preset--color--surface);
	border-top: 1px solid var(--wp--preset--color--border);
	box-shadow: 0 -8px 24px rgb(0 0 0 / 9%);
}

.safiri-book__label {
	flex-grow: 1;
	min-width: 0;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--contrast-soft);
}

.safiri-book .wp-block-buttons,
.safiri-book .wp-block-button {
	flex-shrink: 0;
	margin: 0;
}

.safiri-book .wp-element-button {
	min-height: var(--wp--custom--control--min-height);
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	padding-inline: 1.5rem;
	border-radius: var(--wp--custom--radius--pill);
	background: var(--wp--preset--color--accent);
	color: var(--wp--preset--color--base);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 500;
	text-decoration: none;
}

.safiri-book .wp-element-button:hover,
.safiri-book .wp-element-button:focus {
	background: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--base);
}

/* Keep the last of the page clear of the bar. */
body {
	padding-bottom: 5rem;
}

@media (min-width: 782px) {
	.safiri-book {
		inset-inline: auto;
		inset-inline-end: var(--wp--preset--spacing--40);
		bottom: var(--wp--preset--spacing--40);
		padding: 0;
		background: none;
		border: 0;
		box-shadow: none;
	}

	.safiri-book__label {
		display: none;
	}

	.safiri-book .wp-element-button {
		min-height: 3.5rem;
		padding-inline: 1.75rem;
		box-shadow: var(--wp--preset--shadow--float);
	}

	body {
		padding-bottom: 0;
	}
}

/* The bar is chrome, not content. It has no place on paper. */
@media print {
	.safiri-book,
	.skip-link,
	.wp-block-navigation {
		display: none !important;
	}

	body {
		padding-bottom: 0;
	}
}

/* ---------------------------------------------------------------------------
 * Life
 *
 * Everything below is atmosphere: none of it changes what the operator edits
 * or where it sits. It is what separates a page that is merely correct from
 * one that feels like somewhere you would spend money to go. Every motion
 * respects prefers-reduced-motion through the global rule above.
 * ------------------------------------------------------------------------ */

/* Film grain, as a tiny SVG so it costs no request. Laid over heroes and
   the dark sections at low opacity, it stops flat colour looking like a
   diagram and gives the illustrated posters a photographic finish. */
:root {
	--safiri-grain: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.9 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
	--safiri-ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* The header stays with you, and turns to frosted glass once the page moves. */
.wp-site-blocks > header {
	position: sticky;
	top: 0;
	z-index: 40;
	transition: background-color 0.35s var(--safiri-ease), box-shadow 0.35s var(--safiri-ease), border-color 0.35s var(--safiri-ease);
}

.safiri-scrolled .wp-site-blocks > header {
	background-color: color-mix(in srgb, var(--wp--preset--color--base) 82%, transparent) !important;
	-webkit-backdrop-filter: saturate(160%) blur(14px);
	backdrop-filter: saturate(160%) blur(14px);
	box-shadow: 0 8px 30px rgb(43 35 12 / 8%);
}

/* Heroes: any full-width cover that opens a page. Taller, lit from below,
   and breathing -- the image drifts very slowly, which the eye reads as a
   photograph rather than a graphic. */
.wp-block-post-content > .wp-block-cover:first-child,
main > .wp-block-cover:first-child,
.safiri-hero.wp-block-cover {
	isolation: isolate;
	overflow: hidden;
}

@media (min-width: 782px) {
	.wp-block-post-content > .wp-block-cover:first-child,
	.safiri-hero.wp-block-cover {
		min-height: 82vh;
	}
}

.wp-block-post-content > .wp-block-cover:first-child .wp-block-cover__background,
main > .wp-block-cover:first-child .wp-block-cover__background,
.safiri-hero .wp-block-cover__background {
	/* Replace the flat dim with a gradient: dark where the words are, open
	   at the top where the picture is. */
	background: linear-gradient(to top, rgb(20 15 4 / 82%) 0%, rgb(20 15 4 / 42%) 45%, rgb(20 15 4 / 12%) 100%) !important;
	opacity: 1 !important;
}

.wp-block-post-content > .wp-block-cover:first-child::after,
main > .wp-block-cover:first-child::after,
.safiri-hero.wp-block-cover::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background-image: var(--safiri-grain);
	opacity: 0.18;
	mix-blend-mode: soft-light;
}

.wp-block-post-content > .wp-block-cover:first-child .wp-block-cover__image-background,
main > .wp-block-cover:first-child .wp-block-cover__image-background,
.safiri-hero .wp-block-cover__image-background {
	animation: safiri-drift 26s var(--safiri-ease) both;
	transform-origin: 50% 60%;
	will-change: transform;
}

@keyframes safiri-drift {
	from { transform: scale(1.12); }
	to { transform: scale(1); }
}

/* Inside a hero the words are bigger and tighter, and the eyebrow carries a
   short rule, which is the oldest trick in the luxury-travel book. */
.wp-block-cover .wp-block-cover__inner-container > .wp-block-heading:is(h1) {
	font-size: clamp(2.6rem, 6.5vw, 5.4rem);
	line-height: 1.02;
	letter-spacing: -0.015em;
	text-wrap: balance;
	max-width: 14ch;
	text-shadow: 0 2px 24px rgb(0 0 0 / 25%);
}

.wp-block-cover .safiri-eyebrow::before,
.safiri-eyebrow.has-accent-soft-color::before {
	content: "";
	display: inline-block;
	width: 2.25rem;
	height: 1px;
	margin-right: 0.75rem;
	vertical-align: middle;
	background: currentColor;
	opacity: 0.8;
}

.wp-block-cover .wp-block-cover__inner-container > p:not(.safiri-eyebrow) {
	max-width: 44ch;
	opacity: 0.94;
}

/* The words arrive a beat after the picture. */
.wp-block-cover .wp-block-cover__inner-container > * {
	animation: safiri-rise 0.9s var(--safiri-ease) both;
}

.wp-block-cover .wp-block-cover__inner-container > :nth-child(2) { animation-delay: 0.08s; }
.wp-block-cover .wp-block-cover__inner-container > :nth-child(3) { animation-delay: 0.16s; }
.wp-block-cover .wp-block-cover__inner-container > :nth-child(4) { animation-delay: 0.24s; }
.wp-block-cover .wp-block-cover__inner-container > :nth-child(5) { animation-delay: 0.32s; }

@keyframes safiri-rise {
	from { opacity: 0; transform: translateY(18px); }
	to { opacity: 1; transform: none; }
}

/* Cards. A query grid's items are lists WordPress writes; each becomes a
   card that lifts, with a picture that leans in, on hover. */
.wp-block-post-template.is-layout-grid > li {
	position: relative;
	transition: transform 0.5s var(--safiri-ease);
}

.wp-block-post-template.is-layout-grid > li .wp-block-post-featured-image {
	overflow: hidden;
	border-radius: var(--wp--custom--radius--lg);
	box-shadow: 0 1px 2px rgb(43 35 12 / 6%), 0 10px 30px rgb(43 35 12 / 8%);
	transition: box-shadow 0.5s var(--safiri-ease);
}

.wp-block-post-template.is-layout-grid > li .wp-block-post-featured-image img {
	display: block;
	width: 100%;
	transition: transform 0.9s var(--safiri-ease);
	transform-origin: 50% 60%;
}

.wp-block-post-template.is-layout-grid > li .wp-block-post-featured-image a::after {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(to top, rgb(20 15 4 / 22%), transparent 55%);
	opacity: 0;
	transition: opacity 0.5s var(--safiri-ease);
}

.wp-block-post-template.is-layout-grid > li .wp-block-post-featured-image a {
	position: relative;
	display: block;
}

@media (hover: hover) {
	.wp-block-post-template.is-layout-grid > li:hover {
		transform: translateY(-6px);
	}

	.wp-block-post-template.is-layout-grid > li:hover .wp-block-post-featured-image {
		box-shadow: 0 2px 4px rgb(43 35 12 / 6%), 0 24px 48px rgb(43 35 12 / 16%);
	}

	.wp-block-post-template.is-layout-grid > li:hover .wp-block-post-featured-image img {
		transform: scale(1.06);
	}

	.wp-block-post-template.is-layout-grid > li:hover .wp-block-post-featured-image a::after {
		opacity: 1;
	}
}

.wp-block-post-template.is-layout-grid > li .wp-block-post-title a {
	text-decoration: none;
	color: var(--wp--preset--color--contrast);
	transition: color 0.3s var(--safiri-ease);
}

.wp-block-post-template.is-layout-grid > li:hover .wp-block-post-title a {
	color: var(--wp--preset--color--accent);
}

.wp-block-post-template.is-layout-grid > li .safiri-eyebrow {
	margin-top: 0.9rem;
}

.wp-block-post-template.is-layout-grid > li .wp-block-post-title {
	margin-top: 0.35rem;
}

/* Buttons that feel pressable. */
.wp-element-button,
.wp-block-button__link {
	transition: transform 0.35s var(--safiri-ease), box-shadow 0.35s var(--safiri-ease), background-color 0.35s var(--safiri-ease), color 0.35s var(--safiri-ease);
	box-shadow: 0 1px 2px rgb(43 35 12 / 10%), 0 8px 20px rgb(43 35 12 / 12%);
}

.is-style-outline .wp-block-button__link {
	box-shadow: none;
	-webkit-backdrop-filter: blur(6px);
	backdrop-filter: blur(6px);
}

@media (hover: hover) {
	.wp-element-button:hover,
	.wp-block-button__link:hover {
		transform: translateY(-2px);
		box-shadow: 0 2px 4px rgb(43 35 12 / 10%), 0 14px 30px rgb(43 35 12 / 18%);
	}
}

/* Dark sections take the grain too, and a hairline of gold at the top. */
.has-primary-background-color.alignfull,
.has-contrast-background-color.alignfull:not(.wp-block-cover) {
	position: relative;
	isolation: isolate;
}

.has-primary-background-color.alignfull::before,
.has-contrast-background-color.alignfull:not(.wp-block-cover)::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image: var(--safiri-grain);
	opacity: 0.12;
	mix-blend-mode: soft-light;
	pointer-events: none;
}

.has-primary-background-color.alignfull {
	border-top: 1px solid color-mix(in srgb, var(--wp--preset--color--accent-soft) 55%, transparent);
}

/* Big numbers in the story section read as a statement, not a table. */
.has-primary-background-color .wp-block-heading.has-accent-soft-color.has-xx-large-font-size {
	font-size: clamp(3rem, 6vw, 4.5rem);
	line-height: 1;
}

/* Sections settle into place as you reach them. Movement only, never
   opacity: content that starts invisible is blank to a crawler, a link
   preview, or anyone whose browser never fires the observer. */
.safiri-reveal {
	transform: translateY(18px);
	transition: transform 0.9s var(--safiri-ease);
}

.safiri-reveal.is-visible {
	transform: none;
}

/* Section headings: a touch more room above them, so each part of a page
   is its own moment. */
.wp-block-post-content > .wp-block-group.alignfull,
.wp-block-post-content > .wp-block-group:not(.alignfull) {
	scroll-margin-top: 6rem;
}

.wp-block-post-content > .wp-block-group > .wp-block-heading.has-huge-font-size,
main > .wp-block-group > .wp-block-heading {
	max-width: 22ch;
	text-wrap: balance;
	letter-spacing: -0.01em;
}

/* The floating booking bar becomes glass. */
.safiri-book {
	background: color-mix(in srgb, var(--wp--preset--color--surface) 86%, transparent);
	-webkit-backdrop-filter: saturate(160%) blur(14px);
	backdrop-filter: saturate(160%) blur(14px);
}

/* Tables in destination pages: quieter rules, tinted header. */
.wp-block-table table {
	border-collapse: collapse;
}

.wp-block-table thead th {
	background: var(--wp--preset--color--surface-alt);
	text-align: left;
}

.wp-block-table td,
.wp-block-table th {
	border-color: var(--wp--preset--color--border);
}

/* Selection colour on brand. */
::selection {
	background: var(--wp--preset--color--accent-soft);
	color: var(--wp--preset--color--contrast);
}

/* ---------------------------------------------------------------------------
 * Trip pages
 * ------------------------------------------------------------------------ */

/* The itinerary is a list block with a class. Drawn as a timeline: a gold
   line down the left, a day marker per stop. Delete the class and it is a
   bulleted list again. */
.safiri-itinerary {
	list-style: none;
	padding-left: 0;
	margin-left: 0;
	position: relative;
	counter-reset: safiri-day;
}

.safiri-itinerary::before {
	content: "";
	position: absolute;
	left: 1.1rem;
	top: 0.75rem;
	bottom: 0.75rem;
	width: 1px;
	background: linear-gradient(to bottom, var(--wp--preset--color--accent-soft), var(--wp--preset--color--border));
}

.safiri-itinerary > li {
	position: relative;
	padding: 0.85rem 0 0.85rem 3.4rem;
	margin: 0;
	font-size: var(--wp--preset--font-size--large);
	font-family: var(--wp--preset--font-family--display);
	line-height: 1.3;
}

.safiri-itinerary > li::before {
	counter-increment: safiri-day;
	content: counter(safiri-day);
	position: absolute;
	left: 0;
	top: 0.7rem;
	width: 2.2rem;
	height: 2.2rem;
	border-radius: 50%;
	display: grid;
	place-items: center;
	background: var(--wp--preset--color--contrast);
	color: var(--wp--preset--color--accent-soft);
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
	letter-spacing: 0.04em;
	box-shadow: 0 0 0 4px var(--wp--preset--color--base);
}

/* The sticky card beside the itinerary. */
.safiri-trip-card {
	border: 1px solid var(--wp--preset--color--border);
	border-radius: var(--wp--custom--radius--lg);
	box-shadow: 0 1px 2px rgb(43 35 12 / 5%), 0 18px 40px rgb(43 35 12 / 10%);
}

.safiri-trip-card__price {
	font-family: var(--wp--preset--font-family--display);
	line-height: 1.15;
}

.safiri-trip-card__price:empty,
.safiri-trip-card__fact:empty {
	display: none;
}

.safiri-trip-card__fact {
	padding: 0.55rem 0;
	border-top: 1px solid var(--wp--preset--color--border);
	font-size: var(--wp--preset--font-size--small);
}

.safiri-trip-card__fact a {
	text-decoration: none;
}

@media (min-width: 782px) {
	.safiri-trip-layout > .wp-block-column:last-child > .safiri-trip-card {
		position: sticky;
		top: 6.5rem;
	}
}

/* ---------------------------------------------------------------------------
 * How it works
 * ------------------------------------------------------------------------ */

.safiri-step {
	position: relative;
	padding-top: 0.5rem;
}

.safiri-step__number {
	font-family: var(--wp--preset--font-family--display);
	font-size: clamp(2.5rem, 5vw, 3.75rem);
	line-height: 1;
	color: var(--wp--preset--color--accent);
	margin-bottom: 0.5rem;
}

.safiri-step::before {
	content: "";
	display: block;
	width: 3rem;
	height: 1px;
	margin-bottom: 1.25rem;
	background: var(--wp--preset--color--accent-soft);
}
