/* ==========================================================================
   GrowthStudioz — base
   Single source of truth for colour, type, spacing, radius, motion.

   Every value in the COLOUR and TYPE blocks is transcribed verbatim from the
   GrowthStudioz Figma brand system. Do not "improve" them.

   Values marked DERIVED are not in the Figma file. They were built to be
   consistent with what is, and should be confirmed against the design before
   launch. They are flagged so nobody later mistakes them for brand truth.
   ========================================================================== */

/* ==========================================================================
   DM Sans — self-hosted, latin subset.

   Self-hosted rather than called from Google Fonts: font-optimisation plugins
   across the UFC fleet have a standing habit of rewriting or dropping css2
   requests, which silently takes the typeface with it. Matches how the parent
   theme ships host-grotesk, space-grotesk and jetbrains-mono.

   font-display: swap — text paints immediately in the fallback and reflows,
   rather than holding a blank page while the font loads.
   ========================================================================== */

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-400-latin.woff2") format("woff2");
}

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-500-latin.woff2") format("woff2");
}

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-600-latin.woff2") format("woff2");
}

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 700;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-700-latin.woff2") format("woff2");
}

/* ExtraBold, for the Launchpad hero heading (Figma: DM Sans 800, 6th October
   2026). Without it the browser picks the 900 file for 800, visibly heavier.
   From the same Google Fonts source as the files above (its 700 is
   byte-identical to ours), so the metrics match. */
@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 800;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-800-latin.woff2") format("woff2");
}

/* Black. The Figma heading on the division CTA is weight 900, and without the
   real file the browser synthesises a fake bold from 700 — thicker strokes
   smeared on, not the drawn Black cut, which reads visibly wrong at display
   sizes. */
@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 900;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-900-latin.woff2") format("woff2");
}

/* The rupee sign. The files above are the Latin subset, which stops short of
   U+20B9, so "₹5 Cr+" on the Performance stat tiles fell back to a system
   font for that one character. This is DM Sans's own glyph, cut out of its
   variable Latin Extended file: 1.3KB, and the unicode-range means the
   browser only fetches it on a page that actually prints a ₹.

   ONE RULE PER WEIGHT, each with exactly the weight of a rule above. Do not
   collapse these into a single `font-weight: 100 1000` rule. A browser first
   picks the faces whose weight descriptor matches, and only then looks at
   unicode-range; a range rule matched EVERY weight, was picked ahead of the
   real files, and, holding one glyph, sent all other text on the site to the
   fallback font (1st October 2026, live for a few minutes). With the same
   single weight as the Latin rule, the two are merged into one face and the
   range only decides which file a character comes from. */
@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 400;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-rupee.woff2") format("woff2");
	unicode-range: U+20B9;
}

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-rupee.woff2") format("woff2");
	unicode-range: U+20B9;
}

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-rupee.woff2") format("woff2");
	unicode-range: U+20B9;
}

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 700;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-rupee.woff2") format("woff2");
	unicode-range: U+20B9;
}

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 800;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-rupee.woff2") format("woff2");
	unicode-range: U+20B9;
}

@font-face {
	font-family: "DM Sans";
	font-style: normal;
	font-weight: 900;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-rupee.woff2") format("woff2");
	unicode-range: U+20B9;
}

/* Medium italic, for one thing so far: the quotes on the Launchpad's pain
   cards on a phone (Adarsh's phone frame, 6th October 2026). Without a real
   italic file the browser slants the upright one, which looks cheap. A
   browser only downloads a face it actually renders text in, so no other page
   pays for these.

   Two files, split the way Google serves them: Latin, and Latin Extended for
   the rupee sign ("I spent ₹2 lakh"). An italic ₹ cannot borrow the upright
   rupee face above: a browser matches the style first, so it would fall to a
   system font for that one character. */
@font-face {
	font-family: "DM Sans";
	font-style: italic;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-500-italic-latin.woff2") format("woff2");
	unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
	font-family: "DM Sans";
	font-style: italic;
	font-weight: 500;
	font-display: swap;
	src: url("../fonts/dm-sans/dm-sans-500-italic-latin-ext.woff2") format("woff2");
	unicode-range: U+20B9;
}

