/* =============================================================================
   /careers/  —  ported 2026-09-22
   -----------------------------------------------------------------------------
   Figma v4zuHnfQeDWmJsqAyNqiDq:
     · desktop  page "Careers - Desktop",  frame 905:153  (1440x5198)
     · mobile   page "Careers — Mobile",   frame 1773:89  (392x4803)

   THE INTERACTION SPECS ARE IN FIGMA COMMENTS, NOT IN THE FILE. All ten of them
   are transcribed in `docs/figma-careers-specs.md`. Three matter here:
     1. the hiring process reveals once, left to right, over 4-6s
     2. the benefits character HOPS between cards on scroll; the cards stay put
     3. open positions has a designed empty state, and it hides the second CTA

   Every colour and size is a token. The page's own palette is the Foundations
   palette read out of the file for the first time during this port — black,
   orange, Cloud Dancer, the three Secondary greys, and Grid (#1C1C1C), which is
   new and lives in tokens.css as --color-grid.

   Geometry comes from `get_metadata` on 905:153, which returns exact bounds, so
   the desktop numbers below are the frame's own and not measured off a render.
   ========================================================================== */

.page-careers {
	font: var(--body-l);
	color: var(--color-cream-dim);
	background: var(--color-black);
	/* Opt out of the fixed-header offset, like Labs and the home page: the
	   lattice draws behind the header all the way to the top of the page. The
	   hero's own padding keeps its content clear of the bar. */
	padding-top: 0;
}

.page-careers .site-footer {
	margin-top: 0;
}

/* --- Header ------------------------------------------------------------- */
/* The frame draws the header bar black over a black hero: `headerTheme: dark`
   in the front matter; the theme itself is in base.css. */

/* --- The two runs of lattice ----------------------------------------------- */
/* The frame draws the grid behind the hero and the hiring card, drops it for the
   people team, and brings it back for the benefits. Two plain wrappers, each
   owning its own background, so the sections inside stay unaware of it — the
   pattern Our Work and Services both use.

   .careers-mid wraps only the benefits STAGE, not the whole section. The frame's
   "GRILLA FONDO BENEFITS" starts at 2387.77 — below the eyebrow and the lead,
   which sit on plain black — so wrapping the section drew it 450px too high. */
.careers-top,
.careers-mid {
	background-image: url("/assets/media/home/grid-tile.svg");
	background-repeat: repeat;
	background-size: var(--grid-tile) var(--grid-tile);
}

/* --- Shared section furniture ---------------------------------------------- */
.careers-section__eyebrow {
	font: var(--label-int);
	letter-spacing: var(--ls-label);
	color: var(--color-brand);
	text-align: center;
	margin: 0;
}

/* =============================================================================
   1. Hero — frame 1572:57 (914.35x366.99) at y 305.4
   ========================================================================== */

.careers-hero {
	/* 305.4 is the frame's own hero top, measured from the page top rather than
	   from the header, because the header floats over it. */
	padding: 305px var(--page-gutter) 0;
}

.careers-hero__inner {
	width: min(100%, 914px);
	margin-inline: auto;
	display: flex;
	align-items: flex-start;
	gap: 60px; /* 427.35 - 366.99 */
}

.careers-hero__photo {
	flex: none;
	width: 367px;
	height: 367px;
	object-fit: cover;
	border-radius: var(--radius-panel);
}

.careers-hero__copy {
	/* 487 wide in the frame, starting 25px down from the photo's top edge. */
	max-width: 487px;
	padding-top: 25px;
}

.careers-hero__title {
	font: var(--display-l);
	letter-spacing: var(--ls-display);
	color: var(--color-cream);
	margin: 0;
}

.careers-hero__accent {
	color: var(--color-brand);
}

/* Body/L, 20/110 — the frame's node is 4 lines in 91px, which is 22 a line. */
.careers-hero__lead {
	font: 400 var(--text-lg) / 1.1 var(--font-sans);
	color: var(--color-cream-dim);
	margin: 17px 0 0;
}

.careers-hero__cta {
	margin-top: 28px;
}

/* The same treatment as the home "Explore our blog" pill: muted sand-soft at
   rest, lit to cream on hover. There the pill carries a black fill and the hover
   leaves it alone; here it carries none — the hero lattice shows through it in
   the frame — so the variant's black hover fill is held off instead. Either way
   the hover is the outline and the label brightening, never a fill change.
   Prefixed to outrank .btn--outline-muted:hover rather than lean on file order. */
.page-careers .careers-hero__cta:hover {
	background: transparent;
}

/* =============================================================================
   2. Hiring process — frame 1572:64
   -----------------------------------------------------------------------------
   Desktop is a horizontal path: one rule, four markers on it, labels alternating
   above and below. Below 768 the same markup becomes a vertical timeline.
   ========================================================================== */

.careers-hiring {
	padding: 216px var(--page-gutter) 0;
}

.careers-hiring__card {
	width: min(100%, 1161px);
	margin: 21px auto 0;
	padding: 67px 0 83px; /* 1001.99 - 935.28, and 1431.77 - 1346.09 */
	border: 1.5px solid var(--color-sand);
	border-radius: var(--radius-panel-lg);
	background: var(--color-black);
}

