/*
 * "Trusted Technology Partner for Growing Businesses" section.
 * Figma: heading 1752:4019, badge/copy area around 1752:3942 + 1752:4124,
 * video card group 1795:19893, stats row 1752:4128.
 * Breakpoints reference (Figma frame = 1440): 1440 desktop / 1024
 * small-desktop / 768 tablet / 425,375,320 mobile.
 */

/* Figma 1752:4019 — SemiBold 40, line-height normal (the two-line block
   measures 100px tall, i.e. ~50px per line — not the 40px of --tp-h2),
   #021b42, wrapping inside a 525px box. The heading bottoms out at y=1109
   and the video card starts at y=1151, hence the 42px gap. */
.tp2026-business-stats__heading {
	font: var(--tp-h2);
	/* 50px, not `normal`: Figma's two-line block is exactly 100 tall (1009–1109)
	   and Chrome's `normal` renders 51 per line, which pushed everything below
	   the heading 2px down. */
	line-height: 50px;
	color: var(--tp-heading);
	max-width: 525px;
	margin: 0 0 42px;
	text-transform: capitalize; /* Figma 1752:4019 textCase=TITLE */
}

/* ---------------------------------------------------------------------
 * Two-column grid: (badge + copy, then stats)  |  video card
 *
 * Figma column widths are 708 + 24 + 380 = 1112 (the narrow container).
 * The card (y=1151–1521) is taller than the left column and bottoms out
 * flush with the stats row (y=1415–1521), so the row is bottom-aligned.
 * --------------------------------------------------------------------- */

.tp2026-business-stats__grid {
	display: flex;
	align-items: flex-end;
	gap: 24px;
}

.tp2026-business-stats__main {
	flex: 1 1 708px;
	min-width: 0;
	max-width: 708px;
}

/* Gap is 14, not a round token: Figma's text frame 1752:4124 starts at x=361
   and the badge box 1752:4127 ends at x=347. The card's own left edge is
   further left still (x=265) because it tucks under the coin — that offset is
   the -96 margin on .tp2026-business-stats__intro-copy below, so this gap is
   what positions the *text*, and 347 + 14 = 361 exactly.

   margin-bottom is measured card-to-tiles, not text-to-tiles: the tinted card
   1752:3942 bottoms out at y=1391 and the stat tiles 1752:4128 start at
   y=1415, so 24. (It was 56 while the gap was measured from the copy's own
   baseline at y=1359, before the card existed as a box.) This number is what
   makes the two light boxes line up: the left column is 240 + 24 + 106 = 370
   tall, exactly the video card's 370, so the row's tops meet at y=1151 as
   well as its bottoms at y=1521. Any other value and flex-end alignment
   pushes the card down by the difference. */
.tp2026-business-stats__intro {
	display: flex;
	align-items: center;
	gap: 14px;
	margin-bottom: 24px;
}

/* Figma 1752:3942 — the copy sits on a tinted card (607x240, radius 20)
   that runs from x=265 to the column's right edge at x=872. The badge box
   runs x=151–347, so the card's left edge tucks 82px *under* the badge and
   the coin overhangs it — hence the negative margin pulling the card back
   96px behind the copy, cancelled by an equal padding-left so the text
   itself doesn't move. Padding is Figma's 1752:4124 inset: 32 top/bottom,
   96 left, 30 right. Height is content-driven and lands on 240 naturally.
   Left free to grow rather than capped at Figma's 607 so the card still
   spans the column at the intermediate widths Figma doesn't specify. */
.tp2026-business-stats__intro-copy {
	flex: 1 1 auto;
	min-width: 0;
	margin-left: -96px;
	/* Figma 1752:4124's inset, at full value. An earlier revision wrote these
	   1px short to absorb a 1px hairline; the hairline was removed on request
	   (13-08-2026) once the client's own card export supplied the fill, and
	   1752:3942 has `strokes: []`, so the card is back to matching the design
	   with no stroke at all. Card stays 607x240, copy stays at x=361. */
	padding: 32px 30px 32px 96px;
	border-radius: 20px;
	/* Client supplied the card fill as a flat export ("Rectangle 161125310",
	   1214x480 = the 607x240 card at 2x), so the panel is now painted from that
	   asset rather than rebuilt from the tint + white wash. It is a pure
	   vertical ramp — rgb(241,251,255) at the top to rgb(248,253,255) at the
	   foot, identical across every column — so stretching it to 100% 100% is
	   lossless horizontally and only resamples a smooth ramp vertically. Its
	   own baked corners are ~19px at 1x, under this rule's 20px clip, so the
	   two agree and no seam shows.

	   The gradient below stays as the fallback layer: it is what the export was
	   built from (stops off 1752:3942 — 0.75 @ 26.078%, 0.435 @ 55.087%,
	   0.285 @ 111.18%) and it keeps the card tinted if the PNG ever 404s. */
	background:
		url("../images/business-stats/intro-card-bg.png") 0 0 / 100% 100% no-repeat,
		linear-gradient(0deg, rgba(255, 255, 255, 0.75) 26.078%, rgba(255, 255, 255, 0.435) 55.087%, rgba(255, 255, 255, 0.285) 111.18%),
		var(--tp-ice-blue);
}

/* Figma 1752:4125 — Medium 24/34 #131313 (not the 28px H3). The 481 cap
   used to come from the copy stack itself, which now stretches to carry
   the card, so it moves onto the text to keep the same two-line wrap. */
