/* Defects in Kyle's own export, corrected. Hand written, loaded last.
 *
 * WHY THIS FILE EXISTS SEPARATELY
 *
 * shapes.css is generated and must never be hand edited. shapes-wide.css and
 * shapes-narrow.css are generated too, and both are about width. None of them
 * is the right home for "his file says something that does not work", which is
 * what this is.
 *
 * Same principle the generated files already state: what he drew and what we
 * changed stay possible to tell apart, and to argue about. Every rule in here
 * names the shape it repairs, what was wrong, and how it was proved.
 *
 * A correction only belongs in here when it changes BEHAVIOUR and not the
 * design. Anything that moves a pixel is a deviation, and a deviation goes in
 * DEVIATIONS in docs/audit-scripts/replica.py where it gets counted.
 */

/* -------------------------------------------------------------------------
 * THE HERO CALL TO ACTION COULD NOT BE CLICKED. Six location pages plus the
 * campaign landing page, desktop and mobile.
 *
 * Found by Daniel, 11 Aug 2026, reading the CSS. He said not to believe him
 * without clicking it, which was the right instruction: proved with a real
 * browser, and Playwright refuses the click on every one of them.
 *
 *   /office-design-sheffield/      "Book a free consultation"   REFUSED
 *   /office-fit-out-hull/          "Book a free consultation"   REFUSED
 *   /office-design-leeds/          "Book a free consultation"   REFUSED
 *   /office-fit-out-doncaster/     "Book a free consultation"   REFUSED
 *   /office-fit-out-london/        "Book a free consultation"   REFUSED
 *   /office-fit-out-manchester/    "Book a free consultation"   REFUSED
 *   /office-fit-out-landing/       "Book your free consultation" REFUSED
 *
 * WHAT IS WRONG. He lays a gradient over the hero photograph and gives it
 * pointer-events:none so the picture underneath stays live. That is correct and
 * he does it on six bands. But on these two he also puts the h1 and both
 * buttons INSIDE the gradient div, and pointer-events inherits, so the buttons
 * inherit "none" as well and the browser hit test never reaches the anchor.
 *
 * It is his oversight rather than his intention, and his own file proves it:
 * on 40750d079366 he puts pointer-events:auto back on the inner panel
 * (.d4xafbd8e49, shapes.css line 642). He simply forgot on these two.
 *
 * WHY NOBODY SPOTTED IT. The links still work by keyboard, they still look
 * exactly right, and they carry a hover state. Nothing about the page suggests
 * a problem. replica.py cannot see it either, and that is structural rather
 * than an oversight: it compares our rendering against his, and his page is
 * broken in precisely the same way, so it reports clean. A design checker
 * cannot catch a defect that was faithfully reproduced.
 *
 * The buttons are put back rather than the container opened up, so the
 * photograph underneath the gradient stays clickable exactly as he intended.
 * Changes no geometry, no colour and no type.
 * ------------------------------------------------------------------------- */

/* 9d1aa87c631f, the location page hero, all six towns. */
.d4xfc70bee5 a,
/* 1f5566e1de81, the Office Fit Out Landing hero, same pair of buttons. */
.d4x1f96547c a {
	pointer-events: auto;
}

/* -------------------------------------------------------------------------
 * THE HERO MOVES UP AND DOWN AS YOU GO PAGE TO PAGE. Five pages carrying the
 * shared hero shape 4af106052da3.
 *
 * Alex spotted it on 12 Aug sitting with Kyle, flicking between Brand and
 * Design. Everything below the fold shifts, so the page never settles.
 *
 * MEASURED, at 1440, before changing anything:
 *
 *   page                 hero row   h1 lines   right column
 *   /branding/               214px      3            196px
 *   /office-furniture/       214px      3            196px
 *   /case-studies/           206px      2            206px
 *   /interior-design/        196px      2            196px
 *   /office-fit-out/         167px      2            167px
 *
 * Four different heights across five pages, so the photography below starts
 * at four different places and the whole page jumps as you navigate.
 *
 * THIS IS NOT OUR BUG. His export does exactly the same thing, to the pixel:
 * Brand 427, Design 409, Build 380, Furnish 427, all measured off his own
 * files. We transcribed him faithfully and inherited it. It is a deviation
 * from the design, knowingly, on Alex's instruction, and it is counted in
 * DEVIATIONS in docs/audit-scripts/replica.py.
 *
 * WHAT HE DREW. shapes.css line 438 puts align-items:end on the row, which
 * bottom aligns BOTH columns and leaves the row free to be whatever height the
 * taller one needs. So a three line h1 pushes the top up, a short paragraph
 * pulls the bottom in, and nothing has a fixed edge to sit on.
 *
 * WHAT WE DO INSTEAD, which is Alex's own description of it. The left column
 * is pinned to the top, so the eyebrow and the first line of the h1 land in the
 * same place on every page and a shorter heading leaves space underneath rather
 * than dropping down the page. The right column keeps his bottom alignment, so
 * the two buttons always sit the same distance above the photography. The row
 * gets a floor of three lines of his h1, which is the tallest real case, so the
 * band cannot shrink below it.
 *
 * min-height, not height. A page whose h1 ever runs to four lines grows rather
 * than overlapping the pictures underneath. It would then be the odd one out,
 * which is a copy problem to fix in the copy, and a visible one.
 *
 * Desktop only. Below 900px his layout is one column and everything stacks in
 * order, so there is nothing to align and a floor would only add a gap.
 * ------------------------------------------------------------------------- */

@media (min-width: 901px) {
	.d4x69c3c486 {
		/* Three lines of his 68px h1 at line-height 1.05. Measured at 214px on
		   /branding/ and /office-furniture/, which is where it comes from. */
		min-height: calc(68px * 1.05 * 3);
	}

	.d4x69c3c486 > h1 {
		align-self: start;
	}
}

/* ---------------------------------------------------------------------------
 * The head office map, made to sit still
 * ---------------------------------------------------------------------------
 * Alex, 12 Aug: "can we fix the map so it doesn't move, can't be dragged etc?"
 *
 * His design embeds OpenStreetMap's own iframe, which is a full interactive map:
 * drag it anywhere, zoom in and out, and on a phone a finger meant for the page
 * pans the map instead and the page underneath refuses to scroll. That last one
 * is the worst of it and the least obvious, because on a desktop you only find
 * it if you try.
 *
 * Nobody visiting a contact page wants to explore Doncaster. They want to see
 * roughly where the office is, which one fixed view already tells them.
 *
 * pointer-events, so it becomes a picture. Mouse, touch and the scroll wheel
 * all stop reaching it, which takes the drag, the zoom and the scroll trap in
 * one line and leaves the map itself exactly as he drew it.
 *
 * ADDRESSED BY THE EMBED, NOT BY ITS GENERATED CLASS. A d4x class is a hash of
 * the inline style behind it, so it renames itself the moment that style is
 * touched and the rule silently stops applying. There is one iframe in the
 * whole export and this is it.
 *
 * KNOWN AND ACCEPTED: OpenStreetMap draws its own + and - buttons inside the
 * frame, and they are still visible while doing nothing. They cannot be hidden
 * from out here, because the inside of a frame from another domain is not ours
 * to style. Getting rid of them properly means replacing the embed with a still
 * image of the same view, which is a better answer on four counts (nothing
 * third party loads in the visitor's browser, no cookie question, one image
 * instead of a mapping application, and a click could go to directions) and is
 * a change to his markup rather than to his styling. Worth doing, not worth
 * doing at eleven at night.
 * ------------------------------------------------------------------------- */