.careers-hiring__steps {
	list-style: none;
	margin: 0;
	padding: 0;
	/* FIVE equal columns, not four: the mascot is the fifth stop on the rule, one
	   step past marker 4 (frame marker centres run 347, 537, 727, 917 and the
	   mascot sits at 1112 — the same 190px pitch). The marker row is the middle
	   of three rows, so a label can sit above or below the rule without either
	   one shifting the other. */
	display: grid;
	/* minmax(0, 1fr), not 1fr: the label boxes deliberately overflow their column
	   (see below), and a plain `1fr` has a min-content floor — the 311px "Client
	   interview" box widened its own column and threw the marker pitch out from
	   190 to 188/264/238. Same reason base.css uses minmax on the header grid. */
	grid-template-columns: repeat(5, minmax(0, 1fr));
	/* The marker row is pinned to the marker's own height. The mascot is 88 and
	   OVERFLOWS it, exactly as the frame draws it (its box is 125.51 tall on a
	   66.31 row) — without the pin it would push the two label rows apart and
	   make the card 17px too tall. */
	grid-template-rows: var(--row-above) var(--row-marker) auto;
	align-items: center;
	column-gap: 0;
	position: relative;
	padding-inline: var(--rail-pad);

	/* Named so the rule below can be positioned from the same numbers the rows
	   are built from, instead of a percentage. */
	--rail-pad: 104px; /* (1158 track - 5 x 190 pitch) / 2 */
	--row-above: 120px; /* label box 91 + 29 to the marker */
	--row-marker: 66px; /* the frame's marker row; the mascot overflows it */
}

.careers-step {
	display: contents;
}

/* The rule. It is one element's ::before rather than a border on the list, so it
   can be revealed left-to-right with a scaleX transform — which is what the
   animation spec asks for and what a border cannot do. */
/* The rule, positioned rather than laid out. Both a percentage MARGIN and a
   percentage WIDTH on a grid item spanning 1/-1 resolved against something other
   than the track here (963px against a 942px track), so neither survives; these
   offsets are the frame's own — its Line 12 runs 93px into the track and stops
   69px short of the end, from the first marker's centre to just past the last.

   It is one element rather than a border so it can be wiped left to right with
   scaleX, which is what the animation spec asks for and a border cannot do. */
.careers-hiring__steps::before {
	content: "";
	position: absolute;
	left: calc(var(--rail-pad) + 93px);
	right: calc(var(--rail-pad) + 78px);
	top: calc(var(--row-above) + var(--row-marker) / 2);
	height: 1.5px;
	background: var(--color-cream);
	transform-origin: left center;
}

.careers-step__marker {
	grid-row: 2;
	justify-self: center;
	z-index: 1;
	width: 61px;
	height: 61px;
	display: grid;
	place-items: center;
	border: 2px solid var(--color-cream);
	border-radius: var(--radius-lg);
	font: 700 var(--text-display-xs) / 1 var(--font-sans);
	color: var(--color-cream);
	/* The same mesh family as the CTA band and the Services carousel panel —
	   black at the top left running to orange at the right, with a pale glow out
	   of the bottom left. Its own stops because the box is 61px, not 900. */
	background: var(--gradient-step);
}

/* Each label box is the frame's own width, centred on its column and allowed to
   overflow it — Frame 77 is 260 wide on a 190 pitch, Frame 104 is 311. They
   never collide because consecutive labels alternate above and below the rule,
   so the nearest same-row neighbour is two columns (380px) away. Constraining
   them to the column instead made the bottom row 80px too tall. */
.careers-step__body {
	text-align: center;
	width: var(--label-w, 190px);
	justify-self: center;
}

.careers-step:nth-child(1) .careers-step__body { --label-w: 260px; }
.careers-step:nth-child(2) .careers-step__body { --label-w: 218px; }
.careers-step:nth-child(3) .careers-step__body { --label-w: 311px; }
.careers-step:nth-child(4) .careers-step__body { --label-w: 165px; }
.careers-step:nth-child(5) .careers-step__body { --label-w: 212px; }

/* Every above-label shares a top edge in the frame (y 1001.99) and every
   below-label shares one (y 1222.09), so both boxes are pinned to the frame's
   own height and the text sits at the top of its box. Without the min-heights
   the rows collapse to whatever the copy happens to need and the labels drift
   toward the rule — 17px on the top row alone. They are minimums, not fixed
   heights, so longer copy still grows the card rather than overflowing it. */
.careers-step--above .careers-step__body {
	grid-row: 1;
	align-self: start;
	/* 91 box + 29 gap. box-sizing is border-box, so the min-height has to include
	   the padding — at 91 it never binds and the row collapses to the copy. */
	min-height: 120px;
	padding-bottom: 29px; /* 1122.01 - 1092.99 */
}

.careers-step--below .careers-step__body {
	grid-row: 3;
	align-self: start;
	min-height: 158px; /* 124 box + 34 gap, border-box as above */
	padding-top: 34px; /* 1222.09 - 1188.32 */
}

.careers-step--above .careers-step__marker,
.careers-step--below .careers-step__marker {
	grid-row: 2;
}