.tp2026-business-stats__intro-title {
	font: var(--tp-subhead);
	color: var(--tp-black);
	margin: 0 0 12px;
	max-width: 481px;
	text-transform: capitalize; /* Figma 1752:4125 textCase=TITLE */
}

/* The authored break in 1752:4125. Only the desktop node specifies it, so it
   collapses to a plain space below 769px and the mobile wrap is untouched. */
.tp2026-business-stats__intro-break {
	display: inline;
}

@media (max-width: 768px) {
	.tp2026-business-stats__intro-break {
		display: none;
	}
}

/* Figma 1752:4126 — Regular 16/24 #595959. This paragraph is explicitly
   NOT title-cased in Figma; the reset guards against future inheritance. */
.tp2026-business-stats__intro-text {
	font: var(--tp-body);
	color: var(--tp-gray-700);
	max-width: 481px;
	text-transform: none;
}

.tp2026-business-stats__video {
	flex: 0 0 380px;
	max-width: 380px;
}

/* ---------------------------------------------------------------------
 * FR-017: rotating "15 years" badge.
 * A supplied looping video in place of the old pure-CSS ring + gradient
 * disc. The source is square (540x540) and already carries its own padding
 * around the coin, so the box keeps Figma's 196x174 (98/87) footprint and
 * the video just fills it via object-fit: fill (Figma's crop is STRETCH).
 *
 * The supplied H.264 has no alpha: its backdrop is a flat near-white #fdfdfd
 * (only 43 pixels in a frame reach a true white), which on its own painted a
 * white square over the tinted copy card the coin overhangs. That backdrop is
 * removed the way the design removes it — Figma 1752:4127 carries blendMode
 * MULTIPLY on the rectangle, over a plain opaque IMAGE fill — so the video is
 * served exactly as delivered and mix-blend-mode below does the work. No keyed
 * alpha variant is used.
 * --------------------------------------------------------------------- */

.tp2026-badge {
	position: relative;
	z-index: 1; /* the coin overhangs the tinted copy card and must sit on top */
	flex: 0 0 auto;
	width: 196px;
	/* Figma 1752:4127 exact box (196x174), set as a literal height rather than
	   an aspect-ratio so it is pixel-exact instead of a rounded ratio. It must
	   be declared: the source video is a square 540x540, so with height auto
	   its intrinsic ratio drives the box to 196x196 — 22px too tall, which also
	   drags the ::after shadow's percentage offsets out of place. */
	height: 174px;
	/* Below 768px the intro stacks, making this a column flex item, and a column
	   item's automatic minimum size is content-based — the video's 540x540
	   intrinsic ratio then wins and the box would render square, losing
	   Figma's vertical squeeze, if height were left to shrink. Waive the
	   automatic minimum so the explicit height holds at every width. */
	min-height: 0;
	/* Figma places the badge box at (151, 1171) while the 708 column's left edge
	   is x=164 and the tinted card runs y=1151–1391. So the box is deliberately
	   *not* flush with the gutter and *not* centred on the card: it sits 13px
	   left of the column and 13px above the card's centre line (badge centre
	   1258 vs card centre 1271). The frame carries its own padding around the
	   coin, which is why the design can hang it over the gutter without the
	   coin itself breaking the margin.
	   Left is a margin so the card and text shift with it; the vertical nudge is
	   an offset rather than a margin so it doesn't fight align-items: center. */
	margin-left: -13px;
	top: -13px;
	display: flex;
	align-items: center;
	justify-content: center;
	/* Figma 1752:4127 carries blendMode MULTIPLY on the rectangle itself, with a
	   plain opaque IMAGE fill — the design never keyed the coin out, it just
	   multiplied the whole 540x540 render. This reproduces that literally: the
	   source's flat near-white (253) backdrop drops out arithmetically over both
	   the white page (a no-op) and the #eaf9ff card (leaves the card's own
	   tint), so it is correct in every browser, with no dependence on video
	   alpha and nothing to feature-detect at runtime. It also puts the ::after
	   contact shadow below on MULTIPLY, which is what Figma does to it.
	   Declared on the badge, not the video: .tp2026-badge's z-index makes it a
	   stacking context, so a blend set on the child would have only the badge to
	   blend against.
	   Caveat: multiply only subtracts over a light backdrop. If this section
	   ever moves onto a dark background the plate would need real keying. */
	mix-blend-mode: multiply;
}

/* Figma 1752:4127's fill is scaleMode STRETCH *with* an imageTransform, which
 * in Figma means CROP, not "squash the whole source into the frame":
 *
 *   [[0.9496105313301086, 0, -0.0422031506896019 ],
 *    [0, 0.8462962508201599,  0.07777777314186096]]
 *
 * The matrix maps the frame's unit square into the source's normalised space,
 * so the region actually shown is x -4.2203%..90.7407%, y 7.7778%..92.4074% of
 * the 540x540 render — 512.8x457.0 source px, aspect 1.1221 against the frame's
 * 1.1264. In other words the design crops ~8% off the top and bottom and ~9%
 * off the right, then draws that at very nearly the frame's own aspect. The
 * previous rule stretched the *entire* square into 196x174 instead, squeezing
 * the coin 13.7% vertically.
 *
 * Verified rather than reasoned: rendering node 1752:4127 via the REST image
 * endpoint and diffing it against every frame of the source put frame 0 at a
 * mean error of 3.5/255 under this crop, versus 32.7/255 for the old
 * full-frame stretch. The export also has a transparent 8.5px band down its
 * left edge, which is exactly the -4.22% x-origin reaching past the source.
 *
 * Implementation: size the video so the *crop rect* lands on the badge box
 * (100/0.94961 and 100/0.84630 of it), offset it by the crop origin, and clip
 * it back to the box. clip-path is used rather than overflow:hidden on the
 * badge because the ::after contact shadow deliberately hangs 12px below the
 * box and overflow would eat it. The inset percentages are the crop rect read
 * in the video's own coordinates, hence just the raw matrix values.
 * Percentages throughout, so the 140px mobile badge inherits the same crop. */
