/*
Theme Name: GS Travel
Theme URI: https://gstravel-bg.com/
Author: GS Travel
Description: Block theme for GS Travel — airport transfers from Sofia. Standalone rather than a child theme: no parent stylesheet to override and no vendor update cycle, which was the point of leaving the old commercial theme. Route pages assemble themselves from the GS Transfers plugin's records.
Version: 0.8.1
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 8.1
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: gs-travel
Tags: blog, one-column, custom-colors, custom-menu, block-patterns, full-site-editing, translation-ready
*/

/*
 * Almost everything lives in theme.json. What is here is the handful of things
 * theme.json cannot express: the utility-bar layout, tabular figures, the
 * sticky mobile action bar, and focus rings.
 */

:root {
  --gst-radius: 6px;
  --gst-radius-sm: 4px;
}

/* Tabular figures wherever numbers line up — prices, distances, times. */
.gst-num,
.wp-block-table td,
.wp-block-table th {
  font-variant-numeric: tabular-nums;
}

/* Utility bar above the header */
.gst-utility {
  font-size: var(--wp--preset--font-size--x-small);
}

.gst-utility a {
  color: inherit;
}

/*
 * On a phone the bar had four items and wrapped to three rows, eating most of
 * the first screen before the visitor saw anything about transfers. Below the
 * tablet breakpoint the opening hours drop out - they are stated again in the
 * footer and on the 404 page, so nothing is lost - and what remains is squeezed
 * onto one line: the number to call, the apps to call it on, and the language.
 *
 * The number stays first and stays a link. It is the single most valuable
 * element on the page for a business whose customers are often standing in an
 * arrivals hall.
 */
@media (max-width: 47.99rem) {
  .gst-utility {
    padding-top: 0.4rem !important;
    padding-bottom: 0.4rem !important;
  }

  .gst-utility__hours {
    display: none;
  }

  /* The two inner groups: contact details, and the language switcher. */
  .gst-utility .wp-block-group {
    flex-wrap: nowrap;
    gap: 0.75rem;
  }

  .gst-utility p {
    white-space: nowrap;
  }
}

/*
 * Narrower still - a 360px Android or an older iPhone SE - and even two labels
 * plus the switcher will not fit. The phone number and the language survive;
 * "Viber and WhatsApp" goes, because the icons in the sticky bar and the
 * contacts page carry that information anyway.
 */
@media (max-width: 23rem) {
  .gst-utility__apps {
    display: none;
  }
}

/* Eyebrow label — used above headings throughout */
.gst-eyebrow {
  font-size: var(--wp--preset--font-size--x-small);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--wp--preset--color--brand);
  margin: 0;
}

/* Cards: one radius, one border, no shadow stamped on everything */
.gst-card {
  background: var(--wp--preset--color--surface);
  border: 1px solid var(--wp--preset--color--line);
  border-radius: var(--gst-radius);
}

/* Prose measure — long text should not run the full wide width */
.gst-measure {
  max-width: var(--wp--custom--measure);
}

/* Visible focus for keyboard users, since we removed link underlines */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--wp--preset--color--brand);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Skip link */
.skip-link:focus {
  background: var(--wp--preset--color--surface);
  color: var(--wp--preset--color--ink);
  padding: 0.75rem 1.25rem;
  z-index: 100000;
}

/* Sticky mobile action bar — the pattern the design leans on */
.gst-sticky-bar {
  position: fixed;
  inset: auto 0 0 0;
  background: var(--wp--preset--color--surface);
  border-top: 1px solid var(--wp--preset--color--line-strong);
  box-shadow: 0 -2px 14px rgba(23, 26, 36, 0.09);
  z-index: 20;
  padding: 0.75rem var(--wp--preset--spacing--40);
}

@media (min-width: 782px) {
  .gst-sticky-bar { display: none; }
}

@media (max-width: 781px) {
  body.gst-has-sticky-bar { padding-bottom: 5.5rem; }
}

/* The logo inherits colour, so one file works on light and dark grounds */
.gst-logo svg,
.gst-logo img {
  display: block;
  height: 3.25rem;
  width: auto;
  color: var(--wp--preset--color--brand);
}

.gst-logo--footer svg { color: var(--wp--preset--color--surface); }

@media (max-width: 781px) {
  .gst-logo svg,
  .gst-logo img { height: 2.25rem; }
}

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