/*
 * ADDRESSED BY BEING THE ONE IFRAME rather than by its src, since 15 Aug 2026.
 *
 * It used to be iframe[src*="openstreetmap.org"], which stopped matching the
 * moment the map became Google Maps at Emily's request. Worse, it would have
 * stopped matching silently: the rule simply would not apply and the scroll
 * trap would come back on phones with nothing to say it had.
 *
 * Their consent plugin is the other reason not to key on the src. Complianz
 * holds a blocked embed's address in a data attribute until somebody accepts
 * and only then writes it into src, so for most of a visit there is no src to
 * match on at all.
 *
 * There is exactly one iframe in his whole export and this is it. If a second
 * ever appears this rule wants narrowing, and design-geometry.py counting them
 * is how that would surface.
 */
.d4-shape iframe {
	pointer-events: none;
}

/*
 * BUT A MOUSE GETS IT BACK, and that changed on 15 Aug 2026 with the map.
 *
 * Alex's reason for switching the map off was a finger: on a phone the embed
 * caught the drag and the page underneath would not scroll. That reason is a
 * phone reason. It was applied everywhere because with OpenStreetMap there was
 * nothing to click anyway, only its own zoom buttons.
 *
 * Google's is not like that. It arrives carrying their Business Profile, so the
 * band now shows District Four Design, 1 Water Vole Wy, 5.0 from 11 reviews,
 * and a Directions button. Switching all of that off to solve a phone problem
 * throws away the reason Emily asked for Google in the first place, and 34 per
 * cent of their clicks already go through that profile.
 *
 * THE OLD OBJECTION TO A LIVE MAP ON DESKTOP IS THE SCROLL WHEEL, and it was
 * measured rather than assumed: wheel over the map at 1440 in Chromium, Firefox
 * and WebKit, and the page moved the full 500px every time. Google's embed
 * wants ctrl held before it will zoom, so there is nothing left to protect
 * against. Deployed, measured and set to auto revert in the same step, which is
 * the rule from the day a broken photograph rule was left on staging.
 */
@media (min-width: 901px) {
	.d4-shape iframe {
		pointer-events: auto;
	}
}

/* ---------------------------------------------------------------------------
 * Emily's three video boxes get his corner
 * ---------------------------------------------------------------------------
 * Alex, 12 Aug: the growth audit video holders "are square rather than the same
 * as the contact page with the curve in the bottom right, so it's not on brand".
 *
 * He is right, and it is his own design that says so. The cut bottom right
 * corner is the most repeated shape in the whole export: border-radius 0 0 120px
 * 0 appears 29 times across the site, on hero photography, case study images and
 * the contact page's own video box, which is the one Alex is comparing against.
 * The three audit boxes are the only media on the site without it.
 *
 * WHY THEY WERE SQUARE, because it was not an oversight. Kyle drew the results
 * video box square, and when the intro screen was built for a brief he had no
 * design for, its box was copied off his results box word for word so the two
 * could not drift. They did not drift. They were both square. Copying him
 * faithfully reproduced the one place he had not applied his own rule.
 *
 * ONE CLASS COVERS ALL THREE, which is that same copying paying off: the intro,
 * the results and the saved results all resolve to the same generated class
 * because they were all written from the same declaration.
 *
 * 120px and not a smaller number on a phone, because he does not scale it. The
 * contact page keeps a 120px corner on a box that drops to 252px tall, so a
 * deep curve on a short box IS the design rather than a compromise in it.
 *
 * The holder already clips what is inside it, so the video is cut by the corner
 * rather than sitting square underneath it.
 *
 * ADDRESSED BY THE GENERATED CLASS, which is the one weakness here: that name is
 * a hash of the declaration behind it, so touching the style renames it and this
 * rule silently stops matching. audit-journey.py and audit-results.py both
 * measure the corner now, so a rename goes red rather than quietly going square.
 * ------------------------------------------------------------------------- */

.d4xef039b58 {
	border-radius: 0 0 120px 0;
}

/* ---------------------------------------------------------------------------
 * Two boxes that carry his corner and cannot show it
 * ---------------------------------------------------------------------------
 * Alex, 12 Aug, looking at the Branding page: four service cards, three square
 * and one rounded, "can we make sure they all follow this guideline".
 *
 * They already do. All four are drawn with border-radius 0 0 120px 0, and the
 * one that looked right was the one whose photo has not been uploaded yet. The
 * corner was never missing. It was being covered up.
 *
 * A border-radius only bends the box. It does nothing to a photograph sitting
 * inside unless the box is told to clip, and these two classes are the only two
 * of his twenty four media holders that carry a corner without overflow:hidden.
 * So an EMPTY one shows the curve and a FILLED one draws the picture square
 * straight over it, which is exactly backwards: the slots look correct until
 * Emily's photography lands, and then they quietly go square one page at a time
 * as Kyle fills them in.
 *
 * That is why it read as three square and one round rather than as a bug. It
 * will also get worse on its own, which is the part worth catching now.
 *
 * Restoring his intent rather than deviating from it. He put the corner there
 * on purpose and every other rounded box of his clips properly, so these two
 * are a slip in the export, not a decision.
 *
 * Between them they cover the service cards on Branding, Office fit out and
 * Office furniture, and the wide photograph on About.
 * ------------------------------------------------------------------------- */

.d4x5460f8ce,
.d4xc83fb266 {
	overflow: hidden;
}

/* ---------------------------------------------------------------------------
 * TWO BANNER BANDS AND TEN CLAMPED HEIGHTS USED TO LIVE HERE
 * ---------------------------------------------------------------------------
 * Both were hand corrections to the generated shapes-wide.css, which is never
 * edited directly. On 13 Aug both were fixed at source instead, so they are
 * gone from here and come out of his design on every run:
 *
 *   - a band Kyle drew with no side padding is no longer capped at 1440, which
 *     covers .d4s-40750d079366 and .d4s-9d1aa87c631f and 26 others, including
 *     every case study hero
 *   - a height scaled off the viewport is clamped to the cap by transcribe.py
 *
 * Left as a note rather than deleted, because "where did those go" is the
 * question somebody will have reading the commit that removed them.
 * --------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------
   Full bleed bands do not get the 1440 cap

   Alex, 13 Aug, with a design marked up in red and blue: "if it was full screen
   on the design with no space left/right, those are to be treated the same as
   full screen; else keep the width cap."

   That is a better rule than the blanket cap. The 1440 decision of 4 Aug exists
   to hold the 1.13:1 proportion of a SPLIT band, where copy sits beside a
   picture. It was never meant for a band that runs edge to edge in his design,
   and applying it there strands a full width hero in the middle of the screen.

   So: bands Kyle drew touching the viewport edge keep his own 72px gutter and
   grow with the window. Bands he drew with white space either side keep the cap.

   These two are the case study hero and the client/industry/location bar
   beneath it, the red box in his markup. The general rule belongs in
   transcribe.py, detecting zero side padding in the design, which is the next
   piece of this job.
   ------------------------------------------------------------------------ */