.tp2026-badge__video {
	position: absolute;
	left: 4.44424%;   /* -tx / a */
	top: -9.19042%;   /* -ty / d */
	width: 105.30577%;  /* 1 / a */
	height: 118.16180%; /* 1 / d */
	display: block;
	object-fit: fill;
	clip-path: inset(7.77778% 9.25926% 7.59260% 0);
	pointer-events: none;
}

/* Figma 1752:4123 "Ellipse 2444" — the soft contact shadow the coin casts on
 * the page. 113x10 at canvas (215, 1357).
 *
 * Percentages are measured against the badge box, which is what this
 * pseudo-element is positioned in: the box is 1752:4127 at (151, 1171) 196x174,
 * so the ellipse sits at +64, +186 within it — left 64/196, top 186/174,
 * 113/196 wide, 10/174 tall. Percentage units also carry the ratio down to the
 * 140px badge at 425px.
 *
 * The >100% top is deliberate: 174 is the *frame* height, and the frame crops
 * the render above the coin's contact point, so the shadow lands 12px below
 * the box's bottom edge — exactly where Figma puts it (1345 + 12 = 1357).
 *
 * Gradient is Figma's radial fill with the layer's 30% fill opacity folded
 * into the stops (0.86/0.22/0 -> 0.258/0.066/0). closest-side reproduces the
 * gradient handles (rx = w/2, ry = h/2). Figma blends it MULTIPLY, which over
 * the white page and the #eaf9ff card is arithmetically identical to plain
 * alpha at this darkness. Declaring mix-blend-mode here would also be futile:
 * .tp2026-badge's z-index makes it a stacking context, so a blend set on this
 * pseudo-element has only the badge to blend against. It does not need one —
 * the badge's own MULTIPLY carries this shadow along with it, which is exactly
 * what Figma does.
 *
 * z-index -1 keeps it under the coin and over the tinted card, matching
 * Figma's layer order.
 */
.tp2026-badge::after {
	content: '';
	position: absolute;
	left: 32.6530612%;  /* 64/196 */
	top: 106.8965517%;  /* 186/174 */
	width: 57.6530612%; /* 113/196 */
	height: 5.7471264%; /* 10/174 */
	z-index: -1;
	pointer-events: none;
	background: radial-gradient(
		closest-side,
		rgba(6, 6, 6, 0.258) 3.836%,
		rgba(6, 6, 6, 0.066) 60.096%,
		rgba(6, 6, 6, 0) 100%
	);
}

/* ---------------------------------------------------------------------
 * FR-018: video card
 * --------------------------------------------------------------------- */

/* Figma 1752:3941 — flat #eaf9ff card, radius 20, 16px media inset. No
   border and no shadow in the design. */
/* The whole card is the CTA (FRD CTA table: "See How We Bring Ideas… (video
   card)"), so it takes the pointer even over its padding and caption. */
.tp2026-video-card {
	background: var(--tp-ice-blue);
	border-radius: 20px;
	padding: 16px 16px 24px;
	cursor: pointer;
}

/* Figma 1752:3943 — 348x216, radius 16, photo fill (object-fit: cover). */
.tp2026-video-card__media {
	position: relative;
	aspect-ratio: 348 / 216;
	border-radius: var(--tp-radius-md);
	overflow: hidden;
	background: var(--tp-ice-blue);
	display: flex;
	align-items: center;
	justify-content: center;
}

/* The thumb is absolutely positioned, so the <picture> that now wraps it
   (for the mobile crop) has to become the positioned box itself — otherwise
   it collapses to an inline zero-height box and takes the image out of the
   media frame. */
.tp2026-video-card__media picture {
	position: absolute;
	inset: 0;
	display: block;
}

.tp2026-video-card__thumb {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	border-radius: inherit;
}

.tp2026-video-card__play {
	position: relative;
	z-index: 1;
	width: 58px;
	height: 58px;
	border-radius: 50%;
	/* Figma 1795:19905 — the disc and glyph both live in the exported SVG, so the
	   button itself stays transparent; the radius is only here for the focus ring. */
	background: none;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: transform var(--tp-speed-fast) var(--tp-ease);
}

.tp2026-video-card__play:hover,
.tp2026-video-card__play:focus-visible,
.tp2026-video-card:hover .tp2026-video-card__play {
	transform: scale(1.08);
}

.tp2026-video-card__play-icon {
	display: flex;
}

/* The Figma artwork is optically centred already — no nudge, and it scales with
   the button so a smaller breakpoint would only need the button resized. */
.tp2026-video-card__play-icon svg {
	display: block;
	width: 100%;
	height: 100%;
}

