/* ==========================================================================
   Dot Map — pages
   Cascade position 5 of 5: tokens -> base -> layout -> components -> PAGES
   --------------------------------------------------------------------------
   Page-scoped rules ONLY. Owned by the page agents. The foundation lane
   creates this file with only this header so the enqueue in inc/enqueue.php
   does not 404.

   BEFORE WRITING A LINE HERE, READ SECTION 0 OF assets/css/layout.css.

   SCOPING — this is what keeps three agents out of each other's way.
   Every selector must begin with its page's body class:

     .dm-page-home       front-page.php
     .dm-page-services   page-services.php
     .dm-page-work       page-work.php, archive-case_study.php, the tag archive
     .dm-page-about      page-about.php
     .dm-page-contact    page-contact.php
     .dm-page-case-study single-case_study.php

   Those classes come from dotmap_body_class() in inc/setup.php, and they sit
   on the same <body> as the `.dm-page` root scope — so a selector like
   `.dm-page-home .dm-hero__title` is already at specificity (0,2,0) and
   already outranks Elementor's typography. No extra `.dm-page` prefix is
   needed in this file.

   Keep each page's rules in one clearly delimited block with a banner comment
   naming the owning template, and never edit another page's block.
   ========================================================================== */


/* ===== HOME — Agent 4 — START ===== */
/* front-page.php — hero (partial) · services teaser · CTA band (partial).
   The hero, the cards and the CTA band are all shared components and are
   styled in components.css §9. The only thing that is genuinely page-local
   is the teaser link, which exists on no other page. */

/*
 * "View all services →".
 *
 * ServiceGrid.jsx renders this as a full-width row INSIDE the card grid
 * (gridColumn "1 / -1"), so the 24px grid gap is its only spacing and it
 * needs no margin of its own. justify-self holds it at the container's left
 * edge rather than stretching it across the row — a link spanning a 1200px
 * container is a target a pointer user hits by accident.
 *
 * It must also shed base.css's prose underline, and it does so on
 * specificity rather than with !important: this selector is (0,2,0) against
 * base's `body.dm-page a` (0,1,2) and wins on class count, and the hover pair
 * is (0,3,0) against (0,2,2), also ours. The underline returns on hover
 * because the brand reserves underline-on-hover for text links, and this is
 * one — the no-underline-on-hover rule is about buttons.
 *
 * Transition is colour only, at --duration-fast. No transform, no arrow
 * nudge: the brand's motion law rules both out.
 */
/*
 * 2.5.8 Target Size (Agent 8). Measured at 127 x 21 on the rendered Home page:
 * 14px text at --leading-normal is a 21px line box, and this is a standalone
 * link in a grid cell, not a phrase inside a sentence, so the inline exception
 * does not apply. inline-flex + align-items centres the text and the arrow in
 * the taller box, which is what the link already wanted — the arrow span sat
 * on the text baseline before.
 */
.dm-page-home .dm-home-services__link {
	display: inline-flex;
	align-items: center;
	min-height: var(--space-6); /* 24px — WCAG 2.2 AA 2.5.8 */
	grid-column: 1 / -1;
	justify-self: start;
	color: var(--text-link);
	font-family: var(--font-sans);
	font-size: var(--text-body-sm); /* kit: 14 */
	font-weight: var(--weight-semibold); /* kit: 600 */
	text-decoration: none;
	transition: color var(--duration-fast) var(--ease-standard);
}