@media (min-width: 1441px) {
	.d4s-e1f5a5d6257b > *,
	.d4s-8e9f64c15f47 > * {
		padding-left: 72px;
		padding-right: 72px;
	}
}

/* -------------------------------------------------------------------------
 * THE ORPHAN QUOTATION MARK USED TO BE FIXED HERE, WITH :has.
 *
 * It is done in blocks/shape/render.php now, where the paragraphs it belongs to
 * are already being removed. :has is ignored by Safari before 15.4, so on an
 * older iPhone the mark came back and floated in an empty column, and Kyle
 * tests this site on Safari. Measured by deleting every :has rule at runtime in
 * WebKit and looking at what was left.
 * ------------------------------------------------------------------------- */


/* -------------------------------------------------------------------------
 * A RULE FLOATING 80px BELOW THE WORDS IT BELONGS TO. His services band, on
 * every case study with fewer than eight services, which is 26 of their 27.
 *
 * He draws eight services as a two column grid, each with a line under it. The
 * grid sits beside a taller column, so it stretches to match, and with only
 * three services the four rows become two rows of 100px instead of 50 and every
 * line drifts away from its own text. Nothing is empty and nothing is missing,
 * it just looks like a mistake.
 *
 * Scoped to a grid that does NOT have an eighth item, because the plain version
 * of this rule was wrong. Kyle's own eight do not quite fill the space either:
 * measured, his rows are 49.77px against a content height of 46, so taking the
 * slack out everywhere moved his own page by 15px. His page now keeps his
 * spacing exactly and only a short list is corrected.
 *
 * Measured on /box-refurb-doncaster-rovers/ with eight services, 4 rows of
 * 49.77px before and after, and on the Keepmoat page with three, 100px a row
 * before and 46 after.
 * ------------------------------------------------------------------------- */
.d4s-ee06bbd28ea8 .d4x205968c8:not(:has(> :nth-child(8))) {
	align-content: start;
}

/* -------------------------------------------------------------------------
 * THE FACTS BAR IS A 2 x 2 ON A PHONE, NOT A LIST OF FOUR.
 *
 * Alex, 13 Aug, on a phone: "it looks very clunky, can the black bar and the
 * sections Location / Completion Year be side by side?"
 *
 * He is right. His four columns collapse to one below 900px, which is the
 * transcriber's general rule and the correct default for a row of four, but
 * these are four SHORT pairs: a label and one or two words. Stacked, the black
 * band is 260px tall on a 390px screen and pushes the whole case study down.
 * Two by two, it is 148.
 *
 * A DEVIATION, not a correction. Kyle drew one mobile screen, the fit out
 * landing page, and it has no facts bar on it, so there is nothing of his to be
 * faithful to here and this is our decision. Recorded in DEVIATIONS in
 * docs/audit-scripts/replica.py so it stays arguable.
 *
 * Checked at 320, 390 and 820, and in Firefox and WebKit as well as Chromium.
 * COMPLETION YEAR wraps onto two lines at 320 and that is fine: it is the
 * label, and its value sits under it either way.
 * ------------------------------------------------------------------------- */
@media (max-width: 900px) {
	.d4s-8e9f64c15f47 .d4x7d343394 {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: 20px 24px;
	}
}

/* -------------------------------------------------------------------------
 * THE PLUS ON AN FAQ DROPS ONTO ITS OWN LINE ON A PHONE.
 *
 * Found looking at the DRFC box on a phone in WebKit, which is what Kyle is
 * testing in. His FAQ row is a flex line with the question at one end and a
 * terracotta + at the other. shapes-narrow.css adds flex-wrap:wrap to it below
 * 900px, which is the transcriber's general rule for a flex row on a narrow
 * screen and right nearly everywhere: a row of cards should wrap. Here the
 * second item is a 16px glyph, so as soon as the question runs to two lines the
 * + wraps under it and sits alone above a load of empty space. Every row goes
 * from 76px to 125.
 *
 * NOT a case study fix. The class is shared by ten of his sections, so this is
 * every FAQ on the site: the case studies, all six location pages, Build,
 * Brand, Design, Furnish, Task Seating, Workplace Care, the Cost Estimator and
 * the fit out landing page.
 *
 * min-width on the question because a flex item will not shrink below its
 * content by default, and without it the + is pushed off the end instead of
 * the question wrapping.
 *
 * 1199 rather than 900 since 14 Aug, because the tablet band inherits the same
 * general wrap rule and would drop the + onto its own line on an iPad for the
 * same reason it did on a phone. One correction, both bands.
 * ------------------------------------------------------------------------- */
@media (max-width: 1199px) {
	.d4-shape .d4x59b5b602 {
		flex-wrap: nowrap;
	}

	.d4-shape .d4x59b5b602 > :first-child {
		min-width: 0;
	}
}

/* -------------------------------------------------------------------------
 * THE CLIENT LOGOS: TWO ROWS OF FOUR ON A PHONE.
 *
 * Alex, 14 Aug, marking up a screenshot: two rows boxed and arrows pulling
 * Keepmoat and Bidfood up into them. Both strips hold eight, so four across is
 * exactly two even rows.
 *
 * IT STARTED AS A PIXELATION REPORT, from Kyle on an iPhone 15 Pro: "the logos
 * are pixelated on homepage and other pages with the companies we've worked
 * with". The cause was the layout rather than the pictures. His strip is eight
 * columns and shapes-narrow.css collapses it to one below 900px, which is the
 * transcriber's general rule and right for a row of cards. A logo is not a
 * card. Each came out 350px wide on a 390px screen, so the strip stood 2,968px
 * tall and at a device pixel ratio of 3 the browser wanted 1,050 actual pixels
 * from a 300px file. Four across asks for 226, so the file is comfortably
 * bigger than the need and nothing about the images had to change.
 *
 * The 120px ceiling is what stops any width in between blowing one up again: a
 * 599px screen would otherwise give each logo 173px, and a tablet 221px, both
 * past what a 300px file is worth. Centred, because the cell is then wider than
 * the logo.
 *
 * Two shapes share the class: the homepage strip and the one on Brand, Build
 * and Design. Desktop is untouched at eight across, 141px each.
 * ------------------------------------------------------------------------- */
@media (max-width: 900px) {
	.d4-shape .d4x699b44ab {
		grid-template-columns: repeat(4, minmax(0, 1fr));
		gap: 16px 20px;
	}

	.d4-shape .d4x699b44ab img {
		max-width: 120px;
		margin-left: auto;
		margin-right: auto;
	}
}