/* Figma: media ends at y=1383; the copy (1752:4169) starts at y=1407 with a
   24px left inset, while the arrow chip (1752:4170) starts 4px higher at
   y=1403 and is only 16px from the card's right edge. Card padding is 16, so
   the extra 8px left inset lands the text at 24 and leaves the chip flush. */
.tp2026-video-card__caption {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 13px;
	margin-top: 24px;
	padding: 0 0 0 8px;
}

/* Mobile-only line break — see the note in business-stats.php. Hidden here
   rather than printed conditionally so the breakpoint stays a CSS decision. */
.tp2026-video-card__break {
	display: none;
}

/* Figma 1752:4169 — Medium 20/30, #004a67. Explicitly NOT title-cased. */
.tp2026-video-card__caption p {
	flex: 1 1 auto;
	font: 500 20px/30px var(--tp-font-heading);
	color: var(--tp-teal);
	text-transform: none;
}

/* Figma 1752:4170 — verified against the node's SVG export: a 36.0208px box
   (rounded to 36 — the .0208 is float noise and would only blur the edge),
   radius 5, fill #d5f3ff, and a 1px INSIDE stroke of #56aed2 at 8%, which the
   export draws as a second rect inset 0.5 at radius 4.5. The global border-box
   makes `border` land exactly there. The glyph's #1977f3 is already --tp-blue.
   Sits 4px above the caption text's top edge (y=1403 vs y=1407). */
.tp2026-video-card__arrow {
	flex: 0 0 auto;
	margin-top: -4px;
	width: 36px;
	height: 36px;
	border-radius: 5px;
	background: #d5f3ff;
	border: 1px solid rgba(86, 174, 210, 0.08);
	color: var(--tp-blue);
	display: flex;
	align-items: center;
	justify-content: center;
	/* Now a <button> (FRD: clicking the arrow opens the pop-up), so the chip
	   has to keep the flat look the span had. */
	padding: 0;
	cursor: pointer;
	transition: background var(--tp-speed-fast) var(--tp-ease);
}

.tp2026-video-card__arrow:hover,
.tp2026-video-card__arrow:focus-visible {
	background: #bfeaf9;
}

/* ---------------------------------------------------------------------
 * Stat tiles
 * --------------------------------------------------------------------- */

/* Figma 1752:4128 — three 220x106 tiles, 24px apart, filling the 708px row. */
.tp2026-stat-tiles {
	display: flex;
	flex-wrap: wrap;
	gap: 24px;
}

/* Figma 1752:4129 — white→transparent vertical wash, 1px #cff1ff, radius 12,
   inner content inset 14/17/14/16 with a 7px icon-to-copy gap.
   Figma's stroke is drawn INSIDE the 220x106 box, so its insets are measured
   from the outer edge and already contain the 1px. CSS border-box adds the
   border outside the padding, so each inset is written 1px short to land the
   content in the same place: 13/16/13/15 + 1px border = Figma's 14/17/14/16.
   That also restores the copy column to its designed 122px (220 - 2 border
   - 31 padding - 58 icon - 7 gap) instead of shrinking it to 120. */