.dm-page-home .dm-home-services__link:hover {
	color: var(--text-link-hover);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

/*
 * The arrow lives in its own aria-hidden span so it can never be read as part
 * of the link text and so the space before it cannot collapse.
 */
.dm-page-home .dm-home-services__arrow {
	margin-inline-start: 0.25em;
}
/* ===== HOME — Agent 4 — END ===== */


/* ===== CONTACT — Agent 6 — START ===== */
/* ==========================================================================
   Contact — page-contact.php
   --------------------------------------------------------------------------
   Source spec: ui_kits/marketing-site/ContactSection.jsx (LAYOUT AND VISUAL
   ONLY — its field list is wrong, see content-map §9.0) and content-map §9.2.

   WHAT IS *NOT* HERE, ON PURPOSE
     - Every Formidable rule. components.css §10 is the complete override
       layer, anchored on `.dm-page .dm-formidable`, and the template wraps
       both shortcode embeds in that class. Nothing about the forms belongs
       in this block; a rule added here would drift out of sync with §6's
       matched-pair form controls the first time either is touched.
     - Tab strip and panel styling. components.css §7 owns `.dm-tabs`, and it
       hangs the active underline off `[aria-selected="true"]` so the visual
       and accessible states cannot diverge.
     - Motion. The only transitions on this page are §7's 120ms colour and
       border-colour fades; base.css's prefers-reduced-motion safety net
       already neutralises them, so there is nothing to re-state here.

   So this block is four things and no more: the section's centring, the
   card's two deltas from `.dm-card`, the panel heading, and the layout the
   page falls back to when JavaScript does not run.
   ========================================================================== */

/* --- Section ------------------------------------------------------------- */

/*
 * ContactSection.jsx: `display:flex; justifyContent:center`. Expressed as a
 * column so the optional editor intro stacks above the card rather than
 * sitting beside it.
 */
.dm-page-contact .dm-contact__inner {
	display: flex;
	flex-direction: column;
	align-items: center;
}

/*
 * Optional page-editor content above the card. Capped to the card's own
 * measure so the two share an edge. The template only renders this when the
 * page content does NOT already contain a Formidable form — see the
 * duplicate-form guard in page-contact.php.
 */
.dm-page-contact .dm-contact__intro {
	width: 100%;
	max-width: 560px;
	margin-block-end: var(--space-8);
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	line-height: var(--leading-relaxed);
}

.dm-page-contact .dm-contact__intro > * + * {
	margin-block-start: var(--space-4);
}


/* --- The card ------------------------------------------------------------ */

/*
 * Composed on `.dm-card .dm-card--elevated`, which already supplies the white
 * surface, the 1px --border-default hairline, --radius-lg and --shadow-md.
 * Only two things differ from every other card on the site, and only those
 * two are written here.
 *
 * 1. WIDTH. The kit hardcodes `width: 560`. Fluid with a cap instead, per
 *    content-map §9.2's own build note.
 *
 * 2. PADDING. The kit's --space-8 (32px) is a desktop figure and it does not
 *    survive a phone, because of one fixed-width third party:
 *
 *      390 viewport - 48 (--gutter, both sides) = 342 card
 *      342 - 64 (--space-8 both sides)          = 278 content
 *      Google's reCAPTCHA checkbox widget        = ~304 fixed
 *
 *    278 < 304, so the captcha — the one control on this page that cannot be
 *    resized, restyled or replaced — would overflow and land behind the
 *    horizontal scrollbar components.css §10 gives it as a last resort.
 *    Stepping the padding down to --space-4 leaves 310px of content at 390px
 *    and the widget fits outright. The kit's 32px returns at 900px, where
 *    there is room for it.
 */
.dm-page-contact .dm-contact__card {
	width: 100%;
	max-width: 560px;
	padding: var(--space-4); /* 16 — see the reCAPTCHA arithmetic above */
}

@media (min-width: 640px) {
	.dm-page-contact .dm-contact__card {
		padding: var(--space-6); /* 24 — the standard card padding */
	}
}

@media (min-width: 900px) {
	.dm-page-contact .dm-contact__card {
		padding: var(--space-8); /* 32 — the kit's figure, at the kit's width */
	}
}


/* --- Panel heading ------------------------------------------------------- */

/*
 * ContactSection.jsx: 20px / weight 700 / --text-primary. Shipped as an <h2>
 * per content-map §9.3, so the page outline is h1 (hero) -> h2 (panel), and
 * the size is pinned back to the kit's 20px rather than inheriting base.css's
 * h2 step.
 *
 * Specificity (0,2,0) against base.css's `body.dm-page h2` at (0,1,2): two
 * classes beat one, so this wins without an !important.
 */
.dm-page-contact .dm-contact__heading {
	margin-block: 0 var(--space-4);
	color: var(--text-primary);
	font-family: var(--font-sans);
	font-size: var(--text-h4); /* 1.25rem = 20px — kit: 20 */
	font-weight: var(--weight-bold); /* kit: 700 */
	line-height: var(--leading-snug);
}


/* --- The no-JavaScript layout -------------------------------------------- */

/*
 * THIS IS THE FALLBACK. Read page-contact.php's tab-shell comment with it.
 *
 * The template ships the tab strip with `hidden` and BOTH panels visible.
 * tabs.js reveals the strip, hides the inactive panel and marks the group
 * `.is-enhanced`. So with JavaScript off there is no dead control and no
 * unreachable form: both Formidable forms render in full, each under its own
 * <h2>, and both submit normally — they are server-rendered forms and need
 * nothing from this theme's JavaScript.
 *
 * All this rule does is stop the two stacked forms reading as one long form.
 * It applies only while the group is NOT enhanced, so it costs nothing once
 * tabs.js has run.
 *
 * State classes are never styled alone (layout.css §0): the selector is
 * `.dm-contact__tabs:not(.is-enhanced)`, never a bare `:not(.is-enhanced)`.
 */
.dm-page-contact .dm-contact__tabs:not(.is-enhanced) .dm-tabs__panel + .dm-tabs__panel {
	margin-block-start: var(--space-8);
	border-block-start: var(--border-width-hairline) solid var(--border-default);
}


/* --- Administrator notice ------------------------------------------------ */

/*
 * Shown only when the Formidable shortcode does not exist on the install, and
 * only to a user who can fix that (see page-contact.php). A visitor gets an
 * HTML comment and no invented phone number — there is no verified contact
 * detail anywhere in the content map to fall back to, and fabricating one on
 * the contact page would be the worst possible place to do it. Registered as
 * a gap.
 *
 * Warning palette, as a full hairline box: the brand forbids the coloured
 * left-accent strip outright.
 */
.dm-page-contact .dm-contact__notice {
	margin: 0;
	padding: var(--space-3) var(--space-4);
	border: var(--border-width-hairline) solid var(--color-warning);
	border-radius: var(--radius-md);
	background-color: var(--color-warning-bg);
	color: var(--color-warning);
	font-size: var(--text-body-sm);
	line-height: var(--leading-normal);
}
/* ===== CONTACT — Agent 6 — END ===== */


/* ===== WORK — Agent 5 — START ===== */

/* ==========================================================================
   Work — page-work.php, archive-case_study.php, single-case_study.php
   --------------------------------------------------------------------------
   Body classes covered (dotmap_body_class(), inc/setup.php):
     .dm-page-work        the static /work/ page, /case-studies/, /work-tag/*
     .dm-page-case-study  a single case study at /work/{slug}/

   The card itself is components.css §9.5 (.dm-case-study-card) and the grid is
   layout.css §3 (.dm-grid--2). Nothing here re-declares either — this file
   carries only what is specific to these three templates: the placeholder
   notice, the archive link, pagination, and the single-case-study reading
   column.

   The grid is TWO-UP, not four-up, per docs/content-map.md §6.2
   (`grid-template-columns: 1fr 1fr`) and WorkGrid.jsx. .dm-grid--2 gives one
   column below 640px and two from 640px up, so the phone layout is a single
   column with no max-width query anywhere.
   ========================================================================== */

/* The kit's WorkGrid section sits on --bg-page. The body already is, so this
   is belt-and-braces: it keeps the band correct if the page ground ever
   changes, and it costs one declaration. */
.dm-page-work .dm-work {
	background-color: var(--bg-page);
}

/* Cards in a row share a height so the tag rows line up across the grid. This
   is the grid default; stating it means a later `align-items` on .dm-grid
   cannot silently ragged the rows. */
.dm-page-work .dm-work__grid {
	align-items: stretch;
}


/* --- Placeholder notice -------------------------------------------------- */

/*
 * Shown when no case studies exist yet (page-work.php) and when a published
 * case study has no body content (single-case_study.php, editors only).
 *
 * The dashed hairline is deliberate: it is the same signal .dm-image-slot
 * uses in layout.css §5, so "dashed ring = this is a stand-in" reads as one
 * consistent language across the theme rather than two invented treatments.
 *
 * --teal-600 on --bg-sunken measures 5.36:1 and --text-secondary 7.39:1
 * (components.css §0.2c). --text-muted is NOT used here — it lands at 3.2:1
 * on this background, which fails AA for body text.
 */
.dm-page-work .dm-work-notice,
.dm-page-case-study .dm-work-notice {
	margin-block-end: var(--space-8);
	padding: var(--space-6);
	border: var(--border-width-hairline) dashed var(--border-strong);
	border-radius: var(--radius-lg);
	background-color: var(--bg-sunken);
}

.dm-page-work .dm-work-notice > * + *,
.dm-page-case-study .dm-work-notice > * + * {
	margin-block-start: var(--space-2);
}

.dm-page-work .dm-work-notice__label,
.dm-page-case-study .dm-work-notice__label {
	color: var(--teal-600);
	font-family: var(--font-mono);
	font-size: var(--text-mono-label);
	font-weight: var(--weight-medium);
	letter-spacing: var(--tracking-wide);
	line-height: var(--leading-snug);
}

.dm-page-work .dm-work-notice__text,
.dm-page-case-study .dm-work-notice__text {
	max-width: 62ch;
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	line-height: var(--leading-relaxed);
}

.dm-page-work .dm-work-notice__admin {
	max-width: 62ch;
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	line-height: var(--leading-relaxed);
}

/*
 * A placeholder card carries the dashed edge too, so a card standing in for a
 * project is distinguishable from a real one at a glance even if the notice
 * above it has scrolled off. Everything else about the card is unchanged —
 * same surface, same 10px radius, same shadow.
 */
.dm-page-work .dm-case-study-card--placeholder {
	border-style: dashed;
	border-color: var(--border-strong);
}


/* --- "View all case studies" --------------------------------------------- */

/*
 * Rendered only when more case studies exist than the Work page shows. Styled
 * as the kit styles its "View all services →" teaser link (content-map §4.2):
 * sans 14/600, --text-link, no underline until hover. Text links may underline
 * on hover; buttons may not.
 */
.dm-page-work .dm-work__more {
	margin-block-start: var(--space-8);
}

.dm-page-work .dm-work__more-link {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	color: var(--text-link);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
	text-decoration: none;
	transition: color var(--duration-fast) var(--ease-standard);
}

.dm-page-work .dm-work__more-link:hover {
	color: var(--text-link-hover);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}


/* --- Archive pagination -------------------------------------------------- */

/*
 * the_posts_pagination() emits
 *   <nav class="navigation dm-pagination"><h2 class="screen-reader-text">…
 *     <div class="nav-links"><a class="page-numbers">…
 * so the hooks below are WordPress core's class names, not invented ones.
 *
 * 44px minimum on every target is the WCAG 2.2 AA target size, met by the
 * control itself rather than by the gap around it.
 */
.dm-page-work .dm-pagination {
	margin-block-start: var(--space-10);
}

.dm-page-work .dm-pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2);
}