/* -------------------------------------------------------------------------
 * THE TWO BUTTON ROW HANGS OFF THE RIGHT EDGE AT 901px.
 *
 * A real bug rather than a squeeze, and the only one the tablet sweep found:
 * /office-fit-out/, /branding/, /interior-design/ and /office-furniture/ all
 * scrolled sideways at 901, the page 928px wide inside a 901px window.
 *
 * His hero puts two buttons in a flex row with a 14px gap and no wrap, and the
 * second one carries white-space:nowrap. In the right hand column of a hero at
 * 901px there is not room for both, so the second one simply goes past the end
 * of the page. shapes-narrow.css already wraps every flex row of his below
 * 900px for exactly this reason; the tablet band needs the same, and only for
 * the rows that overflow, because wrapping everything is what put the + on its
 * own line on the FAQ rows above.
 *
 * Costs nothing where the row already fits: flex-wrap only does anything once
 * the children do not.
 * ------------------------------------------------------------------------- */
@media (min-width: 901px) and (max-width: 1199px) {
	.d4-shape .d4x4d1b4fc4 {
		flex-wrap: wrap;
	}
}

/* -------------------------------------------------------------------------
 * THE FOOTER MARK STANDS DOWN IN THE TABLET BAND.
 *
 * His footer is five columns: four of content and a fifth holding the outline
 * mark, which is a fixed 150px. At 901px that leaves the content columns 101px
 * wide, the address comes out one word a line and the footer goes from 541px
 * tall to 744.
 *
 * shapes-tablet.css gives the band four columns instead, and THIS is what pays
 * for them: 150px plus a 48px gap is 198px back, about 40px on every column.
 * Measured at 1024, which is an iPad Pro in portrait: 131px columns become 180,
 * and the footer comes back to 541px, the same height as his desktop.
 *
 * A correction of my own first answer, not of his design. I first took the band
 * to TWO columns, which fixed 901 and made 1024 and 1180 worse: the footer
 * doubled to 1094px with 182px of hole under Follow us. Alex photographed it on
 * an iPad in portrait on 14 Aug. His own layout is already right at 1180.
 *
 * The mark is a watermark at 50 per cent opacity. It is still there on a phone,
 * where everything is stacked and there is room, and from 1200 up where his
 * five columns fit. Deleting this rule puts it back in the band at the cost of
 * 40px a column, which is District Four's call rather than mine.
 * ------------------------------------------------------------------------- */
@media (min-width: 901px) and (max-width: 1199px) {
	.d4x8374bb6c > img {
		display: none;
	}
}

/* -------------------------------------------------------------------------
 * THE FURNITURE GRID: NINE TILES, ONE SIZE.
 *
 * Alex, 14 Aug 2026, looking at /office-furniture/: "these image sizes need to
 * be uniformed; they all have different image size placeholders."
 *
 * He is right, and it is Kyle's own design rather than a fault in the
 * transcription. His Furnish.dc.html draws NINE tiles in one grid out of THREE
 * different components, checked in his file: height:340px three times,
 * height:220px four times, height:170px twice.
 *
 * The 170px pair, Storage Solutions and Accessories & Power, are not just
 * shorter. They are a different card: a bordered box with a dark 170px strip
 * and the title UNDERNEATH it, next to seven cards that put the title over the
 * photograph. Their placeholder reads dark rather than pale for the same
 * reason, because the slot is translucent grey and their strip behind it is
 * #2a2a2a while everyone else's is white. That is the pair Alex can see in the
 * screenshot.
 *
 * 260px for all nine, Alex's choice from three measured options. It sits
 * between his own two sizes and the grid comes out 812px against the 814 it
 * is today, so the page length does not move while every tile matches.
 *
 * The two odd ones are converted here rather than in the shape markup. A shape
 * id is a hash of its markup, so editing the template renames the shape and
 * every page pointing at the old name renders nothing, and the next transcriber
 * run would put it back anyway. Every class below is unique to this one shape,
 * checked, and it is scoped to the section as well.
 *
 * A DEVIATION, not a repair. Recorded in DEVIATIONS in replica.py.
 *
 * 238px below 900px is his own number: it is what the transcriber's phone scale
 * already gives his 340px tile, so a phone is uniform too rather than being
 * left with one tile at 238 and the rest at their desktop heights.
 * ------------------------------------------------------------------------- */
.d4s-de9c01f4eb99 .d4xf098e78c,
.d4s-de9c01f4eb99 .d4xbdce9520,
.d4s-de9c01f4eb99 .d4x1da9e694 {
	height: 260px;
}

@media (max-width: 900px) {
	.d4s-de9c01f4eb99 .d4xf098e78c,
	.d4s-de9c01f4eb99 .d4xbdce9520,
	.d4s-de9c01f4eb99 .d4x1da9e694 {
		height: 238px;
	}
}

/* The bordered box becomes a photograph with the title over it, like the other
   seven. */
.d4s-de9c01f4eb99 .d4x1da9e694 {
	position: relative;
	overflow: hidden;
	border: 0;
}

.d4s-de9c01f4eb99 .d4x8d784ebb {
	position: absolute;
	inset: 0;
	height: auto;
	background: #FFFFFF;
}

/* His pale empty slot, so all nine placeholders read the same. Without this the
   two converted tiles keep the translucent grey, which lands two shades lighter
   than the pale one his other seven use. */
.d4s-de9c01f4eb99 .d4x8d784ebb .d4-shape__slot {
	background: #EAEAE9;
}

/* His scrim, copied from d4x3aa6a026 on the seven tiles that have one as a real
   element. A pseudo element here because CSS cannot add a node, which is also
   why the title needs lifting above it: a ::after paints after everything in
   the box, where his own scrim span sits before the title in source order. */
.d4s-de9c01f4eb99 .d4x1da9e694::after {
	content: "";
	pointer-events: none;
	position: absolute;
	inset: 0;
	background: linear-gradient(180deg, rgba(29, 29, 29, 0) 35%, rgba(29, 29, 29, 0.88) 100%);
}

.d4s-de9c01f4eb99 .d4x3c224db8 {
	position: absolute;
	left: 20px;
	right: 20px;
	bottom: 16px;
	padding: 0;
	z-index: 1;
}

/* And the terracotta 'View' becomes his outlined one. On a white card it read
   as a link; over a photograph it has to be the same control as the other
   seven, and #B84836 on a dark scrim is the weakest contrast on the page. */
.d4s-de9c01f4eb99 .d4x1da9e694 .d4xaceb004e {
	border: 1px solid rgba(255, 255, 255, 0.4);
	font-size: 12px;
	padding: 8px 12px;
	white-space: nowrap;
	color: #ffffff;
}