.tp2026-stat-tile {
	flex: 0 0 220px;
	width: 220px;
	max-width: 220px;
	display: flex;
	align-items: center;
	gap: 7px;
	padding: 13px 16px 13px 15px;
	border: 1px solid #cff1ff;
	border-radius: 12px;
	background: linear-gradient(180deg, #ffffff 0%, rgba(255, 255, 255, 0) 100%);
}

/* Figma 1752:4131 — bare 58px blue icon, no tinted chip behind it. */
.tp2026-stat-tile__icon {
	flex: 0 0 auto;
	width: 58px;
	height: 58px;
	color: var(--tp-blue);
	display: flex;
	align-items: center;
	justify-content: center;
}

.tp2026-stat-tile__icon img,
.tp2026-stat-tile__icon svg {
	display: block;
	width: 100%;
	height: 100%;
}

/* Figma 1752:4132 — the geolocalization artwork is inset 6.25% inside its
   58px frame (50.75px of drawn area); teamwork is full-bleed. */
.tp2026-stat-tile__icon--inset img {
	width: 87.5%;
	height: 87.5%;
}

/* Figma 1752:4142 — 122px copy column, 4px gap. */
.tp2026-stat-tile__copy {
	display: flex;
	flex-direction: column;
	gap: 4px;
	width: 122px;
}

/* Figma 1752:4143 / 4151 / 4167 — SemiBold 32/34 #3b3b3b, textCase=TITLE. */
.tp2026-stat-tile__number {
	font: var(--tp-stat);
	color: var(--tp-gray-800);
	text-transform: capitalize;
}

/* Figma 1752:4144 / 4152 / 4168 — Medium 16, #6d6d6d, textCase=TITLE.
   Figma renders these two lines at 40px total, i.e. 20px per line. That is
   what its "normal" resolves to from the font's own metrics; Chrome's
   `normal` resolves to 21px instead, which made every tile 2px too tall
   (110 vs Figma's 106) and — because the grid is bottom-aligned — pushed the
   video card 4px down out of line with the copy card. Pinned to the design's
   value rather than left to the browser. */
.tp2026-stat-tile__label {
	font: 500 16px/20px var(--tp-font-heading);
	color: var(--tp-gray-500);
	text-transform: capitalize;
}

/* ---------------------------------------------------------------------
 * Lightbox (video pop-up).
 * Backdrop paints nothing at all — no tint, no blur — because the FRD forbids
 * masking the content underneath. It only locks scrolling and swallows clicks.
 * --------------------------------------------------------------------- */

/* Scroll lock. The FRD wants two things at once — "the page underneath must
   not be scrollable" AND "the content underneath must not be masked (darkened
   or hidden)" — so the lock has to freeze the page without disturbing a single
   pixel of it. Two obvious implementations both fail the second half:

   - `overflow: hidden` + `height: 100%` on html AND body (what this rule used
     to be) locks scrolling only by collapsing the document to one viewport,
     which discards the scroll offset and re-renders from the top. The whole
     page behind the pop-up went blank — masked just as surely as by a scrim.
   - Pinning `body { position: fixed; top: -scrollY }` keeps the pixels but
     zeroes window.scrollY, so the header's own scroll handler fires and snaps
     it back to its transparent top-of-page state behind the pop-up.

   What is left is the non-destructive half: `overflow: hidden` on the root
   only. Layout, scroll offset and every scroll-driven class stay exactly as
   they were. JS additionally cancels wheel/touch/key scrolling while open
   (iOS Safari ignores root overflow) — see openLightbox.

   scrollbar-gutter keeps the classic scrollbar's width reserved once the
   scrollbar is suppressed, so nothing behind the pop-up jumps sideways. */
html.tp2026-lightbox-lock {
	overflow: hidden;
	scrollbar-gutter: stable;
}

.tp2026-video-lightbox {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: clamp(14px, 4vw, 24px);
	opacity: 0;
	visibility: hidden;
	transition: opacity var(--tp-speed) var(--tp-ease), visibility var(--tp-speed) var(--tp-ease);
}

.tp2026-video-lightbox.is-open {
	opacity: 1;
	visibility: visible;
}

/* FRD Video Widget Functionality: "The content underneath the video window
   must not be masked (darkened or hidden) by overlay." So the backdrop paints
   nothing at all — no tint, no blur. It exists only to swallow clicks aimed at
   the page behind the panel, which also keeps the "clicking anywhere else must
   not close the widget" rule from being defeated by an accidental link hit. */
.tp2026-video-lightbox__backdrop {
	position: absolute;
	inset: 0;
	background: transparent;
}

/* Figma 1795:15257 puts no white panel/padding around the player — the frame
   itself is the popup (bg-white, rounded-16, overflow-clip), with the close
   button sitting inside its own top-right corner. So the panel here is just
   the positioning/rise-transform wrapper; all the visible chrome (radius,
   shadow, overflow) lives on __frame below. */
.tp2026-video-lightbox__panel {
	position: relative;
	z-index: 1;
	/* 1137px is the Figma frame's own width — at that width or above, the
	   player renders pixel-exact. Third term keeps 16/9 inside a short
	   viewport (landscape phones, split-screen): 48px covers the outer gutter
	   only now that the panel carries no padding of its own. */
	width: min(1137px, 100%, calc((100dvh - 48px) * 16 / 9));
	transform: translateY(64px);
	transition: transform var(--tp-speed-slow) var(--tp-ease-gentle);
}

.tp2026-video-lightbox.is-open .tp2026-video-lightbox__panel {
	transform: translateY(0);
}

/* container-type turns the frame's own rendered width into `cqw` units for
   every child below, so the whole chrome — padding, buttons, icons, type —
   scales in the exact proportions Figma specified at 1137px, at any width,
   instead of jumping between hand-tuned breakpoints. Radius stays a fixed
   token (corner radii don't scale with component size anywhere else on this
   site) and so does the 58px play disc (shared with the video card). */
.tp2026-video-lightbox__frame {
	position: relative;
	container-type: inline-size;
	aspect-ratio: 16 / 9;
	border-radius: var(--tp-radius-md);
	overflow: hidden;
	background: var(--tp-navy-900);
	box-shadow: 0 30px 90px rgba(10, 20, 50, 0.3);
}

.tp2026-video-lightbox__video {
	display: block;
	width: 100%;
	height: 100%;
	/* The stand-in clip and the poster are both wider than 16/9; cover keeps
	   the frame filled rather than letterboxing the placeholder. Swap to
	   `contain` if the delivered corporate video is not 16/9. */
	object-fit: cover;
	background: var(--tp-navy-900);
}

/* z-index 2 puts the disc above the chrome — before the first play, it is the
   one clickable thing in the frame. Hidden after that via .has-started rather
   than .is-playing, so pausing later doesn't bring the big disc back over the
   small transport play icon. */
.tp2026-video-lightbox__play {
	position: absolute;
	top: 50%;
	left: 50%;
	z-index: 2;
	transform: translate(-50%, -50%);
	width: 58px;
	height: 58px;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.35));
	transition: transform var(--tp-speed-fast) var(--tp-ease);
}

.tp2026-video-lightbox__play svg {
	width: 100%;
	height: 100%;
}

.tp2026-video-lightbox__play:hover,
.tp2026-video-lightbox__play:focus-visible {
	transform: translate(-50%, -50%) scale(1.08);
}

.tp2026-video-lightbox__frame.has-started .tp2026-video-lightbox__play {
	display: none;
}

