/*
 * Projects page — patterns/projects-section.php.
 * Geometry: the task handoff's measured table, sourced from
 * .agents/skills/webflow-clone/state/source/pages/projects.html and its
 * paired CSS (.projects-section, .projects-main-block, .collection-list.
 * projects, .projects-card-block.project-page, .projects-card-info,
 * .projects-name, .project-service).
 *
 * Card anatomy (image radius, name/service typography, hover-scale) is NOT
 * repeated here — it reuses .idia-work__card-image-wrapper/.idia-work__card-
 * info/.idia-work__card-name unmodified from work.css (see functions.php:
 * both stylesheets are always enqueued together on this page, matching the
 * same assumption blogs.css already makes about gallery.css). This file only
 * supplies what is new: the section/container/rail chassis, the grid, and
 * the one card-info responsive change work.css's own homepage section never
 * needed (a row-to-column switch at <=991px) — scoped under .idia-projects
 * so the homepage work section is untouched.
 *
 * QUERY CONVERSION (docs/step-projects-cpt.md §3, 2026-08-28): the pattern
 * changed from three hardcoded group blocks to one core/query over the
 * `project` post type (idia-projects plugin). `.idia-projects__grid` now
 * lands on core/query's own `.wp-block-query` element, not a plain group —
 * WordPress's grid layout support prints its own inline
 * grid-template-columns on that element, so the grid rule below needs
 * `!important` to win the tie, and a `display:contents` rule is needed on
 * `.wp-block-post-template` so it does not become an unwanted extra grid
 * item. Both are the exact mechanism project-detail.css already uses for
 * `.idia-project-related__grid.wp-block-query`, copied here rather than
 * reinvented. The gap value and the lone-card centring rule further below
 * are unchanged by the conversion — they key off DOM position, not which
 * block produced the DOM.
 */

/* ---- Section / container ----
   Rail padding for CONTAINER is a literal CSS rule reading --wp--custom--rail
   directly — the same mechanism work.css/gallery.css/blogs.css/pricing.css
   use. WRAPPER (.idia-projects) is align:full with layout:constrained, so
   WordPress's has-global-padding de-dup rule would otherwise zero
   CONTAINER's own auto-applied root padding; !important wins the
   specificity tie against core's own zero-padding de-dup rule, which prints
   after this enqueued file (documented at length in pricing.css). */
.idia-projects__container {
	padding-left: var(--wp--custom--rail) !important;
	padding-right: var(--wp--custom--rail) !important;
}

/* ---- The three-block grid ----
   Each .idia-projects__grid is one .projects-main-block from the reference:
   a 2-column grid. Never a fixed track width (AGENTS.md ban) —
   minmax(0,1fr) tracks reflow to however many cards a block authors, same
   reasoning work.css's own grid documents.

   GAP: 40 -> 20 (<=991) -> 28 (<=479). See the gap-curve block further
   down for the full note. In short: an earlier pass flattened this to a
   flat spacing|16 because the reference's own
   .projects-main-block.project-page declares 16px on both axes with no
   breakpoint override. The reference reading is correct but the flattening
   was wrong — the wider separation is a deliberate departure the owner had
   already set, restored 2026-08-28 on their instruction. Do not re-flatten
   it to match the reference.

   A single core/query grid reproduces the reference's 2/2/1 row rhythm
   automatically for any post count — there is no longer a fixed set of
   three blocks to keep in sync (see the QUERY CONVERSION note above and
   the pattern file's own header comment for why this needs no row-gap
   alternation: the reference's own rule is a flat 16px on both axes with
   no per-row variation, so one uniform grid gap already matches it).

   SUPERSEDED (2026-08-28): this comment previously said a lone card must
   stay in the left column with the right half empty, matching
   .projects-main-block.project-page.single, and must not be touched. The
   owner has since decided a lone card is CENTRED instead — see the
   ":last-child:nth-child(odd)" rule below for the mechanism and the
   reasoning. The reference's own left-aligned behaviour is no longer what
   this page does. The rest of that original note still stands: do not span
   a lone card full-width the way work-section.php's homepage grid does;
   centring at card width and spanning full width are different looks, and
   this page wants the former. */
.idia-projects__grid.wp-block-query {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
	gap: var(--wp--preset--spacing--40);
}

.idia-projects__grid .wp-block-post-template {
	display: contents;
}