.dm-page-work .dm-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding-inline: var(--space-3);
	border: var(--border-width-hairline) solid var(--border-default);
	border-radius: var(--radius-md);
	background-color: var(--bg-surface);
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
	text-decoration: none;
	transition:
		background-color var(--duration-fast) var(--ease-standard),
		border-color var(--duration-fast) var(--ease-standard),
		color var(--duration-fast) var(--ease-standard);
}

.dm-page-work .dm-pagination a.page-numbers:hover {
	border-color: var(--border-strong);
	background-color: var(--bg-sunken);
	color: var(--text-primary);
	text-decoration: none;
}

.dm-page-work .dm-pagination .page-numbers.current {
	border-color: var(--brand-primary);
	background-color: var(--brand-primary);
	color: var(--text-on-brand);
}

/* The ellipsis between page ranges is not a control. */
.dm-page-work .dm-pagination .page-numbers.dots {
	min-width: 0;
	padding-inline: var(--space-1);
	border-color: transparent;
	background-color: transparent;
	color: var(--text-secondary);
}


/* ==========================================================================
   Single case study — .dm-page-case-study (single-case_study.php)
   --------------------------------------------------------------------------
   A reading column, not a marketing grid: the template uses
   .dm-container--narrow (760px) so body copy keeps a comfortable measure.

   Every block below is optional in the markup — an empty meta field renders
   nothing at all rather than an empty styled box (gap G28: no content model
   has been agreed, so nothing is scaffolded that invites a guess).
   ========================================================================== */