/* Inter — SECOND family, loaded for one thing only.

   The statement band's three claim lines are Inter in Figma while everything
   around them, including that band's own body copy, is DM Sans. Only the two
   weights those lines use are self-hosted; nothing else on the site may reach
   for this family, or the "one family, hierarchy from weight" rule the type
   system is built on stops being true. */
@font-face {
	font-family: "Inter";
	font-style: normal;
	font-weight: 600;
	font-display: swap;
	src: url("../fonts/inter/inter-600-latin.woff2") format("woff2");
}

@font-face {
	font-family: "Inter";
	font-style: normal;
	font-weight: 700;
	font-display: swap;
	src: url("../fonts/inter/inter-700-latin.woff2") format("woff2");
}

:root {

	/* --- colour: brand ------------------------------------------------
	   Figma "Colors" collection. */

	--gs-black: #000000;              /* Black  — ink, headings, body strong */
	--gs-red: #F80000;                /* G2     — brand red */

	/* Figma "Diagonal Red Stroke". Decorative only: rules, underlines,
	   accent strokes. Never a text fill, never a large surface. */
	--gs-red-stroke: linear-gradient(135deg, #FF9BA6 0%, #F80000 100%);

	/* --- colour: divisions --------------------------------------------
	   One hue per division. A division colour identifies that division and
	   nothing else — it is never a generic accent, never a UI state. */

	--gs-ux19: #FFDD00;               /* UX19 */
	--gs-pm-red: #E11D2E;             /* Performance Marketing */
	--gs-studio19: #FF6D24;           /* Studio19 */
	--gs-narrativ: #000000;           /* Narrativ */

	/* Deep red. NOT in the Figma brand file — supplied by Adarsh 17th September
	   2026 for the clients band text. Kept as a token rather than a loose hex so
	   it can be found and changed in one place. */
	--gs-red-deep: #BC101E;

	/* Highlight red for a stat called out inside body copy. Supplied by Adarsh
	   18th September 2026. Same value as the Performance Marketing division
	   red, but a separate token because the roles are unrelated — one is a
	   division's identity, the other is emphasis, and they must be free to
	   diverge. */
	--gs-red-highlight: #E11D2E;

	/* Testimonial card border gradient. Supplied by Adarsh 17th September 2026,
	   not in the Figma brand file. */
	--gs-card-border-from: #E0E0E0;
	--gs-card-border-to: #FF2222;

	/* Sub-heading grey. Supplied by Adarsh 18th September 2026; not in the
	   Figma brand file, and distinct from Text Grey #545454. */
	--gs-subhead: #4A4A48;

	/* Softer body grey, for copy set inside a card rather than on the page.
	   Supplied by Adarsh 18th September 2026. Lighter than Text Grey #545454,
	   which stays the default everywhere else. */
	--gs-body-soft: #737373;

	/* --- colour: neutrals ----------------------------------------------
	   Figma "Variable collection / Mode 1". */

	--gs-text-grey: #545454;          /* Text Grey — body copy */
	--gs-grey-l: #F1F1F1;             /* L Grey    — light surface */
	--gs-grey-m: #DDDDDD;             /* M Grey    — borders, dividers */
	--gs-white: #FFFFFF;

	/* --- colour: semantic roles -----------------------------------------
	   Components reference THESE, not the raw brand values above. Changing a
	   role here re-skins the site; changing a brand value above breaks it. */

	--gs-ink: var(--gs-black);
	--gs-body: var(--gs-text-grey);
	--gs-surface: var(--gs-white);
	--gs-surface-alt: var(--gs-grey-l);
	--gs-border: var(--gs-grey-m);
	--gs-action: var(--gs-black);     /* buttons are ink-on-white outlines */
	--gs-accent: var(--gs-red);       /* the single red moment per view */

	/* Dark surfaces (the footer). Foregrounds are declared as their own roles
	   rather than flipped ad hoc at the component: a dark region that borrows
	   --gs-ink renders black-on-black. Hairlines are a white alpha, not a grey
	   hex, so they read correctly over the red bloom too. */

	--gs-surface-dark: var(--gs-black);
	--gs-on-dark: var(--gs-white);
	--gs-on-dark-muted: rgb(255 255 255 / 68%);
	--gs-border-dark: rgb(255 255 255 / 14%);

	/* --- type: family ---------------------------------------------------
	   DM Sans across the whole system. One family, hierarchy from weight and
	   scale, per the Figma type sheet. */

	--gs-font: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI",
		Roboto, "Helvetica Neue", Arial, sans-serif;

	--gs-weight-regular: 400;
	--gs-weight-medium: 500;
	--gs-weight-semibold: 600;
	--gs-weight-bold: 700;

	/* --- type: display --------------------------------------------------
	   Figma gives tracking in px at a fixed size. Converted to em so it holds
	   when the size fluids down:
	     H1  -3.02px / 64px = -0.0472em
	     H2  -2.18px / 48px = -0.0454em
	     H3  -1.50px / 32px = -0.0469em
	   Consistent enough to be one rule. */

	--gs-h1: 4rem;                    /* 64px */
	--gs-h2: 3rem;                    /* 48px */
	--gs-h3: 2rem;                    /* 32px */
	--gs-tracking-display: -0.047em;

	/* Every section heading on the page, one size: 64 on desktop, 32 on a
	   phone (Adarsh, 23rd September 2026). They had drifted to 48/64 desktop
	   and 32/40/48 mobile, section by section. Mobile-first like the gutter and
	   the section padding: phone value here, stepped up at 768. Sections must
	   use this token and never --gs-h1/--gs-h2 directly for their heading, or
	   the drift comes straight back. */
	--gs-section-title: var(--gs-h3);

	/* --- type: body ------------------------------------------------------
	   All Regular, all 0% tracking, per Figma. */

	--gs-b1: 1.5rem;                  /* 24px */
	--gs-b2: 1.25rem;                 /* 20px */
	--gs-b3: 1rem;                    /* 16px */
	--gs-b4: 0.875rem;                /* 14px */
	--gs-b5: 0.75rem;                 /* 12px */

	/* --- type: label -----------------------------------------------------
	   Figma "Label": 24px Bold, 56% tracking. Extreme by design. Reserve for
	   short wide-set labels; never a sentence, never body copy. */

	--gs-label: 1.5rem;               /* 24px */
	--gs-tracking-label: 0.56em;

	/* --- type: line height ----- DERIVED ---------------------------------
	   Figma says "Automatic" everywhere, which is the renderer default rather
	   than a decision. These are explicit so rendering is identical across
	   browsers. Confirm against the design before launch. */

	--gs-lh-display: 1.08;
	--gs-lh-heading: 1.15;
	--gs-lh-body: 1.55;
	--gs-lh-tight: 1.3;

	/* --- spacing ------------- DERIVED -----------------------------------
	   Not present in the Figma extract supplied. 4px base, doubling with
	   half-steps where layouts need them. Confirm against the design. */

	--gs-space-1: 0.25rem;            /*  4px */
	--gs-space-2: 0.5rem;             /*  8px */
	--gs-space-3: 0.75rem;            /* 12px */
	--gs-space-4: 1rem;               /* 16px */
	--gs-space-5: 1.5rem;             /* 24px */
	--gs-space-6: 2rem;               /* 32px */
	--gs-space-7: 3rem;               /* 48px */
	--gs-space-8: 4rem;               /* 64px */
	--gs-space-9: 5rem;               /* 80px */
	--gs-space-10: 6rem;              /* 96px */
	--gs-space-11: 8rem;              /* 128px */

	/* --- layout ----------------------------------------------------------
	   Full-bleed by design: no container cap, so chrome runs edge to edge and
	   the 60px gutter is the only thing holding it off the viewport edge. A
	   1200px cap was leaving dead space either side on wide screens, which the
	   mockups do not have.

	   60px inline padding, confirmed by Adarsh 17th September 2026. Steps down
	   on narrow viewports so the gutter never eats the content. */

	--gs-gutter: var(--gs-space-4);      /* 16px, under 768px */
	--gs-gutter-md: var(--gs-space-6);   /* 32px, tablet */
	--gs-gutter-lg: 3.75rem;             /* 60px, desktop */

	/* The gutter actually in force at the current width. The three values above
	   are applied by media query rather than by redefining one token, so a
	   section breaking out of the gutter otherwise has to repeat all three
	   breakpoints itself (the hero does). This resolves once, here, so a
	   full-bleed section needs a single negative-margin rule and cannot drift
	   out of step with the padding it is cancelling. */
	--gs-gutter-now: var(--gs-gutter);

	/* Vertical rhythm for a full-width section. Every band uses THIS, so the
	   page keeps one cadence instead of each section carrying its own number
	   (they had drifted to 48 / 64 / 48 / 64 / 40 on desktop).

	   HALF the gap, not the gap. Adarsh, 23rd September 2026: the space
	   between any two sections is 80px sitewide. A section cannot know what
	   follows it, so each contributes half and the two halves meet: 40 + 40.

	   It is padding rather than a margin because most of these bands carry a
	   background. A margin would put a white strip between the red creatives
	   band and the grey case studies band, which is exactly the seam we were
	   asked to remove. As padding, the colours meet flush and the 80px is
	   breathing room INSIDE them.

	   Phones get their own gap (Adarsh, 25th September 2026): 45px between
	   sections, so 22.5 each. This is the phone value; the 768px block below
	   restores 40, the 80px gap, from tablet up. */
	--gs-section-pad: 1.40625rem;     /* 22.5px, half of the 45px phone gap */

	/* --- radius ----------------------------------------------------------
	   8px everywhere, confirmed by Adarsh 17th September 2026. The header CTA
	   is 8px, NOT the pill it appears to be in the mockup. */

	--gs-radius-sm: 4px;
	--gs-radius: 8px;

	/* --- buttons ---------------------------------------------------------
	   ONE button size sitewide (Adarsh, 23rd September 2026): a button differs
	   from another button by width, colour and text, never by padding or type
	   size. Text is the Figma button spec, 20px on desktop and 16px on a
	   phone; the padding holds at 16/32 either way, which is what the hero,
	   footer, packages and form submit already rendered. Mobile-first. */

	--gs-btn-size: var(--gs-b3);      /* 16px on phones */
	--gs-btn-pad-y: var(--gs-space-4);
	--gs-btn-pad-x: var(--gs-space-6);

	/* --- borders ---------------------------------------------------------
	   Hairlines only. A border thicker than 1px is a deliberate statement,
	   never decoration. */

	--gs-border-width: 1px;
	--gs-border-rule: var(--gs-border-width) solid var(--gs-border);

	/* --- motion ----------------------------------------------------------
	   Custom curves; the CSS built-ins are too weak to read as intentional.
	   Never ease-in on UI: it delays the first frame, which is exactly when
	   the user is looking. */

	--gs-ease-out: cubic-bezier(0.23, 1, 0.32, 1);
	--gs-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
	--gs-ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

	--gs-dur-press: 140ms;            /* button press feedback */
	--gs-dur-hover: 150ms;            /* colour changes */
	--gs-dur-enter: 300ms;            /* drawer, panel in */
	--gs-dur-exit: 200ms;             /* exit is always faster than enter */

	/* --- z-index ---------------------------------------------------------
	   A named scale. Never an arbitrary 999. */

	--gs-z-dropdown: 100;
	--gs-z-sticky: 200;
	--gs-z-drawer-backdrop: 300;
	--gs-z-drawer: 310;
	--gs-z-toast: 400;
}

/* ==========================================================================
   Element defaults
   ========================================================================== */

/* Border-box everywhere. Without it, any element combining width:100% with
   padding overflows its parent by exactly that padding, which is how a 375px
   viewport ends up scrolling 32px sideways. */
*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
	text-size-adjust: 100%;
}

