/* Cinc Connect app cards.

   Measured off design-preview-v2.pdf page 2 at 144dpi (2x design px) for the
   geometry. The headings survived the export as LIVE TEXT rather than as
   outlines, so their font, size, weight, colour and per-glyph advances are
   quoted out of the file rather than solved — the one section in this theme
   where the type is read instead of derived.

   Comp values, in design px at 1440:

     row          two cards, x72–700 and x740–1368, 40 gap, 72 each side
     card         628 x 656, radius 12
     photograph   fills the card, centre-cropped
     scrim        Deep Green, opaque from the card's top to y+31 (4.7% of the
                  card), gone by roughly y+360 (54.9%)
     heading      Inter 29.8656 / baseline pitch 29.866 (leading 1.0) /
                  -0.0296em / #FBFAF7 / centred, line 1 Regular, line 2 Bold.
                  First line box 41.85 below the card's top.
     screenshot   357 wide (56.85% of the card), its own top 129.15 below the
                  card's top — 27.6 under the heading's line box — running
                  past the card's bottom edge and CUT by it. 526.85 of its
                  696.7 shows; the rest is clipped.

     41.85 + 59.73 + 27.57 + 526.85 = 656.00, the card's height exactly.

   HOW THE SIZE WAS READ. pymupdf's rawdict gives size 29.8656 and fonts
   Inter-Regular / Inter-Bold directly. Two independent checks agree, so the
   number is not being taken on trust: the flat-topped capitals — R in
   "Residents", B in "Board" — measure a 21.75 cap at 8x with antialiasing
   off, and Inter's cap is 2048/2816 = 0.727273 of the em, giving 29.906; and
   the two baselines sit 29.866 apart, which at leading 1.0 IS the size.

   TRACKING. Summing the embedded font's own hmtx advances for each string and
   comparing against the origins the PDF actually places gives -0.0277em on
   "Cinc Connect", -0.0303em on "for Residents" and -0.0308em on "for Board
   Members" — an average of -0.0296. -0.03em, which is what the comps track
   display type at throughout.

   CENTRING. The heading's advance box centres on x381.6 and x1057.6 against
   card centres of 386 and 1054, and the two screenshots' image boxes on
   x382.7 and x1056.0. The two cards are off in OPPOSITE directions by 2–4px,
   so the intent is centred and the offsets are drift in the comp. Everything
   here is centred on the card axis; the largest departure from the comp is
   4.4px on one heading.

   Fidelity notes, all in the summary as well:
     - the comp sets the heading in #FBFAF7, Warm White. The theme's rule is
       that type on a green or dark surface is --ink-inverse, pure white, so
       that is what is used — 14.94:1 on Deep Green against Warm White's
       14.31:1, and the same colour every other dark surface in the theme
       already uses.
     - the row is inset 72 a side. That value is one of the theme's three open
       questions: it is neither --pageGutter (108) nor --bandInset (30), and
       it now has three sections corroborating it. Written locally as
       var(--pillGutter) rather than invented as a token.
     - the scrim reaches for --surface-declaring, the ROLE, where
       magic-moment's scrim reaches past it to the --deep-green palette value.
       Same colour; this one goes through the role as the token file asks. */