/*
 * Links on the dark footer and utility bar. theme.json sets one link colour for
 * the whole document, and brand indigo on brand-deep is unreadable — so these
 * two dark surfaces override it rather than every light surface working around it.
 */
.gst-footer a,
.gst-utility a {
  color: var(--wp--preset--color--surface);
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
}

.gst-footer a:hover,
.gst-footer a:focus-visible,
.gst-utility a:hover,
.gst-utility a:focus-visible {
  color: var(--wp--preset--color--surface);
  text-decoration: underline;
}

.gst-footer a:focus-visible,
.gst-utility a:focus-visible {
  outline-color: var(--wp--preset--color--surface);
}

/* The eyebrow sits on dark grounds too, where brand indigo disappears. */
.gst-footer .gst-eyebrow,
.gst-utility .gst-eyebrow {
  color: color-mix(in srgb, var(--wp--preset--color--surface) 72%, transparent);
}

/*
 * The legal line is a statutory disclosure, not a message. Dimming it keeps the
 * footer hierarchy intact while leaving it comfortably readable on brand-deep.
 * color-mix rather than opacity, to match the eyebrow rule above.
 */
.gst-footer .gst-legal {
  color: color-mix(in srgb, var(--wp--preset--color--surface) 78%, transparent);
  line-height: 1.5;
  /* No max-width here on purpose. Constrained layout centres any child narrower
     than the container using !important margins, so capping the measure
     indented this line away from the notice above it. */
}

/* ---------- breadcrumbs ---------- */

.gst-crumbs {
  font-size: var(--wp--preset--font-size--x-small);
  color: var(--wp--preset--color--ink-3);
}

.gst-crumbs a {
  color: inherit;
}

.gst-crumbs__sep {
  margin: 0 0.15rem;
  color: var(--wp--preset--color--line-strong);
}

.gst-crumbs [aria-current="page"] {
  color: var(--wp--preset--color--ink-2);
}

/* ---------- hero promises ---------- */

/*
 * A tick rather than a bullet, drawn in CSS. It says "included" where a bullet
 * only says "item", and it costs no image request.
 */
.gst-promises {
  list-style: none;
  padding: 0;
  display: grid;
  gap: 0.65rem;
}

.gst-promises li {
  position: relative;
  padding-left: 1.9rem;
  color: var(--wp--preset--color--ink-2);
}

.gst-promises li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.34em;
  width: 1.1rem;
  height: 0.6rem;
  border-left: 2px solid var(--wp--preset--color--go);
  border-bottom: 2px solid var(--wp--preset--color--go);
  transform: rotate(-45deg);
}

/* ---------- specification and company-data rows ---------- */

.gst-spec {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem 1rem;
  justify-content: space-between;
  align-items: baseline;
  margin: 0;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--wp--preset--color--line);
}

.gst-spec:last-child {
  border-bottom: 0;
}

.gst-spec__label {
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--ink-3);
}

.gst-spec__value {
  font-weight: 500;
  text-align: right;
  flex: 1 1 55%;
}

/* ---------- how it works ---------- */

.gst-step-num {
  font-size: var(--wp--preset--font-size--large);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--wp--preset--color--brand);
  margin: 0;
  padding-bottom: 0.6rem;
  border-bottom: 2px solid var(--wp--preset--color--brand-tint);
}

/* ---------- reviews ---------- */

.gst-review {
  height: 100%;
}

.gst-review__by {
  margin-bottom: 0;
}

/* ---------- long-form content ---------- */

/*
 * Content pages set their own measure rather than inheriting the wide layout,
 * because a 75rem paragraph is unreadable. Wide and full-width blocks inside
 * the content still escape it, which is what those alignments are for.
 */
.gst-prose > :not(.alignwide):not(.alignfull) {
  max-width: var(--wp--custom--measure);
  margin-left: auto;
  margin-right: auto;
}


/*
 * The trust strip keeps five columns side by side on a desktop, but at phone
 * width that gave each claim about forty pixels and wrapped "№10607" down the
 * page one character at a time. Two per row below 782px, and the numbers come
 * down in size to match.
 */