/* ---------------------------------------------------------------------------
 * The founders' photograph keeps their heads on a big monitor
 * ---------------------------------------------------------------------------
 * Alex, 15 Aug 2026, on About: "that image needs lowering a bit so you can see
 * kyle's face; currently its cut off".
 *
 * Right at every width Kyle drew for, and wrong above them, which is why nobody
 * working at 1440 had ever seen it. Alex found it on a 3840 screen.
 *
 * His frame is a fixed 560px tall with a fluid width, and d4_shape_photo()
 * writes object-fit cover out longhand so the picture always fills the width.
 * Past a frame of about 840px the picture is therefore TALLER than the frame,
 * and top:50% with translateY(-50%) centres it, so the overflow comes half off
 * the top and half off the bottom. Kyle's head is near the top of the shot and
 * Emily's is lower, which is why only one of them loses a face. Measured:
 *
 *     viewport   frame        photo        cut off the top
 *       1440    720x560      840x560             0px
 *       1600    800x560      840x560             0px
 *       1920    960x560      960x640            40px
 *       2560   1280x560     1280x853           147px
 *       3840   1920x560     1920x1280          360px
 *
 * SLID THROUGH ITS OWN OVERFLOW rather than given a y offset, and that is the
 * point. His framing system does support one ([zoom, x, y] in the shape
 * manifest, and he used the x on this very photograph), but y is a percentage
 * of the FRAME while the overflow grows with the viewport, so a value right at
 * 1920 is wrong at 2560.
 *
 * top:X% with translateY(-X%) is the lever that does scale, because both halves
 * are percentages of different things: the position works out to
 * (frame height - photo height) * X/100. So X=0 is top aligned, X=50 is centred
 * (which is what it was doing), X=100 is bottom aligned, and anything between
 * slides it proportionally at EVERY width.
 *
 * 15%, chosen by rendering 0, 15, 25 and 35 at 3840 and looking. Alex, 15 Aug,
 * on the top aligned version: "it can go up a bit more". At 25 Kyle's forehead
 * starts clipping again, so 15 is close to the limit rather than a round number.
 *
 * A NO-OP AT HIS OWN WIDTH. At 1440 and 1600 the picture is exactly as tall as
 * the frame, so there is nothing to centre and this changes nothing at all.
 *
 * !important BECAUSE THE TOP IS AN INLINE STYLE, and this is where it bit. The
 * first version of this rule left it off. The inline top:50% won, the transform
 * in the same rule DID apply, and the photograph ended up pushed 280px DOWN its
 * frame with white space above it. That went to staging while Alex was looking
 * at it. Deploy and measure in one step, and revert on the spot if the numbers
 * are wrong, rather than leaving a known bad state up while writing the fix.
 *
 * Scoped to this one band. Six framed slots exist across five shapes and the
 * rest are photographs of rooms, where centring is the better answer. If more
 * pictures of PEOPLE go into framed slots this wants to become a choice
 * District Four can make per photograph rather than a rule we write for them.
 * ------------------------------------------------------------------------- */

.d4s-3a6f9c1ff36a .d4-shape__photo--framed {
	top: 15% !important;
	transform: translate(-50%, -15%);
}

/* ---------------------------------------------------------------------------
   An empty photo slot is the size of the photograph that goes in it
   ---------------------------------------------------------------------------

   Alex, 15 Aug 2026, with the DRFC box page and the Discover Financial page side
   by side: "the white section should be the same size or at least big enough to
   fit the image size shown in the template". His 520px photograph with the cut
   corner against a 48px grey strip, in the same band of the same template.

   blocks/shape/render.php now puts the transcribed image class on the
   placeholder as well as on the photograph, so the box is his size and his
   shape before anybody uploads anything. THIS is the half that makes that safe.

   His image classes carry display:block, because they are for an <img>. The
   placeholder is a <span> that has to centre a caption inside it, and both
   selectors are one class, so the generated sheet would win on source order
   alone: shapes.css writes .d4-shape__slot at line 144 and the image classes
   from line 200 onwards.

   One class more specific rather than !important, because !important on display
   would also beat anything written here later, and this is a file of exceptions
   where somebody will want to write one.

   Only the layout properties are repeated. Not width, not height, not the
   corner: those are the whole point and have to come from his class.
   --------------------------------------------------------------------------- */

.d4-shape .d4-shape__slot {
	display: flex;
	align-items: center;
	justify-content: center;
	/* His img rule says object-fit:cover, which does nothing on a span, and
	   overflow:hidden is what actually keeps a long caption inside the corner. */
	overflow: hidden;
}

/* ---------------------------------------------------------------------------
   The contact page stops at 1440 like every other band with words in it
   ---------------------------------------------------------------------------

   Alex, 15 Aug 2026, on a 3840 monitor: the video on the contact page "still
   shows half an image placeholder rather than the full video placeholder".

   MEASURED, because the symptom is three sections away from the cause. The
   video holder is 360px tall and as wide as its column, and the video is 16:9,
   so how much of the frame you see depends entirely on how wide that column is:

     1440   583 x 360   91% of the frame
     1920   811 x 360   79%
     3840  1726 x 360   37%

   Which is his own design at 1440 and a letterbox slice of somebody's face on a
   big monitor. The band was never capped. 129 of his bands centre their content
   above 1440 and this is not one of them, so it kept getting wider while the
   holder kept its stated height.

   IT IS NOT CAPPED BECAUSE OF WHERE THE PADDING IS. transcribe.py's wide layer
   reads the padding off the section's direct child and writes the cap onto that
   same element. On every other band that child is the grid and carries the
   72px. On this one the child is the <form>, which is margin:0 and nothing else,
   and the grid with padding:56px 72px 96px sits one level further in. So the
   generator read zero padding, took it for a band he had drawn edge to edge,
   and left it alone.

   Done here rather than in the generator on purpose. Teaching wide_css to look
   deeper would re-evaluate all 256 bands to fix one, at the end of a long day,
   and the 129 that are right today are right by measurement. The generator now
   at least records the correct root class, which was a second bug in the same
   place and is a no-op on its own; this is the one that moves the pixels.

   Same arithmetic as the generated rule, one element deeper, and only the two
   horizontal sides so his 56px and 96px survive.
   --------------------------------------------------------------------------- */

@media (min-width: 1441px) {
	.d4s-657a4442d7c4 > * > * {
		padding-left: calc((100% - 1440px) / 2 + 72px);
		padding-right: calc((100% - 1440px) / 2 + 72px);
	}
}

/* -------------------------------------------------------------------------
 * THE FOOTER HAD ONE LEGAL LINK AND NEEDS THREE. 16 Aug 2026, task #174.
 *
 * His bottom bar (.d4x1763ab38) is display:flex with justify-content:
 * space-between and exactly two children in it, the copyright line and the
 * privacy link, so they sit at either end of the width. Adding the cookie
 * policy and the terms of use as two more children spreads all four evenly
 * across 1440px, which is not what he drew and reads as four unrelated things.
 *
 * So inc/chrome.php wraps the three in one span and this gives that span his
 * own 24px gap back. Two children again, and the group holds together on a
 * phone because the bar already wraps below 900.
 *
 * A behaviour fix rather than a deviation: the bar keeps his layout exactly,
 * it just has one more thing in the right hand slot.
 * --------------------------------------------------------------------------- */

.d4-footer__legal {
	display: flex;
	flex-wrap: wrap;
	gap: 24px;
}

