/**
 * Block styles.
 *
 * Kept apart from tokens.css: that file holds the design system, this holds the
 * components built on it. Values here are measured from Kyle's export rather
 * than chosen, so where a number looks oddly specific it is because his does.
 *
 * Trimmed on 5 Aug 2026 from 2,003 lines to this. The other 22 sections
 * styled the twenty hand-built blocks that the transcribed shapes replaced,
 * and every one of those blocks is gone. What is left is the enquiry form and
 * the photo lightbox, the two pieces of this layer that carry behaviour rather
 * than an approximation of Kyle's layout.
 */

/* ---------------------------------------------------------------------------
   Enquiry form
   ---------------------------------------------------------------------------
   Ten form sections, two looks.

   "above": Contact and Subcontractors. Label 14px Bold with 8px under it, box
   with a 1px brand grey border and 13px by 14px of padding, 18px between rows,
   terracotta focus ring.

   "inside": Work, the fit out landing page, Workplace Care and the quote basket.
   Placeholder only and 14px by 16px of padding, 14px between rows. On the dark
   panels the border comes off entirely and the box goes white.

   The label is written either way and hidden by CSS in the second, because a
   placeholder is not a label: it disappears the moment anyone types, it is not
   reliably announced, and autofill has nothing to match on.
   --------------------------------------------------------------------------- */

.d4-form .d4-eyebrow { margin: 0 0 24px; }
.d4-form__title { margin: 0 0 18px; }
.d4-form__intro { margin: 0 0 28px; }

.d4-form__stack > * + * { margin-block-start: clamp(1.75rem, 4vw, 40px); }

/* Its own named container, because the thing that decides whether two boxes fit
   beside each other is the width of the form column, not the width of the
   section. On Contact the section is the full page and the form is 45% of it, so
   querying the section would keep two boxes side by side long past the point
   they fit. Named, so it cannot be answered by an outer container by accident. */
.d4-form__main { container: d4-form / inline-size; }

.d4-form__grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 18px;
}

.d4-form--labels-inside .d4-form__grid { gap: 14px; }

.d4-form__row { min-width: 0; }
.d4-form__row--full { grid-column: 1 / -1; }

@container d4-form (max-width: 30rem) {
	.d4-form__grid { grid-template-columns: 1fr; }
	.d4-form__row--half { grid-column: 1 / -1; }
}

.d4-form__label {
	display: block;
	font-size: 14px;
	font-weight: 700;
	margin-bottom: 8px;
	line-height: 1.3;
}

.d4-form__label span {
	color: var(--wp--preset--color--terracotta);
	margin-inline-start: 2px;
}

/* Hidden from view, not from the accessibility tree or from autofill. The same
   clip as the skip link, which is the only way to hide something that still has
   to be reachable. */