@media (max-width: 781px) {
  /* The generated layout container pins flex-wrap to nowrap, so five columns
     kept sharing one line and shrank to 48px each. */
  .gst-trust.is-not-stacked-on-mobile {
    flex-wrap: wrap !important;
    gap: var(--wp--preset--spacing--30);
  }

  .gst-trust.is-not-stacked-on-mobile > .wp-block-column {
    flex-basis: calc(50% - var(--wp--preset--spacing--30) / 2) !important;
    flex-grow: 0;
    flex-shrink: 0;
  }

  .gst-trust .gst-num {
    font-size: var(--wp--preset--font-size--large);
  }
}

/*
 * A page whose content is still empty should not reserve a screenful of
 * padding for it. Harmless once Phase 4 fills these in.
 */
.gst-page-body:has(> .entry-content:empty) {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

/*
 * Route-page prose: a reading measure without centring.
 *
 * Constrained layout would centre these blocks inside the column and leave
 * them indented from the price table directly above, so the column has no
 * single left edge. Default layout adds no auto margins, so a max-width alone
 * caps the line length and keeps everything flush left. Wide and full-width
 * blocks still escape it.
 */
.gst-route-prose > :not(.alignwide):not(.alignfull) {
  max-width: var(--wp--custom--measure);
}

/* ---------- what the price includes ---------- */

.gst-includes {
  border-radius: var(--gst-radius);
}

.gst-includes__list {
  margin: 0;
  padding-left: 1.15rem;
  font-size: var(--wp--preset--font-size--small);
}

.gst-includes__list li {
  margin-bottom: 0.3rem;
}

.gst-includes__list li:last-child {
  margin-bottom: 0;
}

/* ---------- language switcher ---------- */

/* Sits in the dark utility bar. The current language is not a link, so it is
   distinguished by weight rather than colour - a colour difference there would
   read as "disabled" rather than "you are here". */
.gst-lang {
	margin: 0;
	display: flex;
	align-items: center;
	gap: 0;
}

.gst-lang__current {
	font-weight: 600;
}

.gst-lang__link {
	opacity: 0.75;
}

.gst-lang__link:hover,
.gst-lang__link:focus {
	opacity: 1;
}

.gst-lang__sep {
	opacity: 0.45;
}

/* ---------- consent banner ---------- */

/* Bottom of the viewport rather than a full-screen overlay. An overlay that
   blocks the page until you answer is coercion dressed as a choice, and it also
   means a first-time visitor cannot read the privacy notice the banner links
   to. */
.gst-consent {
	position: fixed;
	inset-inline: 0;
	bottom: 0;
	z-index: 60;
	background: var(--wp--preset--color--surface, #fff);
	border-top: 2px solid var(--wp--preset--color--brand, #4C5BA3);
	box-shadow: 0 -6px 24px rgba(23, 26, 36, 0.14);
	padding: 1rem 1.2rem;
}

.gst-consent__inner {
	max-width: 75rem;
	margin: 0 auto;
	display: flex;
	flex-wrap: wrap;
	gap: 0.9rem 1.6rem;
	align-items: center;
	justify-content: space-between;
}

.gst-consent__text {
	flex: 1 1 26rem;
	font-size: 0.875rem;
	line-height: 1.5;
}

.gst-consent__text p {
	margin: 0;
}

.gst-consent__title {
	margin-bottom: 0.2rem !important;
}

.gst-consent__actions {
	display: flex;
	gap: 0.6rem;
	flex: 0 0 auto;
}

/* Both buttons are styled identically and differ only in their words.
   There is no primary action here: accepting and refusing are equally valid
   answers, and a filled "accept" beside an outlined "decline" tilts the
   choice even when both are one click. The first version of this file said
   "identical on purpose" in a comment and then made one of them filled - the
   comment was describing an intention the code did not carry out. */
.gst-consent__btn {
	font: inherit;
	font-size: 0.875rem;
	font-weight: 600;
	padding: 0.55rem 1.1rem;
	border: 1px solid var(--wp--preset--color--brand, #4C5BA3);
	border-radius: 4px;
	background: transparent;
	color: var(--wp--preset--color--brand-deep, #2F3A72);
	cursor: pointer;
	min-width: 8.5rem;
}

.gst-consent__btn:hover,
.gst-consent__btn:focus-visible {
	filter: brightness(1.08);
}

@media (max-width: 40rem) {
	.gst-consent__actions {
		width: 100%;
	}

	.gst-consent__btn {
		flex: 1 1 0;
	}
}