/* Figma 1795:19895 — a single self-contained SVG (circle + X baked in), inset
   inside the frame's own corner. clamp() floors it well above the 24px WCAG
   2.5.8 minimum before cqw would otherwise shrink it past readable. */
.tp2026-video-lightbox__close {
	position: absolute;
	top: clamp(10px, 2.1795cqw, 24.78px);
	right: clamp(10px, 2.1108cqw, 24px);
	z-index: 3;
	width: clamp(32px, 3.6939cqw, 42px);
	height: clamp(32px, 3.6939cqw, 42px);
	padding: 0;
	border: 0;
	background: none;
	cursor: pointer;
	transition: transform var(--tp-speed-fast) var(--tp-ease);
}

.tp2026-video-lightbox__close svg {
	display: block;
	width: 100%;
	height: 100%;
}

.tp2026-video-lightbox__close:hover,
.tp2026-video-lightbox__close:focus-visible {
	transform: scale(1.06);
}

/* Figma splits "Info" and "Web / Player Controllers" into two frames with the
   gradient only on the shorter one; visually they only ever appear together,
   so one wrapper reproduces the same band with one fewer layer. 80.37% is
   Figma's own gradient stop. */
.tp2026-video-lightbox__chrome {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 1;
	display: flex;
	flex-direction: column;
	gap: clamp(8px, 1.505cqw, 17.11px);
	padding: clamp(8px, 1cqw, 11.37px) clamp(12px, 2.5cqw, 28.425px);
	background: linear-gradient(180deg, rgba(8, 9, 13, 0) 0%, rgba(8, 9, 13, 0.9) 80.37%, rgba(8, 9, 13, 0.9) 100%);
	backdrop-filter: blur(0.711px);
	-webkit-backdrop-filter: blur(0.711px);
}

.tp2026-video-lightbox__info {
	display: flex;
	align-items: flex-end;
	justify-content: space-between;
	gap: 12px;
}

.tp2026-video-lightbox__title {
	margin: 0;
	font-family: var(--tp-font-body);
	font-weight: 400;
	font-size: clamp(12px, 1.5cqw, 17.055px);
	line-height: 1;
	color: var(--tp-white);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	min-width: 0;
	/* Client QA (13-08-2026): descenders were being sliced off. `overflow:
	   hidden` (there for the ellipsis) clips to the padding box, and Figma's
	   line-height of exactly 1 makes that box 17px while Plus Jakarta Sans
	   needs 19 — so "g/y/p" and the cap tops were cut. The padding enlarges
	   the clip box only; the equal negative margin cancels its effect on
	   layout, so the caption row keeps Figma's height and the ellipsis still
	   works horizontally. */
	padding: 0.25em 0;
	margin: -0.25em 0;
}

/* Figma specifies Helvetica Neue Light for the time readout; the site only
   ships Plus Jakarta Sans, so this falls back to the platform's own
   Helvetica/Arial rather than loading a second family for one line of text. */
.tp2026-video-lightbox__time {
	flex: 0 0 auto;
	margin: 0;
	font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
	font-weight: 300;
	font-size: clamp(9px, 1cqw, 11.37px);
	line-height: 1;
	color: var(--tp-white);
	white-space: nowrap;
}

.tp2026-video-lightbox__transport {
	display: flex;
	flex-direction: column;
	gap: clamp(8px, 1cqw, 11.37px);
	/* Client QA (13-08-2026): "check the space between the text and the seek
	   bar". Merging Figma's two frames into one `__chrome` wrapper (see above)
	   dropped the inner "Web / Player Controllers" frame's own 11.37 padding-top
	   — 1795:15314. The caption-to-bar gap is Figma's 17.11 *plus* that 11.37,
	   and only the 17.11 was being drawn. Restored here rather than by widening
	   the chrome gap, so each number still traces to one Figma property. */
	padding-top: clamp(8px, 1cqw, 11.37px);
}

.tp2026-video-lightbox__progress {
	position: relative;
	/* Figma's "Progress bar" frame 1795:15320 is 1.42 tall and nothing more, so
	   the box has to be the bar — the 4px it used to carry was phantom height
	   that pushed the visible line 1.29px above where the design puts it. The
	   tappable area is now an overflowing pseudo-element instead, which gives
	   the same generous target with no layout cost. Figma doesn't specify
	   seek-by-click, but a 1.4px-tall click target would be unusable. */
	height: 1.4212px;
	cursor: pointer;
	display: flex;
	align-items: center;
}

.tp2026-video-lightbox__progress::before {
	content: '';
	position: absolute;
	inset: -8px 0;
}

.tp2026-video-lightbox__progress-track,
.tp2026-video-lightbox__progress-fill {
	position: absolute;
	left: 0;
	height: 1.4212px;
	border-radius: 14.2125px;
}

.tp2026-video-lightbox__progress-track {
	right: 2.84px;
	width: auto;
	background: #d9d9d9;
	opacity: 0.4;
}

.tp2026-video-lightbox__progress-fill {
	width: 0%;
	background: var(--tp-white);
}