/* No page scrollbar on screens driven by a mouse or trackpad (Adarsh, 29th
   September 2026). The page still scrolls by wheel, trackpad and keys. Phones
   are left alone: theirs is a thin overlay that takes no width. Hiding it on
   desktop also hands back the 15px Windows and Linux reserve for it, so a
   1440 screen lays out at 1440, as the Figma frames do. */
@media (hover: hover) and (pointer: fine) {
	html {
		scrollbar-width: none;
	}

	html::-webkit-scrollbar,
	body::-webkit-scrollbar {
		display: none;
	}
}

body {
	margin: 0;
	background: var(--gs-surface);
	color: var(--gs-body);
	font-family: var(--gs-font);
	font-size: var(--gs-b3);
	font-weight: var(--gs-weight-regular);
	line-height: var(--gs-lh-body);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

/* Headings are ink, not body grey: the contrast step is part of the
   hierarchy, not a colour preference. */

h1, h2, h3, h4, h5, h6 {
	margin: 0;
	color: var(--gs-ink);
	font-weight: var(--gs-weight-semibold);
	letter-spacing: var(--gs-tracking-display);
	line-height: var(--gs-lh-display);
	text-wrap: balance;
}

h1 { font-size: var(--gs-h1); }
h2 { font-size: var(--gs-h2); }
h3 { font-size: var(--gs-h3); line-height: var(--gs-lh-heading); }

/* h4-h6 are not in the Figma type sheet. Stepping down from h3 keeps the
   ratio consistent rather than inventing new display sizes. DERIVED. */
h4 { font-size: var(--gs-b1); line-height: var(--gs-lh-tight); }
h5 { font-size: var(--gs-b2); line-height: var(--gs-lh-tight); }
h6 { font-size: var(--gs-b3); line-height: var(--gs-lh-tight); }

p {
	margin: 0 0 var(--gs-space-4);
	text-wrap: pretty;
}

/* No measure cap: the layout is full-bleed by request, so prose runs the width
   of its container. Reinstate a max-width here if lines ever need reining in. */

a {
	color: inherit;
	text-decoration-thickness: 1px;
	text-underline-offset: 4px;
	transition: color var(--gs-dur-hover) ease;
}

/* A button is not body text, so it is excluded here rather than every button
   having to out-specify this rule in its own file. That guard was repeated in
   creatives.css, packages.css and divisions.css as `:where(.gs-x) .gs-x__cta`
   and is now unnecessary. */
@media (hover: hover) and (pointer: fine) {
	a:not(.gs-btn):hover { color: var(--gs-accent); }
}

/* A menu item whose page is not built yet (class gs-soon in Menus): still
   listed, greyed out, not a link. header.php takes its href away; no pointer
   events, so it never turns red on hover. Opacity rather than a colour so it
   reads on the white header and the black footer alike. */
.menu-item.gs-soon > a {
	opacity: 0.4;
	cursor: default;
	pointer-events: none;
}

/* Brand-red focus ring, always visible. Never outline:none without a
   replacement. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 2px solid var(--gs-accent);
	outline-offset: 2px;
	border-radius: var(--gs-radius-sm);
}

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

hr {
	height: 0;
	margin: var(--gs-space-6) 0;
	border: 0;
	border-top: var(--gs-border-rule);
}

/* ==========================================================================
   Type utilities
   Named for the Figma styles so design and code share one vocabulary.
   ========================================================================== */

.gs-b1 { font-size: var(--gs-b1); }
.gs-b2 { font-size: var(--gs-b2); }
.gs-b3 { font-size: var(--gs-b3); }
.gs-b4 { font-size: var(--gs-b4); }
.gs-b5 { font-size: var(--gs-b5); }

.gs-b3--medium {
	font-size: var(--gs-b3);
	font-weight: var(--gs-weight-medium);
}

.gs-label {
	font-size: var(--gs-label);
	font-weight: var(--gs-weight-bold);
	letter-spacing: var(--gs-tracking-label);
	line-height: var(--gs-lh-tight);
	/* 0.56em of tracking adds a trailing gap after the last glyph; pulling it
	   back keeps the label optically aligned to its container. */
	margin-right: calc(var(--gs-tracking-label) * -1);
}

.gs-ink { color: var(--gs-ink); }
.gs-muted { color: var(--gs-body); }
.gs-accent { color: var(--gs-accent); }

/* ==========================================================================
   Division theming
   Scope a division colour by class; components read --gs-division and never
   name a division colour directly. Keeps one card component working for all
   three rather than three near-identical ones.
   ========================================================================== */

.gs-division--ux19 { --gs-division: var(--gs-ux19); }
.gs-division--pm { --gs-division: var(--gs-pm-red); }
.gs-division--studio19 { --gs-division: var(--gs-studio19); }
.gs-division--narrativ { --gs-division: var(--gs-narrativ); }

/* UX19 yellow fails contrast against white for text. Anything sitting ON a
   division fill must set its own foreground; ink is correct for yellow and
   orange, white for PM red and for Narrativ's black.

   Narrativ is #000000, which means it is invisible on a dark surface. It is an
   identity token for light backgrounds only — on the dark footer, use the
   default foreground and let the label carry the identity. */
.gs-division--ux19 { --gs-division-ink: var(--gs-black); }
.gs-division--studio19 { --gs-division-ink: var(--gs-black); }
.gs-division--pm { --gs-division-ink: var(--gs-white); }
.gs-division--narrativ { --gs-division-ink: var(--gs-white); }

/* ==========================================================================
   Layout primitives
   ========================================================================== */

.gs-container,
main.wp-block-group {
	width: 100%;
	padding-inline: var(--gs-gutter);
}

@media (min-width: 768px) {
	:root {
		--gs-gutter-now: var(--gs-gutter-md);
		--gs-section-title: var(--gs-h1);
		--gs-btn-size: var(--gs-b2);
		--gs-section-pad: 2.5rem;     /* 40px, half of the 80px gap */
	}

	.gs-container,
	main.wp-block-group { padding-inline: var(--gs-gutter-md); }
}

@media (min-width: 1024px) {
	:root { --gs-gutter-now: var(--gs-gutter-lg); }

	.gs-container,
	main.wp-block-group { padding-inline: var(--gs-gutter-lg); }
}

/* The "Wide page" template (first: Case Studies, Adarsh, 26th September
   2026) sits further in than the global gutter: 80px a side on desktop, 20 on
   a phone, 40 between. Set as the gutter itself, not extra padding, so every
   band inside that breaks out to the edges with --gs-gutter-now still lands
   exactly on them. Header and footer keep the global gutter. A case study's
   own page uses the same. */
.page-template-page-wide main.wp-block-group,
.single-gs_case_study main.wp-block-group {
	--gs-gutter-now: 1.25rem;              /* 20px */
	padding-inline: var(--gs-gutter-now);
}

@media (min-width: 768px) {
	.page-template-page-wide main.wp-block-group,
	.single-gs_case_study main.wp-block-group { --gs-gutter-now: 2.5rem; }     /* 40px */
}

@media (min-width: 1024px) {
	.page-template-page-wide main.wp-block-group,
	.single-gs_case_study main.wp-block-group { --gs-gutter-now: 5rem; }       /* 80px */
}

.gs-stack > * + * { margin-block-start: var(--gs-space-4); }

/* ==========================================================================
   Main to footer

   Two spacings stacked below the last block on every page: main's own bottom
   padding (54px, set inline by the parent template) and WP's block gap above
   the footer (24px). The footer carries its own top padding, so that 78px read
   as a void before the black band.

   The block gap goes everywhere. main's padding goes ONLY where the last thing
   on the page is a section that supplies its own — zeroing it site-wide was
   tried first and left the last paragraph of /faq/ touching the black footer
   at 0px. Pages ending in body copy keep their breathing room.

   !important is needed because the parent template writes that padding as an
   inline style, which no stylesheet can otherwise outrank.
   ========================================================================== */

main.wp-block-group:has(.entry-content > .gs-form-section:last-child) {
	padding-block-end: 0 !important;
}

/* Same at the top: a full-bleed hero is the first thing on the page and should
   meet the header. Two separate spacings again — main's own top padding (36px,
   inline style) and WP's block gap above main (24px margin). Both go. */
main.wp-block-group:has(.entry-content > .gs-hero:first-child),
main.wp-block-group:has(.entry-content > .gs-page-hero:first-child),
main.wp-block-group:has(.entry-content > .gs-launch:first-child) {
	margin-block-start: 0 !important;
	padding-block-start: 0 !important;
}

.wp-site-blocks > footer.wp-block-template-part {
	margin-block-start: 0;
}
.gs-stack--lg > * + * { margin-block-start: var(--gs-space-6); }

/* ==========================================================================
   Buttons

   ONE button, and it lives here (Adarsh, 23rd September 2026): "different
   buttons will either have width / color / text different". So padding, type
   size, radius, border weight and press feedback are settled once, and a
   section sets only the four colour tokens and, where it needs one, a width.

   There were seven near-identical copies of this before, each repeating the
   same structural lines and drifting on padding (12/24 to 16/32) and type
   (14 to 20). Any new button is `.gs-btn` plus tokens; a section that finds
   itself restating padding or font-size is doing it wrong.

   The supplied header mockup shows an OUTLINED CTA, not a red fill, so the
   bare .gs-btn is ink-on-white with a hairline. Red stays logo-and-accent.
   ========================================================================== */

.gs-btn {
	/* The whole per-section surface. Nothing else is meant to be overridden. */
	--btn-fill: transparent;
	--btn-ink: var(--gs-ink);
	--btn-line: var(--gs-ink);
	--btn-fill-hover: var(--gs-ink);
	--btn-ink-hover: var(--gs-white);

	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--gs-space-3);
	padding: var(--gs-btn-pad-y) var(--gs-btn-pad-x);
	/* Every button carries a border, filled ones in their own fill colour, so
	   an outlined and a filled button are the SAME height on one row. */
	border: var(--gs-border-width) solid var(--btn-line);
	border-radius: var(--gs-radius);
	background: var(--btn-fill);
	color: var(--btn-ink);
	font-family: inherit;
	font-size: var(--gs-btn-size);
	font-weight: var(--gs-weight-medium);
	line-height: 1;
	text-align: center;
	text-decoration: none;
	cursor: pointer;
	transition:
		transform var(--gs-dur-press) var(--gs-ease-out),
		background-color var(--gs-dur-hover) ease,
		color var(--gs-dur-hover) ease,
		border-color var(--gs-dur-hover) ease;
}