/* Each step owns its column, in source order. */
.careers-step:nth-child(1) .careers-step__marker,
.careers-step:nth-child(1) .careers-step__body { grid-column: 1; }
.careers-step:nth-child(2) .careers-step__marker,
.careers-step:nth-child(2) .careers-step__body { grid-column: 2; }
.careers-step:nth-child(3) .careers-step__marker,
.careers-step:nth-child(3) .careers-step__body { grid-column: 3; }
.careers-step:nth-child(4) .careers-step__marker,
.careers-step:nth-child(4) .careers-step__body { grid-column: 4; }
.careers-step:nth-child(5) .careers-step__marker,
.careers-step:nth-child(5) .careers-step__body { grid-column: 5; }

.careers-step__title {
	font: 700 var(--text-display-xs) / 1.1 var(--font-sans);
	color: var(--color-brand);
	margin: 0;
}

.careers-step__when {
	display: block;
	font: var(--label-s);
	letter-spacing: var(--ls-label);
	color: var(--color-brand);
	margin-top: 2px;
}

.careers-step__desc,
.careers-step__note {
	font: 400 var(--text-base) / 1.15 var(--font-sans);
	color: var(--color-cream);
	margin: 11px 0 0;
}

.careers-step__note strong {
	font-weight: 700;
}

/* The mascot occupies the marker cell of the fifth step, so it inherits the
   marker's placement but none of its box — it is artwork, not a chip. */
.careers-hiring__mascot {
	width: 88px;
	height: 88px;
	border: none;
	border-radius: 0;
	background: none;
}

.careers-hiring__welcome {
	font: 700 var(--text-display-xs) / 1.1 var(--font-sans);
	color: var(--color-cream);
	text-align: center;
	margin: 0;
}

.careers-hiring__wordmark {
	display: block;
}

.careers-hiring__wordmark span {
	color: var(--color-brand);
}

/* --- The reveal, comment 1 -------------------------------------------------
   One [data-reveal] on the card; everything below is transition delay. The
   sequence is: eyebrow (the card's own fade) -> rule wipes left to right ->
   each marker scales in as the rule reaches it -> that step's text fades up ->
   mascot -> wordmark. Total ~5.1s, inside the 4-6s the spec asks for.

   `.js:not(.reduced-motion)` is what allows the initial state to exist at all:
   without JS, or with the OS set to reduce motion, the timeline renders fully
   drawn and nothing is hidden. reveal.js never adds .is-visible under reduced
   motion, so hiding on `.js` alone left the whole timeline invisible for those
   visitors. Same contract as the team photos below and as reveal.js
   everywhere else. Once .is-visible lands it is never removed, so the sequence
   cannot replay — which the spec explicitly requires.

   Each hidden state has the same specificity as its .is-visible counterpart
   below and comes first, so the visible state wins on source order. */
.js:not(.reduced-motion) .careers-hiring__card .careers-hiring__steps::before {
	transform: scaleX(0);
}

.js:not(.reduced-motion) .careers-hiring__card .careers-step__marker,
.js:not(.reduced-motion) .careers-hiring__card .careers-step__body {
	opacity: 0;
}

.js:not(.reduced-motion) .careers-hiring__card .careers-step__marker {
	transform: scale(0.9);
}

.js:not(.reduced-motion) .careers-hiring__card .careers-step__body {
	transform: translateY(10px);
}

/* The mascot is the fifth marker, so it already lands last and needs no rules of
   its own — only the spec's gentler 95% instead of the numbers' 90%. */
.js:not(.reduced-motion) .careers-hiring__card .careers-hiring__mascot {
	transform: scale(0.95);
}

.js .careers-hiring__card.is-visible .careers-hiring__steps::before {
	transform: scaleX(1);
	transition: transform 2.6s cubic-bezier(0.33, 0, 0.2, 1) 0.35s;
}

.js .careers-hiring__card.is-visible .careers-step__marker {
	opacity: 1;
	transform: scale(1);
	/* --step is 1..4 in the markup; the marker lands as the rule passes it. */
	transition:
		opacity 0.34s ease calc(0.35s + (var(--step) - 1) * 0.62s),
		transform 0.34s cubic-bezier(0.2, 0.7, 0.3, 1.2) calc(0.35s + (var(--step) - 1) * 0.62s);
}

.js .careers-hiring__card.is-visible .careers-step__body {
	opacity: 1;
	transform: none;
	transition:
		opacity 0.4s ease calc(0.55s + (var(--step) - 1) * 0.62s),
		transform 0.4s ease calc(0.55s + (var(--step) - 1) * 0.62s);
}

/* Sequence ends at 0.55s + 4 x 0.62s + 0.4s = 3.43s for the wordmark, inside the
   4-6s the spec asks for once the 0.35s lead-in and the rule's own 2.6s wipe are
   counted. */

/* =============================================================================
   3. Meet our people team — frame 1572:87
   ========================================================================== */

.careers-people {
	padding: 132px var(--page-gutter) 0;
	background: var(--color-black);
}

.careers-people__intro {
	width: min(100%, 415px);
	margin-inline: auto;
	text-align: center;
}

/* Body/M, 16/115 — node 1166:917 is 3 lines in 54px. */
.careers-people__lead {
	font: 400 var(--text-base) / 1.15 var(--font-sans);
	color: var(--color-cream-dim);
	margin: 11px 0 0;
}