section.connect-cards {

	/* --bandInset, 30 a side — the same edge the magic-moment band and the CTA
	   card sit on, not the 72 that boxes elsewhere use.

	   Ruled on 2026-08-26. These two are read as a near-bleed pair with that
	   band rather than as cards in the box column, and at 72 they sat 42px
	   inside it, which is close enough to look like a mistake rather than a
	   distinction. The header note above still describes the old 72 as a
	   corroborating sighting; that is history now, and --pillGutter has since
	   been minted as a real token for the sections that do want the box edge.

	   The heading keeps its own padding-inline further down, so moving the
	   card edge out does not push type toward the screen. */
	.container {
		padding-inline: var(--bandInset);
	}

	.cards {
		display: grid;
		gap: 40px;

		/* minmax(0, 1fr), never minmax(max-content, 1fr): a max-content floor
		   sizes every track to the widest card and cannot shrink. */
		grid-template-columns: minmax(0, 1fr);

		/* 760 rather than promo-cards' 720. These cards are heavier — a
		   30px heading and a phone screenshot each — and two of them in a
		   720 viewport leaves 304px tracks. */
		@media (min-width: 760px) {
			grid-template-columns: repeat(2, minmax(0, 1fr));
		}

		/* --cols comes from the markup: the card count, except four, which
		   stays at two so it wraps to two rows rather than putting a 30px
		   heading in a 300px track. */
		@media (min-width: 1240px) {
			grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr));
		}
	}

	/* The card is a picture, and its height is built rather than declared:
	   heading block + the screenshot's REVEAL. No padding-bottom, because the
	   screenshot runs all the way to the bottom edge and is cut there.

	   overflow: hidden is what does the cutting, and it is also what keeps
	   the photograph inside the radius. isolation: isolate gives the negative
	   z-indexes below a stacking context of their own so they cannot slide
	   behind the section.

	   THIS ELEMENT IS ALSO THE .zoom-frame. The card carries the class in the
	   markup rather than a wrapper being added round the photograph, because
	   the card is ALREADY the box that clips — a second frame would mean two
	   elements clipping the same picture. .zoom-frame declares overflow:
	   hidden as well; the declaration below stays because the cut it makes is
	   this card's own layout, holding the screenshot to the bottom edge and
	   the photograph inside the radius, and that must not become a thing the
	   card only does while a motion utility is attached to it.

	   position: relative is load-bearing twice over — for the photograph and
	   scrim, and as the containing block for the stretched link. */
	.card {
		position: relative;
		isolation: isolate;
		overflow: hidden;
		border-radius: var(--rad);
		text-align: center;

		/* Stands in before a photograph is chosen, and backs the scrim after
		   it — a card whose image has not loaded is Deep Green, not white. */
		background-color: var(--surface-declaring);
		color: var(--ink-inverse);

		/* 41.85 at 1440. vw rather than a percentage: a percentage on
		   padding-block resolves against WIDTH, which would tie this to the
		   column count. The 24 floor is what keeps it from collapsing to
		   11px on a phone. */
		padding-block: clamp(24px, 2.9167vw, 42px) 0;
	}

	/* The transition, the distance and the WebKit anti-shimmer pair all come
	   from .zoom-frame > img in css/utilities/_motion.css now. This rule sets
	   geometry only. */
	.card-photo {
		position: absolute;
		inset: 0;
		z-index: -3;
		width: 100%;
		height: 100%;
		object-fit: cover;
	}

	/* Deep Green, opaque to 4.7% of the card and gone by 54.9%, measured off
	   the comp: down a photograph strip beside the heading the pixels are
	   EXACTLY #002D28 — zero variance across the strip — from the card's top
	   to y+31, and the strip's horizontal detail is back to full strength by
	   about y+360.

	   Percentages of the card's HEIGHT rather than a length, so a card that
	   comes out taller — a heading that wraps to three lines, a narrower
	   track — keeps the same proportion of scrim over the same heading rather
	   than fading out halfway through it.

	   color-mix rather than the transparent keyword: it fades the same colour
	   out rather than interpolating towards transparent black, which greys
	   the middle of the ramp.

	   CONTRAST. Worked with the photograph assumed to be PURE WHITE under the
	   heading — the worst ground a photograph can present — so the numbers
	   hold for any image an author picks. The foot of a two-line heading sits
	   at 15.5% of the card at 1440 and 18.8% on a phone, where the scrim is
	   still 0.78 and 0.72 opaque: 7.59:1 and 6.11:1. A three-line heading on
	   a phone is 4.51:1 and a four-line one 3.51:1, both still clear, since
	   the heading is 24px or larger everywhere and WCAG counts that as
	   large-scale text at 3:1. Five lines over a white photograph would be
	   2.84:1 — that is the case the image field's help text is about. */
	.card-scrim {
		position: absolute;
		inset: 0;
		z-index: -2;
		background: linear-gradient(180deg,
			var(--surface-declaring) 0%,
			var(--surface-declaring) 4.7%,
			color-mix(in srgb, var(--surface-declaring) 0%, transparent) 54.9%);
	}

	/* 29.8656 is read from the file, not derived — see the header. The clamp
	   floor is 24 rather than the usual size/1.44, and it is there for a
	   reason beyond taste: 24px is WCAG's large-scale threshold at any
	   weight, so the heading needs 3:1 rather than 4.5:1 wherever it lands.
	   That is what makes white over a scrim on an unknown photograph safe.
	   Drop this below 24 and the contrast argument in the summary stops
	   holding.

	   Leading 1.0: the comp's two baselines sit 29.866 apart at 29.8656.

	   No text-wrap: balance. The line break is a <br> the author typed, and
	   balance across a forced break is implementation defined. */
	.card-heading {
		margin: 0;
		font-size: clamp(2.4rem, 2.074vw, 2.9866rem);
		line-height: 1;
		font-weight: var(--book);
		letter-spacing: -.03em;
		color: var(--ink-inverse);

		/* Not measurable off the comp — neither heading comes near the card's
		   edge — so this is a choice: enough that a long heading wraps before
		   it touches the sides. 40 at 628. */
		padding-inline: clamp(16px, 6.37%, 40px);

		/* The comp's pair is static Regular over static Bold. Regular moves
		   up one rung to --book, because Inter Variable renders lighter than
		   the cut the comps were set in; Bold is already the top of its band
		   at 700 and stays. */
		--emphasis-weight: var(--bold);
		--emphasis-color: inherit;
	}

	/* The whole-card link.

	   The anchor wraps the heading's text and nothing else; ::after stretches
	   it over the card. One link, one tab stop, accessible name = the
	   heading, and the <h3> stays a heading rather than becoming a div with a
	   click handler. It also keeps the screenshot's alt text outside the
	   link, where a wrapper anchor would have folded it into the link's name.

	   z-index: 1 puts the hit area over the screenshot, which is in normal
	   flow at z-index auto. */
	.card-link {
		&::after {
			content: '';
			position: absolute;
			inset: 0;
			z-index: 1;
			border-radius: var(--rad);
		}

		/* The ring goes on the stretched pseudo, not on the inline text box —
		   a 3px outline around two lines of type inside a 628px card reads as
		   a mistake. Suppressing the inline one is only safe BECAUSE the
		   card-sized one replaces it.

		   Two-tone, and drawn inward: outline-offset outward would be cut off
		   by the card's own overflow: hidden. The inset shadow lays a 6px Deep
		   Green band round the inside of the card and the outline sits on it,
		   so the indicator is 14.31:1 against its own surround whatever the
		   photograph underneath is doing — well past the 3:1 a non-text
		   indicator needs, and not the same change hover makes. */
		&:focus-visible {
			outline: none;

			&::after {
				outline: 3px solid var(--focus-inverse);
				outline-offset: -3px;
				box-shadow: inset 0 0 0 6px var(--surface-declaring);
			}
		}
	}

	/* KEYBOARD FOCUS, AND ONLY KEYBOARD FOCUS — _motion.css DOES NOT COVER IT.
	   The hover half of the old hand-rolled pair is gone: .zoom-frame owns it,
	   at the same 1.04 (--zoom) it was written at.

	   The focus half has nowhere to go. Every zoom selector in _motion.css is
	   a :hover — `.zoom-frame:hover > img` and
	   `:where(a, .lift, .zoom-frame):hover .zoom-frame > img` — and the file
	   has no :focus-within arm for the zoom anywhere. .lift has one; the zoom
	   does not. This card is one big LINK, so tabbing into it must move the
	   photograph or a keyboard user gets a focus ring on a surface that never
	   acknowledged them, which is the argument _motion.css itself makes for
	   .lift:focus-within. So the state stays local until the utility grows one.

	   Nothing else is local: the transition and the anti-shimmer pair come
	   from .zoom-frame > img, and the distance is the --zoom token rather than
	   a second literal 1.04 that could drift away from it.

	   Its reduced-motion arm at the foot of this file is local for the same
	   reason — _motion.css's single guard names the selectors that file owns,
	   and cannot name this one. */
	.card:focus-within .card-photo {
		transform: scale(var(--zoom));
	}

	/* THE CLIPPED SCREENSHOT.

	   .card-device IS WHAT KEEPS THIS SCREENSHOT OUT OF THE ZOOM, and that is a
	   rule rather than markup anyone should tidy. .zoom-frame is on the CARD,
	   and its transform arm names `> img` — a DIRECT child. The background
	   photograph matches it and zooms, which is right: it is decorative, alt=""
	   is hardcoded on it, and a photograph has no meaningful edge to lose. This
	   screenshot is a grandchild, inside the wrapper below, so the selector
	   never reaches it — which is also right, because a device mockup's bezel IS
	   its framing and scale() would cut it off. Flatten this wrapper and a 357px
	   mockup starts losing about 7px a side on hover.

	   solution-cards had the same class on a slot holding a screenshot with no
	   such wrapper, and lost the last column off a table on every hover. See the
	   rule at the head of css/utilities/_motion.css section 4.

	   The slot reserves the REVEAL — 357 x 527, what the comp actually shows
	   — and the image inside it is `height: auto`, so a screenshot with the
	   comp's 357 x 697 proportions is 170px taller than its slot, runs out of
	   the bottom of it, and is cut by the CARD's edge and radius. That is
	   what the comp draws: the artwork continues past the cut, mid-element,
	   with nothing below the card. The alternative — cropping the asset to
	   527 — would give the same picture at 1440 and a differently-cropped one
	   at every other width, and would put the crop in the author's hands
	   rather than the card's.

	   The slot is a plain block, not a flex or grid item, on purpose:
	   min-height: auto on a flex/grid item resolves to the content's size and
	   would grow the slot to fit the whole screenshot, so nothing would ever
	   be clipped.

	   Width: 56.85% of the card is the comp's 357 of 628. The 357 cap holds
	   the screenshot at its measured size when the card is wider than the
	   comp's — a card is not a reason for a phone to grow — and the 200 floor
	   keeps the interface inside it readable on a narrow track.

	   Margin: 27.57 at 1440, from the heading's line box to the screenshot's
	   own top edge. */
	.card-device {
		--glass: 7px;
		/* The full ring: the glass plus its 1px border. */
		--ring: calc(var(--glass) + 1px);
		/* The art's corner. The ring's outer edge is this + 4 — see RADII. */
		--shotRad: 24px;

		position: relative;
		width: clamp(200px, 56.85%, 357px);
		margin-block-start: clamp(16px, 1.9097vw, 27.5px);
		margin-inline: auto;
		aspect-ratio: 357 / 527;

		/* Belt and braces against the automatic minimum size. A box with a
		   preferred aspect ratio can take a CONTENT-BASED minimum in the
		   ratio-dependent axis, which here would be the whole screenshot —
		   the slot would grow to fit it and nothing would ever be clipped.
		   Stating 0 removes the question in every engine. */
		min-block-size: 0;

		/* THE GLASS EDGE — feature-media's .shot recipe, value for value: 7px
		   of frosted ring, a 1px 55%-white border, a 14% white tint, the same
		   blur and the same drop shadow.

		   Drawn OUTWARD as a ::before rather than inward as padding, which is
		   where this diverges from feature-media, and for a reason: every
		   number on this slot — 357 wide, 357/527 reveal, 27.57 under the
		   heading — is measured off the comp, and padding inside a border-box
		   slot would shrink the artwork to 341 and hand every one of those
		   numbers back for re-derivation. The pseudo leaves the slot's
		   geometry exactly as measured and hangs the ring around it: 8px into
		   the gap above the screenshot (19.5 of the 27.5 stay clear at 1440,
		   8 of the 16 at the floor), 8px into the card's open flanks, and out
		   of the card's bottom edge, where the card's overflow cuts it on the
		   same line it cuts the screenshot — a ring that runs off the bottom
		   mid-rail, exactly as the artwork does.

		   z-index -1 slots it into the card's isolated stack above the scrim
		   at -2 and below the screenshot, which as in-flow content paints over
		   every negative layer — so the backdrop the blur samples is the
		   photograph and scrim, and the interior of the ring is covered by the
		   shot everywhere except the silhouette's own rounded corners, the
		   same sliver of glass feature-media's padded box shows.

		   RADII. Chosen on review (2026-08-26): 24 on the art, 28 on the ring's
		   outer edge — softer than the card's 12, and not the rad + glass
		   derivation the ring originally borrowed. Picked here first;
		   feature-media adopted the same pair the same day, so the two glass
		   frames read as one treatment. The curves converge toward the corner
		   rather than running parallel; at these sizes that reads as one
		   rounded object, where mismatched curves at the card's tighter
		   radius did not. */
		&::before {
			content: '';
			position: absolute;
			inset: calc(-1 * var(--ring));
			z-index: -1;
			border: 1px solid color-mix(in srgb, #fff 55%, transparent);
			border-radius: calc(var(--shotRad) + 4px);
			background-color: color-mix(in srgb, #fff 14%, transparent);
			backdrop-filter: blur(12px) saturate(1.15);
			box-shadow: 0 20px 44px -20px rgb(0 0 0 / 0.35);
		}

		/* The art's own corner — see RADII above for how it pairs with the
		   ring's. CSS owns the curve, so an asset that arrives without the
		   silhouette trim gets its corners here: the corner is the card's
		   business now, not the export's. The bottom pair never shows — the
		   art runs off the card's cut edge. */
		img {
			display: block;
			width: 100%;
			height: auto;
			border-radius: var(--shotRad);
		}
	}

	/* No backdrop-filter (older Firefox, and Safari with it switched off)
	   would leave a nearly clear ring reading as a stray outline, so the tint
	   carries the edge on its own instead — feature-media's fallback, same
	   value. */
	@supports not (backdrop-filter: blur(1px)) {
		.card-device::before {
			background-color: color-mix(in srgb, #fff 34%, transparent);
		}
	}

	/* The ONE thing this module still has to guard. _motion.css carries a
	   single reduced-motion block covering everything it owns — the zoom's
	   transition and its hover transforms included — so the only rule left to
	   revoke here is the :focus-within arm above, which is local precisely
	   because that file has no focus-within zoom to guard. */
	@media (prefers-reduced-motion: reduce) {
		.card:focus-within .card-photo {
			transform: none;
		}
	}
}