.dm-page-case-study .dm-case-study {
	background-color: var(--bg-page);
}

.dm-page-case-study .dm-case-study__media {
	margin-block-end: var(--space-8);
}

/*
 * Real featured image. The slot placeholder already rounds itself in
 * layout.css §5; this matches the radius on the real asset so the two states
 * are the same shape.
 */
.dm-page-case-study .dm-case-study__media .dm-media__img {
	aspect-ratio: 16 / 9;
	border-radius: var(--radius-lg);
	object-fit: cover;
}

.dm-page-case-study .dm-case-study__tags {
	margin-block-end: var(--space-6);
}

.dm-page-case-study .dm-case-study__lede {
	margin-block-end: var(--space-8);
	color: var(--text-secondary);
	font-size: var(--text-body-lg);
	line-height: var(--leading-relaxed);
}

.dm-page-case-study .dm-case-study__details {
	margin-block-end: var(--space-8);
}

/*
 * The detail list is built to the card spec exactly — white surface, 1px
 * hairline, 10px radius, 24px padding — rather than as a new surface
 * treatment. One panel language site-wide.
 *
 * <dl> with a <div> per row is valid HTML5 and is what makes the two-column
 * label/value alignment possible without absolute positioning.
 */
.dm-page-case-study .dm-detail-list {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
	padding: var(--space-6);
	border: var(--border-width-hairline) solid var(--border-default);
	border-radius: var(--radius-lg);
	background-color: var(--bg-surface);
	box-shadow: var(--shadow-sm);
}

.dm-page-case-study .dm-detail-list__row {
	display: grid;
	gap: var(--space-1);
}

.dm-page-case-study .dm-detail-list__label {
	color: var(--text-secondary);
	font-family: var(--font-mono);
	font-size: var(--text-mono-label);
	letter-spacing: var(--tracking-wide);
	line-height: var(--leading-snug);
}

.dm-page-case-study .dm-detail-list__value {
	margin: 0;
	color: var(--text-primary);
	font-size: var(--text-body);
	line-height: var(--leading-normal);
}

/* A project URL is one long unbroken token. `anywhere` is the only value that
   will break it mid-string, which is what keeps a 390px layout from scrolling
   sideways. */
.dm-page-case-study .dm-detail-list__link {
	overflow-wrap: anywhere;
}

@media (min-width: 640px) {
	.dm-page-case-study .dm-detail-list__row {
		grid-template-columns: minmax(0, 10rem) minmax(0, 1fr);
		gap: var(--space-4);
		align-items: baseline;
	}
}


/* --- Editor-entered body copy -------------------------------------------- */

/*
 * base.css gives .dm-prose its list padding at :where() specificity so
 * Elementor keeps control inside its own widgets. Vertical rhythm is set here
 * instead of there because it is specific to this template's reading column.
 *
 * `> * + *` rather than a margin on every child: no first/last-child cleanup,
 * and a heading that opens the body never gets a stray top margin.
 */
.dm-page-case-study .dm-case-study__body > * + * {
	margin-block-start: var(--space-4);
}

.dm-page-case-study .dm-case-study__body > h2 + *,
.dm-page-case-study .dm-case-study__body > h3 + * {
	margin-block-start: var(--space-3);
}

.dm-page-case-study .dm-case-study__body > h2 {
	margin-block-start: var(--space-10);
}

.dm-page-case-study .dm-case-study__body > h3 {
	margin-block-start: var(--space-8);
}

/* wp_link_pages() output on a multi-page case study. Rare, but a class with
   no rule behind it renders as a browser default and is invisible to every
   static check — so it gets real declarations, not a stub. */
.dm-page-case-study .dm-page-links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin-block-start: var(--space-6);
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
}


/* --- Back to /work/ ------------------------------------------------------ */

.dm-page-case-study .dm-back-link {
	margin-block-start: var(--space-10);
}

/* min-height is 2.5.8 (Agent 8): measured at 104.5 x 23.1 on the rendered
   case-study single — 0.9px under the 24x24 minimum. Already centred, so the
   extra pixel changes nothing visually. */
.dm-page-case-study .dm-back-link__anchor {
	display: inline-flex;
	align-items: center;
	min-height: var(--space-6); /* 24px — WCAG 2.2 AA 2.5.8 */
	gap: var(--space-2);
	color: var(--text-link);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
	text-decoration: none;
	transition: color var(--duration-fast) var(--ease-standard);
}