.careers-people__grid {
	list-style: none;
	margin: 66px auto 0;
	padding: 0;
	width: min(100%, 894px);
	display: grid;
	/* minmax(0, 1fr): the role label is `white-space: nowrap` below, and a plain
	   `1fr` takes its min-content from that — "[PEOPLE SPECIALIST]" is 186.7px at
	   15px Eurostile, which widened every column and pushed the page 123px wide
	   at 768. */
	grid-template-columns: repeat(4, minmax(0, 1fr));
	/* 45, not the frame's nominal 55: its columns are content-sized and reach
	   189.68, and an equal-column grid only gets there at this gap. At 55 the
	   columns fall to 182 and three of the four role labels wrap. */
	gap: 45px;
	align-items: start;
}

.careers-person {
	text-align: center;
}

.careers-person__photo {
	/* `block` matters: as an inline image it carries a baseline descender gap and
	   makes every card 8px taller than the frame. */
	display: block;
	margin-inline: auto;
	width: 157px;
	height: 157px;
	object-fit: cover;
	border-radius: var(--radius-lg);
}

.careers-person__name {
	font: 700 var(--text-display-xs) / 1.1 var(--font-sans);
	color: var(--color-cream);
	margin: 9px 0 0;
}


.careers-person__role {
	white-space: nowrap;
	font: var(--label-m);
	letter-spacing: var(--ls-label);
	color: var(--color-sand-soft);
	margin: 6px 0 0;
}

/* Comment 5: the photos slide as you scroll, alternating. --drift is -1/1 per
   card, set in the markup by position. careers.js writes --shift (a 0..1 scroll
   progress) on the list; multiplying the two gives each card its direction.
   Purely decorative, so it is cut entirely under reduced motion. */
@media (prefers-reduced-motion: no-preference) {
	.careers-person__photo {
		transform: translateY(calc(var(--drift, 0) * var(--shift, 0) * 14px));
		will-change: transform;
	}
}

/* =============================================================================
   4. Benefits & perks — frame 1573:153
   -----------------------------------------------------------------------------
   A hand-placed scatter, not a grid: five cards of DIFFERENT widths alternating
   sides down a 975px band, each with a tilted orange pill overlapping its top
   edge. The widths and tilts are the frame's own and are carried per card in the
   markup (--card-w, --tilt), because there is no rule behind them to derive.

   This is the one place the repo's "make the geometry uniform" call (Our Work's
   cards, Services' cards) does NOT apply: those were lists, where one geometry
   is what makes them read as a list. This is a composition, and the irregularity
   is the composition.
   ========================================================================== */

.careers-benefits {
	/* 149 in the frame; 145 here, which absorbs the ~4px the two blocks above
	   accumulate against their nodes and puts the eyebrow back on 2085. */
	/* No inline gutter: .careers-mid inside this section runs full-bleed, so the
	   gutter lives on the intro and the stage instead. */
	padding: 145px 0 0;
}

.careers-benefits__intro {
	width: min(100% - 2 * var(--page-gutter), 461px);
	margin-inline: auto;
	text-align: center;
}

/* Body/M, 16/115 — measured at an 18px pitch on the frame's own render. */
.careers-benefits__lead {
	font: 400 var(--text-base) / 1.15 var(--font-sans);
	color: var(--color-cream-dim);
	margin: 17px 0 0;
}

/* Desktop joins the two paragraphs into the single block the desktop frame
   draws; the mobile frame splits them, which is the markup's natural state. */
@media (min-width: 768px) {
	.careers-benefits__lead + .careers-benefits__lead {
		margin-top: 0;
	}
}

/* careers.js appends these at every width; only the mobile block shows them. */
.careers-benefits__dots,
.careers-benefits__hint {
	display: none;
}

.careers-benefits__stage {
	position: relative;
	width: min(100%, 975px);
	margin: 135px auto 0; /* intro bottom 2217.98 -> first card top 2352.92 */
}

.careers-benefits__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
}

.careers-benefit {
	position: relative;
	width: min(100%, var(--card-w));
}

.careers-benefit--left {
	align-self: flex-start;
	text-align: left;
}

.careers-benefit--right {
	align-self: flex-end;
	text-align: right;
}

/* The gaps between cards are the frame's, and they are all different. */
.careers-benefit:nth-child(2) { margin-top: 30px; }
.careers-benefit:nth-child(3) { margin-top: 67px; }
.careers-benefit:nth-child(4) { margin-top: 82px; }
.careers-benefit:nth-child(5) { margin-top: 48px; }

.careers-benefit__pill {
	position: absolute;
	top: -33px;
	z-index: 1;
	margin: 0;
	padding: 6px 26px;
	min-height: 43px;
	display: inline-flex;
	align-items: center;
	border-radius: var(--radius-md);
	background: var(--color-brand);
	color: var(--color-black);
	font: 700 var(--text-display-xs) / 1.1 var(--font-sans);
	transform: rotate(var(--tilt, 0deg));
}

/* Right-hand cards hang their pill 18px in from the card's right edge; left-hand
   cards hang it 29px in from the left. Both measured off the frame. */
.careers-benefit--right .careers-benefit__pill {
	right: 18px;
}

.careers-benefit--left .careers-benefit__pill {
	left: 29px;
}

.careers-benefit__card {
	min-height: 134px;
	display: flex;
	align-items: center;
	padding: 28px 32px;
	border-radius: var(--radius-card);
	background: var(--color-sand-pale);
	color: var(--color-black);
}

.careers-benefit__card p {
	font: 400 var(--text-base) / 1.15 var(--font-sans);
	margin: 0;
	width: 100%;
}