/* The fallback in chrome.php, used only if his privacy link ever moves out of
   the bar. On its own line under the footer rather than nowhere. */
.d4-footer__legal--loose {
	margin: 16px 0 0;
	padding: 0 72px 24px;
	font-size: 13px;
}

/* -------------------------------------------------------------------------
 * THE WORKPLACE GROWTH AUDIT IGNORED THE 1440 CAP. Alex, 16 Aug 2026, from a
 * screenshot: "the padding on this doesn't follow the standard site width
 * rules?" It did not.
 *
 * Measured: on a 1920 monitor every other page starts its copy at 312px, which
 * is calc((100% - 1440px) / 2 + 72px), Alex's 4 Aug canvas decision. The audit
 * started at 72 and ran to the edge. At 2560 it was 560px out.
 *
 * WHY NOTHING CAUGHT IT, and it is worth knowing before writing the next check.
 * At 1440 the capped and uncapped answers are the SAME NUMBER: (1440-1440)/2+72
 * is 72. Every check we own runs at 390, 768, 1024 and 1440, so all of them
 * agreed the page was correct. docs/audit-scripts/site-width.py measures at 1440
 * AND 1920 and subtracts, which is the only way this shows up.
 *
 * The audit is one shape carrying every screen, and it has no wide rule at all:
 * shapes-wide.css has 145 of them and 8f2e173e6844 is not one. It is not in the
 * transcriber's current run either, because the page stopped being Kyle's
 * markup on 9 Aug when Emily's revision landed (#82), so the correction belongs
 * here rather than at source.
 *
 * Two containers, because the audit swaps between them: d4xe19391b6 is the
 * landing screen and d4xfa45d019 is the questions and the results.
 *
 * THOSE CLASS NAMES ARE HASHES of his markup and a re-import would rename them.
 * That is survivable here and only here, because site-width.py goes red the
 * moment it happens. Do not copy this pattern anywhere the checker does not
 * reach.
 * --------------------------------------------------------------------------- */

@media (min-width: 1441px) {
	.d4s-8f2e173e6844 .d4xe19391b6,
	.d4s-8f2e173e6844 .d4xfa45d019 {
		padding-left: calc((100% - 1440px) / 2 + 72px);
		padding-right: calc((100% - 1440px) / 2 + 72px);
	}
}

/* -------------------------------------------------------------------------
 * HIS FULL BLEED BANDS KEPT THEIR PHOTOGRAPH AND LOST THEIR WORDS. 16 Aug 2026,
 * 40 instances on 40 pages, found by docs/audit-scripts/site-width.py.
 *
 * On 13 Aug a band Kyle drew with no side padding was deliberately uncapped so
 * the picture keeps its shape above 1440. That was right for the picture and
 * nobody thought about the words laid on top of it, which stayed at 72 while
 * every band above and below them moved to 312 on a 1920 monitor. The page
 * visibly disagrees with itself, and the fault is OURS rather than his: his
 * export has no maximum at all, so in his design everything sat at 72 and
 * agreed. Alex signed this off on 16 Aug after seeing it side by side.
 *
 * The photograph still bleeds. Only the overlay it sits under moves.
 *
 * Three shapes share one structure, an absolutely positioned overlay carrying
 * its own 72px inset. Two do not and are handled on their own terms below.
 *
 * These are hashed class names and a re-import would rename them. Survivable
 * here because site-width.py goes red the moment it happens.
 * --------------------------------------------------------------------------- */

@media (min-width: 1441px) {

	/* Case study hero (27 pages), location hero (6), fit out landing (1). */
	.d4s-7a21d107b55f .d4x16137416,
	.d4s-9d1aa87c631f .d4xfc70bee5,
	.d4s-1f5566e1de81 .d4x1f96547c {
		padding-left: calc((100% - 1440px) / 2 + 72px);
		padding-right: calc((100% - 1440px) / 2 + 72px);
	}

	/* "Design and build as one" (4 pages). The overlay has no inset of its own
	   and the panel inside it carries the 72, so this adds the gutter only. */
	.d4s-40750d079366 .d4xaec72ace {
		padding-left: calc((100% - 1440px) / 2);
		padding-right: calc((100% - 1440px) / 2);
	}

	/* The three column statistics band (2 pages). Its columns carry a 48px
	   inset rather than 72, which is his own number for this band, so it keeps
	   it and only the gutter is added. */
	.d4s-eb1bc236265d .d4xaba2aab5 {
		padding-left: calc((100% - 1440px) / 2);
		padding-right: calc((100% - 1440px) / 2);
	}
}

/* -------------------------------------------------------------------------
 * HIS CUT CORNER ATE THE END OF THE PROJECT TITLES, AND THE TITLES STARTED IN
 * 5 DIFFERENT PLACES. The Work page, 27 tiles, every width, all three engines.
 *
 * THE FIRST FAULT. The tile is border-radius 0 0 120px 0 with overflow:hidden,
 * and the caption inside it is absolutely positioned at left:24px, right:24px,
 * bottom:20px. Those two numbers disagree: 24px is only enough while the box is
 * still square, and by the height of the last line of the title the arc has cut
 * 40 to 54px in from the right edge, so the end of the line is clipped
 * mid-word. Alex photographed it on 17 Aug 2026, "some of the writing goes over
 * the edge". Measured on all 27 cards at 21 widths from 320 to 1920: 33 clipped
 * lines in Chromium, 50 in Firefox, 51 in WebKit.
 *
 * IT IS HIS OVERSIGHT RATHER THAN HIS INTENTION. It never showed in his export
 * because his thirteen demo titles were long enough to wrap early and land
 * short on the last line: "Office Design and Fit Out in Doncaster, UK for
 * Fastline" runs to two lines. Their real post titles are shorter, sit on one
 * line and run the full width of the box straight into the curve.
 *
 * THE SECOND FAULT, which is his too and is the one that actually offends the
 * eye. The caption is anchored to the BOTTOM, so its top is wherever the title
 * happens to end up. One, two and three line titles start in three different
 * places, and with two card heights in the grid that is 5 distinct start
 * positions across a screen. Alex, looking at a screenshot of the grid: "we now
 * have titles up and down, not all starting in the same positions".
 *
 * SO THE TITLE ALWAYS RESERVES THREE LINES. Alex, 17 Aug 2026: "im happy to
 * make the text always able to fit 3 lines given that's the maximum and move
 * everything up slightly so they fit and can all stay in the same position."
 * min-height rather than height, so the reservation sets the floor and a title
 * that needs a fourth line still gets it instead of being clipped.
 *
 * 3.75em is three lines at his own line-height of 1.25, expressed in em so it
 * follows the font-size down to 17px in the tablet and narrow bands without a
 * second number to keep in step.
 *
 * THREE IS HIS MAXIMUM, NOT THE SITE'S. Counted on all 27 titles at 25 widths
 * in all three engines: 3 lines at 1440 and above, which is what Alex was
 * looking at, but 4 at 1200 to 1240, at 901 to 990, and at 320 in Chromium.
 * Those tiles sit one line higher than the rest of their row. Worth knowing
 * rather than hiding: it is 1 tile at 1200 and 4 at 901, and the alternative
 * was truncating a project title with an ellipsis, which loses words a search
 * engine reads.
 *
 * THE CAPTION STILL HAS TO COME UP. The reservation alone does not clear the
 * curve, because a three line title's last line sits exactly where a one line
 * title used to. At his bottom:20 with the reservation it still clips at 1240,
 * 1200, 1024, 950, 920, 901 and 320, and where it does clear it is by 5.3px at
 * 1440 and 0.1px at 1150. The three engines disagree by about 5px on where a
 * line of Gilroy ends, so those are not margins, they are coincidences.
 *
 *   bottom, with the reservation      Chromium   Firefox   WebKit
 *     20 (his)                        6 clipped  6         6
 *     36                              2          2         2
 *     44                              0          0         0    but 2.1px clear
 *     56                              0          0         0    and 9.7px clear
 *
 * WIDENING THE INSET WAS THE FIRST ANSWER AND IT WAS WRONG TWICE OVER: right:40
 * still clips in all three engines, and right:48 clears by 3.1px while
 * re-wrapping up to 104 titles to do it. Moving the caption keeps the box's
 * width, so not one title re-wraps.
 *
 * His 120px corner, his 24px side insets, his 480 and 340 heights and his
 * narrow-screen rules are all untouched.
 *
 * .d4x8c178844, .d4x1f3531a9 and .d4x0c1e6edc are on the Work grid and nowhere
 * else: checked against every page on the site, 27 instances on /case-studies/
 * and 0 everywhere else. A re-import would rename them, and replica.py carries
 * this as a signed-off deviation, so it goes red rather than silent.
 * --------------------------------------------------------------------------- */