.dm-page-case-study .dm-back-link__anchor:hover {
	color: var(--text-link-hover);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

/* ===== WORK — Agent 5 — END ===== */


/* ===== ABOUT — Agent 5 — START ===== */

/* ==========================================================================
   About — page-about.php (.dm-page-about)
   --------------------------------------------------------------------------
   AboutSection.jsx is two sections: a two-column intro on --bg-page, then a
   three-column values row on --bg-sunken. The values are NOT cards
   (content-map §7.3) — no surface, no border, no shadow, no padding. The
   .dm-value component in components.css §9.6 is built that way and nothing
   here adds a card to it.

   The colour bands come from the shared utilities (.dm-on-sunken in
   layout.css §4); this file sets only the things that are specific to this
   page's two blocks.
   ========================================================================== */

.dm-page-about .dm-about-intro {
	background-color: var(--bg-page);
}

/*
 * The kit's gap is 40px. layout.css's .dm-grid--split uses 48px at 900+,
 * which is the shared default for text-beside-media blocks; 40px is a real
 * token (--space-10), so the kit's figure ships exactly.
 *
 * Below 900px .dm-grid--split has not switched to two columns yet, so the
 * copy stacks above the image slot at the base 24px grid gap. That is the
 * correct phone order — read the paragraphs, then meet the photo.
 */
@media (min-width: 900px) {
	.dm-page-about .dm-about-intro__grid {
		gap: var(--space-10);
	}
}

.dm-page-about .dm-about-intro__copy {
	display: flex;
	flex-direction: column;
	gap: var(--space-4); /* kit: 16 */
}

.dm-page-about .dm-about-intro__text {
	color: var(--text-secondary);
	font-size: 15px; /* kit: 15 — no token sits at this step */
	line-height: var(--leading-relaxed);
}

/*
 * The team-photo slot. The shared .dm-image-slot primitive uses the 10px card
 * radius; AboutSection.jsx asks for `shape="rounded" radius={16}` on this one
 * image, which is --radius-xl. Overriding here rather than in layout.css
 * keeps the primitive's default intact for every other call site.
 *
 * (0,3,0) — .dm-page-about + .dm-image-slot + .dm-about-intro__media — beats
 * layout.css's (0,2,0) without !important, which is the whole point of the
 * scope contract in layout.css §0.
 */
.dm-page-about .dm-image-slot.dm-about-intro__media {
	border-radius: var(--radius-xl);
}

.dm-page-about .dm-image-slot.dm-about-intro__media .dm-image-slot__frame {
	border-radius: inherit;
}


/* --- Values row ---------------------------------------------------------- */

/*
 * Three values in the shared .dm-grid--3 would go two-up at 640 and three-up
 * at 900, which strands the third value alone in a half-empty row for the
 * whole 640–899 band. Three short text columns fit comfortably at 640, so
 * this page goes straight from one column to three.
 *
 * Specificity ties layout.css's `.dm-page .dm-grid--3` at (0,2,0); pages.css
 * prints last in the cascade (inc/enqueue.php declares the dependency chain),
 * so the tie resolves here. That is the documented mechanism, not a
 * coincidence — see layout.css §0.
 */
@media (min-width: 640px) {
	.dm-page-about .dm-about-values__grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* ===== ABOUT — Agent 5 — END ===== */


/* ===== SERVICES — Agent 4 — START ===== */
/* page-services.php — page hero (partial) · 4 service cards · process band ·
   CTA band (partial).

   THIS BLOCK IS DELIBERATELY EMPTY OF RULES. That is a finding, not an
   omission, and it is recorded here so the next person does not go looking
   for the missing half.

   Every visual on this page is already carried by the foundation:

     page hero      components.css §9.2  (.dm-page-hero)
     service cards  components.css §9.4  (.dm-service-card, base variant)
     badges         components.css §4    (.dm-badge--primary)
     process band   components.css §9.7  (.dm-process)
     CTA band       components.css §9.3  (.dm-cta-band)
     2-up -> 1-up   layout.css §3        (.dm-grid--2)
     band rhythm    layout.css §2        (.dm-section, --tight) + .dm-on-sunken

   Verified in a render harness at 390px and 1280px rather than assumed:
   no horizontal overflow at either width, the four-up card grid collapses to
   one column on a phone, and the process band wraps 2x2 at 390px without a
   breakpoint of its own.

   ONE THING WAS CONSIDERED AND DELIBERATELY NOT DONE. The process band has no
   step descriptions (content-map §5.3, gap G31), so at 1280 its four 140px
   columns fill about 57% of the container while the cards above fill 100%.
   Widening or distributing the steps from here would mean overriding
   components.css §9.7's centred composition from a page block — drift between
   a component and one page's idea of it, to compensate for missing copy. The
   centred strip is the kit's own treatment and it reads as deliberate at both
   widths. When the operator supplies step copy (G31), process-step.php
   renders it and .dm-process__text styles it, and the band fills out on its
   own with no change here.

   If a genuinely page-local rule is ever needed, it goes inside these
   delimiters, scoped .dm-page-services, and nowhere else in this file. */
/* ===== SERVICES — Agent 4 — END ===== */


/* ===== FALLBACKS — Agent 7 — START ===== */
/* ==========================================================================
   Template fallbacks
   index.php · page.php · 404.php · search.php · archive.php ·
   taxonomy-case_study_tag.php · searchform.php ·
   template-parts/entry-summary.php
   --------------------------------------------------------------------------
   SCOPING — WHY THIS BLOCK CARRIES NO `dm-page-*` BODY CLASS.

   The header of this file requires every selector to begin with its page's
   body class. Those classes come from dotmap_body_class() in inc/setup.php,
   which emits exactly six: dm-page-home, dm-page-services, dm-page-work,
   dm-page-about, dm-page-contact, dm-page-case-study. A 404, a search results
   page, a date archive and a generic Page get `dm-page` and nothing else —
   there is no seventh class to scope to, and inc/setup.php is another agent's
   file, so one cannot be added from here.

   So these rules scope on `.dm-page` plus a block class that exists only in
   this lane's markup:

       .dm-page .dm-fallback__notice { }      (0,2,0)
       .dm-page .dm-entry__title { }          (0,2,0)
       .dm-page .dm-search-form { }           (0,2,0)

   That is the same specificity FORM the file header mandates — (0,2,0): enough
   to beat Elementor's kit typography at (0,1,1), and deliberately not enough
   to beat Elementor's own widget CSS at (0,2,1), exactly as §8.7 intends. The
   isolation guarantee is unchanged too: `dm-fallback`, `dm-entry`,
   `dm-search-form` and `dm-sitemap-links` appear in no other agent's markup,
   so nothing below can reach another page's HTML.

   ONE DELIBERATE EXCEPTION. taxonomy-case_study_tag.php runs on a body that
   DOES carry `dm-page-work` — dotmap_body_class() already maps
   is_tax( 'case_study_tag' ) to it. That template therefore reuses Agent 5's
   .dm-work, .dm-work__grid, .dm-work-notice and .dm-pagination rules
   unchanged, and only its intro and back-link hooks are defined here. No
   selector below redefines anything Agent 5 owns.

   WHAT IS REUSED RATHER THAN REWRITTEN
     .dm-card + .dm-card--flush + .dm-card__body   the entry-row surface
     .dm-card__text                                the excerpt treatment
     .dm-field + .dm-field__label + .dm-input      the search field
     .dm-btn + .dm-btn--primary + .dm-btn--md      the search submit
     .dm-grid                                      the single-column result list
     .dm-container--narrow                         the prose column
     .dm-prose                                     list padding, from base.css

   Breakpoints: 640 only, min-width. No max-width query below. No !important.
   ========================================================================== */


/* --- The section band ----------------------------------------------------- */

/*
 * Every template in this lane wraps its content in `.dm-section .dm-fallback`.
 * The page ground is already --bg-page, so this is belt-and-braces in exactly
 * the sense Agent 5 uses it on .dm-work: it keeps the band correct if the body
 * ground ever changes, and it costs one declaration. It also means the BEM
 * block class is a real class with a real rule rather than a hook that renders
 * as a browser default.
 */
.dm-page .dm-fallback {
	background-color: var(--bg-page);
}


/* --- Entry row — template-parts/entry-summary.php ------------------------ */

/*
 * The row is `.dm-card .dm-card--flush` with a `.dm-card__body` inside, which
 * is the exact composition card-case-study.php uses — so the brand's card spec
 * (white surface, hairline, 10px radius, --shadow-sm, 24px padding) arrives
 * with no declaration here. Only the three things that genuinely differ from a
 * case-study card are set below.
 *
 * The heading ships as an h3, which base.css sizes at --text-h3 (24px). That is
 * the size of a section heading, not of a row in a list of twelve, so it steps
 * down one to --text-h4. This selector is (0,2,0) against base's (0,1,2) and
 * wins on class count — no !important, and no change to base.css.
 */
.dm-page .dm-entry__title {
	margin: 0;
	color: var(--text-primary);
	font-size: var(--text-h4); /* 20px */
	font-weight: var(--weight-semibold);
	line-height: var(--leading-snug);
}

/*
 * The title is the link; the row is not. Shedding the prose underline is done
 * on specificity, exactly as .dm-case-study-card__title does it:
 * (0,2,1) here against base's `body.dm-page a` at (0,1,2), and (0,3,0) against
 * `body.dm-page a:hover` at (0,2,2). The underline returns on hover because the
 * brand reserves underline-on-hover for text links, and this is one.
 *
 * The 120ms colour transition is inherited from base.css's `a` rule — not
 * restated, so there is one place it can ever change.
 */
.dm-page .dm-entry__title a {
	color: inherit;
	text-decoration: none;
}

.dm-page .dm-entry__title a:hover {
	color: var(--text-link);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

/* Date · author. Mono, because it is data rather than prose — the same reading
   .dm-detail-list__label and .dm-work-notice__label take. --text-secondary is
   7.39:1 on the card's white surface. --text-muted is NOT used: it measures
   3.2:1 there and fails AA. */
.dm-page .dm-entry__meta {
	margin: 0;
	color: var(--text-secondary);
	font-family: var(--font-mono);
	font-size: var(--text-caption); /* 12px */
	line-height: var(--leading-normal);
}

/* The one real difference from .dm-card__text: a case-study card sits in a
   half-width grid column, but this row spans the whole container, so at 1200px
   an uncapped excerpt runs to roughly 1,150px — far past a readable measure. */
.dm-page .dm-entry__text {
	max-width: 68ch;
}


/* --- Search form — searchform.php ---------------------------------------- */

/*
 * Stacked on a phone, one row from 640 up. The field and the button are both
 * standard components; this only arranges them.
 *
 * align-items: flex-end at 640+ is load-bearing. The field is a .dm-field
 * column with a visible label ABOVE the input, so aligning to the start or
 * stretching would float the button level with the label instead of the input.
 * Both controls compute to the same 43px box (10px padding + 14px/1.5 text +
 * 1px borders), so bottom-aligning lands them flush.
 *
 * The max-width matters on search.php, which uses the full 1200px container:
 * without it the input would stretch the whole width and read as a page-wide
 * bar rather than a field.
 */
.dm-page .dm-search-form {
	display: flex;
	flex-direction: column;
	gap: var(--space-3);
	max-width: var(--container-narrow);
}

/* min-width: 0 defeats the flex item's automatic minimum size, which would
   otherwise let a long value in the input push the row wider than its parent
   and give the page a horizontal scrollbar at 390px. */
.dm-page .dm-search-form__field {
	flex: 1 1 auto;
	min-width: 0;
}

@media (min-width: 640px) {
	.dm-page .dm-search-form {
		flex-direction: row;
		align-items: flex-end;
	}

	.dm-page .dm-search-form__submit {
		flex: 0 0 auto;
	}
}


/* --- Empty / no-results notice ------------------------------------------- */

/*
 * Visually identical to Agent 5's .dm-work-notice, restated here rather than
 * shared because that selector is scoped `.dm-page-work` / `.dm-page-case-study`
 * and none of these templates carry either class. The values are matched on
 * purpose: the dashed hairline is the same signal .dm-image-slot uses in
 * layout.css §5, so "dashed ring = this is a stand-in or an empty state" reads
 * as one language across the whole theme instead of two invented treatments.
 *
 * --teal-600 on --bg-sunken is 5.36:1 and --text-secondary is 7.39:1. Again,
 * --text-muted is not used here — 3.2:1 on this ground fails AA.
 */
.dm-page .dm-fallback__notice {
	padding: var(--space-6);
	border: var(--border-width-hairline) dashed var(--border-strong);
	border-radius: var(--radius-lg);
	background-color: var(--bg-sunken);
}

.dm-page .dm-fallback__notice > * + * {
	margin-block-start: var(--space-2);
}

.dm-page .dm-fallback__notice-label {
	color: var(--teal-600);
	font-family: var(--font-mono);
	font-size: var(--text-mono-label);
	font-weight: var(--weight-medium);
	letter-spacing: var(--tracking-wide);
	line-height: var(--leading-snug);
}

.dm-page .dm-fallback__notice-text {
	max-width: 62ch;
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	line-height: var(--leading-relaxed);
}

/* The notice is followed by a search form on index.php and archive.php, and by
   the sitemap on search.php. Either way it needs air beneath it. */
.dm-page .dm-fallback__notice + .dm-search-form,
.dm-page .dm-fallback__notice + .dm-fallback__nav {
	margin-block-start: var(--space-8);
}


/* --- 404.php -------------------------------------------------------------- */

/*
 * 404.php is the only template in this lane with a VISIBLE h2. Everywhere else
 * the section heading is .screen-reader-text, because the visible h1 in the
 * hero already names the content; here the section IS the point of the page —
 * a set of instructions the visitor came to read — so it is shown, and it takes
 * base.css's h2 treatment with no override.
 */
.dm-page .dm-fallback__lede {
	margin-block-start: var(--space-4);
	max-width: 62ch;
	color: var(--text-secondary);
	font-size: var(--text-body-lg);
	line-height: var(--leading-relaxed);
}

.dm-page .dm-fallback__lede + .dm-search-form {
	margin-block-start: var(--space-8);
}


/* --- Sitemap links — the route back out of a dead end --------------------- */

.dm-page .dm-fallback__nav {
	margin-block-start: var(--space-10);
}

/* base.css already strips the bullets and padding from any ul[class] and
   restores the empty ::marker that keeps Safari + VoiceOver announcing it as a
   list, so only the arrangement is set here. The row wraps rather than
   scrolling: at 390px the five links fall onto two or three lines. */
.dm-page .dm-sitemap-links {
	display: flex;
	flex-wrap: wrap;
	gap: 0 var(--space-6);
	margin: 0;
}

/*
 * 44px minimum height is the comfortable touch target, met by the control
 * itself rather than by the gap around it — the same figure the archive
 * pagination uses. It is also why the flex row's vertical gap is 0: the links
 * already carry their own separation through that height.
 */
.dm-page .dm-sitemap-links__link {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	color: var(--text-link);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
	text-decoration: none;
	transition: color var(--duration-fast) var(--ease-standard);
}

.dm-page .dm-sitemap-links__link:hover {
	color: var(--text-link-hover);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

/*
 * .dm-sitemap-links__item carries no rule and that is correct, not an
 * oversight: the <li> is a bare flex item and the <a> inside it carries the
 * whole treatment, including its own 44px target height. The class is still
 * emitted because dotmap_render_nav_fallback() appends `is-current` to it, and
 * a state class needs a block class to hang off — `.dm-sitemap-links__item.is-current`
 * is the selector that would style it if these links ever appear somewhere one
 * of them IS the current page. They do not today (a 404 and an empty search are
 * never one of the five pages), so no `is-current` rule is written either.
 */


/* --- Result / post list --------------------------------------------------- */

/*
 * .dm-grid on its own is already a single column with a 24px gap, which is the
 * list rhythm these templates want at every width, so .dm-fallback__list adds
 * nothing but a hook. align-items is stated for the same reason Agent 5 states
 * it on .dm-work__grid: a later `align-items` on .dm-grid cannot then silently
 * ragged these rows.
 */
.dm-page .dm-fallback__list {
	align-items: stretch;
}

.dm-page .dm-fallback__form {
	margin-block-end: var(--space-10);
}

.dm-page .dm-fallback__intro {
	max-width: 68ch;
	margin-block-end: var(--space-8);
}


/* --- Pagination ----------------------------------------------------------- */

/*
 * the_posts_pagination() emits
 *   <nav class="navigation dm-fallback__pagination"><h2 class="screen-reader-text">…
 *     <div class="nav-links"><a class="page-numbers">…
 * so `nav-links` and `page-numbers` below are WordPress core's class names, not
 * invented ones.
 *
 * These values match Agent 5's .dm-pagination exactly. They are restated rather
 * than shared for the same reason as the notice above: that selector is scoped
 * `.dm-page-work`, and a search results page carries no such class. The class
 * name differs (`dm-fallback__pagination`) precisely so the two never collide
 * or half-apply to each other — one definition per scope, no drift.
 */
.dm-page .dm-fallback__pagination {
	margin-block-start: var(--space-10);
}

.dm-page .dm-fallback__pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--space-2);
}

.dm-page .dm-fallback__pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
	padding-inline: var(--space-3);
	border: var(--border-width-hairline) solid var(--border-default);
	border-radius: var(--radius-md);
	background-color: var(--bg-surface);
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
	text-decoration: none;
	transition:
		background-color var(--duration-fast) var(--ease-standard),
		border-color var(--duration-fast) var(--ease-standard),
		color var(--duration-fast) var(--ease-standard);
}

.dm-page .dm-fallback__pagination a.page-numbers:hover {
	border-color: var(--border-strong);
	background-color: var(--bg-sunken);
	color: var(--text-primary);
	text-decoration: none;
}

.dm-page .dm-fallback__pagination .page-numbers.current {
	border-color: var(--brand-primary);
	background-color: var(--brand-primary);
	color: var(--text-on-brand);
}

/* The ellipsis between page ranges is not a control. */
.dm-page .dm-fallback__pagination .page-numbers.dots {
	min-width: 0;
	padding-inline: var(--space-1);
	border-color: transparent;
	background-color: transparent;
	color: var(--text-secondary);
}


/* --- Singular body — index.php (singular arm) and page.php ---------------- */

.dm-page .dm-fallback__media {
	margin-block-end: var(--space-8);
}

/* layout.css §5 already gives .dm-media__img its display/width/height and the
   sunken ground it shows while decoding. Only the radius is added, matching
   what Agent 5 does on .dm-case-study__media so a real image and an image slot
   round identically. */
.dm-page .dm-fallback__media .dm-media__img {
	border-radius: var(--radius-lg);
}

.dm-page .dm-fallback__meta {
	margin-block-end: var(--space-6);
}

/*
 * base.css gives .dm-prose its list padding at :where() (zero) specificity so
 * Elementor keeps control inside its own widgets. Vertical rhythm is set here
 * instead, because it belongs to this reading column rather than to every
 * .dm-prose on the site.
 *
 * `> * + *` and DIRECT children only. That is what keeps this safe against
 * Elementor-wrapped content (BUILD-BRIEF §8.4): when the_content() returns a
 * single Elementor <div> wrapper, exactly one child matches and nothing inside
 * the wrapper is touched.
 */
.dm-page .dm-fallback__body > * + * {
	margin-block-start: var(--space-4);
}

.dm-page .dm-fallback__body > h2 + *,
.dm-page .dm-fallback__body > h3 + * {
	margin-block-start: var(--space-3);
}

.dm-page .dm-fallback__body > h2 {
	margin-block-start: var(--space-10);
}

.dm-page .dm-fallback__body > h3 {
	margin-block-start: var(--space-8);
}

/* wp_link_pages() output on a multi-page post. Rare, but a class with no rule
   behind it renders as a browser default and is invisible to every static
   check — so it gets real declarations here, not a stub. Agent 5's identical
   rule is scoped .dm-page-case-study and does not reach these templates. */
.dm-page .dm-fallback__body .dm-page-links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-2);
	margin-block-start: var(--space-6);
	color: var(--text-secondary);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
}


/* --- Back to /work/ — taxonomy-case_study_tag.php ------------------------- */

/*
 * A filtered view needs a way to clear the filter, so this renders whether or
 * not the tag has any case studies. Agent 5's .dm-back-link carries the same
 * treatment but is scoped .dm-page-case-study; the tag archive's body class is
 * dm-page-work, so it needs its own. The arrow is a decorative glyph in the
 * markup and is aria-hidden there, not repeated in CSS content.
 */
.dm-page .dm-fallback__back {
	margin-block-start: var(--space-10);
}

.dm-page .dm-fallback__back-link {
	display: inline-flex;
	align-items: center;
	gap: var(--space-2);
	min-height: 44px;
	color: var(--text-link);
	font-size: var(--text-body-sm);
	font-weight: var(--weight-semibold);
	text-decoration: none;
	transition: color var(--duration-fast) var(--ease-standard);
}

.dm-page .dm-fallback__back-link:hover {
	color: var(--text-link-hover);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}
/* ===== FALLBACKS — Agent 7 — END ===== */