.careers-benefit__card strong {
	font-weight: 700;
}

/* The character, comment 2. It is absolutely positioned against the stage and
   careers.js moves it between per-card anchors; the hop itself is this
   transition, and it is short on purpose so it does not read as a continuous
   translateY. Desktop only — the mobile frame has no character. */
.careers-benefits__character {
	position: absolute;
	left: 0;
	top: 0;
	width: 132px; /* the SVG's box: 124 of art, 4px either side for the shadow */
	height: 123px;
	/* In front of the cards AND their pills: the pill carries z-index 1 in the
	   stage's stacking context, and the character overlaps both. */
	z-index: 2;
	pointer-events: none;
	opacity: 0;
	/* --flip is 1 or -1, set per card by careers.js: the drawing faces right, so
	   a left-hand card gets the mirror.

	   `translate` and `scale` as SEPARATE properties, not one `transform`. Inside
	   a transform the flip interpolates from 1 to -1 and passes through
	   scaleX(0), so the character folds flat in the middle of every hop. Split
	   out, only the hop is transitioned and the turn lands instantly with it. */
	translate: var(--cx, 0px) var(--cy, 0px);
	scale: var(--flip, 1) 1;
	transition:
		translate 0.42s cubic-bezier(0.34, 1.3, 0.5, 1),
		opacity 0.3s ease;
}

.careers-benefits__character.is-placed {
	opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
	.careers-benefits__character {
		transition: opacity 0.3s ease;
	}
}

/* The first placement is not animated (careers.js suppresses the transition for
   it), so the character must not start at 0,0 and slide in. */
.careers-benefits__character:not(.is-placed) {
	visibility: hidden;
}

/* =============================================================================
   5. Our team — frame 1238:222
   -----------------------------------------------------------------------------
   15 columns x 6 rows of 69.18px tiles, with four photographs landing on whole
   cells. The frame masks each photo by the union of the squares it covers, which
   cuts a star at every inner junction; the build rounds only the four outer
   corners instead, as home does (owner, 2026-09-29). A span change needs a
   re-crop to the new aspect ratio.
   ========================================================================== */

.careers-team {
	padding: 119px var(--page-gutter) 0; /* 121 in the frame, less 2 of drift */
	background: var(--color-black);
}

.careers-team__grid {
	--careers-team-cols: 15;
	/* A size container, so a photo can size its corners off the grid's width
	   (cqi) and so off the cell: see .careers-team__photo. */
	container-type: inline-size;
	width: min(100%, 1038px);
	margin: 55px auto 0;
	display: grid;
	grid-template-columns: repeat(15, 1fr);
	grid-template-rows: repeat(6, 1fr);
	/* Six rows, square cells. aspect-ratio on the container keeps the cells
	   square at every width without each one needing its own. */
	aspect-ratio: 15 / 6;
	/* One tile per cell, sized off the grid itself so the two can never drift. */
	background-image: url("/assets/media/careers/team-grid-tile.svg");
	background-repeat: repeat;
	background-size: calc(100% / 15) calc(100% / 6);
}

.careers-team__photo {
	width: 100%;
	height: 100%;
	object-fit: cover;
	align-self: stretch;
	/* The whole photo, with only its outer corners rounded — at the tile's own
	   radius (rx 15 of 69 in team-grid-tile.svg), one cell being the grid's
	   width over its column count. So a photo starts and ends on the lattice,
	   as home's collage does (#121), at both breakpoints. */
	border-radius: calc(100cqi / var(--careers-team-cols) * 15 / 69);
}

/* Comment 4: "the images appear in movement and keep changing, the same as on
   home". What home does is fade its collage photos up one after another over the
   lattice, which stays visible throughout — `home-team__photo--a/b/d` at 0.15s,
   0.75s and 1.35s. Same rhythm here for four photos.

   Nothing wraps the photos, unlike home: the lattice is the grid's own
   background, so fading a photo reveals the lattice behind it directly rather
   than a black hole. `.js` gates the hidden initial state, so with JS off the
   photos are simply there. */
html.js:not(.reduced-motion) .careers-team__grid .careers-team__photo {
	transition-property: opacity, transform;
	transition-duration: 1.2s, 1.2s;
	transition-timing-function: ease-out;
}

html.js:not(.reduced-motion) .careers-team__grid[data-reveal]:not(.is-visible) .careers-team__photo {
	opacity: 0;
	transform: scale(1.04);
}

/* Set as longhands, not the `transition` shorthand: the shorthand carries an
   implicit transition-delay:0s and would reset every stagger below — the same
   trap home.css documents on its own collage. */
html.js:not(.reduced-motion) .careers-team__photo--desks  { transition-delay: 0.15s; }
html.js:not(.reduced-motion) .careers-team__photo--ivy    { transition-delay: 0.60s; }
html.js:not(.reduced-motion) .careers-team__photo--woman  { transition-delay: 1.05s; }
html.js:not(.reduced-motion) .careers-team__photo--window { transition-delay: 1.50s; }

.careers-team__photo--desks  { grid-area: 1 / 4 / span 3 / span 4; }
.careers-team__photo--ivy    { grid-area: 2 / 11 / span 4 / span 4; }
.careers-team__photo--woman  { grid-area: 4 / 1 / span 2 / span 2; }
.careers-team__photo--window { grid-area: 5 / 7 / span 2 / span 3; }