/* ---- Kill the inherited flow block-gap on grid children ----
   MEASURED BUG, fixed at the cause. The grid blocks are authored with
   layout:{"type":"default"}, so WordPress emits `is-layout-flow` on them and
   core's own block-gap rule — `.is-layout-flow > * + * { margin-block-start:
   var(--wp--style--block-gap) }` — applies a 24px top margin to every child
   after the first. Grid honours that margin, so the RIGHT-hand card of each
   row rendered 24px lower than the left, and 24px shorter (measured at 1040:
   left card y=861 h=360, right card y=885 h=336 — the margin ate into the
   row). The visual error compounded down the page.

   The gap between cards is already owned by `gap` above, which is the grid's
   own mechanism and the only one that should be spacing these children. This
   rule removes the duplicate spacing rather than compensating for it
   (AGENTS.md §8.4: fix blockGap or the parent's gap, never add a margin;
   §13: remove the cause, never add an offset).

   Scoped to this grid's own children so nothing else on the page is touched.
   The same latent conflict exists on the homepage's .idia-work__grid, where
   it is currently masked by that grid's full-width :last-child span and its
   two hidden cards — noted, not fixed here, since this file must not change
   the homepage.

   Targets `.wp-block-post` (the `<li>` core/post-template emits for each
   post), not `.idia-work__card`: since the query conversion, the actual
   grid item is that `<li>`, not the card group inside it — measured
   directly in the rendered markup as
   `<ul class="wp-block-post-template">` > `<li class="wp-block-post ...">`
   > `<div class="idia-work__card">`. `display:contents` on the `<ul>`
   (above) promotes the `<li>` elements to sit directly in the grid, so it
   is the `<li>` that receives the flow block-gap margin and the `<li>` that
   `:last-child`/`:nth-child` must match below — not the card div one level
   further in, which the earlier version of this rule wrongly targeted. */
.idia-projects__grid .wp-block-post {
	margin-block-start: 0;
}

/* ---- A row holding a single card is centred ----
   OWNER DECISION (2026-08-28), a deliberate departure from the reference.
   The reference leaves a lone card hard left with the right half of its row
   empty (.projects-main-block.project-page.single). That reads as a layout
   error rather than a choice, so a lone card is centred instead.

   NOT the homepage's mechanism. work.css:76 spans its last card full-width
   (grid-column: 1 / -1), which stretches the card and its image to the full
   976px. This centres instead: the card keeps the SAME 468px width and the
   same image proportions as every other card on the page, and only its
   horizontal position changes. Do not "align" the two by copying the
   homepage's span here — the difference is intentional.

   `:last-child:nth-child(odd)` matches a card that is BOTH last in its grid
   and in an odd position, i.e. the left-hand card of a row with no partner.
   It therefore stays correct for any number of cards: it fires for a lone
   card in a block (the current third block), and stays inert whenever the
   last row is full. That matters once the index becomes a query loop
   (docs/step-projects-cpt.md §3) and the card count stops being fixed at
   five — with 5 posts the last card is alone and centres; with 6 it is not
   and this rule does nothing, no markup change either way.

   grid-column: 1 / -1 makes the card own the whole row so it has room to
   move; justify-self: center then places it at the row's centre at its own
   width, rather than stretching it. Both are needed — the span alone would
   stretch it (the homepage's look), and justify-self alone could only centre
   it within the left track, which is a no-op.

   The width is DERIVED, not a literal. A card is one of two equal tracks
   separated by `gap`, i.e. (100% - gap) / 2 — so it resolves to exactly the
   width its siblings get, with no hardcoded px and no new measure token
   (AGENTS.md §8.3 bans an invented px max-width; this is the grid's own
   arithmetic, not a new value). The gap steps 40 -> 20 (<=991) -> 28
   (<=479), so this width needs the matching 991 override below; at 767 the
   grid goes single-column and the reset below takes over before the 479 gap
   step is ever reached, so no 479 width rule is needed.

   Targets `.wp-block-post` (the `<li>`), not `.idia-work__card`, for the
   same reason as the block-gap rule above — that `<li>` is the real grid
   item and the real sibling `:last-child`/`:nth-child` must evaluate
   against, one level outside the card div this rule previously (and
   wrongly) matched on. `width` still resolves correctly since it is set on
   the `<li>` and the card div inside it is a plain flow block that fills
   its parent's width by default. */
.idia-projects__grid .wp-block-post:last-child:nth-child(odd) {
	grid-column: 1 / -1;
	justify-self: center;
	width: calc((100% - var(--wp--preset--spacing--40)) / 2);
}

/* The lone card's derived width tracks the gap curve, so it needs the same
   step at 991 that the gap takes. This block must stay ABOVE the 767 reset
   below: the two rules have equal specificity and both match under 767, so
   source order is what keeps the mobile full-width reset winning. */
@media (max-width: 991px) {

	.idia-projects__grid .wp-block-post:last-child:nth-child(odd) {
		width: calc((100% - var(--wp--preset--spacing--20)) / 2);
	}
}

@media (max-width: 767px) {

	/* Single column below 767 — every card is full width and a lone card is
	   already the only thing in its row, so the centring above must not
	   narrow it to half. Reset to the normal card width. */
	.idia-projects__grid .wp-block-post:last-child:nth-child(odd) {
		width: 100%;
	}
}