/* focus-visible as well as hover: a keyboard user gets the same state a mouse
   user does, which no section-level copy of this did. */
@media (hover: hover) and (pointer: fine) {
	.gs-btn:hover {
		border-color: var(--btn-fill-hover);
		background: var(--btn-fill-hover);
		color: var(--btn-ink-hover);
	}
}

.gs-btn:focus-visible {
	border-color: var(--btn-fill-hover);
	background: var(--btn-fill-hover);
	color: var(--btn-ink-hover);
}

/* Instant physical feedback that the press registered. */
.gs-btn:active { transform: scale(0.97); }

/* --- button arrows -----------------------------------------------------------
   Every up-right arrow (Lucide arrow-up-right, sitewide) turns flat, pointing
   right, while its link or button is hovered or keyboard-focused, and turns
   back after (Adarsh, 6th October 2026). Matched by the arrow's own drawing,
   so any button that uses it, now or later, gets it. Arrows already drawn
   flat (Launchpad, footer socials) are a different path and stay put.

   Transform only, 200ms strong ease-out, a transition so it reverses from
   wherever it is if the pointer leaves mid-turn. Hover only for a real mouse:
   a tap on a phone would leave it stuck flat. Reduced motion: it still turns,
   instantly. */
svg:has(> path[d="M7 17 17 7"]) {
	transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1);
}