/* =============================================================================
   6. Open positions — frame 1573:170, and 1030:43 for the empty state
   -----------------------------------------------------------------------------
   The page's only cream band. It runs full-bleed and the footer follows it, so
   the page ends light even though everything above is black.
   ========================================================================== */

.careers-positions {
	margin-top: 173px;
	padding: 112px var(--page-gutter) 107px;
	background: var(--color-cream);
	color: var(--color-carbon);
}

.careers-positions__eyebrow {
	color: var(--color-grid);
}

.careers-roles {
	width: min(100%, 888px);
	margin: 52px auto 0;
	display: flex;
	align-items: center;
	gap: 24px;
}

.careers-roles__arch {
	flex: none;
	background: none;
	border: none;
	padding: 0;
	cursor: pointer;
	line-height: 0;
}

.careers-roles__arch[hidden] {
	display: none;
}

.careers-roles__track {
	list-style: none;
	margin: 0;
	padding: 0;
	flex: 1;
	display: flex;
	gap: 31px;
	/* `safe` centre: with one role the card sits in the middle of the track, as
	   the frame's pair does, but once the roles overflow it falls back to
	   flex-start so the first card cannot end up scrolled off the left edge. */
	justify-content: safe center;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
}

.careers-roles__track::-webkit-scrollbar {
	display: none;
}

.careers-role {
	flex: 0 0 375px;
	scroll-snap-align: center;
	display: flex;
	flex-direction: column;
	min-height: 319px;
	padding: 31px 42px;
	border-radius: var(--radius-panel-lg);
	color: var(--color-cream);
	/* The frame fills the card with the brand mesh — black at the bottom left
	   running to orange at the top right. Same family as the step marker, its own
	   stops because the box is portrait rather than square. */
	background: var(--gradient-role-card);
}

.careers-role__title {
	font: 700 var(--text-display-xs) / 1.1 var(--font-sans);
	color: var(--color-white);
	margin: 0;
}

.careers-role__desc {
	font: 400 var(--text-base) / 1.15 var(--font-sans);
	margin: 17px 0 0;
}

.careers-role__labels {
	display: flex;
	flex-direction: column;
	gap: 7px;
	margin: 22px 0 0;
	font: var(--label-s);
	letter-spacing: var(--ls-label);
	color: var(--color-cream);
}

/* Pins the button to the bottom so all the cards agree on height however long a
   role's description runs — the same device the Services cards use. */
.careers-role__cta {
	margin-top: auto;
	align-self: flex-start;
}

.careers-positions__more,
.careers-positions__empty {
	width: min(100%, 416px);
	margin: 90px auto 0;
	text-align: center;
}

.careers-positions__more-title,
.careers-positions__empty-title {
	font: 700 var(--text-display-xs) / 1.1 var(--font-sans);
	color: var(--color-carbon);
	margin: 0;
}

.careers-positions__empty-title {
	font-size: var(--text-2xl);
}

/* 16/1.2 — the frame's lead node is 3 lines in 57px. */
.careers-positions__more-lead {
	font: 400 var(--text-base) / 1.2 var(--font-sans);
	color: var(--color-carbon-muted);
	margin: 12px 0 0;
}

.careers-positions__cta {
	margin-top: 12px;
}

/* =============================================================================
   The 1100 block — derived, not designed
   -----------------------------------------------------------------------------
   Nothing between the 1440 and 392 frames is drawn, so this block carries no
   authority; it exists so the page does not break at tablet widths. Same status
   as the equivalent blocks on Our Work and Services.
   ========================================================================== */

@media (max-width: 1100px) {
	.careers-hero {
		padding-top: 220px;
	}

	.careers-hero__inner {
		gap: 40px;
	}

	.careers-hiring__steps {
		--rail-pad: 24px;
	}

	/* The frame's fixed label widths (up to 311px) only fit on a 190px pitch. On
	   a 1440 track there is room for them to overflow their column; below that
	   there is not, and at 768 the fifth one pushed the page 123px wide. Here
	   they go back to filling their own column. */
	.careers-step__body {
		--label-w: auto;
		padding-inline: 8px;
	}

	.careers-people__grid {
		gap: 32px;
	}

	/* The photo is a fixed 157 on desktop, which needs a column at least that
	   wide; below ~880 of content the four columns fall under it. And the role
	   label stops being nowrap, because there is no longer room for it on one
	   line — only the 1440 frame has that. */
	.careers-person__photo {
		width: 100%;
		max-width: 157px;
		height: auto;
		aspect-ratio: 1;
	}

	.careers-person__role {
		white-space: normal;
	}

	.careers-benefit {
		--card-w: 100%;
	}

	.careers-benefits__character {
		display: none;
	}

	.careers-role {
		flex-basis: 320px;
	}
}

/* =============================================================================
   Mobile — frame 1773:89 (392x4803)
   -----------------------------------------------------------------------------
   Four things are not a narrower desktop, and each is called out where it lands:
     · the hiring process becomes a vertical timeline
     · the benefits become a swipe carousel, and the character goes away
     · the people team becomes a 2x2 grid
     · the lattice tile drops to 49.11 (eight across 392), the site-wide mobile
       value the Our Work mobile port established
   ========================================================================== */