/* ---- Gap curve: 40 -> 20 (<=991) -> 28 (<=479) ----
   RESTORED 2026-08-28 at the owner's instruction. A prior pass flattened
   this to spacing|16 on the grounds that the reference's own
   .projects-main-block.project-page declares a flat 16px on both axes. That
   reading of the reference is accurate, but the spacing on this page is a
   deliberate departure from it that the owner had already set — the wider
   card separation is the intended look here, not a transcription error.
   Do not "correct" it back to the reference value again.

   MEASURED RESOLVED VALUES, not the slug names. Each slug carries its own
   breakpoint curve (style.css), so the effective gap is:

     >991   spacing|40 -> 40px
     <=991  spacing|20 -> 20px   (gap--20 is flat 20 at every width)
     <=479  spacing|28 -> 18px   (padding--2-x steps 28 -> 24 -> 18)

   So the real curve is 40 -> 20 -> 18, and it is NON-MONOTONIC in the same
   way spacing|120 is (AGENTS.md §8.4 documents that as reproduced from the
   reference, not a bug): the <=479 step is 2px SMALLER than the 20px above
   it, not larger as the slug name "28" suggests. Verified at 390px: gap
   computes to 18px. This is exactly what the pre-conversion file did — the
   restoration is faithful to it, oddity included. Flagged rather than
   silently "fixed": if the intent was 28px at the smallest width, this
   wants spacing|28's token curve changed or a different slug, which is a
   theme.json decision, not a stylesheet one. */
@media (max-width: 991px) {

	.idia-projects__grid.wp-block-query {
		gap: var(--wp--preset--spacing--20);
	}
}

@media (max-width: 767px) {

	.idia-projects__grid.wp-block-query {
		grid-template-columns: 1fr !important;
	}
}

@media (max-width: 479px) {

	.idia-projects__grid.wp-block-query {
		gap: var(--wp--preset--spacing--28);
	}
}

/* ---- Card info: row-to-column switch at <=991 ----
   .idia-work__card-info (work.css) is flex row / space-between / align-
   items:center at every width — correct for the homepage's own 2-up grid,
   which never needed a narrower column layout of its own. This page's
   reference (.projects-card-info) additionally switches to
   flex-direction:column / align-items:flex-start at <=991px. Scoped under
   .idia-projects so work.css's homepage section is untouched — the two
   sections share the base rule, only this page adds the breakpoint. */
@media (max-width: 991px) {

	.idia-projects .idia-work__card-info {
		flex-direction: column;
		align-items: flex-start;
	}
}

/* ---- Image radius ----
   Reference curve: 32px desktop -> 12px at <=767 -> 16px at <=479.
   .idia-work__card-image-wrapper (work.css) already sets border-radius:
   var(--wp--preset--border-radius--2-xl), i.e. --wp--custom--radius--32,
   which supplies the 32px desktop value for free (shared with the
   homepage's own card). But --radius--32 does NOT hold flat below that: it
   steps 32 -> 24 (<=991) -> 16 (<=767) -> 16 (<=479) (style.css), and no
   other token in the scale produces the reference's own 12/16 curve either
   — --radius--12 is 12px at 1440/991/767 and drops to 4px only at <=479
   (a different breakpoint than needed), --radius--16 is flat 16px at every
   width. Composing --radius--12 for <=767 and --radius--16 for <=479 gets
   the closest match without a raw px: 12px is exact, 16px is exact, and the
   only deviation is that --radius--12 would otherwise still read 12px at
   479 without this override — moot here since the 479 rule overrides it
   explicitly. AGENTS.md §15.6 says stop and ask rather than invent a token
   for a genuine gap; flagged in the report as a token curve neither preset
   was built for, not resolved by adding a new one unilaterally. */
@media (max-width: 767px) {

	.idia-projects .idia-work__card-image-wrapper {
		border-radius: var(--wp--custom--radius--12);
	}
}

@media (max-width: 479px) {

	.idia-projects .idia-work__card-image-wrapper {
		border-radius: var(--wp--custom--radius--16);
	}
}

/* ---- Image height ----
   Reference: height 100% desktop (the image fills whatever the aspect-ratio
   box gives it, work.css's own object-fit:cover + aspect-ratio:16/9
   mechanism already does this) -> 300px at <=991 -> 320px at <=479. These
   two are literal pixel heights in the reference with no matching spacing
   or measure token (they are not vertical rhythm, not a max-width) — kept
   as plain CSS per AGENTS.md's own allowance for values that are genuinely
   one-off, not a preset candidate. */
@media (max-width: 991px) {

	.idia-projects .idia-work__card-image-wrapper img {
		height: 300px;
	}
}

@media (max-width: 479px) {

	.idia-projects .idia-work__card-image-wrapper img {
		height: 320px;
	}
}