@media (hover: hover) and (pointer: fine) {
	a:hover svg:has(> path[d="M7 17 17 7"]),
	button:hover svg:has(> path[d="M7 17 17 7"]) {
		transform: rotate(45deg);
	}
}

a:focus-visible svg:has(> path[d="M7 17 17 7"]),
button:focus-visible svg:has(> path[d="M7 17 17 7"]) {
	transform: rotate(45deg);
}

@media (prefers-reduced-motion: reduce) {
	svg:has(> path[d="M7 17 17 7"]) {
		transition: none;
	}
}

/* --- colour variants ------------------------------------------------------
   Fill and ink only. If a variant ever needs a different size, the answer is
   a new token here, not a per-section rule. */

/* Ink fill, red on hover. Cards on white: divisions, packages. */
.gs-btn--solid {
	--btn-fill: var(--gs-ink);
	--btn-line: var(--gs-ink);
	--btn-ink: var(--gs-white);
	--btn-fill-hover: var(--gs-accent);
}

/* Brand red. The one loud action per view: hero, form submit. */
.gs-btn--accent {
	--btn-fill: var(--gs-accent);
	--btn-line: var(--gs-accent);
	--btn-ink: var(--gs-white);
	--btn-fill-hover: var(--gs-pm-red);
}

/* Inverted, for the dark bands: the red creatives wall and the black footer.
   Ink-on-light going to light-on-ink, the reverse of the default. */