@media (max-width: 767px) {
	.careers-top,
	.careers-mid {
		background-size: var(--grid-tile-sm) var(--grid-tile-sm);
	}

	/* --- Hero: stacks and centres -------------------------------------- */
	.careers-hero {
		padding: 119px var(--page-gutter-sm) 0;
		text-align: center;
	}

	.careers-hero__inner {
		flex-direction: column;
		align-items: center;
		gap: 33px;
	}

	.careers-hero__photo {
		/* The mobile frame crops the square to 254x180; object-fit does that
		   without a second asset. */
		width: 254px;
		height: 180px;
		border-radius: var(--radius-lg);
	}

	.careers-hero__copy {
		max-width: none;
		padding-top: 0;
	}

	.careers-hero__title {
		font: 700 var(--text-display-s) / 1 var(--font-sans);
	}

	.careers-hero__lead {
		font: 400 var(--text-sm) / 1.35 var(--font-sans);
		margin-top: 15px;
	}

	.careers-hero__cta {
		margin-top: 22px;
	}

	/* --- Hiring process: a vertical timeline ---------------------------- */
	.careers-hiring {
		padding: 76px var(--page-gutter-sm) 0;
	}

	.careers-hiring__card {
		margin-top: 22px;
		/* 39 inline, not 24: the frame puts the marker 40.6 from the card's left
		   edge, which with a 45 marker and a 20 gap lands the text on 106. 39
		   rather than 41 because the card's own 1.5px border sits inside it. */
		padding: 40px 39px 36px;
		border-radius: var(--radius-panel);
	}

	.careers-hiring__steps {
		display: flex;
		flex-direction: column;
		/* `stretch`, and it is load-bearing. The desktop rule sets
		   `align-items: center`, which is vertical centring in that grid — but in
		   a COLUMN flex container the same declaration centres each row at its own
		   intrinsic width, so every step indented by half its own slack and the
		   markers walked right down the list (25.5, 25.5, 25.5, 41.2, 61). */
		align-items: stretch;
		gap: 30px;
		padding-inline: 0;
	}

	/* `display: contents` is what lets a step span three grid rows on desktop.
	   Here each step is its own flex row again, so it has to come back. */
	.careers-step {
		display: flex;
		align-items: flex-start;
		gap: 20px; /* marker right 85.6 -> text left 106.1 */
		position: relative;
	}

	/* The rule turns 90 degrees. It is drawn per step rather than once, so it
	   stops cleanly at the last marker instead of running past it. */
	.careers-hiring__steps::before {
		display: none;
	}

	.careers-step:not(:last-child)::before {
		content: "";
		position: absolute;
		/* The frame runs the rule through the markers' centres — 45 / 2, less half
		   the rule's own 1.5px width. */
		left: 21.75px;
		top: 45px;
		bottom: -30px;
		width: 1.5px;
		background: var(--color-cream);
		transform-origin: top center;
	}

	/* Hidden only when it will be revealed — see "The reveal" above. */
	.js:not(.reduced-motion) .careers-hiring__card .careers-step:not(:last-child)::before {
		transform: scaleY(0);
	}

	.js .careers-hiring__card.is-visible .careers-step:not(:last-child)::before {
		transform: scaleY(1);
		transition: transform 0.5s ease calc(0.35s + (var(--step) - 1) * 0.62s);
	}

	.careers-step__marker {
		flex: none;
		width: 45px;
		height: 45px;
		font-size: var(--text-lg);
	}

	/* The mascot is bigger than a marker and the frame centres it on the SAME
	   axis rather than aligning its left edge, so the rule runs straight into it.
	   Negative inline margins keep it centred in the 45px lane without moving the
	   text, which stays on 106 like every other step. */
	.careers-hiring__mascot {
		width: 78px;
		height: 77px;
		margin-inline: -16.5px;
	}

	/* The desktop label boxes carry a fixed --label-w and a row min-height so the
	   horizontal path lines up. Both have to be undone here or the fixed width
	   overflows the 392 track (it pushed the markers to -38px) and the
	   min-height makes every step 158 tall. */
	.careers-step__body,
	.careers-step--above .careers-step__body,
	.careers-step--below .careers-step__body {
		text-align: left;
		padding: 0;
		flex: 1;
		width: auto;
		min-height: 0;
	}

	.careers-step__title {
		font-size: var(--text-lg);
	}

	.careers-step__desc,
	.careers-step__note {
		font-size: var(--text-sm);
		line-height: 1.35;
		margin-top: 6px;
	}

	.careers-hiring__end {
		flex-direction: row;
		justify-content: flex-start;
		gap: 14px;
		margin-top: 40px;
	}

	.careers-hiring__welcome {
		text-align: left;
		font-size: var(--text-xl);
	}

	/* --- People team: a 2x2 grid ---------------------------------------- */
	.careers-people {
		padding: 84px var(--page-gutter-sm) 0;
	}

	.careers-people__grid {
		grid-template-columns: repeat(2, 1fr);
		/* 120px photos with a 22px gutter, which is what the mobile frame draws
		   (its two columns run 665..785 and 807..927 of a 392 frame). */
		gap: 34px 22px;
		margin-top: 40px;
		max-width: 262px;
	}

	.careers-person__photo {
		width: 100%;
		height: auto;
		aspect-ratio: 1;
	}

	/* 16, not 20: the frame's names sit on one line inside a 120px column, and
	   "Verena Grunow" is 150px wide at 20. */
	.careers-person__name {
		font-size: var(--text-base);
	}

	.careers-person__role {
		font-size: var(--text-4xs);
	}

	/* --- Benefits: a swipe carousel ------------------------------------- */
	.careers-benefits {
		padding: 80px 0 0;
	}

	.careers-benefits__intro {
		/* The desktop rule subtracts two DESKTOP gutters from 100%, which leaves
		   232px at 392 and wraps the lead to a column. The mobile gutter is
		   padding here instead. */
		width: auto;
		padding-inline: var(--page-gutter-sm);
	}

	.careers-benefits__lead {
		font-size: var(--text-sm);
		line-height: 1.35;
	}

	.careers-benefits__stage {
		margin-top: 46px;
		width: 100%;
	}

	.careers-benefits__list {
		flex-direction: row;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		scrollbar-width: none;
		/* A slide is the full track width, so no neighbour is ever on screen and a
		   swipe moves by exactly one card — the same contract the Our Work mobile
		   quote carousel holds itself to. */
		gap: 0;
	}

	.careers-benefits__list::-webkit-scrollbar {
		display: none;
	}

	.careers-benefit,
	.careers-benefit--left,
	.careers-benefit--right {
		flex: 0 0 100%;
		width: 100%;
		max-width: none;
		margin-top: 0;
		align-self: stretch;
		text-align: left;
		scroll-snap-align: start;
		padding: 33px var(--page-gutter-sm) 0;
	}

	.careers-benefit__pill,
	.careers-benefit--left .careers-benefit__pill,
	.careers-benefit--right .careers-benefit__pill {
		left: 44px;
		right: auto;
		top: 0;
		font-size: var(--text-xl);
		min-height: 48px;
	}

	.careers-benefit__card {
		min-height: 200px;
		padding: 36px 28px 28px;
		border-radius: var(--radius-card-sm);
	}

	.careers-benefit__card p {
		font-size: var(--text-base);
		line-height: 1.3;
	}

	.careers-benefits__character {
		display: none;
	}

	/* Dots + hint, generated by careers.js from the card count so adding a
	   sixth benefit needs nothing here. */
	/* The dots are components/carousel-dots.css, cream on this dark ground. */
	.careers-benefits__dots {
		--carousel-dot-color: var(--color-cream);
		display: flex;
		justify-content: center;
		gap: 10px;
		margin-top: 30px;
	}

	.careers-benefits__hint {
		display: block;
		text-align: center;
		font: 400 var(--text-sm) / 1.3 var(--font-sans);
		color: var(--color-cream-dimmer);
		margin: 18px 0 0;
	}

	/* --- Our team: the same four photos on an 8-column grid -------------- */
	/* Each photo keeps its own span, so its crop is unchanged. The arrangement
	   is the mobile frame's rhythm rather than its exact placement — see the
	   note in the page. */
	.careers-team {
		padding: 72px var(--page-gutter-sm) 0;
	}

	.careers-team__grid {
		--careers-team-cols: 8;
		grid-template-columns: repeat(8, 1fr);
		grid-template-rows: repeat(15, 1fr);
		aspect-ratio: 8 / 15;
		margin-top: 34px;
		background-size: calc(100% / 8) calc(100% / 15);
		/* A little breathing room below the last tile row: the coincide-edge tile
		   meets the grid's bottom with its outer half-stroke clipped, which reads
		   as a cut. Confining the lattice to the content box and adding a small
		   bottom padding lets it end clear of the section boundary. */
		padding-bottom: 6px;
		background-origin: content-box;
		background-clip: content-box;
	}

	/* The photos keep their own spans, so their crops fit; only where they sit
	   changes. */
	.careers-team__photo--desks  { grid-area: 1 / 3 / span 3 / span 4; }
	.careers-team__photo--ivy    { grid-area: 5 / 1 / span 4 / span 4; }
	.careers-team__photo--window { grid-area: 10 / 5 / span 2 / span 3; }
	.careers-team__photo--woman  { grid-area: 13 / 1 / span 2 / span 2; }

	/* --- Open positions -------------------------------------------------- */
	.careers-positions {
		margin-top: 96px;
		padding: 60px var(--page-gutter-sm) 64px;
	}

	.careers-roles {
		margin-top: 34px;
		gap: 8px;
	}

	.careers-role {
		flex-basis: 100%;
		min-height: 0;
		padding: 28px 26px;
		border-radius: var(--radius-panel);
	}

	.careers-roles__track {
		gap: 16px;
	}

	.careers-positions__more,
	.careers-positions__empty {
		margin-top: 48px;
	}

	.careers-positions__more-title,
	.careers-positions__empty-title {
		font-size: var(--text-xl);
	}

	/* The site-wide mobile footer puts the social row in a black band with the
	   home grid behind it, above the cream footer. On this page that band sits
	   right under the cream [Open Positions] section and reads as a foreign black
	   box; here it drops the black and the grid so the row sits on the page cream
	   like the section above it. The footer here is cream already, so no seam to
	   paint over. Icons in sand-soft (frame), not the mobile default's orange. */
	.page-careers .site-footer__social {
		background: none;
	}

	.page-careers .site-footer__social a {
		background-color: var(--color-sand-soft);
	}
}