.d4x8c178844 {
	bottom: 56px;
}

.d4x1f3531a9 {
	min-height: 3.75em;
}

/* AND THE TABLET BAND NEEDS THE SMALLER CAPTION TO GO WITH IT.
 *
 * Lifting the caption costs nothing where the tile is 340px tall. Between 901
 * and 1199 it is 195 to 249, because that band is his desktop grid at 71 per
 * cent, and the caption was still set at his desktop 22px. Four line titles
 * there are 186px tall inside a 195px tile, so the lift pushed the eyebrow and
 * the first line straight out of the top of the card, where overflow:hidden cut
 * them off. Six tiles at 901px, the worst 46.8px out. That was worse than the
 * fault it was fixing and it was mine, not his: caught by measuring the
 * deployed page rather than the intention.
 *
 * The type drops to the size he himself uses on his one mobile screen, 17px and
 * 11px, which is what shapes-narrow.css already applies below 900. That band
 * having no size of its own between his two is the gap the whole tablet layer
 * exists to fill.
 *
 * Measured across 901, 920, 950, 990, 1024, 1100 and 1199, all 27 cards, three
 * engines: 0 clipped, 0 spilling out of the tile, smallest clearance 9.7px.
 * --------------------------------------------------------------------------- */

@media (min-width: 901px) and (max-width: 1199px) {

	.d4x1f3531a9 {
		font-size: 17px;
	}

	.d4x0c1e6edc {
		font-size: 11px;
	}
}

/* -------------------------------------------------------------------------
 * THE CLIENT'S OWN WORDS ON A CASE STUDY. His band, three corrections.
 *
 * Alex, 17 Aug 2026: "some of the case studies have a testimonial which because
 * we didnt include it in the template, isnt showing on the new template".
 *
 * 13 of their 27 live case studies carry one. None was dropped by the rebuild,
 * which took a wrong answer to establish: seven are in Kyle's own quote slot at
 * the foot of the call to action and six were absorbed into THE OUTCOME as
 * ordinary paragraphs, where a client's words read as District Four's. This band
 * is where both kinds move to.
 *
 * NOTHING HERE IS A NEW DESIGN. Shape 42b2228b3cf5 is Kyle's own quote band off
 * his Office Fit Out Landing page: grey #C7C8C1, 88px 72px, an eyebrow, his
 * terracotta quote glyph, the quote at 20px Light and the attribution at 14px
 * Bold. It already carries real client words (KEEPMOAT and PYRO FIRE) and it
 * already has his narrow and tablet rules and his 1440 cap. The band was
 * hunted for before anything was drawn, on Charlotte's instruction, precisely
 * so this would not become an invented component.
 *
 * The live site sets its testimonials in ITALIC and CENTRED. Both go, and the
 * italic is not a taste call: there is no italic Gilroy in this theme in any
 * weight or format, and all three declared faces are fontStyle normal. So
 * font-style:italic asks the browser to shear the upright letters about twelve
 * degrees, which on a Light geometric sans is visibly wrong, on the website of
 * a firm that sells design. His own band is upright.
 *
 * 1. THE EYEBROW IS UNREADABLE ON HIS OWN GREY, and this is the only one of the
 *    three that is a fault rather than a fit. Terracotta #B84836 on #C7C8C1
 *    measures 3.10:1 and WCAG AA wants 4.5:1 for 12px. Of their four brand
 *    colours it is the only value that works on grey: ink is 10.0:1, white is
 *    1.68:1, grey on grey is 1:1. So there is one option, not a preference.
 *
 *    tokens.css already solves exactly this on their DARK bands (see the note
 *    at .d4-on-dark .d4-eyebrow, terracotta is 3.23:1 there) and stops. This
 *    finishes the same rule on the other surface, and it picks a treatment Kyle
 *    has already used himself: the homepage quote band sets its eyebrow in ink.
 *
 *    Applied to the band wherever it appears rather than only on case studies,
 *    because a contrast failure is not less of one on a landing page.
 *
 *    ADJACENT AND DELIBERATELY NOT FIXED HERE: the same terracotta eyebrow sits
 *    on grey in 35 places across 33 pages, WHY THIS PROJECT MATTERS on every
 *    case study included. That is a site wide sweep and a brand decision for
 *    Kyle, not something to slip in under a testimonial commit.
 *
 * 2. HIS GRID IS TWO FIXED COLUMNS, because his landing page carries two quotes
 *    side by side. A case study has one, which would leave half the band empty.
 *    auto-fit handles one, two and the four Google review snippets on Burrito
 *    Picante with a single rule and no new breakpoints, and at his own two quote
 *    width it resolves to the same two columns he drew.
 *
 * 3. ONE QUOTE IN A FULL WIDTH BAND RUNS TOO LONG TO READ. At 1440 the band is
 *    1296px inside its padding, which at 20px Gilroy Light is about 130
 *    characters a line, roughly double the readable maximum. 64ch holds it near
 *    70. It never bites on his two column version, where each column is already
 *    about 600px.
 *
 * Two quotes of different lengths top align rather than centring, because they
 * are separate statements and a ragged bottom is correct.
 * --------------------------------------------------------------------------- */

.d4x8da87f8c {
	color: #1D1D1D;
}

.d4xe76e45af {
	grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
	align-items: start;
}