.gs-btn--light {
	--btn-fill: var(--gs-white);
	--btn-line: var(--gs-white);
	--btn-ink: var(--gs-ink);
	--btn-fill-hover: var(--gs-ink);
	--btn-ink-hover: var(--gs-white);
}

/* --- width ----------------------------------------------------------------
   The one dimension a section IS expected to set. */

.gs-btn--block {
	width: 100%;
}

.gs-btn__icon {
	width: 1em;
	height: 1em;
	flex: none;
}

/* ==========================================================================
   Section rhythm

   WP's constrained layout puts a 24px block-gap margin above every sibling
   block. With each section already contributing its own 40px, that margin
   made the real gap 104px and put a white strip between bands that carry a
   background. Zeroed HERE, on the sections themselves, rather than by
   changing --wp--style--block-gap, which would also collapse the spacing
   between ordinary paragraphs and headings in page content.

   Listed explicitly. There is no shared .gs-section class in the markup, and
   inventing one would mean touching every render callback; the list is
   finite, lives in one place, and a new band is one line here.
   ========================================================================== */

.gs-hero,
.gs-clients,
.gs-divisions,
.gs-packages,
.gs-creatives,
.gs-testimonials,
.gs-cases,
.gs-form-section,
.gs-cta,
.gs-pagevideo,
.gs-audit,
.gs-services,
.gs-stat,
.gs-questions,
.gs-process,
.gs-page-hero,
.gs-casegrid,
.gs-results,
.gs-tiles,
.gs-backed,
.gs-faq,
.gs-launch,
.gs-stats,
.gs-pillars,
.gs-roadmap,
.gs-launched,
.gs-reels,
.gs-midcta,
.gs-promises,
.gs-problem,
.gs-booking,
.gs-pricing {
	margin-block-start: 0;
}