.tp2026-video-lightbox__controls {
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.tp2026-video-lightbox__controls-left,
.tp2026-video-lightbox__controls-right {
	display: flex;
	align-items: center;
	gap: clamp(4px, 0.5cqw, 5.685px);
}

.tp2026-video-lightbox__ctrl {
	width: clamp(26px, 3cqw, 34.11px);
	height: clamp(26px, 3cqw, 34.11px);
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: var(--tp-white);
	cursor: pointer;
	transition: background var(--tp-speed-fast) var(--tp-ease);
}

.tp2026-video-lightbox__ctrl:hover,
.tp2026-video-lightbox__ctrl:focus-visible {
	background: rgba(255, 255, 255, 0.12);
}

.tp2026-video-lightbox__ctrl svg {
	width: clamp(13px, 1.5cqw, 17.055px);
	height: clamp(13px, 1.5cqw, 17.055px);
	display: block;
}

.tp2026-video-lightbox__ctrl--more svg {
	width: clamp(11px, 1.25cqw, 14.212px);
	height: clamp(11px, 1.25cqw, 14.212px);
}

/* Play/pause and mute each carry both icon states in the markup; the frame's
   state classes pick which one shows, so no JS ever touches an SVG. */
.tp2026-video-lightbox__ctrl--playpause .tp2026-video-lightbox__icon-pause,
.tp2026-video-lightbox__ctrl--mute .tp2026-video-lightbox__icon-muted {
	display: none;
}

.tp2026-video-lightbox__frame.is-playing .tp2026-video-lightbox__icon-play {
	display: none;
}

.tp2026-video-lightbox__frame.is-playing .tp2026-video-lightbox__icon-pause {
	display: block;
}

.tp2026-video-lightbox__frame.is-muted .tp2026-video-lightbox__icon-unmuted {
	display: none;
}

.tp2026-video-lightbox__frame.is-muted .tp2026-video-lightbox__icon-muted {
	display: block;
}

/* ---------------------------------------------------------------------
 * Responsive
 * --------------------------------------------------------------------- */

@media (max-width: 1024px) {
	/* The left column is unwrapped so the three blocks stack in reading
	   order (copy → video → stats) instead of the desktop side-by-side. */
	.tp2026-business-stats__grid {
		flex-direction: column;
		align-items: stretch;
		gap: 40px;
	}

	.tp2026-business-stats__main {
		display: contents;
	}

	.tp2026-business-stats__intro {
		order: 1;
		margin-bottom: 0;
	}

	.tp2026-business-stats__video {
		order: 2;
		flex: 1 1 auto;
		max-width: 480px;
		align-self: center;
	}

	.tp2026-stat-tiles {
		order: 3;
	}
}

/*
 * Mobile — Figma frame 2215:1750 ("homepage thinkpalm mobile", 360px).
 * This is a different composition, not a narrowed desktop: the rotating coin
 * is gone, the copy card and the stat rows sit in reading order above the
 * video card, and every tile becomes a full-width row with the number and
 * label side by side. Box map (frame coords, all x=20 w=320):
 *   heading  2225:2622  y951   h102   28/34
 *   card     2225:2624  y1077  h214   r20, 30/20 padding
 *   tiles    2243:3662  y1303  h234   3 x 70, 12 apart
 *   video    2243:3699  y1561  h329   r16, 12px media inset
 *   rule     2243:3740  y1942  h1
 */
@media (max-width: 768px) {
	/* 2225:2622 — SemiBold 28/34, three lines, 24px clear of the card. */
	.tp2026-business-stats__heading {
		font-size: 28px;
		line-height: 34px;
		max-width: none;
		margin-bottom: 24px;
	}

	/*
	 * The mobile frame has no rotating "15 years" coin at all — the copy card
	 * sits straight under the heading. Hidden rather than deleted from the
	 * markup: FR-017 still calls for the badge, and it is the design that
	 * drops it on phones, not the requirement.
	 */
	.tp2026-badge {
		display: none;
	}

	/* Figma order is card -> stat rows -> video card, against the
	   card -> video -> rows the 1024 breakpoint sets up. Gaps are 12 to the
	   rows and 24 to the video, so the second one is a margin on top of the
	   grid's own 12. */
	.tp2026-business-stats__grid {
		gap: 12px;
	}

	.tp2026-business-stats__intro {
		display: block;
		margin-bottom: 0;
	}

	.tp2026-stat-tiles {
		order: 2;
		flex-direction: column;
		gap: 12px;
	}

	.tp2026-business-stats__video {
		order: 3;
		max-width: none;
		align-self: stretch;
		margin-top: 12px;
	}

	/*
	 * 2225:2624 — 320x214, radius 20, 30/20 padding. The fill is #EAF9FF under
	 * a white gradient at 75% layer opacity, and Figma's handles run diagonally
	 * from outside the box (-0.228,1.407 -> 0.509,-0.112), which works out to
	 * 36deg with the stops landing at -31.4% / 34.4% / 79.8% of the CSS
	 * gradient line — not the 24.67deg the Dev Mode codegen reports, which
	 * ignores the box being taller than it is wide.
	 */
	.tp2026-business-stats__intro-copy {
		width: 100%;
		margin-left: 0;
		/* Figma's 30/20 inset at full value — the desktop rule no longer adds a
		   hairline for this to absorb, so the mobile card keeps its 320x214 box. */
		padding: 30px 20px;
		border-radius: 20px;
		background:
			linear-gradient(35.98deg, rgba(255, 255, 255, 0.75) -31.4%, rgba(255, 255, 255, 0.435) 34.4%, rgba(255, 255, 255, 0.285) 79.8%),
			var(--tp-ice-blue);
	}

	/* 2225:2627 — Medium 18/26 #131313, two lines. */
	.tp2026-business-stats__intro-title {
		font-size: 18px;
		line-height: 26px;
		max-width: none;
	}

	/* 2225:2628 — Regular 12/18 #595959, five lines. The 1px nudge is the
	   usual leading split: with the block landing on Figma's y=1171 exactly,
	   the glyphs still came out a pixel high (the 18px headings and 14px
	   labels on this screen don't — only the 12/18 body does). */
	.tp2026-business-stats__intro-text {
		font-size: 12px;
		line-height: 18px;
		max-width: none;
		position: relative;
		top: 1px;
	}

	/*
	 * 2238:3520 etc — full-width 70px rows. Figma's insets are 14/17/14/40 and
	 * its 1px stroke is drawn INSIDE the box, so each one is written a pixel
	 * short for CSS border-box (see [[figma-vs-css-box-traps]]).
	 */
	.tp2026-stat-tile {
		flex: 0 0 auto;
		width: auto;
		max-width: none;
		gap: 12px;
		padding: 13px 16px 13px 39px;
	}

	/* 2243:3663 / 3675 / 3651 — 42px icons, down from the desktop 58. */
	.tp2026-stat-tile__icon {
		width: 42px;
		height: 42px;
	}

	/* The number and label sit side by side here, not stacked. */
	.tp2026-stat-tile__copy {
		flex-direction: row;
		align-items: center;
		gap: 4px;
		width: auto;
	}

	/* 2238:3534 — SemiBold 28/34 in a fixed 80px column, so "04", "100+" and
	   "700+" all put their labels on the same x. */
	.tp2026-stat-tile__number {
		flex: 0 0 80px;
		width: 80px;
		font-size: 28px;
		line-height: 34px;
	}

	/* 2238:3535 — Medium 14, two lines. Figma's `normal` leading measures 18px
	   per line here; Chrome's would be ~17.6 and shrink the block by a pixel. */
	.tp2026-stat-tile__label {
		font-size: 14px;
		line-height: 18px;
	}

	/* 2243:3688 — flat #eaf9ff card, radius 16, 12px media inset, 24px below
	   the photo to the caption and 24px under it to the card's edge. */
	.tp2026-video-card {
		border-radius: 16px;
		padding: 12px 12px 24px;
	}

	/* 2243:3696 — 296x203. */
	.tp2026-video-card__media {
		aspect-ratio: 296 / 203;
	}

	/* 2243:3698 — 20px gap to the chip; the 8px side padding turns the card's
	   12px inset into Figma's 20px text inset on both edges. */
	.tp2026-video-card__caption {
		margin-top: 24px;
		gap: 20px;
		padding: 0 8px;
	}

	/* 2243:3697 — Medium 14/22 #004A67, three lines. */
	.tp2026-video-card__caption p {
		font-size: 14px;
		line-height: 22px;
	}

	.tp2026-video-card__break {
		display: inline;
	}

	/* 2243:3686 — 34px chip, radius 4.72, and no -4px lift: mobile aligns it
	   with the caption's top rather than 4px above it. */
	.tp2026-video-card__arrow {
		width: 34px;
		height: 34px;
		border-radius: 4.72px;
		margin-top: 0;
	}

	/*
	 * 2243:3740 — the rule sits 52px under the video card and 52px above the
	 * Awards heading. The sections either side already contribute 40px of
	 * .tp-section padding each, so the rule's own margins supply the last 12.
	 */
	.tp-divider {
		margin: 12px 0;
	}
}

/* Below the 360px design width the tile's generous 40px left inset costs the
   label the 4px it needs to keep Figma's two-line break — "Global Delivery"
   drops a third line and the row grows to 82px. Pulled in to a 20px inset
   (19 + the 1px stroke) only here, which is enough to hold the break at 320.
   359, not 360: `max-width` is inclusive, so 360px would pull the inset in on
   the design width itself. */
@media (max-width: 359px) {
	.tp2026-stat-tile {
		padding-left: 19px;
	}
}

/* Lightbox, phone sizing. Breakpoint is 600px rather than the section's usual
   425px because the panel is viewport-width-driven: by 600px the -18px close
   overhang is already eating into the overlay gutter and the 20px white margin
   around the frame reads as wasted width, not as a frame. */
/* Everything in the chrome (padding, buttons, icons, type, close inset) is
   already cqw-scaled with a usability floor via clamp() above, so it doesn't
   need breakpoint overrides. Only the 58px play disc is a fixed token shared
   with the video card, so it still needs its own phone-size step. */
@media (max-width: 600px) {
	.tp2026-video-lightbox__play {
		width: 48px;
		height: 48px;
	}
}

/* Motion pass: the lightbox rules live further down the file than the badge's
   reduced-motion block, so their resets have to come last to win on source
   order. Everything becomes instant; the panel loses its rise entirely. */
@media (prefers-reduced-motion: reduce) {
	.tp2026-video-lightbox,
	.tp2026-video-card__play {
		transition: none;
	}

	.tp2026-video-lightbox__panel {
		transform: none;
		transition: none;
	}

	/* Keep the centring translate — only the hover scale is motion. */
	.tp2026-video-lightbox__play,
	.tp2026-video-lightbox__play:hover,
	.tp2026-video-lightbox__play:focus-visible {
		transform: translate(-50%, -50%);
		transition: none;
	}
}