.d4xaf824066 {
	max-width: 64ch;
}

/* Space above the footer, on Kyle's 7 pages rather than on all 34.
 *
 * shapes.css sets `.d4-site-footer{margin-top:96px}` for every page. Kyle sets
 * it on 7 of his 34: Brand, Brand v2, Build, Cost Estimator, Design, Furnish
 * and the homepage. On the other 27, including Work, the footer sits directly
 * against the last band.
 *
 * Work ends with the grey and white contact split, so the site-wide rule put
 * 96px of white under the grey and the section stopped short of the footer.
 * Measured before the fix: section bottom 5131.8, footer top 5227.8.
 *
 * Alex approved the split staying at Kyle's 1fr / 1.2fr. It was only ever the
 * gap that was ours. inc/chrome.php adds .d4-footer-gap from _d4_source_file.
 */
.d4-site-footer { margin-top: 0; }
body.d4-footer-gap .d4-site-footer { margin-top: 96px; }

/* Heading over the enquiry form. A DELIBERATE DEVIATION, see inc/chrome.php.
 *
 * Kyle's contact split puts the eyebrow and heading in the grey column and
 * starts the white one at the first input, so the form arrives with nothing
 * introducing it. Alex called it on 17 Aug 2026.
 *
 * Sized below his 44px h2 on the left so it reads as a label for the column
 * rather than competing with the heading it sits beside, and set in his own
 * 300 weight so it belongs to the same page.
 */
.d4-form__heading {
	margin: 0 0 28px;
	font-size: 28px;
	line-height: 1.15;
	font-weight: 300;
	letter-spacing: -0.02em;
	color: #1D1D1D;
}

@media (max-width: 900px) {
	/* The columns stack here, so the two headings end up one above the other
	   and the gap between them wants closing. */
	.d4-form__heading { font-size: 24px; margin-bottom: 20px; }
}

/* Keep a phone number whole.
 *
 * Alex, 17 Aug 2026, from a 4K screen: "i think the phone number should all be
 * on one line". His render broke "01302 712 686" after the second group, so a
 * bare "686." started the next line.
 *
 * nowrap on the link rather than non-breaking spaces in the content, because
 * the number is a field an editor can change and a fix that lives in the CSS
 * cannot be undone by retyping it. If the whole number no longer fits, it moves
 * to the next line intact instead of splitting, which is what he asked for.
 *
 * Applied to every tel: link in a shape rather than this one instance. There is
 * no width at which splitting a phone number is the better outcome.
 */
.d4-shape a[href^="tel:"] { white-space: nowrap; }

/*
 * The white headline on the location page heroes, which fails on every phone.
 *
 * FOUND 17 AUG 2026, and only because the London hero changed and the new
 * photograph prompted an actual measurement. The measurement is the finding:
 *
 *   page         1440px            390px
 *   London       2.54:1   8.4%     1.74:1  58.9% of the headline under 3.0:1
 *   Manchester   3.07:1   0.0%     1.74:1  24.2%
 *   Doncaster    2.91:1   0.0%     1.84:1   3.8%
 *   Sheffield    2.67:1   0.1%     1.53:1   5.7%
 *   Leeds        2.98:1   0.0%     2.23:1  33.7%
 *   Hull         2.43:1   2.2%     1.59:1  42.7%
 *
 * WCAG wants 3.0:1 for large text. All six failed, and five of six were far
 * worse on a phone than on a laptop, which is the opposite of where anybody
 * had been looking. Nothing here was a regression: it has been like this since
 * the heroes were built, on the pages most likely to be opened on a phone.
 *
 * WHY THE PHONE IS WORSE, which is not obvious. The headline wraps to more
 * lines at 390px, so it occupies far more of the image's height and reaches up
 * out of the dark foot of the gradient into the light middle band Kyle put
 * there on purpose. The photograph is also cropped differently. So the same
 * scrim that just about holds at 1440 has nothing left at 390.
 *
 * THE FIX, and what it deliberately does not do. Kyle's gradient is three
 * stops: dark at the top for the menu, light through the middle so the
 * photograph reads, dark at the foot for the headline. That shape is his and it
 * is kept. What changes is that the dark foot starts higher and finishes
 * stronger, and more so on narrow screens where the text needs more of it. The
 * top stop is untouched, so the header end of his design is exactly as drawn.
 *
 * Scoped to .d4xfc70bee5, which is used on the six location pages and nowhere
 * else on the site. Checked page by page before changing it.
 */
.d4xfc70bee5 {
	background: linear-gradient(
		180deg,
		rgba(29, 29, 29, 0.5) 0%,
		rgba(29, 29, 29, 0.22) 38%,
		rgba(29, 29, 29, 0.64) 68%,
		rgba(29, 29, 29, 0.9) 100%
	);
}

@media (max-width: 900px) {
	.d4xfc70bee5 {
		background: linear-gradient(
			180deg,
			rgba(29, 29, 29, 0.5) 0%,
			rgba(29, 29, 29, 0.38) 20%,
			rgba(29, 29, 29, 0.82) 52%,
			rgba(29, 29, 29, 0.95) 100%
		);
	}
}

/* -------------------------------------------------------------------------
 * THE MOBILE LOGO WAS NOT A LINK. Every page, mobile only.
 *
 * Alex, 18 Aug 2026: "on mobile when you click the logo in the top left it
 * should take you back to the homepage". He is right, and the desktop header
 * has always done it: shapes/site-header.html wraps its logo in an anchor and
 * shapes/site-header-mobile.html did not. A bare <img>, on every page, for the
 * three quarters of a phone screen where a logo is the back button people
 * reach for first.
 *
 * The markup fix is in the shape, which is safe here because the chrome shapes
 * are named files rather than hash named ones, so nothing is orphaned by
 * editing them. It uses the same "District Four Homepage.dc.html" value the
 * desktop header does, resolved through d4_resolve_link(), rather than a hard
 * coded path.
 *
 * THIS RULE IS THE PART THAT WOULD OTHERWISE BE A DEVIATION. An anchor is
 * inline, so the image inside it sits on a text baseline and the browser
 * reserves descender space underneath. Measured on live at 390px before and
 * after: the header stayed 76px, but the logo moved from y=26 to y=23.5. Two
 * and a half pixels is small and it is still a pixel Kyle did not ask to move.
 *
 * display:block does NOT fix it, which is worth writing down because it was my
 * first guess and it changed nothing. A flex item is blockified already, so the
 * anchor was display:block before the rule was ever added. Measuring the anchor
 * rather than guessing again gave the real number: the anchor is 29px tall
 * around a 24px image, and those 5px are the descender space a browser reserves
 * under an INLINE image sitting on a text baseline. align-items:center then
 * centres the 29px box, which lifts the image inside it by half the difference.
 *
 * display:flex removes the baseline, because a flex item is not inline and has
 * no descender to reserve. Verified across chromium, firefox and webkit at
 * 390px: header 76px and logo back at y=26, matching the pre-change geometry to
 * the pixel.
 */
.d4-site-header-mobile > a { display: flex; }