/* Bands that set their OWN top margin (white space outside a coloured band)
   are deliberately not in the list above. */

/* The division template has no page title, so its first band sits straight
   under the header — and WP's block gap was putting 24px of white between the
   two. Scoped to that template's body class rather than to `main` generally,
   so ordinary pages, which DO open with a title, keep their breathing room.
   The Wide page template and a case study's page have no title either. */
.page-template-page-division .wp-site-blocks > main.wp-block-group,
.page-template-page-wide .wp-site-blocks > main.wp-block-group,
.single-gs_case_study .wp-site-blocks > main.wp-block-group {
	margin-block-start: 0;
}

/* The 80px holds even where a neighbour contributes nothing.

   The hero is a full-bleed media band: giving it 40px of its own padding
   would just make the black taller, so it has none, and the gap below it came
   out at 40 rather than 80. The section that FOLLOWS it therefore pays the
   whole gap instead of half.

   Written as a sibling rule so it can only ever apply directly under the
   hero, and so a section that is moved away from the hero goes back to its
   normal half without anything being edited.

   The `.wp-site-blocks` prefix is there for specificity, not scope: each
   section sets its own `padding-block` from a single-class rule in its own
   file, and those files load AFTER base.css, so a single-class rule here
   would lose the tie on source order. Two classes wins it without
   !important. */
.wp-site-blocks .gs-hero + * {
	padding-block-start: calc(var(--gs-section-pad) * 2);
}

/* ==========================================================================
   Section headings
   One size for every band on the page, from one token. See --gs-section-title.
   ========================================================================== */

.gs-section-title {
	margin: 0;
	max-width: none;
	font-size: var(--gs-section-title);
}

/* ==========================================================================
   Reduced motion
   Not optional. Keep opacity and colour, drop movement.
   ========================================================================== */

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

	.gs-btn:active { transform: none; }
}