.d4-form--labels-inside .d4-form__label:not(.d4-form__label--check) {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.d4-form__input {
	width: 100%;
	font: inherit;
	font-size: 14px;
	line-height: 1.4;
	color: var(--wp--preset--color--ink);
	background-color: var(--wp--preset--color--paper);
	border: 1px solid var(--wp--preset--color--grey);
	border-radius: 0;
	padding: 13px 14px;
	transition: border-color var(--d4-transition), box-shadow var(--d4-transition);
	/* 16px on iOS or Safari zooms the whole page in on focus and never zooms back
	   out. His 14px is the design, so the size only lifts where it has to. */
	min-height: 46px;
}

@supports (-webkit-touch-callout: none) {
	.d4-form__input { font-size: 16px; }
}

.d4-form--labels-inside .d4-form__input { padding: 14px 16px; }

.d4-form__input::placeholder {
	color: var(--wp--preset--color--ink);
	opacity: 0.55;
}

.d4-form__input:focus-visible {
	outline: 2px solid var(--wp--preset--color--terracotta);
	outline-offset: 1px;
	border-color: var(--wp--preset--color--terracotta);
}

/* Safari draws its own inner shadow on inputs and rounds the corners of selects,
   neither of which is in the design. */
.d4-form__input,
select.d4-form__input {
	appearance: none;
	-webkit-appearance: none;
}

select.d4-form__input {
	/* The arrow Safari would otherwise remove along with the appearance. */
	background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
		linear-gradient(135deg, currentColor 50%, transparent 50%);
	background-position: calc(100% - 19px) 50%, calc(100% - 14px) 50%;
	background-size: 5px 5px, 5px 5px;
	background-repeat: no-repeat;
	padding-inline-end: 38px;
}

textarea.d4-form__input {
	resize: vertical;
	min-height: 120px;
}

/* On a dark panel he drops the border and paints the box white. */
.d4-on-dark .d4-form__input {
	border-color: transparent;
	background-color: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
}

.d4-form__row--check {
	display: flex;
	align-items: flex-start;
	gap: 12px;
}

.d4-form__check {
	width: 20px;
	height: 20px;
	margin: 2px 0 0;
	flex-shrink: 0;
	accent-color: var(--wp--preset--color--terracotta);
}

.d4-form__label--check {
	margin: 0;
	font-weight: 300;
	font-size: 14px;
	line-height: 1.5;
}

/* A label only a screen reader gets. WordPress prints this class in places of
   its own and every starter theme carries the rule. It lives here rather than
   in templates.css because that stylesheet only loads on the five leftover
   templates, and the placeholder-only halves of Kyle's forms need it on any
   page they sit on.

   position:absolute matters as well as hides: three of his five forms put the
   controls straight into a two-column grid, and an in-flow label beside one
   would take a cell and shunt the rest of the form along. Out of flow, the grid
   never sees it. */
.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.d4-form__error {
	margin: 6px 0 0;
	font-size: 13px;
	font-weight: 700;
	color: var(--wp--preset--color--terracotta);
}

/* On a transcribed form this is a span that is always rendered, empty or not,
   so the id its control's aria-describedby points at is always a real element.
   Empty it must take no room at all: his forms are drawn to the pixel and six
   spare pixels under all nine boxes on Contact is his layout, moved. */
.d4-form__error { display: block; }
.d4-form__error:empty { display: none; }

.d4-form__alert {
	margin: 0 0 18px;
	padding: 14px 16px;
	font-size: 14px;
	font-weight: 700;
	color: var(--wp--preset--color--paper);
	background-color: var(--wp--preset--color--terracotta);
}

.d4-form__foot {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	align-items: center;
	gap: 24px;
	margin-top: 20px;
}

.d4-form__print { margin: 0; }

.d4-form__print p {
	font-size: 12px;
	line-height: 1.6;
	max-width: 46ch;
}

/* The honeypot.
 *
 * Clipped to a pixel where it stands, not parked at left:-9999px. Both hide it
 * from a person and neither is display:none, which is what a bot checks. The
 * difference is that -9999px is a real element 9999px off the side of the page,
 * so the overflow check reports it as broken layout on all 18 combinations, and
 * a check that cries wolf is a check nobody reads. Same lesson as the skip link.
 *
 * Never marked required: a hidden required field silently refuses to submit in
 * Safari, with no message and nothing on screen to point at. That one has cost us
 * an afternoon before on a different site. */
.d4-form__hp {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.d4-form__done {
	border: 1px solid var(--d4-rule-on-light);
	padding: clamp(1.5rem, 4vw, 40px);
}

.d4-on-dark .d4-form__done { border-color: var(--d4-rule-on-dark); }

.d4-form__done-head {
	margin: 0 0 12px;
	font-size: clamp(22px, 2.4vw, 28px);
	font-weight: 700;
}

.d4-form__done p {
	font-size: 15px;
	line-height: 1.7;
	max-width: none;
}

/* The reassurance list beside a form. Same ruled rows and chevron as the old
   checklist block, because it was the same thing in a different container.
   It used to live under "Plans and pricing", which is why the trim above nearly
   took it: it is the only rule in this file that was filed under a section
   belonging to a different block. */
.d4-form__points {
	list-style: none;
	margin: 28px 0 0;
	padding: 0;
	font-size: 14px;
	line-height: 1.5;
	border-bottom: 1px solid var(--d4-rule-on-light);
}

.d4-on-dark .d4-form__points { border-bottom-color: var(--d4-rule-on-dark); }

.d4-form__points li {
	display: flex;
	gap: 14px;
	align-items: baseline;
	padding-block: 12px;
}

.d4-form__points li::before {
	content: ">";
	color: var(--wp--preset--color--terracotta);
	flex-shrink: 0;
	font-weight: 700;
}

/* ---------------------------------------------------------------------------
   Left behind by the trim
   ---------------------------------------------------------------------------
   .d4-hero was the root of the photo hero block, and 404.php, home.php,
   search.php, single.php and archive-d4_case_study.php borrow it. Those five
   templates are leftovers from the cancelled March design and 36 of the classes
   they use have no rule anywhere, so they render unstyled today and did before
   this trim as well. This is here so the trim leaves nothing worse than it
   found it, not because one rule fixes those pages. See the task list.
   --------------------------------------------------------------------------- */

.d4-hero {
	position: relative;
	display: grid;
}

/* ==========================================================================
   The Workplace Growth Audit
   ========================================================================== */

/* His five agree/disagree options.

   He drew them as <button>, because his prototype held the answer in its own
   state. Ours are real radios, so the twenty answers are form state the browser
   owns: they survive the back button, they submit without JavaScript, and a
   screen reader announces them as the group of five they are.

   The radio itself is hidden and the span beside it carries his treatment. That
   makes this rule the entire selected state, with no JavaScript involved, which
   is what keeps the audit working with scripting off. The values are his, out of
   the catQuestions map in his component script:

     fontWeight: 700 : 300
     border:     1px solid #af4835 : #bfbfb9
     background: #af4835 : none
     color:      #ffffff : #1d1d1d

   corrected to the brand guide's terracotta, the same as every other colour in
   the export. The unselected half is on the generated class already; only the
   four that change are here. */
.d4-opt { display: block; cursor: pointer; }

/* The radio is taken off the screen, not out of the page. display:none and
   visibility:hidden would both make it unfocusable, so the whole audit would
   become unreachable with a keyboard: twenty questions nobody can tab to.
   Absolutely positioned at 1px it still takes focus, and the ring goes on the
   span below. Same treatment as .screen-reader-text above, and for the same
   reason. */
.d4-opt__in {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
	-webkit-appearance: none;
	appearance: none;
}

.d4-opt__in:checked + .d4-opt__face {
	font-weight: 700;
	border-color: var(--wp--preset--color--terracotta);
	background: var(--wp--preset--color--terracotta);
	color: #ffffff;
}

/* A visually hidden radio still takes keyboard focus, and a focus ring on a
   1px box nobody can see is a focus ring nobody can see. Put it on the thing
   that is actually on screen. */
.d4-opt__in:focus-visible + .d4-opt__face {
	outline: 2px solid var(--wp--preset--color--ink);
	outline-offset: 2px;
}

/* Before main.js runs, only his landing screen should be on the page. Without
   this the browser paints all twenty questions and then collapses them, which
   for the tenth of a second it lasts looks like something breaking.

   The noscript override in inc/audit.php puts them back for anyone without
   JavaScript, who needs every question visible because there is nothing to page
   between them with.

   data-d4-on rather than an inline style, because main.js showing a pane by
   clearing style.display would land straight back on this rule and hide it
   again. That is not hypothetical: it is what the first version did, and the
   audit could not be answered at all. */
[data-d4-audit-stage],
[data-d4-audit-pane],
[data-d4-audit-gate] {
	display: none;
}

[data-d4-audit-stage][data-d4-on],
[data-d4-audit-pane][data-d4-on],
[data-d4-audit-gate][data-d4-on] {
	display: block;
}

/* The intro screen needs both of its rules a weight heavier than the three
   above, and getting that wrong cost an hour on 12 Aug.

   It became two columns that night, laid out on the same generated class as
   his landing screen, and that class carries display:grid. A generated class
   is ONE class and [data-d4-audit-intro] is ONE attribute, so the two tie on
   specificity and the winner is whichever stylesheet loads last. shapes.css
   loads after this file. So display:none lost, the intro never hid at all, and
   every question screen opened 865px down the page with the intro still
   sitting above it.

   Nothing looked broken from the outside, which is the dangerous part. The
   attribute came off correctly, the hidden property was set correctly, and
   main.js was doing exactly its job. Only the computed style said otherwise.
   audit-journey.py caught it in all three engines at all three widths.

   :not([data-d4-on]) rather than !important, because it is the same shape as
   the rule it is fighting and reads as what it means: hidden unless it has
   been turned on. Two attribute selectors beat one class whatever the load
   order, so this cannot come back if the stylesheets are ever reordered.

   The three above are deliberately left as they are. Their wrappers carry no
   display of their own, so one attribute is enough, and adding weight they do
   not need would only leave the next person wondering what it was for. */
[data-d4-audit-intro]:not([data-d4-on]) {
	display: none;
}

[data-d4-audit-intro][data-d4-on] {
	display: grid;
}

/* Space under Emily's intro video, retired 12 Aug 2026 and left here as a
   note, because the reason it went is worth more than the rule was.

   Alex spotted on 11 Aug that the first line of copy sat hard against the
   bottom of the video, and this put 40px under it on desktop and 20px on a
   phone, addressed by position as "the first div in the intro".

   On 12 Aug the screen became two columns, so on desktop there is no longer
   anything underneath the video to be clear of: the copy sits beside it, and
   the space between them is his own 88px column gap. On a phone the grid stacks
   and his own 44px row gap does the same job, more generously than the 20px
   this was giving it. Both numbers are his, off the landing screen, so the
   spacing is no longer ours to keep in step with anything.

   Deleting the rule rather than leaving it: it would still have matched the
   video's cell and quietly added a margin inside it, which is the sort of
   thing that survives for a year because it looks deliberate. audit-journey.py
   still measures the space, now as a layout check rather than as a margin. */

/* His recommendation cards sit two across, and when an odd number of them show
   he spans the last one across both columns at half width so it centres rather
   than leaving a hole. Below 900 the grid is already one column, so half width
   is just a 163px sliver of a card with the text squeezed into it.

   !important because that rule arrives as an inline style: which card gets it
   depends on the score, so it is written per request by render.php rather than
   living in a class that shapes-narrow.css could override the normal way. */
@media (max-width: 900px) {
	[data-d4-rec] {
		grid-column: auto !important;
		width: auto !important;
		justify-self: auto !important;
	}
}

/* ---------------------------------------------------------------------------
 * The Cost Estimator
 *
 * His buttons are radios here, for the same reason the audit's likert options
 * are: a <button> held state his runtime owned, and a radio holds it in the
 * page, so the browser remembers it, the back button works and the whole thing
 * still posts with JavaScript switched off.
 * ------------------------------------------------------------------------- */

.d4-est-opt {
	display: block;
}

/* Visually hidden, not display:none. A hidden radio cannot be focused or
 * reached by keyboard, and a radio group nobody can tab to is a control only a
 * mouse user has. */
.d4-est-opt__in {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.d4-est-opt__face {
	display: block;
}

/* His selected treatment, from optStyle, tabStyle, pillStyle and pillLight. The
 * unselected half is on the element as an inline style, so it becomes a
 * generated class; these win on specificity rather than on order. */
.d4-est-opt__in:checked + .d4-est-opt__face--opt,
.d4-est-opt__in:checked + .d4-est-opt__face--tab {
	border-color: var(--wp--preset--color--terracotta);
	background: var(--wp--preset--color--terracotta);
}

.d4-est-opt__in:checked + .d4-est-opt__face--pill {
	font-weight: 700;
	border-color: var(--wp--preset--color--terracotta);
	background: var(--wp--preset--color--terracotta);
}

.d4-est-opt__in:checked + .d4-est-opt__face--light {
	font-weight: 700;
	border-color: var(--wp--preset--color--terracotta);
	background: var(--wp--preset--color--terracotta);
	color: #ffffff;
}

/* A focus ring the hidden input cannot show for itself. */
.d4-est-opt__in:focus-visible + .d4-est-opt__face {
	outline: 2px solid #ffffff;
	outline-offset: 2px;
}

.d4-est-opt__in:focus-visible + .d4-est-opt__face--light {
	outline-color: #1d1d1d;
}

/* The number between his two stepper buttons. He drew it as text, so it is
 * dressed as text; it is a real number box underneath, which is what lets it be
 * typed into, posted on its own and used without JavaScript. */
.d4-est-step__val {
	border: 0;
	background: none;
	color: inherit;
	font-family: inherit;
	padding: 0;
	/* His span is min-width:20px and grows to its digits, which a number box
	 * cannot do. 2.5ch is the nearest thing that holds two digits without
	 * pushing his plus button along: 3.5em put it 43px to the right of where
	 * he drew it. His own min-width comes through on the element's class. */
	width: 2ch;
	-moz-appearance: textfield;
	appearance: textfield;
}

.d4-est-step__val::-webkit-outer-spin-button,
.d4-est-step__val::-webkit-inner-spin-button {
	-webkit-appearance: none;
	margin: 0;
}

/* His modal, which is a fixed overlay. Hidden until it is asked for, and the
 * attribute rather than a class so the server can render it open after an
 * error bounce without JavaScript having to run first.
 *
 * :not() rather than a plain attribute, and that is not style. The attribute
 * sits on HIS element, which carries display:flex from his own inline style,
 * and the transcriber turns every inline style into a class. One attribute and
 * one class weigh the same, so the later stylesheet wins and shapes.css loads
 * after this one: written the obvious way, his overlay covered the whole page
 * and nothing underneath it could be clicked. Two attributes outweigh one
 * class. Same trap as the audit's noscript rule, from the other direction.
 *
 * There is no open rule, because his own class already says display:flex. */
[data-d4-est-modal]:not([data-d4-est-modal-open]) {
	display: none;
}

.d4-est-recalc {
	display: block;
	width: 100%;
	box-sizing: border-box;
	margin-top: 18px;
	padding: 16px;
	border: 1px solid #1d1d1d;
	background: none;
	color: #1d1d1d;
	font-family: inherit;
	font-size: 15px;
	font-weight: 700;
	cursor: pointer;
}

/* His two modes and his two ways of giving a size. All four panes are in the
 * page so the browser holds the whole configuration and switching tabs loses
 * nothing; hidden here so the page does not flash both modes at once before
 * estimator.js runs. The noscript rule in inc/estimator.php puts them all back
 * when there is no script to do the switching. */
[data-d4-est-when]:not([data-d4-on]) {
	display: none;
}

/*
 * iOS SAFARI ZOOMS IN ON A FIELD UNDER 16px AND NEVER ZOOMS BACK OUT.
 *
 * Alex hit this on his phone, 9 Aug 2026: tap the first name box on the audit,
 * Safari scales the whole viewport up to make the text legible, and it stays
 * there. Every screen after it is then rendered too wide, so the questions run
 * off the right edge and the answer buttons are half off screen. Nothing looks
 * wrong until you touch a field.
 *
 * Measured rather than guessed: every one of the audit's seven fields computes
 * to 13px, which is Kyle's design, and 16px is the threshold Safari uses.
 *
 * The other way out is maximum-scale=1 on the viewport tag. Not doing that: it
 * takes pinch zoom away from everybody, which is an accessibility problem for
 * the sake of one browser's habit, and iOS has ignored it since version 10
 * anyway.
 *
 * Scoped to narrow screens so his 13px survives everywhere it is not a problem.
 * !important because his sizes arrive as generated single-declaration classes
 * that would otherwise win on order.
 */
@media (max-width: 900px) {
    .d4-main input:not([type="radio"]):not([type="checkbox"]):not([type="hidden"]),
    .d4-main select,
    .d4-main textarea {
        font-size: 16px !important;
    }
}

/* A video filling one of his media slots. His boxes are a fixed aspect ratio
   with overflow hidden, so the video is sized to the box rather than the box to
   the video, exactly as a photograph is. Without this it renders at its own
   intrinsic size and hangs out of the bottom of a 16:9 box. */
.d4-shape__video {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	background: #1d1d1d;
}

/* ---------------------------------------------------------------------------
 * The Cost Estimator, version B
 *
 * Ours, not Kyle's: his export carries no media queries at all, so there is no
 * design of his to deviate from here. Built 11 Aug 2026 so he can see both and
 * pick one. See wp-cli/d4-import/bindings.py, estimator_simple.
 * ------------------------------------------------------------------------- */

/*
 * THE FIGURE, PINNED WHERE A THUMB CAN SEE IT.
 *
 * Measured on staging at 390px before writing a line of this: only four of the
 * eight whole office controls could be used with the number on screen, and the
 * four that could not were the project type, the finish, the size toggle and
 * the floor area slider, which are the four that move the money most. His
 * result card stacks below every control on narrow, so the whole premise of
 * the thing (watch the number move) did not exist on a phone.
 *
 * TOP rather than bottom, and that is the whole reason it is written this way:
 * the meeting room and desk controls are type="number" and raise the on screen
 * keyboard, and an iOS keyboard comes up from the BOTTOM. A bottom anchored
 * bar would be underneath it at exactly the moment the number matters.
 *
 * Hidden above 900px because his card is already beside the controls there and
 * a second copy of the same figure is just noise.
 */
.d4-est-sticky {
	display: none;
}

@media (max-width: 900px) {
	.d4-est-sticky {
		display: flex;
		position: sticky;
		/*
		 * Hard against the top, because below 900px there is nothing above it.
		 * Measured rather than assumed: his desktop header IS sticky but
		 * collapses to zero height here, and the separate mobile header that
		 * replaces it is position:static and scrolls away with the page. An
		 * earlier version of this offset the bar by --d4-header-h and left a
		 * 48px slot of page content showing through above it, which looked
		 * exactly like a z-index bug and was not one.
		 */
		top: 0;
		z-index: 5;
		align-items: baseline;
		flex-wrap: wrap;
		gap: 4px 10px;
		margin: 0 0 24px;
		padding: 12px 16px;
		background: #1d1d1d;
		border-bottom: 1px solid var(--d4-rule-on-dark);
	}

	.d4-est-sticky__label {
		flex: 1 0 100%;
		color: #c7c8c1;
		font-size: 11px;
		font-weight: 700;
		letter-spacing: 0.08em;
		text-transform: uppercase;
	}

	.d4-est-sticky__range {
		color: #ffffff;
		font-size: 24px;
		font-weight: 300;
		/* The figure changes as a slider moves and the columns should not
		   jitter while it does. */
		font-variant-numeric: tabular-nums;
	}

	.d4-est-sticky__vat {
		color: #b84836;
		font-size: 12px;
		font-weight: 700;
	}
}

/*
 * THE DISCLOSURE.
 *
 * Everything from his "4. FURNITURE" heading onward, in both modes, so each
 * one opens on the three questions that actually move the number.
 *
 * A plain <details> on purpose. His data-d4-est-when panes are driven off
 * posted state, so reusing one would mean a new field, a new bound, and a new
 * thing for the PHP and the JavaScript to disagree about. <details> needs no
 * state and no script, it still posts everything inside it whether it is open
 * or shut, and it is keyboard operable for free.
 */
.d4-est-more {
	margin-top: 8px;
	border-top: 1px solid var(--d4-rule-on-dark);
}

.d4-est-more__summary {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 2px 10px;
	padding: 18px 0;
	cursor: pointer;
	/* Both of these, or Safari keeps drawing its own triangle. */
	list-style: none;
}

.d4-est-more__summary::-webkit-details-marker {
	display: none;
}

.d4-est-more__label {
	color: #ffffff;
	font-size: 13px;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

/* Drawn rather than a character, so it cannot pick up a font that has no
   glyph for it. Rotates to point down when the disclosure is open. */
.d4-est-more__label::before {
	content: "";
	display: inline-block;
	width: 7px;
	height: 7px;
	margin-right: 10px;
	border-right: 2px solid #b84836;
	border-bottom: 2px solid #b84836;
	transform: translateY(-2px) rotate(-45deg);
	transition: transform var(--d4-transition);
}

.d4-est-more[open] .d4-est-more__label::before {
	transform: translateY(-3px) rotate(45deg);
}

/* Named, because this is not decoration. Glazing is the biggest swing item on
   a room job and his own note under the slider says so, so somebody who never
   opens this should at least know what is behind it. */
.d4-est-more__hint {
	color: #c7c8c1;
	font-size: 13px;
	font-weight: 300;
}

.d4-est-more__summary:focus-visible {
	outline: 2px solid #b84836;
	outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
	.d4-est-more__label::before {
		transition: none;
	}
}

/*
 * THE CAPTURE LADDER.
 *
 * His page had one call to action, and it was the top one: "Book a workplace
 * review" means arranging access and telling your boss you have invited a
 * contractor in. The person reading a cost page is usually not the person who
 * signs anything, so what they actually do next is forward it.
 *
 * The lower rung sits ABOVE his, and both are the same size on purpose. This is
 * a ladder, not a primary and a fallback: one of them ends in a site visit and
 * the other ends in a forwarded page, and District Four want both. His button
 * is untouched, terracotta and all. Ours is the brand near black, so they read
 * as two real choices rather than one button and its shadow.
 */
.d4-est-ladder__go {
	width: 100%;
	border: none;
	background: #1d1d1d;
	color: #ffffff;
	font-family: inherit;
	font-size: 15px;
	font-weight: 700;
	padding: 16px 0;
	cursor: pointer;
}

.d4-est-ladder__go:hover {
	background: #333333;
}

.d4-est-ladder__go:focus-visible {
	outline: 2px solid #b84836;
	outline-offset: 3px;
}

/* What the button will and will not do, under the button rather than in a
   tooltip, because the reason somebody does not press it is that they think it
   books a visit. */
.d4-est-ladder__note {
	margin: 10px 0 18px;
	color: #c7c8c1;
	font-size: 13px;
	font-weight: 300;
	line-height: 1.5;
}

/*
 * THE SAVED ESTIMATE.
 *
 * Empty on every ordinary visit: the slot is in the markup, the panel is only
 * built when a signed reference resolves, so the tool looks exactly as it did
 * to everybody else.
 *
 * It goes at the top because of who reads it. The person it was forwarded to
 * asked for none of this and needs to know what they are looking at before they
 * meet a slider.
 */
.d4-est-saved {
	margin: 0 0 24px;
	padding: 20px 22px;
	background: #1d1d1d;
	border-left: 4px solid #b84836;
}

.d4-est-saved__head {
	margin: 0;
	color: #ffffff;
	font-size: 16px;
	font-weight: 700;
	line-height: 1.45;
}

.d4-est-saved__next {
	margin: 10px 0 0;
	color: #c7c8c1;
	font-size: 14px;
	font-weight: 300;
	line-height: 1.55;
}

.d4-est-saved__link {
	margin: 16px 0 0;
	font-size: 13px;
	/* A URL has no spaces in it, so a long one would push the panel sideways
	   and take the page with it on a phone. */
	overflow-wrap: anywhere;
}

.d4-est-saved__label {
	display: block;
	margin: 0 0 4px;
	color: #c7c8c1;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	font-size: 11px;
}

.d4-est-saved__link a {
	color: #ffffff;
}

.d4-est-saved__print {
	margin: 16px 0 0;
	padding: 10px 18px;
	background: none;
	border: 1px solid var(--d4-rule-on-dark);
	color: #ffffff;
	font-family: inherit;
	font-size: 13px;
	font-weight: 700;
	cursor: pointer;
}

.d4-est-saved__print:hover {
	background: #333333;
}

.d4-est-saved__print:focus-visible {
	outline: 2px solid #b84836;
	outline-offset: 3px;
}

/*
 * PRINTING IT.
 *
 * The point of the artefact is that it survives being handed to somebody in a
 * meeting, so it has to come out of a printer as the figures rather than as a
 * calculator with half its answers folded away.
 *
 * The disclosure is the part that needs saying. A closed <details> is hidden
 * with content-visibility rather than display, and no CSS can force one open,
 * but content-visibility CAN be overridden, so the detail somebody never
 * expanded still prints. Without this a printed estimate silently omits
 * glazing, partitions and desks, which on a room job is three of the six
 * biggest numbers on it.
 */
@media print {
	.d4-est-sticky,
	.d4-est-saved__print,
	.d4-est-recalc,
	[data-d4-est-modal] {
		display: none !important;
	}

	.d4-est-more__summary {
		list-style: none;
	}

	.d4-est-more:not([open]) > *:not(summary) {
		content-visibility: visible !important;
	}

	.d4-est-saved {
		border-left: 4px solid #b84836;
		background: none;
	}

	.d4-est-saved__head,
	.d4-est-saved__next,
	.d4-est-saved__link a {
		color: #1d1d1d;
	}
}

/* ---------------------------------------------------------------------------
   A section with nothing written in it yet.

   Only ever seen by somebody logged in who can edit the page. A visitor is not
   sent the band at all; see the note beside $d4_blank in blocks/shape/render.php.

   Deliberately loud, because the point is to be told that what you are looking
   at is not what the public sees. Sits above the band rather than over it so it
   cannot hide the slots it is talking about.
   --------------------------------------------------------------------------- */
.d4-shape__blank {
	margin: 0;
	padding: 10px 16px;
	background: #B84836;
	color: #fff;
	font-size: 13px;
	line-height: 1.4;
	letter-spacing: 0.02em;
	text-align: center;
}

/* ---------------------------------------------------------------------------
   The photo lightbox
   ---------------------------------------------------------------------------
   Ours, not his. He drew the zoom cursor on 23 photographs and never drew what
   it opens, the same way he drew the hamburger and never drew the menu behind
   it. So this follows the same rule that panel does: his palette, and nothing
   invented that competes with the photograph.

   Near black at 97%. Not pure black, so the page underneath is still faintly
   there and the overlay does not read as having navigated somewhere; not the
   94% it opened at either, which left the body copy behind it legible enough
   to compete with the photograph. Checked by looking, at 390 and at 1440.

   The chevrons and the cross are drawn in CSS rather than set in type. Gilroy
   has no arrow glyph and a fallback font would put three different shapes on
   three different machines.
   --------------------------------------------------------------------------- */

.d4-lightbox {
	position: fixed;
	inset: 0;
	z-index: 10000;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 12px;
	padding: 24px;
	background: rgba(29, 29, 29, .97);
}

.d4-lightbox[hidden] { display: none; }

body.d4-lightbox-open { overflow: hidden; }

.d4-lightbox__frame {
	margin: 0;
	max-width: 100%;
	max-height: 100%;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 14px;
}

.d4-lightbox__img {
	display: block;
	max-width: 100%;
	/* Room for the caption underneath without the picture ever overflowing. */
	max-height: calc(100vh - 120px);
	width: auto;
	height: auto;
	object-fit: contain;
}

.d4-lightbox__caption {
	margin: 0;
	max-width: 68ch;
	text-align: center;
	color: #C7C8C1;
	font-size: 14px;
	font-weight: 300;
	line-height: 1.5;
}

.d4-lightbox__caption[hidden] { display: none; }

.d4-lightbox__close,
.d4-lightbox__step {
	flex: 0 0 auto;
	width: 48px;
	height: 48px;
	padding: 0;
	border: 1px solid rgba(199, 200, 193, .35);
	background: none;
	cursor: pointer;
	position: relative;
}

.d4-lightbox__close:hover,
.d4-lightbox__step:hover { border-color: #B84836; background: #B84836; }

.d4-lightbox__close:focus-visible,
.d4-lightbox__step:focus-visible { outline: 2px solid #B84836; outline-offset: 3px; }

.d4-lightbox__close[hidden],
.d4-lightbox__step[hidden] { display: none; }

.d4-lightbox__close {
	position: absolute;
	top: 20px;
	right: 20px;
}

/* Two lines crossed, so there is no glyph to fall back on. */
.d4-lightbox__close::before,
.d4-lightbox__close::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 18px;
	height: 1px;
	background: #ffffff;
}

.d4-lightbox__close::before { transform: translate(-50%, -50%) rotate(45deg); }
.d4-lightbox__close::after { transform: translate(-50%, -50%) rotate(-45deg); }

/* Half a square, turned. */
.d4-lightbox__step::before {
	content: "";
	position: absolute;
	top: 50%;
	left: 50%;
	width: 12px;
	height: 12px;
	border-top: 1px solid #ffffff;
	border-right: 1px solid #ffffff;
}

.d4-lightbox__step--next::before { transform: translate(-65%, -50%) rotate(45deg); }
.d4-lightbox__step--prev::before { transform: translate(-35%, -50%) rotate(-135deg); }

@media (max-width: 900px) {
	/* The arrows stop being worth 96px of a phone screen. Swiping is not built,
	   so they move under the picture rather than going away. */
	/* align-content, because without it the two wrapped rows stretch to fill
	   the screen and the arrows end up floating 240px below the caption with
	   nothing between them. */
	.d4-lightbox { flex-wrap: wrap; align-content: center; padding: 16px; }
	.d4-lightbox__frame { order: -1; flex: 0 0 100%; }
	.d4-lightbox__img { max-height: calc(100vh - 190px); }
	.d4-lightbox__close { top: 12px; right: 12px; }
}
