/*
 * ULP site presentation, v1.2.0
 *
 * Rebuilt on the ULP structure, measured from the four reference screenshots
 * supplied with the brief.
 *
 * THE GRID, and it is the whole design
 *
 *   rail 34%          content column 63%           right margin 3%
 *   +---------------+ +--------------------------------------------+
 *   | wordmark      | | row: ONE large image, full column          |
 *   |               | +--------------------------------------------+
 *   |               | | row: TWO images, 48% each, 4% gutter       |
 *   | navigation    | +--------------------------------------------+
 *   +---------------+
 *
 * Rows contain one large image or two small ones. Nothing else. Text, numbers,
 * awards and portraits all occupy cells of the same grid, so nothing floats in
 * open whitespace. The feed starts flush against the top edge of the viewport.
 *
 * Every rule is prefixed .ulp-template, added to body_class only on ULP routes,
 * so nothing reaches an Elementor or WPBakery page.
 */

/* ---------------------------------------------------------------- tokens */

.ulp-template {
	--ulp-black: #000000;
	--ulp-charcoal: #2c2222;

	/* Secondary text grey.
	 *
	 * The approved proof used #b2b4b1 here. On white that measures 2.09:1, which
	 * fails AA at every size the system uses it at, including the 24px rail
	 * navigation, which misses even the 3:1 large-text threshold. The brief lists
	 * weak contrast as a confirmed defect to eliminate, so the proof's value could
	 * not be carried forward.
	 *
	 * This value clears AA on BOTH surfaces the design uses, which is the point:
	 * the first correction was verified against white only, and the footer band is
	 * bone, not white, so the copyright and legal lines sitting on it still failed
	 * at 4.26:1.
	 *
	 *   on white   #ffffff   5.14:1
	 *   on bone    #f2f2f0   4.58:1
	 *
	 * Bone is also behind the About figures, the award cells and the light panel,
	 * so any grey text there is covered by the same value.
	 *
	 * It governs the inactive rail navigation, caption subtitles, filters, index
	 * meta, portrait roles, the footer copyright and the legal links. Changing it
	 * here changes all of them. */
	--ulp-grey: #6a6f69;

	--ulp-white: #ffffff;
	--ulp-bone: #f2f2f0;

	/* Two block colours, one dark and one light, as the reference does. Not four. */
	--ulp-green: #4a6030;
	--ulp-sand: #e2ddd2;

	/* Three further panel grounds, carried over from the earlier version of the
	 * site. Each is dark enough to take white ink, so they extend the panel set
	 * without changing how a panel behaves. */
	--ulp-terracotta: #8C5F4A;
	--ulp-slate: #4B5563;
	--ulp-teal: #3F5551;

	--ulp-face: "Helvetica Neue", "HelveticaNeue", "Neue Haas Grotesk Display Pro", "Suisse Int'l", Helvetica, Arial, sans-serif;

	--ulp-rail: 34%;
	--ulp-pad: 42px;
	--ulp-gutter: 4%;   /* between two images in a row */
	--ulp-row: 120px;   /* between rows */
	--ulp-inset: 34px;  /* padding inside a colour block */
	--ulp-measure: 62ch;
}

/* --------------------------------------------------- scoped parent reset
 *
 * Selectors are separated explicitly. The v1.0.3 reset was missing its commas,
 * so it matched nothing and the Essentials parent styles leaked through.
 */

.ulp-template,
.ulp-template body {
	margin: 0;
	padding: 0;
	background: var(--ulp-white);
}

.ulp-template {
	font-family: var(--ulp-face);
	color: var(--ulp-black);
	-webkit-font-smoothing: antialiased;
	font-size: 19px;
	line-height: 1.5;
}

.ulp-template *,
.ulp-template *::before,
.ulp-template *::after {
	box-sizing: border-box;
}

.ulp-template h1,
.ulp-template h2,
.ulp-template h3,
.ulp-template h4,
.ulp-template p,
.ulp-template ul,
.ulp-template ol,
.ulp-template dl,
.ulp-template dd,
.ulp-template dt,
.ulp-template figure,
.ulp-template figcaption,
.ulp-template blockquote {
	margin: 0;
	padding: 0;
	font-weight: 400;
	font-size: inherit;
	line-height: inherit;
	color: inherit;
	font-family: inherit;
}

.ulp-template ul,
.ulp-template ol {
	list-style: none;
}

.ulp-template img,
.ulp-template svg,
.ulp-template video {
	display: block;
	max-width: 100%;
}

.ulp-template a {
	color: var(--ulp-black);
	text-decoration: none;
}

.ulp-template a:hover,
.ulp-template a:focus-visible {
	color: var(--ulp-charcoal);
}

.ulp-template :focus-visible {
	outline: 2px solid var(--ulp-black);
	outline-offset: 4px;
}

.ulp-template #wrapper,
.ulp-template .site-content,
.ulp-template .content-wrap,
.ulp-template .container {
	max-width: none;
	width: auto;
	margin: 0;
	padding: 0;
}

/* ----------------------------------------------------------------- shell */

/* The shell is a plain block holding two things: the body, which is the rail
 * and the content column, and the footer beneath it. The split matters: the
 * rail is sticky, and its sticky container is the body rather than the whole
 * page, so when the footer rises the rail rises with the content instead of
 * sitting over it. */
.ulp-template .ulp-shell { display: block; }

.ulp-template .ulp-shell-body {
	display: grid;
	grid-template-columns: var(--ulp-rail) minmax(0, 1fr);
	align-items: start;
	min-height: 100vh;
}

/* The rail holds the wordmark at the top and the navigation at the bottom, and
 * nothing else. The reference puts no contact details here; the contact block
 * closes the page instead. */
.ulp-template .ulp-rail {
	position: sticky;
	top: 0;
	height: 100vh;
	padding: var(--ulp-pad);
	display: grid;
	grid-template-rows: auto 1fr auto;
	background: var(--ulp-white);
	z-index: 20;
}

.ulp-template .ulp-rail-logo {
	display: block;
	justify-self: start;
	position: relative;
	z-index: 1001;
}

/* The three delivery pathways as a second, quieter list under the primary
 * navigation: text rather than marks, so the rail holds one wordmark and two
 * lists of words. */
.ulp-template .ulp-rail-brands {
	margin-top: 26px;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 4px;
}

.ulp-template .ulp-rail-brand {
	display: block;
	color: var(--ulp-grey);
	text-decoration: none;
	font-size: clamp(15px, 1.05vw, 19px);
	letter-spacing: -0.01em;
	transition: color 220ms ease;
}

.ulp-template .ulp-rail-brand:hover,
.ulp-template .ulp-rail-brand:focus-visible { color: var(--ulp-black); }

/* The planner is a saved shortlist rather than a pathway, so it sits a little
 * apart from the three marks and takes the ink of a current page while the
 * planner itself is open. */
.ulp-template .ulp-rail-planner { margin-top: 14px; }

/* Alone in the row it needs no separation from anything above it. */
.ulp-template .ulp-rail-planner.is-only { margin-top: 0; }

.ulp-template .ulp-rail-planner.is-current { color: var(--ulp-black); }

@media (max-width: 1000px) {
	.ulp-template .ulp-rail-brands {
		margin-top: 10px;
		flex-direction: row;
		align-items: center;
		gap: 20px;
	}

	/* In a row the column's separation would read as a dropped baseline, so the
	 * planner sets its own top margin aside. */
	.ulp-template .ulp-rail-planner { margin-top: 0; }
}

/* The wordmark is about 13% of viewport width in the reference, so it holds its
 * proportion to the rail rather than sitting at a fixed 260px. */
.ulp-template .ulp-logo {
	width: clamp(150px, 13vw, 320px);
	height: auto;
	transform-origin: top left;
}

.ulp-template .ulp-navwrap {
	grid-row: 3;
	align-self: end;
}

/* Navigation is small and quiet, and scales with the viewport like everything
 * else. The rejected build set it at 29px, which read as a heading stack. */
.ulp-template .ulp-nav-list {
	display: flex;
	flex-direction: column;
	font-size: clamp(19px, 1.7vw, 40px);
	line-height: 1.42;
}

/* The size is repeated on the link, not left to inherit from the list. On
 * WordPress the parent theme's own anchor rules match these menu links and set
 * an explicit size, which beats an inherited one, so the rail rendered at the
 * parent's size at every width and the clamp above never took effect. */
.ulp-template .ulp-nav-list .ulp-nav-link {
	font-size: clamp(19px, 1.7vw, 40px);
	line-height: 1.42;
}

.ulp-template .ulp-nav-link {
	color: var(--ulp-grey);
	transition: color 200ms ease;
}

.ulp-template .ulp-nav-link:hover,
.ulp-template .ulp-nav-link:focus-visible,
.ulp-template .ulp-nav-link[aria-current="page"],
.ulp-template .ulp-nav-link.is-current {
	color: var(--ulp-black);
}

/* The content column. Flush against the top edge: the feed begins at y=0, which
 * is what puts photography above the fold in the reference. */
.ulp-template .ulp-main {
	min-width: 0;
	padding: 0 3% var(--ulp-row) 0;
}

/* ------------------------------------------------------------------ rows */

.ulp-template .ulp-feed {
	display: flex;
	flex-direction: column;
	gap: var(--ulp-row);
}

/* One large image. */
.ulp-template .ulp-row-full {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
}

/* A pair row left with one visible cell by the filters runs full width, so
 * the row never shows a half-width hole. */
.ulp-template .ulp-row-pair.is-single { grid-template-columns: minmax(0, 1fr); }

/* Two small images. */
.ulp-template .ulp-row-pair {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: var(--ulp-gutter);
}

/* Three square images across the content column. Each cell carries a step
 * label, a title and around 200 characters of copy, so its type is sized
 * against the cell itself rather than the viewport, and the row holds three
 * across only while the cell is wide enough for the passage to clear the
 * inset — below that it stacks, as the pair rows do. */
.ulp-template .ulp-row-trio {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--ulp-gutter);
}

.ulp-template .ulp-row-trio .ulp-block {
	aspect-ratio: 1 / 1;
	container-type: inline-size;
}

.ulp-template .ulp-row-trio .ulp-block-step { font-size: clamp(13px, 4.4cqi, 15px); }
.ulp-template .ulp-row-trio .ulp-block-lead { font-size: clamp(19px, 7cqi, 26px); }
.ulp-template .ulp-row-trio .ulp-block-title { font-size: clamp(19px, 8cqi, 26px); }
/* A step panel can name its stage at the top of the panel. That slot normally
 * carries a micro-label, so a stage name is given heading treatment instead:
 * sentence case, display size, no tracking. */
.ulp-template .ulp-block-lead {
	font-size: clamp(19px, 7cqi, 26px);
	font-weight: 600;
	letter-spacing: -0.01em;
	text-transform: none;
	line-height: 1.15;
}

/* The three step panels read as one set, so their text block is bottom-aligned
 * and the space between stage name, headline and paragraph is the same on each
 * card whatever the length of the copy. */
.ulp-template .ulp-row-steps .ulp-panel {
	justify-content: flex-end;
	gap: 14px;
}

.ulp-template .ulp-row-steps .ulp-block-foot { gap: 10px; }

/* The step panels carry a full paragraph, so their copy is set a step smaller
 * than a caption and the panel clips rather than spilling past the tile. */
.ulp-template .ulp-row-trio .ulp-block-meta { font-size: clamp(13px, 3.9cqi, 17px); }
.ulp-template .ulp-row-trio .ulp-block-foot { gap: 10px; }

/* Grid children stretch, so the figure is a flex column and the block inside it
 * fills the height the grid gives it. This is the stretched-row fix. */
.ulp-template .ulp-row-full > *,
.ulp-template .ulp-row-pair > * {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

.ulp-template .ulp-row-full > * > .ulp-block,
.ulp-template .ulp-row-pair > * > .ulp-block {
	flex: 1 1 auto;
}

/* The stretched-row rules above set display on every row child, which outranks
 * the browser's own [hidden] rule — so a filtered-out cell or an emptied row
 * has to be collapsed explicitly, after them. */
.ulp-template .ulp-feed > [hidden],
.ulp-template .ulp-row-full > [hidden],
.ulp-template .ulp-row-pair > [hidden] { display: none; }

/* A text cell occupies one column of a row, so prose sits on the grid rather
 * than floating in the open whitespace beside it. */
.ulp-template .ulp-cell {
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
	min-width: 0;
}

.ulp-template .ulp-cell-end {
	justify-content: flex-end;
}

/* --------------------------------------------------------------- blocks */

.ulp-template .ulp-block {
	display: block;
	position: relative;
	overflow: hidden;
	background: var(--ulp-bone);
	aspect-ratio: 3 / 2;
	container-type: inline-size;
}

.ulp-template .ulp-block-square { aspect-ratio: 1 / 1; }

/* An image block with nothing in it yet: the frame at its usual 3:2 with a
 * faint inset edge and its own label, so a page can be laid out and reviewed
 * before the photography exists and it is obvious where each image goes. */
.ulp-template .ulp-block-slot {
	display: grid;
	place-items: center;
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.14);
	background: var(--ulp-bone);
}

.ulp-template .ulp-slot-label {
	font-size: 15px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

/* A panoramic frame keeps its own proportion instead of being cropped to 3:2,
 * so a stitched wide photograph is shown whole. Grid children stretch the
 * block to the row height, which would override the aspect ratio, so the
 * panoramic frame opts out of that stretch. */
.ulp-template .ulp-block-pano { aspect-ratio: 16 / 5; }
.ulp-template .ulp-row-full > * > .ulp-block-pano { flex: none; }

/* Holds a tall photograph to its lower edge, used where the subject sits at
 * the bottom of the frame and a centre crop would cut it off. */
.ulp-template .ulp-crop-low { object-position: 50% 86%; }

/* Crops a slice off the right and bottom edges of a photograph, used where a
 * supplied file carries a watermark in its bottom-right corner. */
.ulp-template .ulp-crop-br { transform: scale(1.07); transform-origin: top left; }

/* A rendering supplied on a white ground rather than a photograph: shown whole
 * and sat on the frame's lower edge, so the drawing is not cropped and the
 * white of the file reads as the white of the page. Set on the element to beat
 * the object-fit the general photo rule declares below it. */
.ulp-template img.ulp-photo-render {
	object-fit: contain;
	/* Centred rather than sat on the lower edge: a render wider than its frame
	 * was leaving a band of empty white above the drawing. */
	object-position: 50% 50%;
	background: #fff;
}

/* The range search: a field at the top right of the page, under the filter
 * row, that filters what is on the page and lists matches from elsewhere in
 * the range beneath itself. Framed, captioned and carrying a magnifier rather
 * than set as a bare underline, so it reads as a search field at a glance. */
/* The range search belongs to the filter row: it sits at the right end of the
 * range links, on their line, so the row stays two lines deep and the field is
 * where the eye already is. Its results hang below the field rather than
 * growing the row. */
.ulp-template .ulp-search {
	position: relative;
	flex: 0 1 auto;
	margin: -9px 0 0 auto;
	display: flex;
	flex-direction: column;
	align-items: stretch;
}

.ulp-template .ulp-search-label {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
}

.ulp-template .ulp-search-box {
	position: relative;
	width: min(320px, 100%);
	display: flex;
	align-items: center;
	gap: 10px;
	padding: 0 14px;
	border: 1px solid rgba(0, 0, 0, 0.28);
	background: var(--ulp-bone);
	transition: border-color 220ms ease, background-color 220ms ease;
}

.ulp-template .ulp-search-box:focus-within {
	border-color: var(--ulp-black);
	background: var(--ulp-white);
}

.ulp-template .ulp-search-box svg { flex: none; color: var(--ulp-grey); }

.ulp-template .ulp-search-field {
	flex: 1;
	min-width: 0;
	padding: 11px 0;
	border: 0;
	border-radius: 0;
	background: transparent;
	color: inherit;
	font-family: inherit;
	font-size: 16px;
	text-align: left;
	appearance: none;
}

/* The field's own chrome is asserted, not left at the browser default. On
 * WordPress the parent theme styles `input` directly - a grey fill, a border
 * and a radius - which painted a second box inside ours. Same defect as the
 * enquiry labels, same remedy. */
.ulp-template .ulp-search .ulp-search-field,
.ulp-template .ulp-search-wide .ulp-search-field {
	appearance: none;
	background: transparent;
	border: 0;
	border-radius: 0;
	box-shadow: none;
	padding: 0;
	margin: 0;
	height: auto;
	color: inherit;
	font: inherit;
}

.ulp-template .ulp-search-field::placeholder { color: var(--ulp-grey); }

.ulp-template .ulp-search-field:focus-visible { outline: 0; }

.ulp-template .ulp-search-status {
	position: absolute;
	top: calc(100% + 9px);
	right: 0;
	margin: 0;
	width: min(320px, 100%);
	font-size: 14px;
	letter-spacing: 0.02em;
	color: var(--ulp-grey);
	text-align: left;
}

.ulp-template .ulp-search-status:empty { display: none; }

.ulp-template .ulp-search-results {
	position: absolute;
	top: calc(100% + 34px);
	right: 0;
	margin: 0;
	padding: 0;
	list-style: none;
	width: min(320px, 100%);
	text-align: left;
	background: var(--ulp-white);
	z-index: 6;
}

.ulp-template .ulp-search-results:empty { display: none; }

.ulp-template .ulp-search-results a {
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 9px 0;
	border-top: 1px solid rgba(0, 0, 0, 0.12);
	color: inherit;
	text-decoration: none;
}

.ulp-template .ulp-search-name { font-size: 17px; }

.ulp-template .ulp-search-where {
	font-size: 13px;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

.ulp-template .ulp-search-results a:hover .ulp-search-name { text-decoration: underline; }

@media (max-width: 1000px) {
	.ulp-template .ulp-search {
		flex: 0 0 100%;
		margin: 14px 0 0;
	}

	.ulp-template .ulp-search-box,
	.ulp-template .ulp-search-status,
	.ulp-template .ulp-search-results { width: auto; }

	.ulp-template .ulp-search-status,
	.ulp-template .ulp-search-results { position: static; }

	.ulp-template .ulp-search-status { margin-top: 9px; }
	.ulp-template .ulp-search-results { margin-top: 12px; }
}

/* The delivery steps set as text rather than as three frames: the short form
 * that closes a category page, where the full trio would repeat the landing
 * page. Each step is a tag, a name and one line. */
.ulp-template .ulp-steplist {
	margin: 40px 0 0;
	padding: 0;
	list-style: none;
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--ulp-gutter);
}

/* Three across is the arrangement this was built for. A longer process reads
 * down the page instead: any other count in a three-up grid leaves empty cells
 * in a ragged final row, and a four or five step sequence is clearer read in
 * order anyway. */
.ulp-template .ulp-steplist:has(> li:nth-child(4)) {
	grid-template-columns: minmax(0, 1fr);
	gap: 0;
}

.ulp-template .ulp-steplist:has(> li:nth-child(4)) > li {
	display: grid;
	grid-template-columns: 120px minmax(0, 1fr);
	align-items: baseline;
	gap: 6px 24px;
	padding: 21px 0;
}

.ulp-template .ulp-steplist:has(> li:nth-child(4)) > li .ulp-steplist-name { grid-column: 2; }
.ulp-template .ulp-steplist:has(> li:nth-child(4)) > li .ulp-steplist-copy { grid-column: 2; }

@media (max-width: 700px) {
	.ulp-template .ulp-steplist:has(> li:nth-child(4)) > li { grid-template-columns: minmax(0, 1fr); gap: 8px; }
	.ulp-template .ulp-steplist:has(> li:nth-child(4)) > li .ulp-steplist-name,
	.ulp-template .ulp-steplist:has(> li:nth-child(4)) > li .ulp-steplist-copy { grid-column: 1; }
}

.ulp-template .ulp-steplist > li {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 10px;
	padding-top: 20px;
	border-top: 1px solid rgba(0, 0, 0, 0.14);
}

.ulp-template .ulp-steplist-tag {
	font-size: 12px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

.ulp-template .ulp-steplist-name {
	font-size: 21px;
	line-height: 1.2;
	letter-spacing: -0.01em;
}

.ulp-template .ulp-steplist-copy {
	font-size: 17px;
	line-height: 1.5;
	color: var(--ulp-grey);
}

@media (max-width: 1000px) {
	.ulp-template .ulp-steplist { grid-template-columns: minmax(0, 1fr); gap: 28px; }
}

/* SPROUTS products: a tile that opens in place.
 *
 * Each product is a details element sitting in the pair grid, so at rest the
 * page reads as the same two-up rhythm of frames the rest of the site uses.
 * Clicking one opens it across the full row - the gallery of three views, the
 * description and the planner control need the whole width - and the tile
 * beside it drops to the next row rather than being squeezed.
 */
.ulp-template .ulp-row-sprouts {
	align-items: start;
	/* A percentage row gap cannot be resolved while the grid's own height is
	 * still being determined, so the section measured itself short by the gaps
	 * and whatever followed sat on top of the last row of tiles. A length is
	 * counted in the height, so the row grows as products are added. */
	row-gap: 72px;
	/* A category's tiles belong to the heading above them, so this row closes
	 * most of the feed's standard gap; the full gap stays above the heading,
	 * where one category ends and the next begins. */
	margin-top: calc(40px - var(--ulp-row));
}

.ulp-template .ulp-sprout[open] { grid-column: 1 / -1; }

.ulp-template .ulp-sprout-summary {
	display: block;
	cursor: pointer;
	list-style: none;
}

.ulp-template .ulp-sprout-summary > figure { margin: 0; }

/* The cue on the tile: a quiet arrow beside the word, forward while the tile
 * is closed and back once it is open. */
.ulp-template .ulp-cue-state {
	display: inline-flex;
	align-items: center;
	gap: 8px;
}

.ulp-template .ulp-cue-state[data-cue-close] { display: none; }

/* An open tile has nothing left to reveal, so the panel and its hover
 * exchange step aside: the image stays put, the name is carried by the heading
 * in the column beside it and the way out is the close control on the frame. */
.ulp-template .ulp-sprout[open] .ulp-panel { display: none; }
.ulp-template .ulp-sprout[open] .ulp-photo { opacity: 1; }
.ulp-template .ulp-sprout[open] .ulp-touch-cap { display: none; }

.ulp-template .ulp-sprout-summary::-webkit-details-marker { display: none; }

.ulp-template .ulp-sprout-summary:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }

/* An open tile lays its own parts out on one grid: the frame and the three
 * views stack in the wide column, the description and the planner control take
 * the narrow one and start at the top beside the frame rather than beginning
 * level with the views and running past their lower edge. */
.ulp-template .ulp-sprout[open] { grid-column: 1 / -1; }

/* An open tile shows its own panel in place of the closed frame: the frame,
 * the rail and the description are laid out inside the panel itself rather
 * than across the details element, so nothing depends on how a browser boxes
 * a details element's content. */
.ulp-template .ulp-sprout[open] > .ulp-sprout-summary { display: none; }

.ulp-template .ulp-sprout-body {
	display: grid;
	grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
	column-gap: var(--ulp-gutter);
	row-gap: var(--ulp-gutter);
	/* A hairline around the open panel, so an expanded product reads as one
	 * piece set apart from the tiles around it. */
	padding: var(--ulp-gutter);
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.14);
}

.ulp-template .ulp-sprout-hero {
	grid-column: 1;
	grid-row: 1;
}

.ulp-template .ulp-sprout-hero .ulp-block { position: relative; }

.ulp-template .ulp-sprout-copy {
	grid-column: 2;
	grid-row: 1 / span 2;
	display: flex;
	flex-direction: column;
}

/* The product's name at the head of the column, at the size the block panels
 * use, so the open tile has a title of its own once the panel is gone. */
.ulp-template .ulp-sprout-title {
	margin: 0 0 22px;
	font-size: clamp(24px, 1.9vw, 34px);
	font-weight: 400;
	line-height: 1.1;
	letter-spacing: -0.01em;
	text-wrap: pretty;
}

/* The description sits in a narrow column beside the frame, so it is set at
 * the smaller of the site's two body sizes: the page's full prose size gave
 * fewer than twenty characters a line and read as a second heading. */
.ulp-template .ulp-sprout-copy .ulp-prose {
	max-width: none;
	font-size: 19px;
	line-height: 1.55;
}

/* A quiet line under the description, in the same manner as the onward links
 * elsewhere on the site. */
.ulp-template .ulp-sprout-note {
	margin: 16px 0 0;
	font-size: 17px;
	line-height: 1.5;
}

.ulp-template .ulp-sprout-note a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	color: var(--ulp-grey);
	text-decoration: none;
	transition: color 220ms ease;
}

.ulp-template .ulp-sprout-note a:hover { color: var(--ulp-black); }

/* The planner control sits at the foot of the column, level with the lower
 * edge of the views, rather than trailing the description. */
.ulp-template .ulp-sprout-planner {
	margin-top: auto;
	padding-top: 34px;
}

/* The three views sit under the frame in the wide column and scroll sideways
 * as a rail, so a product can carry more than three: three are shown at a time
 * and the next arrow pages through the rest. */
.ulp-template .ulp-sprout-gallery {
	position: relative;
	grid-column: 1;
	grid-row: 2;
}

.ulp-template .ulp-sprout-rail {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: calc((100% - (var(--ulp-gutter) * 2)) / 3);
	gap: var(--ulp-gutter);
	overflow-x: auto;
	scroll-behavior: smooth;
	scroll-snap-type: x mandatory;
	scrollbar-width: none;
}

.ulp-template .ulp-sprout-rail::-webkit-scrollbar { display: none; }

.ulp-template .ulp-sprout-rail > figure { margin: 0; scroll-snap-align: start; }

/* Shown only while the tile is open. Sat inside the rail's edges rather than
 * straddling them, so neither button crosses the page inset. */
.ulp-template .ulp-sprout-step {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	display: none;
	place-items: center;
	width: 46px;
	height: 46px;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.92);
	box-shadow: 0 2px 14px rgba(17, 17, 17, 0.16);
	color: var(--ulp-black);
	cursor: pointer;
	opacity: 0.72;
	transition: opacity 220ms ease, background-color 220ms ease;
	z-index: 2;
}

.ulp-template .ulp-sprout-prev { left: 12px; }
.ulp-template .ulp-sprout-next { right: 12px; }

.ulp-template .ulp-sprout[open] .ulp-sprout-step { display: grid; }

.ulp-template .ulp-sprout-step:hover { opacity: 1; background: #fff; }

.ulp-template .ulp-sprout-step:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; opacity: 1; }

/* The close control: a plain circle in the frame's top left corner, the one
 * place on the image that is always the way out. */
.ulp-template .ulp-sprout-close {
	position: absolute;
	top: 18px;
	left: 18px;
	display: none;
	place-items: center;
	width: 42px;
	height: 42px;
	padding: 0;
	border: 0;
	border-radius: 999px;
	background: rgba(17, 17, 17, 0.82);
	color: #fff;
	cursor: pointer;
	transition: background-color 220ms ease;
	z-index: 3;
}

.ulp-template .ulp-sprout[open] .ulp-sprout-close { display: grid; }

.ulp-template .ulp-sprout-close:hover { background: var(--ulp-black); }

.ulp-template .ulp-sprout-close:focus-visible { outline: 2px solid #fff; outline-offset: -6px; }

/* Forward and back on the frame itself, the same reach-for-the-edge cue the
 * guide preview uses: the zone is always there, the pill only on hover. */
.ulp-template .ulp-sprout-turn {
	position: absolute;
	top: 0;
	bottom: 0;
	width: 26%;
	display: none;
	align-items: flex-end;
	padding: 0 0 26px;
	border: 0;
	background: none;
	cursor: pointer;
	opacity: 0;
	transition: opacity 220ms ease;
	z-index: 2;
}

.ulp-template .ulp-sprout[open] .ulp-sprout-turn { display: flex; }

.ulp-template .ulp-sprout-turn-back { left: 0; justify-content: flex-start; }
.ulp-template .ulp-sprout-turn-next { right: 0; justify-content: flex-end; }

.ulp-template .ulp-sprout-turn:hover,
.ulp-template .ulp-sprout-turn:focus-visible { opacity: 1; }

.ulp-template .ulp-sprout-turn span {
	display: inline-block;
	margin: 0 22px;
	padding: 9px 16px;
	border-radius: 999px;
	background: rgba(17, 17, 17, 0.82);
	color: #fff;
	font-size: 12px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}



@media (max-width: 1000px) {
	.ulp-template .ulp-sprout-body { grid-template-columns: minmax(0, 1fr); }
	.ulp-template .ulp-sprout-copy { grid-column: 1; grid-row: auto; }
	.ulp-template .ulp-sprout-gallery { grid-row: auto; }
	/* One column: the rail is read by swiping, so the arrows step out and the
	 * frame keeps only its close control. */
	.ulp-template .ulp-sprout-rail { grid-auto-columns: 78%; }
	.ulp-template .ulp-sprout[open] .ulp-sprout-step,
	.ulp-template .ulp-sprout[open] .ulp-sprout-turn { display: none; }
}

.ulp-template .ulp-photo {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: opacity 400ms ease;
}

/* The hover panel. Title at the top, one quiet line at the bottom, nothing
 * else. No arrow glyph inside the panel: the cursor grows a ring over anything
 * interactive, which is the job that arrow was doing twice. */
.ulp-template .ulp-panel {
	position: absolute;
	inset: 0;
	opacity: 0;
	transition: opacity 400ms ease;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	padding: var(--ulp-inset);
	overflow: hidden;
}

/* Revealed by hover, and by focus so the text is reachable without a pointer.
 * Plain :focus is listed alongside :focus-visible because a cell that does not
 * navigate carries tabindex="0", and :focus-visible does not match focus that
 * was not driven by the keyboard heuristics, which would leave the panel
 * unreachable in exactly the case it was added for. */
.ulp-template .ulp-block:hover .ulp-panel,
.ulp-template .ulp-block:focus .ulp-panel,
.ulp-template .ulp-block:focus-visible .ulp-panel,
.ulp-template .ulp-block:focus-within .ulp-panel { opacity: 1; }

/* Only a block that actually has a panel trades its photograph for one: a
 * plain gallery photograph has nothing to reveal, so fading it out would just
 * make it disappear under the cursor. */
.ulp-template .ulp-block:has(.ulp-panel):hover .ulp-photo,
.ulp-template .ulp-block:has(.ulp-panel):focus .ulp-photo,
.ulp-template .ulp-block:has(.ulp-panel):focus-visible .ulp-photo,
.ulp-template .ulp-block:has(.ulp-panel):focus-within .ulp-photo { opacity: 0; }

/* Where the panel is itself the focusable element, as on the process animation,
 * no descendant selector above can match its own focus. */
.ulp-template .ulp-panel:focus,
.ulp-template .ulp-panel:focus-visible { opacity: 1; }

/* THE FLIP VARIANT
 *
 * The inverse of the default: colour panel with the heading at rest, photograph
 * revealed on hover. Used to alternate down a run so a grid of blocks does not
 * read as one repeating treatment. Declared after the default rules on purpose,
 * because the selectors carry equal specificity and source order decides. */
.ulp-template .ulp-flip .ulp-photo { opacity: 0; }
.ulp-template .ulp-flip .ulp-panel { opacity: 1; }

.ulp-template .ulp-flip:hover .ulp-photo,
.ulp-template .ulp-flip:focus .ulp-photo,
.ulp-template .ulp-flip:focus-visible .ulp-photo,
.ulp-template .ulp-flip:focus-within .ulp-photo { opacity: 1; }

.ulp-template .ulp-flip:hover .ulp-panel,
.ulp-template .ulp-flip:focus .ulp-panel,
.ulp-template .ulp-flip:focus-visible .ulp-panel,
.ulp-template .ulp-flip:focus-within .ulp-panel { opacity: 0; }

/* Text colour is declared on the panel colour class AND on every descendant, so
 * nothing inside a coloured panel can inherit the wrong colour. Dark panel takes
 * white, light panel takes charcoal. */
.ulp-template .ulp-panel-dark,
.ulp-template .ulp-panel-dark * {
	background: var(--ulp-green);
	color: var(--ulp-white);
}

.ulp-template .ulp-panel-terracotta,
.ulp-template .ulp-panel-terracotta * {
	background: var(--ulp-terracotta);
	color: var(--ulp-white);
}

.ulp-template .ulp-panel-slate,
.ulp-template .ulp-panel-slate * {
	background: var(--ulp-slate);
	color: var(--ulp-white);
}

.ulp-template .ulp-panel-teal,
.ulp-template .ulp-panel-teal * {
	background: var(--ulp-teal);
	color: var(--ulp-white);
}

.ulp-template .ulp-panel-light,
.ulp-template .ulp-panel-light * {
	background: var(--ulp-sand);
	color: var(--ulp-charcoal);
}

.ulp-template .ulp-panel-ink,
.ulp-template .ulp-panel-ink * {
	background: var(--ulp-charcoal);
	color: var(--ulp-white);
}

.ulp-template .ulp-panel-dark *,
.ulp-template .ulp-panel-light *,
.ulp-template .ulp-panel-terracotta *,
.ulp-template .ulp-panel-slate *,
.ulp-template .ulp-panel-teal *,
.ulp-template .ulp-panel-ink * {
	background: transparent;
}

/* Block type. Both sizes are far smaller than the rejected build's 52px, which
 * is why its panels read as posters rather than as captions on photography. */
.ulp-template .ulp-block-title {
	font-size: clamp(24px, 2.4vw, 34px);
	line-height: 1.12;
	letter-spacing: -0.01em;
	text-wrap: pretty;
	max-width: 26ch;
}

/* A panel whose copy runs the full width of the block rather than sitting in a
 * caption measure, for a long passage on a full-width photograph. */
.ulp-template .ulp-panel-wide .ulp-block-title,
.ulp-template .ulp-panel-wide .ulp-block-meta { max-width: none; }

.ulp-template .ulp-block-meta {
	font-size: clamp(16px, 1.5vw, 22px);
	line-height: 1.35;
	max-width: 34ch;
}

/* Process step label, top of a panel. Sentence-case titles do the talking on
 * this site, so the step is small, spaced and quiet rather than a pill. */
.ulp-template .ulp-block-step {
	font-size: 15px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

/* The step label as a resting tag on the photograph: visible before hover and
 * held through it, so the sequence reads without interaction. Sits above the
 * panel so the reveal does not cover it. */
.ulp-template .ulp-step-tag {
	white-space: nowrap;
	position: absolute;
	top: var(--ulp-inset);
	left: var(--ulp-inset);
	z-index: 2;
	font-size: 15px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ulp-white);
	background: var(--ulp-green);
	padding: 7px 12px 6px;
	pointer-events: none;
}

/* Inside a panel the step label is already the tag's job, so the in-panel copy
 * drops it and keeps only the title and its line. */
.ulp-template .ulp-block:has(.ulp-step-tag) .ulp-block-step { visibility: hidden; }

/* A stage name is not the step label, so it stays visible even where the tag
 * hides that slot. */
.ulp-template .ulp-block:has(.ulp-step-tag) .ulp-block-lead { visibility: visible; }

/* Groups the title and its copy at the foot of the panel, so the step label
 * holds the top edge under the panel's space-between. */
.ulp-template .ulp-block-foot {
	display: flex;
	flex-direction: column;
	gap: 12px;
}

/* A colour block with no photograph behind it: permanent, not a hover state. */
.ulp-template .ulp-solid {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	padding: var(--ulp-inset);
	aspect-ratio: 3 / 2;
	overflow: hidden;
}

/* Video sits behind a 3:2 block and is overscanned horizontally, so a 16:9
 * embed fills the frame and cannot disagree in height with the block beside it. */
.ulp-template .ulp-video {
	position: absolute;
	top: 0;
	left: -9.26%;
	width: 118.52%;
	height: 100%;
	border: 0;
	pointer-events: none;
}

/* The two-layer swap form is retired. Every block uses one form now: photograph
 * at rest with the panel on hover, or .ulp-flip for the inverse. Its rules are
 * deliberately not kept, so the treatment cannot creep back by accident. */

/* -------------------------------------------------------------- captions
 *
 * The reference shows no caption under a homepage image and a three-part
 * caption on the archive pages: name, then subtitle and category in grey.
 */

.ulp-template .ulp-cap {
	padding-top: 16px;
	font-size: 19px;
	line-height: 1.4;
}

.ulp-template .ulp-cap-name { display: block; }
.ulp-template .ulp-cap-meta { display: block; color: var(--ulp-grey); }

/* Shown on touch, where there is no hover to reveal the panel. */
.ulp-template .ulp-touch-cap { display: none; }

.ulp-template .ulp-sr {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

/* ----------------------------------------------------------- type scale */

/* The page statement.
 *
 * Sized as a proportion of the viewport, not to a fixed cap. Measured from the
 * reference work archive: the statement occupies about 3.7% of viewport width
 * per em, so it grows with the screen instead of stopping at a ceiling. The
 * earlier value capped at 48px, which held at 48px on a 2560px display where the
 * reference sets about 95px.
 *
 * The measure is 40ch rather than 30ch so the sentence uses the whole content
 * column, as the reference does, and wraps in three lines rather than four. */
.ulp-template .ulp-statement {
	font-size: clamp(30px, 3.7vw, 96px);
	line-height: 1.08;
	letter-spacing: -0.015em;
	text-wrap: pretty;
	max-width: 40ch;
	padding: 0 0 var(--ulp-row);
}

.ulp-template .ulp-statement-top { padding-top: 120px; }

.ulp-template .ulp-h2 {
	font-size: clamp(24px, 2.4vw, 34px);
	line-height: 1.15;
	letter-spacing: -0.01em;
	text-wrap: pretty;
	max-width: 26ch;
}

/* Body copy scale, set once for the whole site: the About page's larger reading
 * size is now the default, dropping back to a flat 19px on narrow screens. */
.ulp-template .ulp-prose {
	max-width: var(--ulp-measure);
	font-size: clamp(19px, 1.5vw, 30px);
	line-height: 1.32;
	text-wrap: pretty;
}

.ulp-template .ulp-prose + .ulp-prose { margin-top: 1.2em; }

/* A pull quote. Sits between .ulp-h2 at 34px and .ulp-prose at 19px, with its
 * own measure: it was referenced by the About page before it was defined, so it
 * rendered at body size across the full column width. */
/* A standalone company statement. Set between the page's h2 and its body copy,
 * on a generous measure and with a wide margin of white above and below, so it
 * reads as the page pausing to say something rather than as another paragraph.
 * The closing line carries the weight. */
.ulp-template .ulp-statement-quiet {
	max-width: 34ch;
	padding: clamp(28px, 3.6vw, 72px) 0;
	font-size: clamp(28px, 3.4vw, 62px);
	line-height: 1.14;
	letter-spacing: -0.02em;
	text-wrap: pretty;
	color: var(--ulp-charcoal);
}

.ulp-template .ulp-statement-quiet strong {
	display: block;
	padding-top: 0.7em;
	font-weight: 400;
	color: var(--ulp-grey);
}

.ulp-template .ulp-lede {
	font-size: clamp(22px, 2.1vw, 30px);
	line-height: 1.25;
	letter-spacing: -0.005em;
	max-width: 40ch;
	text-wrap: pretty;
}

/* Text link with a thin diagonal arrow, matching the reference's glyph. */
.ulp-template .ulp-arrowlink {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	font-size: 19px;
}

.ulp-template .ulp-arrowlink svg {
	flex: none;
	transition: transform 240ms cubic-bezier(0.33, 1, 0.68, 1);
}

.ulp-template .ulp-arrowlink:hover svg { transform: translate(3px, 3px); }

/* -------------------------------------------------------------- filters */

/* The filter row holds to the top of the window as the feed scrolls under it,
 * so the sector can be changed from anywhere in a long index. It carries the
 * page surface with it — the photography would otherwise run behind the words
 * — and the padding above it is what the row scrolled out of.
 *
 * --ulp-topbar is set by the filter script: zero while the rail is a left-hand
 * column, and the rail's measured height once it collapses into a bar across
 * the top of the window, so the two sticky elements stack rather than collide. */
.ulp-template .ulp-filters {
	position: sticky;
	top: var(--ulp-topbar, 0px);
	z-index: 4;
	display: flex;
	flex-wrap: wrap;
	gap: 6px 26px;
	padding: 26px 0 var(--ulp-row);
	background: var(--ulp-white);
	font-size: 19px;
}

.ulp-template .ulp-filter { color: var(--ulp-grey); transition: color 200ms ease; }

.ulp-template .ulp-filter:hover,
.ulp-template .ulp-filter:focus-visible,
.ulp-template .ulp-filter.is-current { color: var(--ulp-black); }

.ulp-template .ulp-filter-lead {
	color: var(--ulp-black);
	width: 100%;
	padding-bottom: 2px;
}

/* ---------------------------------------------------------- story page
 *
 * The reference story page is: title, one image, two or three short
 * paragraphs, one image, contact. No facts table, no step sequence, no
 * section headings. Everything below follows that.
 */

.ulp-template .ulp-story-title {
	font-size: clamp(30px, 3.7vw, 96px);
	line-height: 1.08;
	letter-spacing: -0.015em;
	padding: 120px 0 var(--ulp-row);
	max-width: 40ch;
}

/* Two other projects from the same category, closing every project page. The
 * heading is what separates these from the project's own photography, so it is
 * always present rather than left to the panels alone. */
.ulp-template .ulp-more { padding-top: var(--ulp-row); }

.ulp-template .ulp-more-head {
	margin: 0 0 34px;
	color: var(--ulp-grey);
	font-size: 15px;
	font-weight: 400;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

/* Project type, client and scope as one line under the title rather than a
 * facts table: three short values, separated, in the same grey the captions
 * and index meta use. The page still opens on title then photograph.
 *
 * The title's own bottom padding is closed up when the meta line follows it,
 * so the gap between the two is one declared value at every width — a
 * negative margin here would have been eating into a padding that is itself
 * overridden per breakpoint. */
.ulp-template .ulp-story-title:has(+ .ulp-story-meta) { padding-bottom: 22px; }

.ulp-template .ulp-story-meta {
	display: flex;
	flex-wrap: wrap;
	gap: 0 18px;
	margin: 0 0 var(--ulp-row);
	padding: 0;
	list-style: none;
	color: var(--ulp-grey);
	font-size: 15px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

.ulp-template .ulp-story-meta li + li::before {
	content: "";
	display: inline-block;
	width: 1px;
	height: 0.85em;
	margin-right: 18px;
	vertical-align: -0.05em;
	background: currentColor;
	opacity: 0.5;
}

.ulp-template .ulp-story-copy {
	max-width: var(--ulp-measure);
	padding: var(--ulp-row) 0;
}

.ulp-template .ulp-story-copy p + p { margin-top: 1.2em; }

/* The opening copy with the range's three marks alongside it: the text holds
 * its measure in the left column and the marks stack in the right, each in a
 * set. The three marks are drawn to one width rather than one height, so
 * their left and right edges line up down the column. */
.ulp-template .ulp-story-split {
	display: grid;
	grid-template-columns: minmax(0, var(--ulp-measure)) minmax(0, 1fr);
	gap: var(--ulp-gutter);
	align-items: start;
}

.ulp-template .ulp-story-split .ulp-story-copy { max-width: none; }

.ulp-template .ulp-brand-set {
	display: grid;
	gap: clamp(24px, 3vw, 44px);
	width: min(100%, 340px);
	margin: 0;
	padding: var(--ulp-row) 0;
	list-style: none;
}

.ulp-template .ulp-brand-set li { display: block; }

.ulp-template .ulp-brand-set img {
	display: block;
	width: 100%;
	height: auto;
}

/* DELIVERY PATHWAY CARDS
 *
 * Three brand marks across the feed. At rest the mark sits alone, centred in
 * its cell; on hover or focus it settles into the top-left corner and the
 * pathway description fades in below it. The mark is moved by margin rather
 * than by flex alignment so the change can be transitioned. */
.ulp-template .ulp-pathway {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	/* At rest the panel is only as tall as the mark it holds, so the row of
	 * logos sits with its heading rather than adrift in white. On hover it opens
	 * to full height, which is what gives the description and the cue room to
	 * stand clear of each other. */
	min-height: clamp(190px, 17vw, 250px);
	padding: var(--ulp-inset);
	padding-bottom: calc(var(--ulp-inset) * 2.4);
	transition: background 400ms ease, min-height 400ms cubic-bezier(0.33, 1, 0.68, 1);
}

/* The logos belong to the heading above them, so this row closes most of the
 * feed's standard gap. */
.ulp-template .ulp-feed > .ulp-row-trio:has(.ulp-pathway) {
	margin-top: calc(34px - var(--ulp-row));
}

.ulp-template .ulp-pathway-mark {
	display: block;
	width: min(100%, 300px);
	height: auto;
	margin: auto;
	transition: margin 400ms ease, width 400ms ease;
}

/* The description shares the column with the mark instead of overlaying it, so
 * long copy can never run across the logo. It is collapsed to no height at
 * rest, which is what lets the mark sit optically centred until hover. */
.ulp-template .ulp-pathway-copy {
	width: 100%;
	margin: 0;
	font-size: clamp(15px, 1.3vw, 18px);
	line-height: 1.4;
	color: var(--ulp-charcoal);
	text-wrap: pretty;
	max-height: 0;
	overflow: hidden;
	opacity: 0;
	transition: max-height 400ms ease, opacity 400ms ease, padding-top 400ms ease;
}

.ulp-template .ulp-pathway:hover,
.ulp-template .ulp-pathway:focus,
.ulp-template .ulp-pathway:focus-visible,
.ulp-template .ulp-pathway:focus-within {
	background: var(--ulp-sand);
	min-height: clamp(300px, 27vw, 400px);
}

.ulp-template .ulp-pathway:hover .ulp-pathway-mark,
.ulp-template .ulp-pathway:focus .ulp-pathway-mark,
.ulp-template .ulp-pathway:focus-visible .ulp-pathway-mark,
.ulp-template .ulp-pathway:focus-within .ulp-pathway-mark {
	width: min(100%, 190px);
	margin: 0 auto 0 0;
}

.ulp-template .ulp-pathway:hover .ulp-pathway-copy,
.ulp-template .ulp-pathway:focus .ulp-pathway-copy,
.ulp-template .ulp-pathway:focus-visible .ulp-pathway-copy,
.ulp-template .ulp-pathway:focus-within .ulp-pathway-copy {
	max-height: 24em;
	opacity: 1;
	padding-top: 18px;
}

/* The same three brand marks laid across the feed rather than stacked beside a
 * passage of copy, for the delivery pathways row. */
.ulp-template .ulp-brand-row {
	width: 100%;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	align-items: center;
	padding: 0;
	gap: var(--ulp-gap, clamp(24px, 3vw, 44px));
}

.ulp-template .ulp-brand-row img { width: min(100%, 300px); }

@media (max-width: 1000px) {
	.ulp-template .ulp-story-split { grid-template-columns: minmax(0, 1fr); gap: 0; }
	.ulp-template .ulp-brand-set { padding-top: 0; }
	.ulp-template .ulp-brand-row { grid-template-columns: minmax(0, 1fr); justify-items: start; }
}

/* ----------------------------------------------------------- hero strip
 *
 * A full-bleed band of photography under the opening statement, scrolled by
 * hand rather than on a timer: one photograph fills the band, the next is a
 * swipe or a drag away, and the snap holds each one square to the frame. It
 * bleeds past the content column's padding to the edges of the page, so the
 * band runs from the rail to the right edge of the window.
 */
.ulp-template .ulp-strip {
	margin: 0 calc(-1 * var(--ulp-pad));
	padding-top: var(--ulp-row);
	overflow-x: auto;
	overflow-y: hidden;
	scroll-snap-type: x mandatory;
	overscroll-behavior-x: contain;
	/* The band is its own scroller; the bar itself would sit across the
	 * photograph, so it is hidden and the snap does the signalling. */
	scrollbar-width: none;
}

.ulp-template .ulp-strip::-webkit-scrollbar { display: none; }

.ulp-template .ulp-strip-track { display: flex; }

/* One slide is one band, measured against the scroller rather than the window:
 * the band sits right of the rail, so a viewport-width slide would hang off the
 * frame by the width of the rail and the snap would never bring it back. */
/* Holds the band and the two step zones, which sit on the photograph rather
 * than inside the scroller, where they would scroll away with it. */
.ulp-template .ulp-strip-shell {
	position: relative;
	margin: 0 calc(-1 * var(--ulp-pad));
}

.ulp-template .ulp-strip-shell .ulp-strip { margin: 0; }

/* A band down each edge of the frame steps the photograph. The zone itself is
 * invisible: what the visitor sees is a word and an arrow beside the cursor,
 * which is the only control the band has. The middle of the picture is left
 * alone, so most of the frame is still just a photograph to drag. */
.ulp-template .ulp-strip-zone {
	position: absolute;
	top: var(--ulp-row);
	bottom: 0;
	width: clamp(120px, 20%, 340px);
	padding: 0;
	border: 0;
	background: transparent;
	overflow: hidden;
	cursor: pointer;
}

.ulp-template .ulp-strip-zone[data-dir="-1"] { left: 0; }
.ulp-template .ulp-strip-zone[data-dir="1"] { right: 0; }
.ulp-template .ulp-strip-shell.is-dragging .ulp-strip-zone { cursor: grabbing; }

/* Clicking a step zone left Safari's default focus ring drawn around half the
 * photograph: a black rectangle over the picture, which Chrome does not draw
 * for a mouse click. The ring is kept for the keyboard, where it is the only
 * thing showing which half is selected, and drawn white and inset so it reads
 * against a photograph rather than as a border on the frame. */
.ulp-template .ulp-strip-zone:focus { outline: none; }

.ulp-template .ulp-strip-zone:focus-visible {
	outline: 2px solid #ffffff;
	outline-offset: -8px;
}

.ulp-template .ulp-strip-hint {
	position: absolute;
	/* Anchored near the foot of the photograph and following the cursor only
	 * sideways, so the word sits on a steady line instead of wandering over
	 * the picture. */
	bottom: clamp(28px, 4vw, 60px);
	left: 0;
	display: flex;
	align-items: center;
	gap: 18px;
	color: var(--ulp-white);
	font-size: clamp(19px, 1.6vw, 26px);
	line-height: 1;
	white-space: nowrap;
	pointer-events: none;
	opacity: 0;
	transition: opacity 200ms ease;
}

.ulp-template .ulp-strip-zone:hover .ulp-strip-hint,
.ulp-template .ulp-strip-zone:focus-visible .ulp-strip-hint { opacity: 1; }
.ulp-template .ulp-strip-shell.is-dragging .ulp-strip-hint { opacity: 0; }

.ulp-template .ulp-strip-mark {
	display: grid;
	place-items: center;
	width: clamp(48px, 4.4vw, 68px);
	aspect-ratio: 1 / 1;
	border: 1.5px solid currentColor;
	border-radius: 50%;
}

.ulp-template .ulp-strip-mark svg { width: 45%; height: 45%; }

/* The word and arrow replace the site's cursor ring while a zone is live:
 * two arrows at once read as two controls. The cursor script writes its own
 * opacity inline on every move, so this has to outrank it. */
.ulp-template .ulp-cursor[data-mute="1"] {
	opacity: 0 !important;
	transition: none;
}

/* Position of the frame in the set, sat in the margin under the band: six
 * short rules, the live one drawn at full strength. Small enough to read as
 * punctuation rather than a control panel, and the only permanent marking the
 * band carries. */
.ulp-template .ulp-strip-dots {
	display: flex;
	gap: 10px;
	justify-content: center;
	padding: 28px var(--ulp-pad) 0;
}

.ulp-template .ulp-strip-dot {
	width: 26px;
	height: 2px;
	padding: 0;
	border: 0;
	background: currentColor;
	opacity: 0.28;
	cursor: pointer;
	transition: opacity 240ms ease;
}

.ulp-template .ulp-strip-dot[data-on="1"] { opacity: 1; }
.ulp-template .ulp-strip-dot:hover { opacity: 0.7; }
.ulp-template .ulp-strip-dot[data-on="1"]:hover { opacity: 1; }

/* On touch there is no cursor to stand beside, so the zones drop out. */
@media (hover: none) {
	.ulp-template .ulp-strip-zone { display: none; }
}

/* The band is the page's hero, so it is sized like one — against the window
 * rather than a fixed ceiling, as the reference site does. The width term keeps
 * it from becoming a tower on narrow windows; the floor keeps it a band on
 * phones. */
.ulp-template .ulp-strip img {
	display: block;
	flex: 0 0 100%;
	height: min(80vh, 62vw);
	min-height: 360px;
	object-fit: cover;
	background: var(--ulp-bone);
	scroll-snap-align: start;
}

/* -------------------------------------------------------- numbers, grid
 *
 * Three confirmed numbers, each in its own cell of a three-column row so they
 * sit on the grid instead of floating across empty white.
 */

.ulp-template .ulp-figures {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: var(--ulp-gutter);
}

.ulp-template .ulp-figure {
	display: flex;
	flex-direction: column;
	justify-content: flex-end;
	padding: var(--ulp-inset);
	aspect-ratio: 3 / 2;
	background: var(--ulp-bone);
}

.ulp-template .ulp-figure-num {
	font-size: clamp(30px, 3.4vw, 48px);
	line-height: 1;
	letter-spacing: -0.02em;
}

.ulp-template .ulp-figure-label {
	padding-top: 10px;
	font-size: 17px;
	line-height: 1.35;
	color: var(--ulp-charcoal);
}

/* ------------------------------------------------------------- portraits
 *
 * The rejected build put the name and the role in two inline spans with no
 * separation, so they ran together as "George AdamsDirector and Design
 * Director". Both are blocks here.
 *
 * Six portraits in two rows of three, circular and large. At rest they are
 * black and white, which is how the reference treats its quieter photographic
 * moments. Hover or keyboard focus brings the colour back and lifts the name
 * and the role over the foot of the circle, so the exchange reveals the face
 * rather than hiding it.
 */

/* -------------------------------------------------------------- credentials
 *
 * The licence and insurance lines. Each is a discrete fact, so they are a list
 * rather than a paragraph: one column, left aligned, stacked under the
 * paragraph above.
 */

.ulp-template .ulp-creds {
	margin: 21px 0 0;
	padding: 0;
	list-style: none;
	font-size: 19px;
	line-height: 1.5;
	text-align: left;
}

.ulp-template .ulp-creds > li + li { margin-top: 8px; }

/* ------------------------------------------------------------------- notes
 *
 * Square colour blocks carrying the About copy, two to a row. They are square
 * by preference and grow taller when the copy needs the room, so a long block
 * and a short one in the same row stay the same height without the text being
 * clipped. They take the same surface as the figure blocks: on a white page a
 * light tint of the page, and on the colour field a slight darkening of the
 * field with the type reversed out, so a panel reads as a card without
 * introducing a third colour.
 *
 * At rest a panel shows only its heading, set large. Hover or keyboard focus
 * turns the panel white, drops the heading to reading size, brings the
 * description up and scales the panel 5% over its neighbours: the same
 * exchange the photographic blocks make, in type rather than in image. The
 * scale is a transform, so the grid does not reflow and nothing below the row
 * moves. A panel spans its whole column and the column has no spare width, so
 * growth is anchored to the panel's outer edge and runs inward: the left panel
 * grows to the right, the right panel to the left. Anchoring to the centre
 * instead pushed the panel over the rail and off the page. In the one-column
 * state the panel is the full content width, so there is nowhere to grow and
 * the scale is dropped. The panel is focusable so the description is reachable
 * from the keyboard, and on touch, where there is no hover, both are shown.
 */

.ulp-template .ulp-note {
	/* Square by preference, expressed as a floor rather than as aspect-ratio: a
	 * grid item carrying an aspect-ratio is not stretched, so the two panels in
	 * a row would size independently and their bottom edges would not line up.
	 * The floated pseudo-element sets the square minimum while the height stays
	 * auto, which lets ordinary grid stretch equalise the pair. */
	display: block;
	position: relative;
	z-index: 0;
	padding: var(--ulp-inset);
	background: var(--ulp-bone);
	color: var(--ulp-black);
	/* Hovering a panel turns it white, the same exchange the photographic
	 * blocks make when their panel comes up. */
	transition: background-color 220ms ease, color 220ms ease, transform 260ms ease;
}

.ulp-template .ulp-note::before {
	content: "";
	float: left;
	padding-top: 100%;
}

.ulp-template .ulp-note::after {
	content: "";
	display: table;
	clear: both;
}

.ulp-template .ulp-row-pair > .ulp-note:hover,
.ulp-template .ulp-row-pair > .ulp-note:focus-visible,
.ulp-template .ulp-row-pair > .ulp-note:focus-within {
	transform: scale(1.05);
	z-index: 1;
}

.ulp-template .ulp-row-pair > .ulp-note:nth-child(odd) { transform-origin: left center; }
.ulp-template .ulp-row-pair > .ulp-note:nth-child(even) { transform-origin: right center; }

@media (prefers-reduced-motion: reduce) {
	.ulp-template .ulp-note,
	.ulp-template .ulp-note-title { transition: none; }

	.ulp-template .ulp-note:hover,
	.ulp-template .ulp-note:focus-visible,
	.ulp-template .ulp-row-pair > .ulp-note:focus-within { transform: none; }
}

.ulp-template .ulp-note-title {
	margin: 0;
	font-size: clamp(30px, 2.6vw, 52px);
	font-weight: 400;
	line-height: 1.12;
	letter-spacing: -0.015em;
	text-wrap: balance;
	/* A single long word, e.g. an account handle, breaks rather than running out
	 * past the panel edge. */
	overflow-wrap: anywhere;
	transition: font-size 260ms ease;
}

/* The handle is one unbroken word, so it is set smaller than a sentence
 * heading and holds on one line inside the panel. */
.ulp-template a.ulp-note .ulp-note-title { font-size: clamp(22px, 1.8vw, 34px); }

.ulp-template .ulp-note:hover .ulp-note-title,
.ulp-template .ulp-note:focus-visible .ulp-note-title,
.ulp-template .ulp-note:focus-within .ulp-note-title { font-size: 27px; }

.ulp-template .ulp-note:focus-visible { outline: 2px solid currentColor; outline-offset: -6px; }

/* The Instagram feed inside a panel: a grid of recent posts that comes up with
 * the hover, filling the panel under its handle. Where no feed plugin is
 * connected the tiles render as empty paper squares, so the panel still reads
 * as a feed rather than as a broken embed.
 */
.ulp-template .ulp-feedgrid {
	flex: none;
	margin-top: auto;
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 6px;
	margin: 0;
	padding: 0;
	list-style: none;
	opacity: 0;
	transition: opacity 220ms ease;
}

.ulp-template .ulp-note:hover .ulp-feedgrid,
.ulp-template .ulp-note:focus-visible .ulp-feedgrid,
.ulp-template .ulp-note:focus-within .ulp-feedgrid { opacity: 1; }

.ulp-template .ulp-feedgrid li {
	aspect-ratio: 1 / 1;
	background: rgba(0, 0, 0, 0.08);
	overflow: hidden;
}

.ulp-template .ulp-feedgrid img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

@media (max-width: 1000px) {
	.ulp-template .ulp-feedgrid { margin-top: 34px; opacity: 1; }
}

/* The award emblems, as one continuous rail running under the awards copy
 * rather than a grid of badges. It carries no band of its own: the panel it
 * sits in turns bone on hover, and the marks' white backgrounds are multiplied
 * away against it, so the rail reads as printed on the panel. The track
 * carries the marks twice and translates by exactly half its width, which is
 * what makes the loop seamless.
 */
/* A panel carrying a reveal at its foot is strictly square, not square-or-taller
 * like the copy-only panels: the square floor is a minimum, so the copy inside
 * these two would push them past it. They become a flex column instead, with
 * the copy taking the space between the heading and the rail rather than
 * setting the panel's height. */
.ulp-template .ulp-note:has(.ulp-awardrail),
.ulp-template .ulp-note:has(.ulp-feedgrid) {
	display: flex;
	flex-direction: column;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	container-type: inline-size;
}

.ulp-template .ulp-note:has(.ulp-awardrail)::before,
.ulp-template .ulp-note:has(.ulp-feedgrid)::before { content: none; }

/* One paragraph at a tighter setting: the copy and the emblem strip share a
 * fixed square, so what the copy does not take is what the marks can have. */
.ulp-template .ulp-note:has(.ulp-awardrail) .ulp-note-body {
	flex: none;
	font-size: 17px;
	line-height: 1.4;
}

.ulp-template .ulp-awardrail {
	/* At the foot of the panel's column, with the slack between it and the copy
	 * above rather than under the marks, so the strip sits on the bottom edge
	 * the way the grid of posts does in the panel beside it. */
	flex: none;
	margin-top: auto;
	padding-top: 20px;
	overflow: hidden;
	opacity: 0;
	transition: opacity 220ms ease;
	-webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
	mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}

.ulp-template .ulp-awardrail-track {
	display: flex;
	align-items: center;
	gap: 56px;
	width: max-content;
	animation: ulp-awardrail 72s linear infinite;
}

.ulp-template .ulp-awardrail img {
	display: block;
	/* Sized against the panel rather than in fixed pixels: the copy plus a
	 * fixed strip does not fit the square in the narrowest two-column case, so
	 * the marks scale with the panel and stop growing at 88px. */
	height: clamp(99px, 26cqw, 153px);
	width: auto;
	flex: none;
	mix-blend-mode: multiply;
}

@keyframes ulp-awardrail {
	from { transform: translateX(0); }
	to { transform: translateX(-50%); }
}

/* Below the pair breakpoint the panel has no square floor, so there is no
 * foot to pin the rail to: it returns to ordinary flow under the copy. */
/* One column: nothing to match, so the panels size to their content again. */
@media (max-width: 1000px) {
	.ulp-template .ulp-note:has(.ulp-awardrail),
	.ulp-template .ulp-note:has(.ulp-feedgrid) { aspect-ratio: auto; overflow: visible; }

	.ulp-template .ulp-awardrail { margin-top: 34px; padding-top: 0; }
	.ulp-template .ulp-awardrail img { height: 109px; }
}

/* The rail is decorative motion, so it stops rather than slowing down. */
@media (prefers-reduced-motion: reduce) {
	.ulp-template .ulp-awardrail-track { animation: none; }
	.ulp-template .ulp-awardrail { overflow-x: auto; }
}

.ulp-template .ulp-note-body > p { margin: 0; }

.ulp-template .ulp-note-body > p + p { margin-top: 1em; }

.ulp-template .ulp-note-body {
	margin: 18px 0 0;
	font-size: 19px;
	line-height: 1.5;
	text-wrap: pretty;
	opacity: 0;
	transition: opacity 220ms ease;
}

.ulp-template .ulp-note:hover .ulp-note-body,
.ulp-template .ulp-note:focus-visible .ulp-note-body,
.ulp-template .ulp-note:focus-within .ulp-note-body { opacity: 1; }

/* The rail comes up with the copy, and only there: the marks are the
 * elaboration on the claim, not the claim itself. */
.ulp-template .ulp-note:hover .ulp-awardrail,
.ulp-template .ulp-note:focus-visible .ulp-awardrail,
.ulp-template .ulp-note:focus-within .ulp-awardrail { opacity: 1; }

/* The two panels that carry content of their own - the awards square and the
 * Instagram square - show it at rest. Held behind hover they read as two empty
 * coloured boxes, which is not how the rest of the site behaves: everywhere
 * else a panel of this size is already carrying a photograph or a rail. Hover
 * still makes the colour exchange, and the heading is set at its revealed size
 * from the outset so nothing shifts under the cursor. */
.ulp-template .ulp-note:has(.ulp-awardrail) .ulp-note-body,
.ulp-template .ulp-note:has(.ulp-feedgrid) .ulp-note-body,
.ulp-template .ulp-awardrail,
.ulp-template .ulp-feedgrid { opacity: 1; }

.ulp-template .ulp-note:has(.ulp-awardrail) .ulp-note-title,
.ulp-template .ulp-note:has(.ulp-feedgrid) .ulp-note-title { font-size: clamp(24px, 2vw, 34px); }

/* A panel that is itself a link keeps the panel's own colours rather than the
 * page's link colour, and takes the focus ring the other panels take. */
a.ulp-note { text-decoration: none; }
.ulp-template.ulp-field a.ulp-note { color: var(--ulp-white); }
.ulp-template a.ulp-note:focus-visible { outline: 2px solid currentColor; outline-offset: -6px; }

/* The square floor only makes sense while two panels sit side by side. Below
 * the width at which the pair rows collapse to one column, a square would be
 * as tall as the content column and mostly empty, so the floor is dropped. */
@media (max-width: 1000px) {
	.ulp-template .ulp-note::before { padding-top: 0; }

	/* One column: the panel already spans the content width. */
	.ulp-template .ulp-row-pair > .ulp-note:hover,
	.ulp-template .ulp-row-pair > .ulp-note:focus-visible,
	.ulp-template .ulp-row-pair > .ulp-note:focus-within { transform: none; }
}

/* No hover on touch, so heading and description are simply both shown. */
@media (hover: none) {
	.ulp-template .ulp-note-title { font-size: 27px; }
	.ulp-template .ulp-note-body { opacity: 1; }
	.ulp-template .ulp-awardrail { opacity: 1; }
	.ulp-template .ulp-row-pair > .ulp-note:focus-within { transform: none; }
}

.ulp-template .ulp-people {
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: var(--ulp-gutter);
}

.ulp-template .ulp-person {
	position: relative;
	margin: 0;
	width: 100%;
	max-width: 420px;
	aspect-ratio: 1 / 1;
	border-radius: 50%;
	overflow: hidden;
}

.ulp-template .ulp-person img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	filter: grayscale(1);
	transition: filter 260ms ease;
}

.ulp-template .ulp-person:hover img,
.ulp-template .ulp-person:focus-visible img,
.ulp-template .ulp-person:focus-within img { filter: grayscale(0); }

/* A supplied portrait framed tighter than the studio set: the crop is pulled
 * up so the whole head sits inside the circle with the shoulders at the
 * bottom edge, matching the others. */
.ulp-template .ulp-person-high img { object-position: 50% 12%; }

.ulp-template .ulp-person-empty {
	width: 100%;
	height: 100%;
	background: rgba(255, 255, 255, 0.09);
}

.ulp-template .ulp-person figcaption {
	position: absolute;
	inset: auto 0 0;
	display: flex;
	flex-direction: column;
	gap: 2px;
	padding: 46px 12% 12%;
	text-align: center;
	background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0));
	color: var(--ulp-white);
	opacity: 0;
	transition: opacity 220ms ease;
}

.ulp-template .ulp-person:hover figcaption,
.ulp-template .ulp-person:focus-visible figcaption,
.ulp-template .ulp-person:focus-within figcaption { opacity: 1; }

.ulp-template .ulp-person:focus-visible { outline: 2px solid currentColor; outline-offset: 6px; }

.ulp-template .ulp-person-name {
	display: block;
	font-size: 19px;
	line-height: 1.35;
	text-wrap: balance;
}

.ulp-template .ulp-person-role {
	display: block;
	font-size: 17px;
	line-height: 1.35;
	color: rgba(255, 255, 255, 0.82);
	text-wrap: balance;
}

/* The portrait caption sits on the photograph, not on the page, so it carries
 * its own scrim and white type on every surface and needs no field-tone
 * override. */

@media (max-width: 700px) {
	.ulp-template .ulp-people { grid-template-columns: repeat(2, 1fr); }
}

/* No hover on touch, so the portraits are simply in colour with their names
 * showing. */
@media (hover: none) {
	.ulp-template .ulp-person img { filter: grayscale(0); }
	.ulp-template .ulp-person figcaption { opacity: 1; }
}

/* ------------------------------------------------------------------ enquiry
 *
 * The enquiry block that closes a page: the invitation and the form on the
 * left, the map and then the contact details on the right. All of them are
 * direct children of one grid rather than two stacked columns, so both sides
 * share row lines: the invitation has the first row to itself, the form and the
 * map sit on the second, and the details and the accounts follow under the map.
 * The map drops by exactly one label line so its top edge meets the first field
 * rather than the field's label. It sits above the
 * footer, so it never repeats the footer's own invitation styling; the two
 * read as one closing sequence.
 *
 * The map is an ordinary embed, desaturated so it does not introduce a second
 * palette into the page, and comes back to colour on hover, the same way the
 * portraits and the award emblems do. It sits under the contact details so its
 * top edge lines up with the first field of the form beside it.
 */

.ulp-template .ulp-enquiry {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	grid-template-rows: auto auto auto auto;
	gap: 40px var(--ulp-gutter);
	align-items: start;
	padding-top: var(--ulp-row);
}

/* The contact details and the accounts follow the form down the first column,
 * under the reply time, so the enquiry reads as one sequence and the map holds
 * the second column on its own. */
.ulp-template .ulp-enquiry-head { grid-column: 1; grid-row: 1; }
.ulp-template .ulp-enquiry-form { grid-column: 1; grid-row: 2; }
.ulp-template .ulp-details { grid-column: 1; grid-row: 3; }
.ulp-template .ulp-social { grid-column: 1; grid-row: 4; }
/* The map closes the left column, below the social accounts, rather than
 * sitting opposite the form. */
.ulp-template .ulp-map { grid-column: 1; grid-row: 5; }

.ulp-template .ulp-enquiry-invite {
	font-size: clamp(24px, 2.4vw, 34px);
	line-height: 1.15;
	letter-spacing: -0.01em;
	text-wrap: pretty;
}

.ulp-template .ulp-enquiry-sub {
	margin-top: 4px;
	font-size: clamp(24px, 2.4vw, 34px);
	line-height: 1.15;
	letter-spacing: -0.01em;
	color: var(--ulp-grey);
	text-wrap: pretty;
}

.ulp-template .ulp-enquiry-note { margin-top: 26px; font-size: 19px; line-height: 1.5; }

.ulp-template .ulp-form {
	display: flex;
	flex-direction: column;
	gap: 21px;
}

.ulp-template .ulp-enquiry-form { display: grid; gap: 26px; }

.ulp-template .ulp-formrow {
	display: flex;
	flex-direction: column;
	gap: 8px;
	font-size: 19px;
}

.ulp-template .ulp-formrow input,
.ulp-template .ulp-formrow textarea {
	width: 100%;
	padding: 14px 16px;
	border: 1px solid currentColor;
	border-radius: 0;
	/* A faint well rather than a transparent box: at browser zoom levels the
	 * 1px hairline falls on a sub-pixel and the left edge can drop out of the
	 * raster, which read as the field being cropped. The tint is the same
	 * darkened surface the cells on a coloured field take, so the field has a
	 * body of its own and no longer depends on the hairline alone. */
	background: rgba(0, 0, 0, 0.1);
	box-shadow: inset 1px 0 0 currentColor;
	color: inherit;
	font-family: inherit;
	font-size: 19px;
	line-height: 1.4;
}

.ulp-template .ulp-formrow textarea { min-height: 200px; resize: vertical; }

.ulp-template .ulp-formrow input:focus-visible,
.ulp-template .ulp-formrow textarea:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* The label and the field take the page's ink explicitly. Inheriting it was
 * enough in the approved page on its own, but on WordPress the parent theme
 * styles `label`, `input` and `textarea` directly, and those rules beat an
 * inherited colour: on the colour field the labels rendered charcoal on green
 * at about 1.6:1. Same defect the rail navigation had, same remedy. */
.ulp-template .ulp-formrow > label { color: inherit; }

.ulp-template.ulp-field .ulp-formrow,
.ulp-template.ulp-field .ulp-formrow > label,
.ulp-template.ulp-field .ulp-form .ulp-formrow > label,
.ulp-template.ulp-field .ulp-formrow input,
.ulp-template.ulp-field .ulp-formrow textarea {
	color: var(--ulp-white);
	border-color: rgba(255, 255, 255, 0.58);
}

.ulp-template.ulp-field .ulp-formrow input::placeholder,
.ulp-template.ulp-field .ulp-formrow textarea::placeholder { color: rgba(255, 255, 255, 0.6); }

.ulp-template .ulp-submit {
	align-self: start;
	padding: 14px 26px;
	border: 1px solid currentColor;
	/* Same hairline treatment as the fields above, so the left edge holds at
	 * any zoom rather than falling on a sub-pixel. */
	background: rgba(0, 0, 0, 0.1);
	box-shadow: inset 1px 0 0 currentColor;
	color: inherit;
	font-family: inherit;
	font-size: 19px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	cursor: pointer;
	transition: background-color 220ms ease, color 220ms ease;
}

.ulp-template .ulp-submit:hover { background: var(--ulp-white); color: var(--ulp-black); box-shadow: inset 1px 0 0 currentColor; }

.ulp-template .ulp-reply { font-size: 19px; }

/* The embed is capped rather than left to fill its column. At 4:3 of a wide
 * column it became a square the height of the viewport; the cap holds it at the
 * size the approved page renders, and it still shrinks with a narrow column. */
.ulp-template .ulp-map {
	display: block;
	width: 100%;
	max-width: 560px;
	aspect-ratio: 4 / 3;
	max-height: 420px;
	border: 0;
	filter: grayscale(1);
	transition: filter 320ms ease;
}

.ulp-template .ulp-map:hover,
.ulp-template .ulp-map:focus-within { filter: grayscale(0); }

.ulp-template .ulp-details { display: grid; gap: 40px; }

.ulp-template .ulp-details-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
	gap: 21px var(--ulp-gutter);
	align-items: start;
}

.ulp-template .ulp-details-label { color: var(--ulp-grey); font-size: 19px; }

.ulp-template .ulp-details-list {
	display: grid;
	gap: 21px;
	margin: 0;
	padding: 0;
	list-style: none;
	font-size: 19px;
	line-height: 1.4;
}

.ulp-template .ulp-details-list li { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 14px; align-items: start; }

.ulp-template .ulp-details-list svg { width: 20px; height: 20px; margin-top: 2px; }

.ulp-template .ulp-social-row { display: flex; flex-wrap: wrap; gap: 26px; font-size: 19px; }

/* The accounts as their own marks rather than words: four glyphs in a line, at
 * the same weight as the small icons in the details list above. */
.ulp-template .ulp-social-row[data-icons] { gap: 22px; align-items: center; }

.ulp-template .ulp-social-row[data-icons] a {
	display: inline-flex;
	width: 26px;
	height: 26px;
	white-space: normal;
}

.ulp-template .ulp-social-row[data-icons] svg { width: 100%; height: 100%; }

.ulp-template .ulp-social-row[data-icons] a:hover { opacity: 0.72; }

/* Label and arrow are one unit, as in the footer: inline flow would let the
 * arrow wrap onto its own line. */
.ulp-template .ulp-social-row a {
	display: inline-flex;
	align-items: baseline;
	gap: 8px;
	white-space: nowrap;
}

.ulp-template .ulp-social-row a svg { flex: none; }

@media (max-width: 1000px) {
	.ulp-template .ulp-enquiry { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; }

	/* One column: the blocks run in reading order, and because stacking drops
	 * the two-column placement, the order is restated here — the details and the
	 * accounts follow the form, as they do beside it, and the map closes. */
	.ulp-template .ulp-enquiry-head,
	.ulp-template .ulp-enquiry-form,
	.ulp-template .ulp-details,
	.ulp-template .ulp-social,
	.ulp-template .ulp-map { grid-column: 1; grid-row: auto; }

	.ulp-template .ulp-enquiry-head { order: 1; }
	.ulp-template .ulp-enquiry-form { order: 2; }
	.ulp-template .ulp-details { order: 3; }
	.ulp-template .ulp-social { order: 4; }
	.ulp-template .ulp-map { order: 5; }

	.ulp-template .ulp-map { margin-top: 0; }
	.ulp-template .ulp-details-row { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------------------------------------------------------- awards
 *
 * The rejected build let raw emblems of wildly different shapes float on white
 * at wildly different sizes. Each emblem now sits in a bone cell of a fixed
 * ratio and is contained inside it, so the row reads as one row.
 */

.ulp-template .ulp-awards {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
	gap: 20px;
}

/* Each emblem sits in a cell of a fixed ratio and is contained inside it, so a
 * row of marks with very different proportions reads as one row. No cell
 * background: the emblems carry their own. */
.ulp-template .ulp-award {
	display: flex;
	align-items: center;
	justify-content: center;
	aspect-ratio: 3 / 2;
	padding: 18px;
}

.ulp-template .ulp-award img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
}

/* ---------------------------------------------------- index, knowledge */

.ulp-template .ulp-index {
	display: flex;
	flex-direction: column;
	gap: 56px;
}

.ulp-template .ulp-index-item {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: var(--ulp-gutter);
	align-items: start;
}

.ulp-template .ulp-index-title {
	font-size: clamp(22px, 2.1vw, 30px);
	line-height: 1.15;
	letter-spacing: -0.01em;
	text-wrap: pretty;
}

.ulp-template .ulp-index-meta { color: var(--ulp-grey); font-size: 17px; }

/* --------------------------------------------------------- global footer
 *
 * A full-bleed band, spanning the rail as well as the content column, which is
 * the one place in the design where anything crosses the rail. Four columns:
 * the invitation, the address block, the social accounts, the accreditation
 * marks. All type is black and large; there is no grey secondary text and no
 * "Follow us on" lead, because the reference has neither.
 *
 * It sits outside <main> as a grid item of the shell, spanning both columns, so
 * the band reaches both edges of the viewport.
 */

/* The footer sizes to its content. It reads as a field of its own because it
 * rises past the rail, not because it is stretched to the viewport: a forced
 * full height only opened a hole between the address block and the base row.
 * Its rows sit at a comfortable measure rather than running the full width. */
.ulp-template .ulp-footer {
	display: flex;
	flex-direction: column;
	gap: 56px;
	background: var(--ulp-bone);
	padding: 96px var(--ulp-pad) 48px;
}

/* The footer runs to the page padding rather than the 1600px measure the
 * content column holds to, so the marks and the legal links sit against the
 * right edge of the screen. */
.ulp-template .ulp-footer-grid,
.ulp-template .ulp-footer-base { max-width: none; }

/* ------------------------------------------------------- prequalification
 *
 * The prequalification marks sit at the right-hand end of the footer row, small
 * and quiet, as the reference does it. They carry no tile of their own: the
 * artwork is reversed out, white on transparent, so each mark sits directly on
 * the footer surface. White reads on the colour field but disappears on the
 * bone footer, so on a light footer the artwork is inverted back to black. The
 * paper is transparent either way, so inverting only affects the marks
 * themselves.
 */
.ulp-template .ulp-prequal {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
	gap: 16px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.ulp-template .ulp-prequal li {
	display: flex;
	align-items: center;
	justify-content: center;
	/* Capped on both axes, not height alone. The marks are supplied at very
	 * different proportions, so scaling them all to one height made the wide
	 * ones (Local Government Procurement, Queensland Government) three times
	 * the visual weight of the square ones. */
	height: 56px;
	max-width: 160px;
}

/* The files carry a white ground rather than transparency, so they are
 * multiplied into the footer band: white drops out and the artwork stays. */
.ulp-template .ulp-prequal img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
	mix-blend-mode: multiply;
}

/* ---------------------------------------------------------- memberships
 *
 * The membership and prequalification marks as one row across the content
 * column, each contained in a cell of the same height so a row of very
 * different proportions reads as one row. The artwork is a single charcoal
 * ink on transparent paper, so on the colour field it is driven to white
 * rather than sitting at 1.5:1 against the green. */
.ulp-template .ulp-memberships {
	display: grid;
	grid-template-columns: repeat(7, minmax(0, 1fr));
	align-items: center;
	gap: var(--ulp-gutter);
	margin: 0;
	padding: 0;
	list-style: none;
}

.ulp-template .ulp-memberships li {
	display: flex;
	align-items: center;
	justify-content: center;
	height: clamp(38px, 4vw, 67px);
}

.ulp-template .ulp-memberships img {
	width: 100%;
	height: auto;
	aspect-ratio: 411 / 245;
	max-width: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
}

/* These files are opaque: dark ink on a solid white background, not
 * transparent paper. Driving every pixel to white therefore produced seven
 * white boxes. Inverting turns the ink white and the background black, and
 * screening then drops that black into the green, so what is left is the mark
 * in white with no panel behind it. */
.ulp-template.ulp-field .ulp-memberships img {
	/* Grayscale first so a coloured mark cannot invert to a muddy hue, then
	 * lifted and hardened so the artwork reads as crisp white rather than a
	 * mid-grey wash on the green. */
	filter: grayscale(1) invert(1) brightness(1.25) contrast(1.6);
	mix-blend-mode: screen;
}

@media (max-width: 1000px) {
	.ulp-template .ulp-memberships { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
}

@media (max-width: 1000px) {
	.ulp-template .ulp-footer { gap: 40px; }
	.ulp-template .ulp-prequal { justify-content: flex-start; gap: 12px; }
	.ulp-template .ulp-prequal li { height: 48px; max-width: 132px; }
}

/* Three columns: the invitation, the address block, and the accreditation marks
 * held to the right edge. The social accounts are not here, because they are
 * listed in the enquiry block above and would only be repeated. */
.ulp-template .ulp-footer-grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
	gap: 48px var(--ulp-gutter);
	align-items: start;
}

.ulp-template .ulp-footer-invite {
	font-size: clamp(24px, 2.4vw, 34px);
	line-height: 1.15;
	letter-spacing: -0.01em;
	max-width: 20ch;
	text-wrap: pretty;
}

.ulp-template .ulp-footer-contact {
	display: flex;
	flex-direction: column;
	gap: 26px;
	font-size: clamp(19px, 1.9vw, 28px);
	line-height: 1.2;
}


.ulp-template .ulp-footer-contact a {
	display: inline-flex;
	align-items: baseline;
	gap: 8px;
	color: var(--ulp-black);
}

.ulp-template .ulp-footer-contact svg {
	flex: none;
	align-self: center;
	transition: transform 220ms cubic-bezier(0.33, 1, 0.68, 1);
}

.ulp-template .ulp-footer-contact a:hover svg { transform: translate(2px, -2px); }

/* Text only. The accreditation marks are gone: the emblems have very different
 * aspect ratios and read as clutter at footer scale, so the band carries the
 * invitation, the address block and the accounts, and nothing else. */

.ulp-template .ulp-footer-base {
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: 8px 24px;
	padding-top: 84px;
	font-size: 15px;
	color: var(--ulp-grey);
}

.ulp-template .ulp-footer-legal {
	display: flex;
	flex-wrap: wrap;
	gap: 4px 24px;
}

.ulp-template .ulp-footer-legal a { color: var(--ulp-grey); }
.ulp-template .ulp-footer-legal a:hover { color: var(--ulp-black); }

/* ------------------------------------------------------- colour field page
 *
 * The reference About page is not a white page: the brand colour runs full
 * bleed across the rail, the content column and the footer, with the wordmark
 * and the navigation reversed out of it. It is the one page in the system that
 * is a field rather than a sheet.
 *
 * ULP's brand colour is the sage green. White on #4a6030 measures 6.6:1, so the
 * field carries white type throughout. The wordmark has no reversed artwork, so
 * the charcoal file is driven to white with a filter, which is the documented
 * stand-in in the ULP design system until real reversed artwork exists.
 */

/* The footer is deliberately outside this list: it carries the same bone
 * surface on every page, field or sheet, so the close of the site reads the
 * same everywhere. */
.ulp-template.ulp-field .ulp-shell,
.ulp-template.ulp-field .ulp-rail {
	background: var(--ulp-green);
}

.ulp-template.ulp-field,
.ulp-template.ulp-field body { background: var(--ulp-green); }

.ulp-template.ulp-field .ulp-statement,
.ulp-template.ulp-field .ulp-prose,
.ulp-template.ulp-field .ulp-creds,
.ulp-template.ulp-field .ulp-lede,
.ulp-template.ulp-field .ulp-h2,
.ulp-template.ulp-field .ulp-figure-num,
.ulp-template.ulp-field .ulp-figure-label { color: var(--ulp-white); }

/* The wordmark and the navigation reverse out of the field. */
.ulp-template.ulp-field .ulp-logo { filter: brightness(0) invert(1); }

/* 0.75 rather than a lighter value: blended over the green this resolves to
 * 4.74:1, which clears AA at the 17px the navigation drops to on mobile. At 0.66
 * it measured 4.09, which passes only as large text and so failed there. */
.ulp-template.ulp-field .ulp-nav-link { color: rgba(255, 255, 255, 0.75); }

.ulp-template.ulp-field .ulp-nav-link:hover,
.ulp-template.ulp-field .ulp-nav-link:focus-visible,
.ulp-template.ulp-field .ulp-nav-link[aria-current="page"],
.ulp-template.ulp-field .ulp-nav-link.is-current { color: var(--ulp-white); }

/* Photography sits directly on the field, so the loading placeholder and the
 * figure panels take a darker green rather than bone. */
.ulp-template.ulp-field .ulp-block { background: rgba(0, 0, 0, 0.12); }
.ulp-template.ulp-field .ulp-figure,
.ulp-template.ulp-field .ulp-note { background: rgba(0, 0, 0, 0.12); }

/* The emblems carry their own light band inside the panel, so the panel itself
 * is the usual darkened cell with white type. */

.ulp-template.ulp-field .ulp-note,
.ulp-template.ulp-field .ulp-note-title { color: var(--ulp-white); }
.ulp-template.ulp-field .ulp-note-body { color: rgba(255, 255, 255, 0.86); }

/* The revealed panel takes a surface of its own rather than all six turning
 * white: two sand, two bone and two charcoal, set per panel in the markup so
 * the sequence reads as a rhythm across the three rows. Light surfaces carry
 * black type, the charcoal one reverses. */
.ulp-template.ulp-field .ulp-note:hover,
.ulp-template.ulp-field .ulp-note:focus-within { background: var(--ulp-sand); }

.ulp-template.ulp-field .ulp-note[data-reveal="bone"]:hover,
.ulp-template.ulp-field .ulp-note[data-reveal="bone"]:focus-within { background: var(--ulp-bone); }

.ulp-template.ulp-field .ulp-note[data-reveal="ink"]:hover,
.ulp-template.ulp-field .ulp-note[data-reveal="ink"]:focus-within { background: var(--ulp-charcoal); }

.ulp-template.ulp-field .ulp-note:hover,
.ulp-template.ulp-field .ulp-note:hover .ulp-note-title,
.ulp-template.ulp-field .ulp-note:focus-within,
.ulp-template.ulp-field .ulp-note:focus-within .ulp-note-title { color: var(--ulp-black); }

.ulp-template.ulp-field .ulp-note:hover .ulp-note-body,
.ulp-template.ulp-field .ulp-note:focus-within .ulp-note-body { color: var(--ulp-charcoal); }

.ulp-template.ulp-field .ulp-note[data-reveal="ink"]:hover,
.ulp-template.ulp-field .ulp-note[data-reveal="ink"]:hover .ulp-note-title,
.ulp-template.ulp-field .ulp-note[data-reveal="ink"]:focus-within,
.ulp-template.ulp-field .ulp-note[data-reveal="ink"]:focus-within .ulp-note-title { color: var(--ulp-white); }

.ulp-template.ulp-field .ulp-note[data-reveal="ink"]:hover .ulp-note-body,
.ulp-template.ulp-field .ulp-note[data-reveal="ink"]:focus-within .ulp-note-body { color: rgba(255, 255, 255, 0.86); }

.ulp-template.ulp-field .ulp-enquiry-invite,
.ulp-template.ulp-field .ulp-enquiry-note,
.ulp-template.ulp-field .ulp-form,
.ulp-template.ulp-field .ulp-reply,
.ulp-template.ulp-field .ulp-details,
.ulp-template.ulp-field .ulp-details-list a,
.ulp-template.ulp-field .ulp-social-row a { color: var(--ulp-white); }

.ulp-template.ulp-field .ulp-details-list a:hover,
.ulp-template.ulp-field .ulp-social-row a:hover { color: rgba(255, 255, 255, 0.72); }

.ulp-template.ulp-field .ulp-enquiry-sub,
.ulp-template.ulp-field .ulp-details-label { color: rgba(255, 255, 255, 0.72); }

.ulp-template.ulp-field .ulp-submit:hover { background: var(--ulp-white); color: var(--ulp-black); }

.ulp-template.ulp-field .ulp-cursor { --ulp-ink: #ffffff; }

/* On a field page the statement runs larger than on a white page, and the prose
 * sits in a narrow measure at display size beside it, both as the reference
 * sets them. */
.ulp-template.ulp-field .ulp-statement {
	font-size: clamp(32px, 4.4vw, 110px);
	line-height: 1.06;
}

.ulp-template.ulp-field .ulp-prose {
	font-size: clamp(19px, 1.5vw, 30px);
	line-height: 1.32;
	max-width: 44ch;
}

.ulp-template.ulp-field .ulp-story-copy { padding: var(--ulp-row) 0; }

/* ---------------------------------------------------- display copy scale
 *
 * The About page sets the reference for body copy: prose runs at display size
 * in a narrow 44ch measure, not at the 19px reading size the other templates
 * use. Schools and Childcare take the same treatment without taking the green
 * field, so the scale lives in its own class rather than in .ulp-field. Values
 * are held identical to the field rule above on purpose — change both together. */
.ulp-template.ulp-copy-field .ulp-prose {
	font-size: clamp(19px, 1.5vw, 30px);
	line-height: 1.32;
	max-width: 44ch;
}

.ulp-template.ulp-copy-field .ulp-story-copy {
	max-width: 44ch;
	padding: var(--ulp-row) 0;
}

/* Section headings scale with the display copy. Body copy on these pages runs
 * up to 30px, and ulp-h2 caps at 34px, so heading and body converged and the
 * hierarchy read flat: the heading keeps a clear step above the passage. */
.ulp-template.ulp-copy-field .ulp-h2,
.ulp-template.ulp-field .ulp-h2 {
	font-size: clamp(28px, 2.9vw, 44px);
}

@media (max-width: 1000px) {
	.ulp-template.ulp-copy-field .ulp-prose { font-size: 19px; max-width: none; }
	.ulp-template.ulp-copy-field .ulp-story-copy { max-width: none; }
}

@media (max-width: 1000px) {
	.ulp-template.ulp-field .ulp-statement { font-size: clamp(28px, 7.4vw, 38px); }
	.ulp-template.ulp-field .ulp-prose { font-size: 19px; max-width: none; }
}

@media (max-width: 1000px) {
	.ulp-template .ulp-prose { font-size: 19px; }
}

/* ------------------------------------------------------------ boot screen
 *
 * The page is held behind its own surface until the document has loaded, with
 * the ULP symbol turning at the centre. It is the mark itself doing the work —
 * no bar, no percentage, no second graphic invented for the purpose. The screen
 * is removed by script on load and, if the script never runs, it fades itself
 * out so a page can never be left behind it.
 */
.ulp-boot {
	position: fixed;
	inset: 0;
	z-index: 100;
	display: grid;
	place-items: center;
	background: var(--ulp-white);
	animation: ulp-boot-out 4s 3.4s forwards;
}

/* The boot surface is white on every route, including the colour field: the
 * supplied symbol is charcoal with white counters and has no reversed variant,
 * so it is only legible on a light surface. */

.ulp-boot img {
	width: clamp(48px, 5vw, 76px);
	height: auto;
	animation: ulp-boot-spin 1.6s linear infinite;
}

.ulp-boot[data-done="1"] {
	animation: none;
	opacity: 0;
	pointer-events: none;
	transition: opacity 320ms ease;
}

@keyframes ulp-boot-spin {
	from { transform: rotate(0deg); }
	to { transform: rotate(360deg); }
}

@keyframes ulp-boot-out {
	to { opacity: 0; visibility: hidden; }
}

/* No spin where motion is not wanted: the mark simply holds until the page is
 * ready. */
@media (prefers-reduced-motion: reduce) {
	.ulp-boot img { animation: none; }
}

/* -------------------------------------------------------- kinetic cursor */

.ulp-template .ulp-cursor {
	position: fixed;
	top: 0;
	left: 0;
	width: 76px;
	height: 76px;
	margin: -38px 0 0 -38px;
	pointer-events: none;
	z-index: 1100;
	opacity: 0;
	transition: opacity 180ms ease;
	will-change: transform;
	--ulp-ink: #000000;
	--ulp-key: transparent;
}

.ulp-template .ulp-cursor[data-tone="dark"] { --ulp-ink: #ffffff; }
.ulp-template .ulp-cursor[data-tone="photo"] { --ulp-ink: #ffffff; --ulp-key: rgba(0, 0, 0, 0.5); }

.ulp-template .ulp-press {
	position: absolute;
	inset: 0;
	display: block;
	transform-origin: 38px 38px;
	transition: transform 150ms cubic-bezier(0.33, 1, 0.68, 1);
}

.ulp-template .ulp-cursor[data-press="1"] .ulp-press { transform: scale(0.94); }

.ulp-template .ulp-cursor svg { position: absolute; inset: 0; overflow: visible; }

.ulp-template .ulp-ring { opacity: 0; transition: opacity 180ms ease; }
.ulp-template .ulp-cursor[data-over="1"] .ulp-ring { opacity: 1; }

.ulp-template .ulp-loose {
	stroke-dasharray: 170;
	stroke-dashoffset: 170;
	transition: stroke-dashoffset 200ms cubic-bezier(0.4, 0, 0.2, 1), opacity 200ms ease;
}

.ulp-template .ulp-cursor[data-over="1"] .ulp-loose { stroke-dashoffset: 0; }

.ulp-template .ulp-cursor[data-reduce="1"] .ulp-press,
.ulp-template .ulp-cursor[data-reduce="1"] .ulp-ring { transition: none; }
.ulp-template .ulp-cursor[data-reduce="1"] .ulp-loose { transition: none; stroke-dashoffset: 0; }

@media (pointer: fine) {
	.ulp-template .ulp-shell.ulp-cursor-on,
	.ulp-template .ulp-shell.ulp-cursor-on * { cursor: none; }
}

.ulp-template .ulp-sheet {
	position: fixed;
	inset: 0;
	background: var(--ulp-white);
	z-index: 1000;
	opacity: 1;
	pointer-events: none;
	display: none;
}

/* ------------------------------------------------------- touch behaviour */

@media (pointer: coarse), (hover: none) {
	.ulp-template .ulp-cursor { display: none; }
	.ulp-template .ulp-block .ulp-panel { display: none; }
	.ulp-template .ulp-block .ulp-photo { opacity: 1; }
	/* a flip cell has no hover to reveal its photograph with, so it shows it */
	.ulp-template .ulp-flip .ulp-photo { opacity: 1; }
	.ulp-template .ulp-touch-cap { display: block; }
}

/* The step cells stack rather than squeeze: at a third of a narrower column a
 * square cannot hold its passage. They stay square once stacked, where the
 * full column width gives the copy more room than it needs. */
@media (max-width: 1300px) {
	.ulp-template .ulp-row-trio { grid-template-columns: minmax(0, 1fr); }
}

/* A stacked step tile is as wide as the column, so a square makes it enormous
 * and its panel copy small; a 3:2 tile keeps the paragraph legible and inside
 * the frame. */
@media (max-width: 900px) {
	.ulp-template .ulp-row-trio .ulp-block { aspect-ratio: 3 / 2; }
}

/* ---------------------------------------------------------------- tablet */

@media (max-width: 1200px) {
	.ulp-template {
		--ulp-rail: 30%;
		--ulp-row: 84px;
		--ulp-inset: 26px;
	}
	.ulp-template .ulp-logo { width: 200px; }
	.ulp-template .ulp-nav-list { font-size: 21px; }
	.ulp-template .ulp-nav-list .ulp-nav-link { font-size: 21px; }
	.ulp-template .ulp-index-item,
	.ulp-template .ulp-footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.ulp-template .ulp-figure { aspect-ratio: 1 / 1; }
	.ulp-template .ulp-statement-top,
	.ulp-template .ulp-story-title { padding-top: 84px; }
}

/* ---------------------------------------------------------------- mobile */

@media (max-width: 1000px) {
	.ulp-template {
		--ulp-pad: 21px;
		--ulp-gutter: 21px;
		--ulp-row: 48px;
		--ulp-inset: 21px;
	}

	.ulp-template .ulp-shell-body { grid-template-columns: minmax(0, 1fr); }


	/* Restrained sticky header: the wordmark comes down, the navigation runs on
	 * one sideways-scrolling line inside the rail, so the bar that stays on
	 * screen is around 100px rather than a full-height rail. The scroller is
	 * inside the rail, so the page itself never overflows horizontally. */
	.ulp-template .ulp-rail {
		position: sticky;
		top: 0;
		height: auto;
		display: block;
		padding: 14px 21px 12px;
	}

	.ulp-template .ulp-logo { width: 148px; }

	.ulp-template .ulp-navwrap {
		margin-top: 8px;
		overflow-x: auto;
		overscroll-behavior-x: contain;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
	}

	.ulp-template .ulp-navwrap::-webkit-scrollbar { display: none; }

	.ulp-template .ulp-nav-list {
		flex-direction: row;
		flex-wrap: nowrap;
		gap: 18px;
		font-size: 17px;
		white-space: nowrap;
	}

	.ulp-template .ulp-nav-list .ulp-nav-link { font-size: 17px; }

	.ulp-template .ulp-main { padding: 0 var(--ulp-pad) 56px; }

	.ulp-template .ulp-statement,
	.ulp-template .ulp-story-title {
		font-size: clamp(26px, 7vw, 34px);
		max-width: none;
		padding: 32px 0 40px;
	}

	.ulp-template .ulp-statement-top { padding-top: 32px; }

	.ulp-template .ulp-row-pair,
	.ulp-template .ulp-index-item,
	.ulp-template .ulp-footer-grid,
	.ulp-template .ulp-figures { grid-template-columns: minmax(0, 1fr); }

	.ulp-template .ulp-footer { padding: 48px var(--ulp-pad) 40px; }
	.ulp-template .ulp-footer-grid { gap: 32px; }
	.ulp-template .ulp-footer-base { padding-top: 48px; }

	.ulp-template .ulp-block,
	.ulp-template .ulp-solid { aspect-ratio: 4 / 3; }

	.ulp-template .ulp-row-trio .ulp-block { aspect-ratio: 1 / 1; }

	.ulp-template .ulp-block-square { aspect-ratio: 1 / 1; }
	.ulp-template .ulp-block-pano { aspect-ratio: 16 / 5; }

	/* Crops a slice off the right and bottom edges of a photograph, used where
	 * a supplied file carries a watermark in its bottom-right corner. */
	.ulp-template .ulp-crop-br { transform: scale(1.07); transform-origin: top left; }
	.ulp-template .ulp-figure { aspect-ratio: 16 / 9; }

	.ulp-template .ulp-video { left: -16.67%; width: 133.34%; }

	.ulp-template .ulp-people { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.ulp-template .ulp-awards { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
	.ulp-template .ulp-award { padding: 8px; }
	.ulp-template .ulp-index { gap: 40px; }
	.ulp-template .ulp-filters { padding-bottom: var(--ulp-row); font-size: 17px; }
	.ulp-template .ulp-story-copy { padding: 40px 0; }
}

@media (prefers-reduced-motion: reduce) {
	.ulp-template .ulp-photo,
	.ulp-template .ulp-panel,
	.ulp-template .ulp-cursor,
	.ulp-template .ulp-press,
	.ulp-template .ulp-ring,
	.ulp-template .ulp-loose,
	.ulp-template .ulp-arrowlink svg { transition: none; }
}

@media print {
	.ulp-template .ulp-cursor,
	.ulp-template .ulp-sheet { display: none; }
	.ulp-template .ulp-rail { position: static; height: auto; }
	.ulp-template .ulp-shell-body { display: block; }
}


/* ---- Image download deterrence -------------------------------------------
 * Paired with assets/js/ulp-protect.js. Stops drag-to-save, the iOS long-press
 * save sheet and image selection. The logo is left alone so it can still be
 * used for press and partner requests. */
.ulp-template img:not(.ulp-logo) {
	-webkit-user-drag: none;
	-webkit-touch-callout: none;
	user-select: none;
	-webkit-user-select: none;
}


/* ------------------------------------------------------------ section cue
 *
 * The bottom-right corner mark on any photographic block that navigates: the
 * destination section named in words, with a 45-degree arrow pointing down and
 * to the right. It sits above the hover panel so the cue survives the reveal,
 * and pulses slowly at rest so a still page reads as clickable. Pointer events
 * pass through to the link beneath it.
 */
@keyframes ulp-cue-pulse {
	0%, 100% { transform: translate(0, 0); }
	50% { transform: translate(3px, 3px); }
}

.ulp-template .ulp-block > .ulp-cue {
	position: absolute;
	right: var(--ulp-inset);
	bottom: var(--ulp-inset);
	z-index: 3;
	display: flex;
	align-items: center;
	gap: 12px;
	color: var(--ulp-white);
	pointer-events: none;
	padding: 10px 4px 6px 22px;
	background: radial-gradient(120% 180% at 100% 100%, rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0) 72%);
}

.ulp-template .ulp-cue-name {
	font-size: clamp(24px, 2.4vw, 34px);
	line-height: 1;
	letter-spacing: -0.01em;
}

/* text-shadow does not touch SVG paint, so the arrow carries its own shadow.
 * The pulse moves it and nothing else: the stroke stays at full strength, which
 * is what keeps it readable over a sunlit photograph. */
.ulp-template .ulp-cue-arrow {
	width: clamp(26px, 2.4vw, 38px);
	height: auto;
	filter: drop-shadow(0 1px 10px rgba(0, 0, 0, 0.5));
	animation: ulp-cue-pulse 2.4s ease-in-out infinite;
}

/* Against a hover panel that has already gone dark the cue would double up on
 * its own shadow, so it drops the glow once the panel is showing. */
.ulp-template .ulp-block:hover > .ulp-cue,
.ulp-template .ulp-block:focus > .ulp-cue,
.ulp-template .ulp-block:focus-visible > .ulp-cue,
.ulp-template .ulp-block:focus-within > .ulp-cue { background: none; }

/* Over a light hover panel white ink would vanish, so once the panel is
 * showing the cue takes the panel's own charcoal. The arrow's shadow goes with
 * it: on a flat pale ground there is nothing to lift the stroke off. */
.ulp-template .ulp-block:has(.ulp-panel-light):hover > .ulp-cue,
.ulp-template .ulp-block:has(.ulp-panel-light):focus > .ulp-cue,
.ulp-template .ulp-block:has(.ulp-panel-light):focus-visible > .ulp-cue,
.ulp-template .ulp-block:has(.ulp-panel-light):focus-within > .ulp-cue { color: var(--ulp-charcoal); }

.ulp-template .ulp-block:has(.ulp-panel-light):hover .ulp-cue-arrow,
.ulp-template .ulp-block:has(.ulp-panel-light):focus .ulp-cue-arrow,
.ulp-template .ulp-block:has(.ulp-panel-light):focus-visible .ulp-cue-arrow,
.ulp-template .ulp-block:has(.ulp-panel-light):focus-within .ulp-cue-arrow { filter: none; }

/* The panel's quiet bottom line shares its baseline with the cue. The cue is
 * absolutely positioned, so the line cannot see it and has to be told to keep
 * clear: it reserves the cue's own width, which is near enough fixed, rather
 * than a share of a box that shrinks. The floor keeps the line readable on a
 * mid-width tile. Below the width where both can sit on one line the cue drops
 * its label and continues as the arrow alone, which is the part that carries
 * the meaning. */
.ulp-template .ulp-block:has(> .ulp-cue) .ulp-block-meta {
	max-width: max(18ch, min(34ch, calc(100% - 300px)));
}

@container (max-width: 520px) {
	.ulp-template .ulp-cue-name { display: none; }
	.ulp-template .ulp-block:has(> .ulp-cue) .ulp-block-meta {
		max-width: min(34ch, calc(100% - 58px));
	}
}

@media (prefers-reduced-motion: reduce) {
	.ulp-template .ulp-cue-arrow { animation: none; }
}


/* ------------------------------------------------------------ onward links
 *
 * The two links that close an environment page. They borrow the footer's
 * contact-link pattern, an inline arrow that shifts on hover, so a link is
 * legible as a link without underlines or chrome, and sit in a flex row so
 * the pair reads as one set rather than two stray sentences.
 */
.ulp-template .ulp-onward {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 14px 42px;
	padding: 8px 0 0;
	list-style: none;
}

.ulp-template .ulp-onward a {
	display: inline-flex;
	align-items: baseline;
	gap: 10px;
	font-size: clamp(19px, 1.4vw, 26px);
	color: var(--ulp-black);
}

.ulp-template .ulp-onward svg {
	flex: none;
	align-self: center;
	transition: transform 220ms cubic-bezier(0.33, 1, 0.68, 1);
}

.ulp-template .ulp-onward a:hover svg { transform: translate(2px, 2px); }


/* ---------------------------------------------------------- project planner
 *
 * The shortlist control on an environment page and the planner page that
 * collects it. The add button is the one solid element on these pages, because
 * it is the only thing on them that changes state; everything else is
 * photography and copy.
 */
.ulp-template .ulp-planner-add {
	display: inline-flex;
	align-self: flex-start;
	align-items: center;
	gap: 12px;
	padding: 16px 26px;
	border: 0;
	border-radius: 7px;
	background: var(--ulp-black);
	color: var(--ulp-white);
	font: inherit;
	font-size: clamp(17px, 1.2vw, 21px);
	cursor: pointer;
	transition: background 220ms ease;
}

/* The one element on the page that grows under the cursor, because it is the
 * one element that does something. Green on hover and while it holds an
 * environment, so the state reads the same either way. */
.ulp-template .ulp-planner-add {
	transform-origin: left center;
	transition: background 220ms ease, transform 220ms cubic-bezier(0.33, 1, 0.68, 1);
}

.ulp-template .ulp-planner-add:hover,
.ulp-template .ulp-planner-add:focus-visible {
	background: var(--ulp-green);
	transform: scale(1.05);
}

.ulp-template .ulp-planner-add[aria-pressed="true"] { background: var(--ulp-green); }

@media (prefers-reduced-motion: reduce) {
	.ulp-template .ulp-planner-add:hover,
	.ulp-template .ulp-planner-add:focus-visible { transform: none; }
}

.ulp-template .ulp-planner-note {
	max-width: 46ch;
	padding-top: 14px;
	font-size: 15px;
	line-height: 1.45;
	color: var(--ulp-grey);
}

.ulp-template .ulp-planner-list {
	display: flex;
	flex-direction: column;
	gap: 2px;
	list-style: none;
	padding: 0;
}

.ulp-template .ulp-planner-item {
	display: grid;
	grid-template-columns: 132px minmax(0, 1fr) auto;
	align-items: start;
	gap: 24px;
	padding: 20px 0;
	border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}

.ulp-template .ulp-planner-thumb {
	display: block;
	aspect-ratio: 3 / 2;
	background: var(--ulp-bone);
	overflow: hidden;
}

.ulp-template .ulp-planner-thumb img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.ulp-template .ulp-planner-copy > a {
	display: inline-block;
	font-size: clamp(19px, 1.5vw, 26px);
	line-height: 1.2;
}

.ulp-template .ulp-planner-blurb {
	max-width: 60ch;
	padding-top: 8px;
	font-size: 15px;
	line-height: 1.45;
	color: var(--ulp-grey);
}

@media (max-width: 640px) {
	.ulp-template .ulp-planner-item { grid-template-columns: 96px minmax(0, 1fr); }
	.ulp-template .ulp-planner-remove { grid-column: 2; justify-self: start; }
}

.ulp-template .ulp-planner-remove {
	flex: none;
	border: 0;
	background: none;
	padding: 0;
	font: inherit;
	font-size: 15px;
	color: var(--ulp-grey);
	cursor: pointer;
}

.ulp-template .ulp-planner-remove:hover { color: var(--ulp-black); }

/* The count that rides beside a planner link. Empty until something is on the
 * shortlist, so an untouched planner shows no stray zero. */
.ulp-template [data-planner-count]:not(:empty) {
	display: inline-block;
	margin-left: 8px;
	padding: 1px 8px;
	border-radius: 999px;
	background: var(--ulp-green);
	color: var(--ulp-white);
	font-size: 13px;
	line-height: 1.6;
}

/* The intellectual-property notice that closes an environment page: present,
 * legible, and deliberately quiet. */
.ulp-template .ulp-fineprint {
	max-width: 92ch;
	padding-top: clamp(48px, 6vw, 96px);
	font-size: 13px;
	line-height: 1.55;
	color: var(--ulp-grey);
}

.ulp-template .ulp-fineprint strong {
	display: block;
	padding-bottom: 6px;
	font-weight: 500;
	color: var(--ulp-charcoal);
}


/* The planner chip is not part of the product index it sits beside, so it is
 * pushed to the far end of the chip row and kept clear of the range links. */
.ulp-template .ulp-filter-planner { margin-left: auto; }

@media (max-width: 700px) {
	.ulp-template .ulp-filter-planner { margin-left: 0; }
}


/* An environment's description and its planner button read as one unit: the
 * copy at half width on the left, the button at the top of the right column.
 * The pair is held at two columns below the width where rows normally
 * collapse, and only stacks on a phone. */
.ulp-template .ulp-row-pair-hold {
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (max-width: 1000px) {
	.ulp-template .ulp-row-pair-hold {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--ulp-gap, clamp(24px, 3vw, 44px));
	}
	.ulp-template .ulp-row-pair-hold .ulp-prose { max-width: none; }
}

@media (max-width: 640px) {
	.ulp-template .ulp-row-pair-hold { grid-template-columns: minmax(0, 1fr); }
}


/* The brief's send block. The decoy field is a spam trap: it is removed from
 * the reading order and from view, and a brief that arrives with it filled is
 * discarded server-side. */
.ulp-template .ulp-planner-send {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 14px;
	padding-top: 32px;
}

.ulp-template .ulp-planner-decoy {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
}

.ulp-template .ulp-planner-status:empty { display: none; }

.ulp-template .ulp-planner-status {
	max-width: 52ch;
	font-size: 17px;
	line-height: 1.45;
	color: var(--ulp-green);
}

.ulp-template .ulp-planner-status[data-state="error"] { color: #8c3a2a; }
.ulp-template .ulp-planner-status[data-state="working"] { color: var(--ulp-grey); }


/* ------------------------------------------------------------- page mark
 *
 * The Playform wordmark, set opposite the page title on the pages that belong
 * to the range. The title keeps its own type scale and the mark sits on the
 * far edge of the same line, so the two read as one masthead rather than a
 * logo dropped into the feed.
 */
.ulp-template .ulp-pagehead {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: clamp(24px, 4vw, 64px);
}

.ulp-template .ulp-pagehead .ulp-statement { flex: 1 1 auto; min-width: 0; }

.ulp-template .ulp-pagemark {
	flex: none;
	width: clamp(120px, 15vw, 220px);
	height: auto;
	align-self: flex-start;
	margin-top: clamp(6px, 1vw, 18px);
}

@media (max-width: 700px) {
	.ulp-template .ulp-pagehead { flex-direction: column; }
	.ulp-template .ulp-pagemark { width: 140px; margin-top: 0; }
}


.ulp-template a.ulp-pagemark-link {
	flex: none;
	display: block;
	align-self: flex-start;
	margin-top: clamp(6px, 1vw, 18px);
	line-height: 0;
	border: 0;
	opacity: 1;
	transition: opacity 160ms ease;
}

.ulp-template a.ulp-pagemark-link:hover { opacity: 0.6; }
.ulp-template a.ulp-pagemark-link .ulp-pagemark { margin-top: 0; }


.ulp-template a.ulp-filter-lead {
	text-decoration: none;
	color: inherit;
	border: 0;
	transition: opacity 160ms ease;
}

.ulp-template a.ulp-filter-lead:hover { opacity: 0.55; }


/* The Playform pathway is also the way into the range, so that one cell is an
 * anchor rather than a static panel. It keeps the panel's own type colour and
 * loses the underline a link would otherwise carry. */
.ulp-template a.ulp-pathway,
.ulp-template a.ulp-pathway .ulp-pathway-copy {
	color: var(--ulp-charcoal);
	text-decoration: none;
}


.ulp-template .ulp-pathway > .ulp-cue {
	position: absolute;
	right: var(--ulp-inset);
	bottom: var(--ulp-inset);
	z-index: 3;
	display: flex;
	align-items: center;
	gap: 12px;
	color: var(--ulp-charcoal);
	pointer-events: none;
	background: none;
}

.ulp-template .ulp-pathway > .ulp-cue .ulp-cue-name { font-size: clamp(19px, 1.5vw, 24px); }
.ulp-template .ulp-pathway > .ulp-cue .ulp-cue-arrow { filter: none; }

/* Footer invitation. The invitation itself is the control: pressing it opens
 * the two ways to make contact just beneath, so a resting page carries only
 * the invitation. */
.ulp-template .ulp-footer-ask {
	position: relative;
}

.ulp-template .ulp-footer-trigger {
	font: inherit;
	color: inherit;
	letter-spacing: inherit;
	text-align: left;
	background: none;
	border: 0;
	margin: 0;
	padding: 0;
	cursor: pointer;
}

.ulp-template .ulp-footer-trigger:hover,
.ulp-template .ulp-footer-trigger[aria-expanded="true"] {
	opacity: 0.62;
}

.ulp-template .ulp-footer-ways {
	list-style: none;
	margin: 22px 0 0;
	padding: 0;
	display: grid;
	gap: 10px;
	justify-items: start;
}

.ulp-template .ulp-footer-ways[hidden] {
	display: none;
}

.ulp-template .ulp-footer-ways a {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	font-size: 1.05rem;
	text-decoration: none;
	color: var(--ulp-ink, #111);
}

.ulp-template .ulp-footer-ways a:hover {
	opacity: 0.62;
}


/*
 * CHILDCARE GUIDE — PRE-DOWNLOAD PREVIEW
 *
 * The guide is gated, so the page has to earn the email address before it asks
 * for it. Four pages of the document — cover, contents, foreword and one
 * interior page — are reproduced here from the guide's own source at A4
 * proportions, then scaled to fit the column: what the visitor previews is the
 * document they receive, not an approximation of it. The sheets are inert.
 */
/* The pages sit in a flick book in the left column, with the request beside
 * them: one page is shown at a time and the others wait behind it, so the
 * preview never grows into a wall of sheets. */
.ulp-template .ulp-guide-layout {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(28px, 3.4vw, 64px);
	align-items: start;
	padding-top: clamp(28px, 3vw, 52px);
}

/* The book is capped at the width its photography can carry: the guide's own
 * full-bleed images are 1200px on the long edge, so a sheet wider than this
 * would upscale them and the photographic pages would go soft beside the crisp
 * text ones. It also keeps the sheet a readable page rather than a poster when
 * the columns stack. */
/* A card that links to the guide shows the document itself — cover and index
 * side by side — rather than a photograph of a playground. The ground is the
 * site's own light paper so the pages read as pages; the tile's caption panel
 * covers the whole tile on hover, so no foot room is needed. */
.ulp-template .ulp-photo-doc {
	object-fit: cover;
	object-position: center;
	background: #f2f2f0;
}

.ulp-template .ulp-guide-flick { max-width: 620px; }

.ulp-template .ulp-guide-flick-frame {
	position: relative;
	width: 100%;
	aspect-ratio: 210 / 297;
}

.ulp-template .ulp-guide-flick-frame .ulp-guide-sheet {
	position: absolute;
	inset: 0;
	aspect-ratio: auto;
	opacity: 0;
	visibility: hidden;
	transition: opacity 320ms ease;
}

.ulp-template .ulp-guide-flick-frame .ulp-guide-sheet[data-shown] { opacity: 1; visibility: visible; }

/* The page turns where a reader would reach for it: a click anywhere down the
 * left or right edge of the sheet. The cue only appears on hover, so a still
 * page stays a page. */
.ulp-template .ulp-guide-turn {
	position: absolute;
	top: 0;
	bottom: 0;
	width: 26%;
	display: flex;
	align-items: flex-end;
	padding: 0 0 26px;
	border: 0;
	background: none;
	cursor: pointer;
	opacity: 0;
	transition: opacity 220ms ease;
	z-index: 2;
}

.ulp-template .ulp-guide-turn-back { left: 0; justify-content: flex-start; }
.ulp-template .ulp-guide-turn-next { right: 0; justify-content: flex-end; }

.ulp-template .ulp-guide-turn:hover,
.ulp-template .ulp-guide-turn:focus-visible { opacity: 1; }

.ulp-template .ulp-guide-turn span {
	display: inline-block;
	margin: 0 22px;
	padding: 9px 16px;
	border-radius: 999px;
	background: rgba(17, 17, 17, 0.82);
	color: #fff;
	font-size: 12px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.ulp-template .ulp-guide-flick-bar {
	display: flex;
	align-items: center;
	gap: 18px;
	padding-top: 20px;
}

.ulp-template .ulp-guide-flick-step {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	border: 1px solid rgba(17, 17, 17, 0.18);
	border-radius: 50%;
	background: transparent;
	color: var(--ulp-charcoal);
	cursor: pointer;
	transition: background 200ms ease, color 200ms ease, border-color 200ms ease;
}

.ulp-template .ulp-guide-flick-step:hover,
.ulp-template .ulp-guide-flick-step:focus-visible {
	background: var(--ulp-charcoal);
	border-color: var(--ulp-charcoal);
	color: #fff;
}

.ulp-template .ulp-guide-flick-label {
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

.ulp-template .ulp-guide-flick .ulp-guide-meta { padding-top: 14px; }

.ulp-template .ulp-guide-sheet {
	position: relative;
	margin: 0;
	width: 100%;
	aspect-ratio: 210 / 297;
	overflow: hidden;
	border-radius: 4px;
	background: #fff;
	box-shadow: 0 24px 60px rgba(17, 17, 17, 0.12);
	user-select: none;
	pointer-events: none;
}

/* The page is laid out at its true A4 size and then scaled, so every measure in
 * the document — type size, margins, the mm grid — holds its proportion. The
 * scale factor is set by ulp-guide.js against the sheet's measured width. */
.ulp-template .ulp-guide-sheet-page {
	position: absolute;
	top: 0;
	left: 0;
	width: 210mm;
	height: 297mm;
	transform-origin: top left;
	transform: scale(var(--ulp-sheet-scale, 0.5));
}

.ulp-template .ulp-guide-sheet-face { width: 210mm; height: 297mm; }

.ulp-template .ulp-guide-meta {
	padding-top: 18px;
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

/* The form always stays on the page. An accepted request adds the download
 * below it rather than replacing it, so the fields are never missing — the
 * next person at the same desk can request their own copy. */
.ulp-template .ulp-guide-gate { display: flex; flex-direction: column; gap: 26px; }

.ulp-template .ulp-guide-done { display: grid; gap: 22px; justify-items: start; }

.ulp-template .ulp-guide-again {
	padding: 0;
	border: 0;
	background: none;
	font-size: 17px;
	color: var(--ulp-grey);
	text-decoration: underline;
	text-underline-offset: 4px;
	cursor: pointer;
}

.ulp-template .ulp-guide-again:hover,
.ulp-template .ulp-guide-again:focus-visible { color: var(--ulp-charcoal); }

@media (max-width: 1000px) {
	.ulp-template .ulp-guide-layout { grid-template-columns: minmax(0, 1fr); }
}

/* ------------------------------------------------------------------ chat
 *
 * The launcher is an outline mark on the page's own surface rather than a
 * filled bubble: a hairline circle and a stroked speech mark, which is the
 * same drawing weight the cues and arrows elsewhere use. The panel opens above
 * it on the bone surface with a hairline edge, so it reads as a card of the
 * site rather than as a third-party widget dropped on top.
 */

.ulp-template .ulp-chat {
	position: fixed;
	right: clamp(18px, 2.4vw, 42px);
	bottom: clamp(18px, 2.4vw, 42px);
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 14px;
	z-index: 60;
}

/* The launcher is the speech mark itself: a small white bubble with a hairline
 * edge, no circle around it. The word comes up beside it on hover, so at rest
 * the corner holds one small drawing. */
.ulp-template .ulp-chat-launcher {
	position: relative;
	display: block;
	padding: 0;
	border: 0;
	border-radius: 0;
	background: none;
	color: var(--ulp-charcoal);
	cursor: pointer;
}

.ulp-template .ulp-chat-launcher svg {
	display: block;
	width: 62px;
	height: 53px;
	transition: transform 240ms ease;
}

/* Out of flow, so at rest the button is the bubble and nothing else: a flex
 * child at zero opacity would still carry width and a hit area over the page
 * beside it. */
.ulp-template .ulp-chat-word {
	position: absolute;
	top: 50%;
	right: calc(100% + 12px);
	transform: translate(6px, -50%);
	white-space: nowrap;
	font-size: 17px;
	letter-spacing: 0.02em;
	color: var(--ulp-charcoal);
	opacity: 0;
	pointer-events: none;
	transition: opacity 240ms ease, transform 240ms ease;
}

.ulp-template .ulp-chat-launcher:hover .ulp-chat-word,
.ulp-template .ulp-chat-launcher:focus-visible .ulp-chat-word {
	opacity: 1;
	transform: translate(0, -50%);
}

.ulp-template .ulp-chat-launcher:hover svg { transform: translateY(-2px); }

.ulp-template .ulp-chat-launcher:focus-visible { outline: 2px solid currentColor; outline-offset: 6px; }

/* Closed the panel is out of the way and out of the tab order; open it takes
 * its place above the launcher. */
.ulp-template .ulp-chat-panel {
	width: min(360px, calc(100vw - 36px));
	padding: 26px;
	border: 1px solid rgba(0, 0, 0, 0.16);
	background: var(--ulp-bone);
	opacity: 0;
	visibility: hidden;
	transform: translateY(8px);
	transition: opacity 240ms ease, transform 240ms ease, visibility 240ms;
}

.ulp-template .ulp-chat[data-open="true"] .ulp-chat-panel {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.ulp-template .ulp-chat-eyebrow {
	margin: 0;
	font-size: 12px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

.ulp-template .ulp-chat-lead {
	margin: 12px 0 20px;
	font-size: 17px;
	line-height: 1.45;
	color: var(--ulp-black);
}

.ulp-template .ulp-chat-form { display: flex; flex-direction: column; }

.ulp-template .ulp-chat-label {
	margin-bottom: 6px;
	font-size: 12px;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

.ulp-template .ulp-chat-input {
	margin-bottom: 16px;
	padding: 11px 12px;
	border: 1px solid rgba(0, 0, 0, 0.28);
	border-radius: 0;
	background: var(--ulp-white);
	color: inherit;
	font-family: inherit;
	font-size: 16px;
	appearance: none;
}

.ulp-template .ulp-chat-input:focus-visible { outline: 0; border-color: var(--ulp-black); }

.ulp-template .ulp-chat-textarea { resize: vertical; min-height: 84px; line-height: 1.45; }

/* A field only a machine fills in. */
.ulp-template .ulp-chat-trap {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip-path: inset(50%);
}

.ulp-template .ulp-chat-send {
	padding: 13px 18px;
	border: 1px solid var(--ulp-black);
	background: var(--ulp-black);
	color: var(--ulp-white);
	font-family: inherit;
	font-size: 15px;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	cursor: pointer;
	transition: background-color 220ms ease, color 220ms ease;
}

.ulp-template .ulp-chat-send:hover { background: var(--ulp-white); color: var(--ulp-black); }

.ulp-template .ulp-chat-send:disabled { opacity: 0.5; cursor: default; }

.ulp-template .ulp-chat-status {
	margin: 12px 0 0;
	font-size: 14px;
	line-height: 1.45;
	color: var(--ulp-grey);
}

.ulp-template .ulp-chat-status:empty { display: none; }

.ulp-template .ulp-chat-status[data-state="error"] { color: var(--ulp-black); }

.ulp-template .ulp-chat-sent p {
	margin: 0 0 10px;
	font-size: 16px;
	line-height: 1.5;
}

.ulp-template .ulp-chat-sent p:last-child { margin-bottom: 0; color: var(--ulp-grey); }

.ulp-template .ulp-chat-sent a { color: inherit; }

/* The custom cursor is hidden over the panel, so the fields behave like
 * fields. */
@media (hover: none) {
	.ulp-template .ulp-chat { gap: 10px; }
}

@media (prefers-reduced-motion: reduce) {
	.ulp-template .ulp-chat-panel,
	.ulp-template .ulp-chat-launcher { transition: none; }
}

/* Go High Level's chat widget carries the conversation and its own launcher
 * opens it, wearing ULP's mark and colour. ULP's bubble is only the corner's
 * placeholder while the widget loads, and while the widget is missing it
 * becomes a link to the enquiry form; once the widget mounts, ulp-chat.js
 * marks the root native and this rule takes ULP's bubble out of the corner. */
.ulp-template .ulp-chat[data-mode="native"] { display: none; }

/* A dated list of past work, one year to a row: the year holds a column of its
 * own so the years read down the page, with the organisation and what was done
 * beside it. Used by the Projects From the Heart timeline. */
.ulp-template .ulp-years {
	margin: 42px 0 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid rgba(0, 0, 0, 0.12);
}

.ulp-template .ulp-years > li { border-bottom: 1px solid rgba(0, 0, 0, 0.12); }

/* At rest a row is the year and the organisation, nothing more: the timeline
 * reads as a list of fifteen years rather than as a wall of paragraphs. What
 * was done opens under the row on click. */
.ulp-template .ulp-year-item > summary,
.ulp-template .ulp-year-plain {
	display: grid;
	grid-template-columns: 120px minmax(0, 1fr) 24px;
	gap: 24px;
	align-items: baseline;
	padding: 21px 0;
	list-style: none;
}

.ulp-template .ulp-year-item > summary { cursor: pointer; }
.ulp-template .ulp-year-item > summary::-webkit-details-marker { display: none; }

.ulp-template .ulp-year-item > summary:focus-visible { outline: 2px solid currentColor; outline-offset: -4px; }

/* A quiet plus that becomes a minus, in the row's third column. */
.ulp-template .ulp-year-item > summary::after {
	content: "+";
	justify-self: end;
	font-size: 21px;
	line-height: 1;
	color: var(--ulp-grey);
}

.ulp-template .ulp-year-item[open] > summary::after { content: "\2013"; }

.ulp-template .ulp-year {
	font-size: 17px;
	letter-spacing: 0.04em;
	color: var(--ulp-grey);
}

.ulp-template .ulp-year-name {
	font-size: 19px;
	line-height: 1.4;
	max-width: 52ch;
}

.ulp-template .ulp-year-note {
	margin: 0;
	padding: 0 24px 24px calc(120px + 24px);
	max-width: 62ch;
	font-size: 19px;
	line-height: 1.5;
	color: var(--ulp-grey);
}

/* A third-level heading inside a cell, used for the named causes. */
.ulp-template .ulp-h3 {
	margin: 0;
	/* Held above .ulp-prose, which reaches 30px on a wide screen, and below
	 * .ulp-h2 at 34px, so the three levels read in order at every width. */
	font-size: clamp(21px, 1.8vw, 32px);
	font-weight: 400;
	line-height: 1.2;
	letter-spacing: -0.01em;
}

@media (max-width: 700px) {
	.ulp-template .ulp-year-item > summary,
	.ulp-template .ulp-year-plain { grid-template-columns: 78px minmax(0, 1fr) 20px; gap: 14px; }
	.ulp-template .ulp-year-note { padding-left: 92px; }
}

/* The line of facts under a role's title: where, what type, whether it is open. */
.ulp-template .ulp-role-meta {
	margin: 10px 0 0;
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

/* Career pathways: the same open-on-click row as the timeline, but here the
 * role is the primary label and the sentence beside it the elaboration, so the
 * emphasis is the other way round and the label column sizes to the longest
 * role rather than to a year. */
.ulp-template .ulp-paths {
	margin: 42px 0 0;
	padding: 0;
	list-style: none;
	border-top: 1px solid rgba(0, 0, 0, 0.12);
}

.ulp-template .ulp-paths > li { border-bottom: 1px solid rgba(0, 0, 0, 0.12); }

.ulp-template .ulp-path-item > summary {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 24px;
	gap: 24px;
	align-items: baseline;
	padding: 21px 0;
	cursor: pointer;
	list-style: none;
}

.ulp-template .ulp-path-item > summary::-webkit-details-marker { display: none; }
.ulp-template .ulp-path-item > summary:focus-visible { outline: 2px solid currentColor; outline-offset: -4px; }

/* Name and lead share the first column, one under the other; the marker keeps
 * the narrow second column to itself. */
.ulp-template .ulp-path-item > summary > * { grid-column: 1; }

.ulp-template .ulp-path-item > summary::after {
	content: "+";
	grid-area: 1 / 2;
	justify-self: end;
	font-size: 21px;
	line-height: 1;
	color: var(--ulp-grey);
}

.ulp-template .ulp-path-item[open] > summary::after { content: "\2013"; }

.ulp-template .ulp-path-name {
	display: block;
	font-size: clamp(21px, 1.5vw, 27px);
	line-height: 1.2;
	letter-spacing: -0.01em;
}

.ulp-template .ulp-path-lead {
	display: block;
	padding-top: 6px;
	font-size: 19px;
	line-height: 1.4;
	color: var(--ulp-grey);
}

.ulp-template .ulp-path-note {
	margin: 0;
	padding: 0 48px 24px 0;
	max-width: 62ch;
	font-size: 19px;
	line-height: 1.5;
}

/* A strip of team photographs, sized to the row and scrolled sideways rather
 * than stacked: seven images at a glance. */
/* Seven marks in a row. The feed's 4% gutter was sized for photographs and
 * left them floating apart, so the row takes a gap of its own, keeps the marks
 * to a readable size and sits centred rather than stretched across the column. */
.ulp-template .ulp-teamstrip {
	display: grid;
	grid-template-columns: repeat(7, minmax(0, 1fr));
	gap: clamp(10px, 1.1vw, 22px);
	margin: 0;
	padding: 0;
	list-style: none;
}

/* The files are 411 x 245, so the cell takes that proportion and the artwork
 * is shown whole: forced into a square and cropped to fill, each one lost
 * about 40% of its width. */
/* Seven equal cells across the column, each filled by its image, so the row
 * reads as one continuous band rather than as seven floating pictures. */
.ulp-template .ulp-teamstrip img {
	display: block;
	width: 100%;
	aspect-ratio: 411 / 245;
	height: auto;
	object-fit: cover;
	background: var(--ulp-bone);
}

@media (max-width: 700px) {
	.ulp-template .ulp-teamstrip { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}



/* Shows a photograph whole inside its frame rather than cropping it to fill:
 * used where the subject runs to the edges of the file and any crop would cut
 * someone out. */
.ulp-template .ulp-photo-whole {
	object-fit: contain;
	background: var(--ulp-bone);
}

/* A frame with no surface of its own, for a photograph shown whole where the
 * page's white should carry it rather than the usual bone panel. */
.ulp-template .ulp-block-bare { background: transparent; }
.ulp-template .ulp-block-bare .ulp-photo-whole { background: transparent; }

/* The team photograph closing a page: cropped at the waist and sat flush on the
 * footer, so the group reads as standing behind it rather than as another
 * framed image. */
/* Flush on the footer: rather than guessing a negative margin against the main
 * column's responsive foot padding, the page that closes on a photograph drops
 * that padding altogether. */
.ulp-template .ulp-main-flush { padding-bottom: 0; }

/* The flush treatment keyed on a class the old Careers template put on <main>.
 * The imported template renders a generic <main>, so the class went and the
 * page's closing padding came back: the group photograph floated in white
 * instead of standing against the footer. Keyed on the row itself now, so it
 * holds however the page is rendered. */
.ulp-template .ulp-main:has(.ulp-standin-row) { padding-bottom: 0; }

.ulp-template .ulp-standin-row {
	padding-bottom: 0;
	margin-bottom: 0;
}

/* The footer paints over the photograph's lower edge, which is what makes the
 * group read as standing behind it. */
.ulp-template .ulp-footer { position: relative; z-index: 1; }

/* The file is a 10:1 panorama of the team, already cut at the waist, so the
 * frame takes the image's own proportion and shows it whole at full width
 * rather than cropping into the middle third of it. */
.ulp-template .ulp-standin {
	aspect-ratio: 2560 / 254;
	overflow: hidden;
	background: transparent;
}

.ulp-template .ulp-standin img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: 50% 0;
}

/* The coloured hover exchange, on the white pages too: until now every rule
 * that changed a note's surface was scoped to the green field, so panels on a
 * white page revealed their copy without the colour that goes with it. */
.ulp-template .ulp-note:hover,
.ulp-template .ulp-note:focus-within { background: var(--ulp-sand); }

.ulp-template .ulp-note[data-reveal="bone"]:hover,
.ulp-template .ulp-note[data-reveal="bone"]:focus-within { background: var(--ulp-bone); }

.ulp-template .ulp-note[data-reveal="ink"]:hover,
.ulp-template .ulp-note[data-reveal="ink"]:focus-within {
	background: var(--ulp-charcoal);
	color: var(--ulp-white);
}

.ulp-template .ulp-note[data-reveal="ink"]:hover .ulp-note-title,
.ulp-template .ulp-note[data-reveal="ink"]:focus-within .ulp-note-title { color: var(--ulp-white); }

.ulp-template .ulp-note[data-reveal="ink"]:hover .ulp-note-body,
.ulp-template .ulp-note[data-reveal="ink"]:focus-within .ulp-note-body { color: rgba(255, 255, 255, 0.86); }

/* A note that carries only a title and a paragraph has nothing to fill a
 * square with, so it takes its height from its content instead. */
.ulp-template .ulp-note-flat::before { content: none; }
.ulp-template .ulp-note-flat { min-height: clamp(200px, 18vw, 280px); }

/* The position title held in the corner of the card, so the roles can be read
 * without hovering each one. It sits above the panel, and the panel's own
 * title is set smaller than usual because the tag has already named the role. */
/* The position title, set as the cue at the other corner is set: white text
 * straight on the photograph at the same size, with no tag around it. */
.ulp-template .ulp-role-tag {
	position: absolute;
	top: var(--ulp-inset);
	left: var(--ulp-inset);
	z-index: 2;
	max-width: calc(100% - (var(--ulp-inset) * 2));
	color: var(--ulp-white);
	font-size: clamp(24px, 2.4vw, 34px);
	line-height: 1.05;
	letter-spacing: -0.01em;
	pointer-events: none;
}

/* The photographs are light, so they are held back a little to carry the white
 * title and the cue. */
.ulp-template .ulp-block:has(.ulp-role-tag) .ulp-photo { filter: brightness(0.68); }

/* The corner title stays put while the panel opens, so the panel's own copy
 * starts below it rather than under it. */
.ulp-template .ulp-block:has(.ulp-role-tag) .ulp-panel { padding-top: calc(var(--ulp-inset) + clamp(38px, 3.4vw, 52px)); }

/* Over a light hover panel white ink would vanish, so the corner title takes
 * the panel's own ink once the panel is up, the same exchange the cue makes. */
.ulp-template .ulp-block:has(.ulp-panel-light):hover .ulp-role-tag,
.ulp-template .ulp-block:has(.ulp-panel-light):focus .ulp-role-tag,
.ulp-template .ulp-block:has(.ulp-panel-light):focus-visible .ulp-role-tag,
.ulp-template .ulp-block:has(.ulp-panel-light):focus-within .ulp-role-tag { color: var(--ulp-charcoal); }

/* A short label over a list, so two lists in a row start on the same line
 * without one of them borrowing a section heading to do it. */
.ulp-template .ulp-list-lead {
	margin: 0 0 21px;
	padding-bottom: 14px;
	border-bottom: 1px solid rgba(0, 0, 0, 0.14);
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

/* A note used as one of six cards in a run is not the featured panel the About
 * page notes are, so its title sits at the section-heading scale instead of
 * above it. */
.ulp-template .ulp-note-flat .ulp-note-title { font-size: clamp(24px, 2vw, 34px); }

/* The onward line held in the foot of a panel that is itself a link: set like
 * the onward links elsewhere, and shown at rest rather than on hover so the
 * destination is readable without reaching for the card. */
.ulp-template .ulp-note-cue {
	position: absolute;
	left: var(--ulp-inset);
	bottom: var(--ulp-inset);
	display: inline-flex;
	align-items: center;
	gap: 10px;
	font-size: 19px;
	line-height: 1.2;
}

.ulp-template .ulp-note:has(.ulp-note-cue) { padding-bottom: calc(var(--ulp-inset) * 2.6); }

/* The same three grounds on the panels that carry a title and a description,
 * so a run of cards can be told apart by colour as well as by name. */
.ulp-template .ulp-note[data-reveal="terracotta"]:hover,
.ulp-template .ulp-note[data-reveal="terracotta"]:focus-within { background: var(--ulp-terracotta); color: var(--ulp-white); }

.ulp-template .ulp-note[data-reveal="slate"]:hover,
.ulp-template .ulp-note[data-reveal="slate"]:focus-within { background: var(--ulp-slate); color: var(--ulp-white); }

.ulp-template .ulp-note[data-reveal="teal"]:hover,
.ulp-template .ulp-note[data-reveal="teal"]:focus-within { background: var(--ulp-teal); color: var(--ulp-white); }

.ulp-template .ulp-note[data-reveal="terracotta"]:hover .ulp-note-title,
.ulp-template .ulp-note[data-reveal="terracotta"]:focus-within .ulp-note-title,
.ulp-template .ulp-note[data-reveal="slate"]:hover .ulp-note-title,
.ulp-template .ulp-note[data-reveal="slate"]:focus-within .ulp-note-title,
.ulp-template .ulp-note[data-reveal="teal"]:hover .ulp-note-title,
.ulp-template .ulp-note[data-reveal="teal"]:focus-within .ulp-note-title { color: var(--ulp-white); }

.ulp-template .ulp-note[data-reveal="terracotta"]:hover .ulp-note-body,
.ulp-template .ulp-note[data-reveal="terracotta"]:focus-within .ulp-note-body,
.ulp-template .ulp-note[data-reveal="slate"]:hover .ulp-note-body,
.ulp-template .ulp-note[data-reveal="slate"]:focus-within .ulp-note-body,
.ulp-template .ulp-note[data-reveal="teal"]:hover .ulp-note-body,
.ulp-template .ulp-note[data-reveal="teal"]:focus-within .ulp-note-body { color: rgba(255, 255, 255, 0.86); }

/* On the colour field the same three take precedence over the field's own
 * exchange, so a card behaves the same on either ground. */
.ulp-template.ulp-field .ulp-note[data-reveal="terracotta"]:hover,
.ulp-template.ulp-field .ulp-note[data-reveal="terracotta"]:focus-within { background: var(--ulp-terracotta); }

.ulp-template.ulp-field .ulp-note[data-reveal="slate"]:hover,
.ulp-template.ulp-field .ulp-note[data-reveal="slate"]:focus-within { background: var(--ulp-slate); }

.ulp-template.ulp-field .ulp-note[data-reveal="teal"]:hover,
.ulp-template.ulp-field .ulp-note[data-reveal="teal"]:focus-within { background: var(--ulp-teal); }

/* A portrait shot wider than the rest of the set: scaled up inside its own
 * frame so the head sits at the same size as the others. */
.ulp-template .ulp-person-tight {
	transform: scale(1.22);
	transform-origin: 50% 22%;
}

/* A placeholder set below the feature cards rather than beside them: shallower
 * than a full frame so it reads as a smaller slot awaiting content. */
.ulp-template .ulp-block-slot-sm { aspect-ratio: 21 / 9; }

/* The knowledge search where it stands in the feed rather than in a filter
 * row: a full-width field with its label shown, since here it is the whole
 * point of the section rather than a control beside a list. */
.ulp-template .ulp-search-wide {
	position: static;
	display: block;
	margin-top: 34px;
	max-width: none;
}

/* The label says the same thing as the field's own prompt, so it is left for
 * screen readers only rather than printed above the field. */

.ulp-template .ulp-search-wide .ulp-search-box {
	display: flex;
	align-items: center;
	gap: 12px;
	width: 100%;
	padding: 16px 18px;
	border: 1px solid currentColor;
	background: rgba(0, 0, 0, 0.04);
}

.ulp-template .ulp-search-wide .ulp-search-field {
	flex: 1;
	min-width: 0;
	font-size: 19px;
}

.ulp-template .ulp-search-wide .ulp-search-status {
	margin: 14px 0 0;
	font-size: 15px;
	color: var(--ulp-grey);
}

.ulp-template .ulp-search-wide .ulp-search-results {
	position: static;
	margin: 14px 0 0;
	padding: 0;
	list-style: none;
	border: 0;
	background: none;
	box-shadow: none;
}

.ulp-template .ulp-search-wide .ulp-search-results:empty { display: none; }

.ulp-template .ulp-search-wide .ulp-search-results a {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 18px;
	padding: 14px 0;
	border-bottom: 1px solid rgba(0, 0, 0, 0.12);
	font-size: 19px;
	text-decoration: none;
}

.ulp-template .ulp-search-wide .ulp-search-results a:hover .ulp-search-name { text-decoration: underline; }

.ulp-template .ulp-search-wide .ulp-search-where {
	flex: none;
	font-size: 13px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

/* A long list of questions read as a set rather than as a row of onward links:
 * a two-column grid, so items align into columns and rows instead of packing
 * raggedly the way a wrapping flex row does. Each row is a rule, so the eye
 * can follow a line across. */
.ulp-template .ulp-onward-grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	column-gap: 42px;
	row-gap: 0;
}

.ulp-template .ulp-onward-grid > li {
	padding: 14px 0;
	border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}

@media (max-width: 900px) {
	.ulp-template .ulp-onward-grid { grid-template-columns: minmax(0, 1fr); }
}

/* A comparison table inside an article: ruled rows and a ruled head, no cell
 * borders or fills, so it reads as part of the page rather than as a widget.
 * Scrolls sideways on a narrow screen rather than crushing its columns. */
.ulp-template .ulp-table {
	display: block;
	overflow-x: auto;
	width: 100%;
	margin: 34px 0 0;
	border-collapse: collapse;
	font-size: 17px;
	line-height: 1.5;
}

.ulp-template .ulp-table thead th {
	padding: 0 24px 12px 0;
	border-bottom: 1px solid currentColor;
	text-align: left;
	font-weight: 400;
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
	white-space: nowrap;
}

.ulp-template .ulp-table tbody th,
.ulp-template .ulp-table tbody td {
	padding: 16px 24px 16px 0;
	border-bottom: 1px solid rgba(0, 0, 0, 0.12);
	text-align: left;
	vertical-align: top;
}

.ulp-template .ulp-table tbody th {
	font-weight: 400;
	color: var(--ulp-charcoal);
	min-width: 160px;
}

.ulp-template .ulp-table tbody td { color: var(--ulp-grey); }

/* A paragraph that follows a list, rather than another paragraph, takes the
 * same separation: the adjacent-sibling prose rule cannot match across a list,
 * so the two would otherwise touch. */
.ulp-template .ulp-creds + .ulp-prose,
.ulp-template .ulp-creds + .ulp-fineprint,
.ulp-template .ulp-table + .ulp-prose { margin-top: 1.2em; }

/* A named external source inside an article: set as a directive line rather
 * than a paragraph, so the reader can see where to go next. Becomes an ordinary
 * link once its address is set. */
.ulp-template .ulp-source-link {
	margin: 21px 0 0;
	padding-top: 18px;
	border-top: 1px solid rgba(0, 0, 0, 0.12);
	/* Above .ulp-prose at every width, the way .ulp-h3 is: this line is the
	 * point of the section, not a footnote to it. */
	font-size: clamp(21px, 1.8vw, 32px);
	line-height: 1.25;
	color: var(--ulp-charcoal);
}

.ulp-template .ulp-source-link a {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	text-decoration: underline;
	text-underline-offset: 4px;
	text-decoration-thickness: 1px;
}

.ulp-template .ulp-source-link a:hover { text-decoration-thickness: 2px; }

/* The platform marks inside the panel, at the site's icon weight. Repeated in
 * the touch caption, because the panel itself is not shown on touch. */
.ulp-template .ulp-social-marks {
	display: flex;
	gap: 21px;
	padding-top: 21px;
}

.ulp-template .ulp-social-marks a {
	display: inline-flex;
	transition: opacity 220ms ease;
}

.ulp-template .ulp-social-marks a:hover { opacity: 0.62; }

.ulp-template .ulp-social-marks a:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }


/* The description and the platform marks as one panel child: the panel
 * distributes with space-between, so a third child would be pushed to the foot
 * away from the copy it belongs to. */
.ulp-template .ulp-social-block {
	display: flex;
	flex-direction: column;
}


/* The platform marks at the foot of a panel that carries a feed above them.
 * They take the panel's own ink rather than a fixed colour, so they are white
 * on the green field at rest and charcoal once the panel turns to bone. */
.ulp-template .ulp-note .ulp-social-marks { padding: 24px 0; }

/* The feed sits on the panel's foot, level with the award rail in the card
 * beside it. */
.ulp-template .ulp-note .ulp-feedgrid { margin-top: auto; }

.ulp-template .ulp-note .ulp-social-marks a { color: inherit; }


/* ================================================== enquiry form
 *
 * Two nested disclosures. A page at rest shows one line, "Tell us about your
 * space"; opening it reveals the fields; inside that, a second control reveals
 * the optional planning questions. Nothing opens itself.
 *
 * Everything here is scoped under .ulp-form so the theme's own form rules
 * cannot reach in, and every value is one of the site's own: the same type
 * scale as the editorial pages, the same charcoal and grey, and the three
 * secondary grounds used sparingly to mark the three question groups.
 */

.ulp-template .ulp-enquiry-form {
	max-width: 62rem;
	container-type: inline-size;
	container-name: ulpform;
}

/* --- the two disclosure controls --- */

.ulp-template .ulp-disclose {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 24px;
	width: 100%;
	padding: 21px 0;
	border: 0;
	border-top: 1px solid var(--ulp-charcoal);
	border-bottom: 1px solid rgba(0, 0, 0, 0.14);
	background: transparent;
	color: inherit;
	font: inherit;
	text-align: left;
	cursor: pointer;
}

.ulp-template .ulp-disclose:focus-visible { outline: 2px solid currentColor; outline-offset: 3px; }

.ulp-template .ulp-disclose-label {
	display: flex;
	flex-direction: column;
	gap: 4px;
	min-width: 0;
}

.ulp-template .ulp-disclose-kicker {
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-terracotta);
}

.ulp-template .ulp-disclose-title {
	font-size: clamp(21px, 1.7vw, 30px);
	line-height: 1.15;
	letter-spacing: -0.01em;
	text-wrap: pretty;
}

/* A plus that becomes a minus, drawn rather than set, so it lines up with the
 * type at every size. */
.ulp-template .ulp-disclose-mark {
	position: relative;
	flex: 0 0 auto;
	width: 22px;
	height: 22px;
	align-self: center;
}

.ulp-template .ulp-disclose-mark::before,
.ulp-template .ulp-disclose-mark::after {
	content: "";
	position: absolute;
	top: 50%;
	left: 0;
	width: 100%;
	height: 1px;
	background: currentColor;
	transition: transform 240ms cubic-bezier(0.33, 1, 0.68, 1);
}

.ulp-template .ulp-disclose-mark::after { transform: rotate(90deg); }
.ulp-template .ulp-disclose[aria-expanded="true"] .ulp-disclose-mark::after { transform: rotate(0deg); }

/* The nested control is a step quieter than the one above it. */
.ulp-template .ulp-disclose-sub {
	border-top: 1px solid rgba(0, 0, 0, 0.14);
	padding: 18px 0;
}

.ulp-template .ulp-disclose-sub .ulp-disclose-title { font-size: clamp(19px, 1.4vw, 24px); }

.ulp-template .ulp-disclose-note {
	margin: 14px 0 0;
	max-width: 68ch;
	font-size: 15px;
	line-height: 1.5;
	color: var(--ulp-grey);
	text-wrap: pretty;
}

.ulp-template .ulp-basic { padding-top: 28px; }
.ulp-template .ulp-detail { margin-top: 48px; }
.ulp-template .ulp-detail-body { padding-top: 28px; }

/* --- fields --- */

.ulp-template .ulp-required-note {
	margin: 0 0 24px;
	font-size: 15px;
	line-height: 1.5;
	color: var(--ulp-grey);
}

/* Two fields to a row where there is room, so the basic form is four rows
 * rather than eight. */
.ulp-template .ulp-fieldpair {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 0 24px;
}

.ulp-template .ulp-form .ulp-formrow { margin: 0 0 34px; }

.ulp-template .ulp-form .ulp-formrow > label {
	display: block;
	margin-bottom: 10px;
	font-size: 17px;
	line-height: 1.35;
	color: var(--ulp-charcoal);
}

.ulp-template .ulp-optional {
	font-size: 12px;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--ulp-slate);
}

.ulp-template .ulp-formhelp {
	display: block;
	margin: -4px 0 12px;
	max-width: 56ch;
	font-size: 15px;
	line-height: 1.5;
	color: var(--ulp-grey);
}

.ulp-template .ulp-form input,
.ulp-template .ulp-form select,
.ulp-template .ulp-form textarea {
	width: 100%;
	box-sizing: border-box;
	padding: 12px 14px;
	border: 1px solid rgba(0, 0, 0, 0.28);
	border-radius: 0;
	background: rgba(0, 0, 0, 0.03);
	color: inherit;
	font: inherit;
	font-size: 17px;
	line-height: 1.4;
	box-shadow: none;
	transition: border-color 180ms ease, background-color 180ms ease;
}

.ulp-template .ulp-form textarea {
	resize: vertical;
	overflow: hidden;
	/* Three lines and its padding: the floor the growing script grows from, and
	 * the height a field keeps if it is measured while its panel is closed. */
	min-height: 5.7em;
	height: auto;
}

.ulp-template .ulp-form input:hover,
.ulp-template .ulp-form select:hover,
.ulp-template .ulp-form textarea:hover { border-color: rgba(0, 0, 0, 0.5); }

.ulp-template .ulp-form input:focus-visible,
.ulp-template .ulp-form select:focus-visible,
.ulp-template .ulp-form textarea:focus-visible {
	outline: 0;
	border-color: var(--ulp-charcoal);
	background: var(--ulp-white);
	box-shadow: inset 0 0 0 1px var(--ulp-charcoal);
}

.ulp-template .ulp-form select {
	appearance: none;
	padding-right: 38px;
	background-image: linear-gradient(45deg, transparent 49%, currentColor 50%), linear-gradient(-45deg, transparent 49%, currentColor 50%);
	background-position: calc(100% - 20px) 56%, calc(100% - 14px) 56%;
	background-size: 6px 6px, 6px 6px;
	background-repeat: no-repeat;
}

/* The attribute has to win here, because a form row is display:flex. */
.ulp-template .ulp-formrow[hidden],
.ulp-template .ulp-basic[hidden],
.ulp-template .ulp-share-panel[hidden],
.ulp-template .ulp-detail-body[hidden] { display: none; }

/* Off-screen rather than display:none, so a robot filling every field still
 * finds it while nobody sees or tabs to it. */
.ulp-template .ulp-formrow-trap {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* --- the planning questions --- */

.ulp-template .ulp-detail-group {
	display: flex;
	align-items: baseline;
	gap: 12px;
	margin: 42px 0 0;
	padding-bottom: 10px;
	border-bottom: 1px solid rgba(0, 0, 0, 0.14);
	font-size: 13px;
	font-weight: 400;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

.ulp-template .ulp-detail-group:first-child { margin-top: 0; }

/* One accent per group, so the three sections are distinguishable at a glance
 * without a card or a border around anything. */
.ulp-template .ulp-detail-group::before {
	content: "";
	width: 21px;
	height: 3px;
	background: var(--ulp-terracotta);
}

.ulp-template .ulp-detail-group:nth-of-type(2)::before { background: var(--ulp-slate); }
.ulp-template .ulp-detail-group:nth-of-type(3)::before { background: var(--ulp-teal); }

.ulp-template .ulp-qset {
	margin: 0;
	padding: 24px 0 0;
	border: 0;
}

.ulp-template .ulp-q {
	display: flex;
	/* A legend sizes to fit by default, which had questions wrapping to two
	 * lines a third of the way across an 880px column. Full width lets each
	 * question sit on one line where it fits. */
	width: 100%;
	box-sizing: border-box;
	gap: 12px;
	padding: 0 0 4px;
	font-size: 19px;
	line-height: 1.35;
	color: var(--ulp-charcoal);
	text-wrap: pretty;
}

.ulp-template .ulp-q-num {
	flex: 0 0 auto;
	min-width: 1.4em;
	font-size: 15px;
	color: var(--ulp-grey);
	font-variant-numeric: tabular-nums;
}

.ulp-template .ulp-q-text { max-width: 46ch; }

/* The tip sits with its question, not under the answers. */
.ulp-template .ulp-tip {
	margin: 0 0 12px 2.4em;
	font-size: 14px;
	line-height: 1.5;
	color: var(--ulp-grey);
	max-width: 56ch;
}

/* Options in columns, the count set per question by how many there are: one
 * column to four, two to eight, three beyond that where the labels are short.
 * Grid rather than multicol, so the keyboard order matches the reading order
 * down each column and related choices stay together. */
/* Column-major fill with an explicit row count, so a seven-option question
 * reads four on the left and three on the right rather than snaking across.
 * The count is set per question on the element, because only the markup knows
 * how many options there are. */
.ulp-template .ulp-choices {
	display: grid;
	gap: 2px 32px;
	margin-left: 2.4em;
	grid-auto-flow: column;
	grid-template-columns: repeat(var(--ulp-choice-cols, 1), minmax(0, 1fr));
	grid-template-rows: repeat(var(--ulp-choice-rows, 1), auto);
}

.ulp-template .ulp-choices[data-cols="1"] {
	grid-auto-flow: row;
	grid-template-columns: minmax(0, 1fr);
	grid-template-rows: none;
}

.ulp-template .ulp-form .ulp-check {
	display: flex;
	align-items: flex-start;
	gap: 10px;
	padding: 8px 0;
	min-height: 44px;
	box-sizing: border-box;
	font-size: 16px;
	line-height: 1.35;
	color: var(--ulp-charcoal);
	cursor: pointer;
}

.ulp-template .ulp-form .ulp-check input {
	flex: 0 0 auto;
	width: 20px;
	height: 20px;
	margin: 1px 0 0;
	padding: 0;
	border: 0;
	background: transparent;
	box-shadow: none;
	accent-color: var(--ulp-charcoal);
}

.ulp-template .ulp-form .ulp-check:has(input:checked) { color: var(--ulp-black); }

/* A question nested inside another: the investment range under funding. */
.ulp-template .ulp-subset {
	margin: 21px 0 0 2.4em;
	padding: 18px 0 0 18px;
	border: 0;
	border-left: 2px solid var(--ulp-slate);
}

.ulp-template .ulp-subq {
	margin: 0 0 6px;
	font-size: 17px;
	line-height: 1.35;
	color: var(--ulp-charcoal);
}

.ulp-template .ulp-subset .ulp-tip { margin-left: 0; }
.ulp-template .ulp-subset .ulp-choices { margin-left: 0; }
.ulp-template .ulp-qset .ulp-formrow { margin: 16px 0 0 2.4em; }

/* A row inside a subset belongs to the subset's own left edge, not to the
 * answer column of the question above it. Set after the rule above, and as the
 * same shorthand, so the indent is replaced rather than half-overridden. */
.ulp-template .ulp-subset .ulp-formrow { margin: 16px 0 0; }

/* --- the upload bar --- */

/* The block sits flush with the fields around it. Inside a question it takes
 * that question's answer column instead, the way its choices do. */
.ulp-template .ulp-upload { margin: 18px 0 0; }
.ulp-template .ulp-qset .ulp-upload { margin: 18px 0 0 2.4em; }
.ulp-template .ulp-subset .ulp-upload { margin: 18px 0 0; }

/* A bar about two lines high, not a drop zone: the label and the control on
 * one line, and the list below only once there is something in it. */
.ulp-template .ulp-upload-bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 18px;
	min-height: 62px;
	box-sizing: border-box;
	padding: 12px 14px;
	border: 1px dashed rgba(0, 0, 0, 0.3);
	font-size: 15px;
	line-height: 1.4;
	color: var(--ulp-grey);
}

.ulp-template .ulp-upload-btn {
	flex: 0 0 auto;
	margin: 0;
	padding: 9px 16px;
	white-space: nowrap;
	border: 1px solid currentColor;
	color: var(--ulp-charcoal);
	font-size: 15px;
	cursor: pointer;
	transition: background-color 180ms ease, color 180ms ease;
}

.ulp-template .ulp-upload-btn:hover { background: var(--ulp-charcoal); color: var(--ulp-white); }

.ulp-template .ulp-upload-btn input {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
}

.ulp-template .ulp-upload-btn:focus-within { outline: 2px solid currentColor; outline-offset: 3px; }

.ulp-template .ulp-upload-list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.ulp-template .ulp-upload-row {
	display: flex;
	align-items: center;
	gap: 14px;
	padding: 10px 14px;
	border: 1px solid rgba(0, 0, 0, 0.14);
	border-top: 0;
	font-size: 15px;
}

.ulp-template .ulp-upload-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ulp-template .ulp-upload-size { flex: 0 0 auto; color: var(--ulp-grey); font-variant-numeric: tabular-nums; }

.ulp-template .ulp-upload-remove {
	flex: 0 0 auto;
	padding: 4px 0;
	border: 0;
	background: transparent;
	color: var(--ulp-grey);
	font: inherit;
	font-size: 14px;
	text-decoration: underline;
	cursor: pointer;
}

.ulp-template .ulp-upload-remove:hover { color: var(--ulp-charcoal); }

.ulp-template .ulp-upload-status {
	margin: 8px 0 0;
	font-size: 14px;
	line-height: 1.45;
	color: var(--ulp-grey);
}

.ulp-template .ulp-upload-status[data-tone="error"] { color: var(--ulp-terracotta); }

/* --- sharing with colleagues --- */

.ulp-template .ulp-share {
	margin: 24px 0 0 2.4em;
	padding: 18px 0 0;
	border-top: 1px solid rgba(0, 0, 0, 0.14);
}

.ulp-template .ulp-share-ask {
	margin: 0 0 10px;
	font-size: 16px;
	line-height: 1.45;
	max-width: 56ch;
}

.ulp-template .ulp-linkbtn {
	display: inline-block;
	margin: 0;
	padding: 6px 0;
	border: 0;
	background: transparent;
	color: var(--ulp-charcoal);
	font: inherit;
	font-size: 15px;
	text-decoration: underline;
	text-underline-offset: 3px;
	cursor: pointer;
}

.ulp-template .ulp-linkbtn:hover { color: var(--ulp-terracotta); }
.ulp-template .ulp-linkbtn:disabled { opacity: 0.4; cursor: default; text-decoration: none; }

.ulp-template .ulp-share-panel { padding-top: 14px; }

.ulp-template .ulp-colleague {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 0 18px;
	padding: 14px 0 0;
	border-top: 1px solid rgba(0, 0, 0, 0.08);
}

.ulp-template .ulp-colleague:first-child { border-top: 0; padding-top: 0; }
.ulp-template .ulp-colleague .ulp-formrow { margin-bottom: 14px; }

/* Nothing is sent to anyone without this, so it carries more weight than the
 * choices around it. */
.ulp-template .ulp-form .ulp-check-consent {
	margin-top: 16px;
	padding: 14px;
	background: rgba(0, 0, 0, 0.05);
	border-left: 2px solid var(--ulp-teal);
	font-size: 15px;
}

/* --- privacy, submission and confirmation --- */

.ulp-template .ulp-privacy {
	margin: 34px 0 24px;
	padding-top: 18px;
	border-top: 1px solid rgba(0, 0, 0, 0.14);
	font-size: 14px;
	line-height: 1.55;
	color: var(--ulp-grey);
	max-width: 68ch;
}

.ulp-template .ulp-privacy a { color: inherit; text-decoration: underline; }
.ulp-template .ulp-privacy a:hover { color: var(--ulp-charcoal); }

.ulp-template .ulp-submitrow {
	display: flex;
	align-items: center;
	gap: 24px;
	flex-wrap: wrap;
}

.ulp-template .ulp-form .ulp-submit {
	padding: 15px 30px;
	border: 1px solid var(--ulp-charcoal);
	background: var(--ulp-charcoal);
	color: var(--ulp-white);
	font: inherit;
	font-size: 17px;
	cursor: pointer;
	box-shadow: none;
	transition: background-color 200ms ease, color 200ms ease;
}

.ulp-template .ulp-form .ulp-submit:hover { background: var(--ulp-white); color: var(--ulp-charcoal); }
.ulp-template .ulp-form .ulp-submit[aria-busy="true"] { opacity: 0.55; cursor: progress; }

.ulp-template .ulp-submitnote { font-size: 15px; color: var(--ulp-grey); }
.ulp-template .ulp-submitnote a { color: var(--ulp-charcoal); }

.ulp-template .ulp-enquiry-status {
	margin: 14px 0 0;
	font-size: 16px;
	line-height: 1.5;
	max-width: 62ch;
}

.ulp-template .ulp-enquiry-status[data-tone="error"] { color: var(--ulp-terracotta); }
.ulp-template .ulp-enquiry-status[data-tone="working"] { color: var(--ulp-grey); }

.ulp-template .ulp-enquiry-done { padding-top: 8px; }

.ulp-template .ulp-enquiry-done-head {
	margin: 0 0 16px;
	font-size: clamp(24px, 2vw, 34px);
	font-weight: 400;
	line-height: 1.15;
	letter-spacing: -0.01em;
}

.ulp-template .ulp-visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
}

@container ulpform (max-width: 860px) {
	/* Two columns at most on a tablet, and the row count no longer applies, so
	 * the fill goes back to reading across. */
	.ulp-template .ulp-choices[data-cols="3"] {
		grid-auto-flow: row;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		grid-template-rows: none;
	}

	.ulp-template .ulp-colleague { grid-template-columns: minmax(0, 1fr); }
}

@container ulpform (max-width: 620px) {
	.ulp-template .ulp-fieldpair { grid-template-columns: minmax(0, 1fr); }

	/* One column on a phone: two would cramp the labels and force each onto
	 * two or three lines. */
	.ulp-template .ulp-choices,
	.ulp-template .ulp-choices[data-cols="2"],
	.ulp-template .ulp-choices[data-cols="3"] {
		grid-auto-flow: row;
		grid-template-columns: minmax(0, 1fr);
		grid-template-rows: none;
		margin-left: 0;
	}

	.ulp-template .ulp-tip,
	.ulp-template .ulp-qset .ulp-formrow,
	.ulp-template .ulp-upload,
	.ulp-template .ulp-share,
	.ulp-template .ulp-subset { margin-left: 0; }

	/* Stacked, so the fixed two-line height no longer applies. */
	.ulp-template .ulp-upload-bar { flex-direction: column; align-items: stretch; gap: 12px; min-height: 0; }
	.ulp-template .ulp-upload-text { display: block; }
	.ulp-template .ulp-upload-btn { width: 100%; text-align: center; box-sizing: border-box; }
	.ulp-template .ulp-form .ulp-submit { width: 100%; }
	.ulp-template .ulp-submitrow { gap: 14px; }
}

/* Two ways to talk to us, sitting with the navigation as a pair of solid
 * marks. The number and address are held until the mark is hovered or focused,
 * and are read out to assistive software from the link's own label, so nothing
 * depends on a hover to be reachable. */
.ulp-template .ulp-rail-contact {
	position: relative;
	display: flex;
	gap: 14px;
	margin: 34px 0 0;
	font-size: 15px;
	line-height: 1.4;
}

.ulp-template .ulp-rail-contact a {
	display: block;
	color: var(--ulp-grey);
	text-decoration: none;
	transition: color 240ms ease;
}

.ulp-template .ulp-rail-contact a:hover,
.ulp-template .ulp-rail-contact a:focus-visible { color: var(--ulp-charcoal); }

/* The same lift the chat launcher makes, over the same duration, so the two
 * pairs of marks on either side of the page behave alike. */
.ulp-template .ulp-rail-contact svg {
	display: block;
	transition: transform 240ms ease;
}

.ulp-template .ulp-rail-contact a:hover svg,
.ulp-template .ulp-rail-contact a:focus-visible svg { transform: translateY(-2px); }

.ulp-template .ulp-rail-contact a:focus-visible { outline: 2px solid currentColor; outline-offset: 6px; }

/* The label is taken out of flow, so revealing it moves nothing: the two marks
 * hold their places and the rail keeps its width. */
.ulp-template .ulp-rail-contact-text {
	position: absolute;
	left: 0;
	top: calc(100% + 8px);
	white-space: nowrap;
	color: var(--ulp-charcoal);
	opacity: 0;
	transform: translateY(-4px);
	pointer-events: none;
	transition: opacity 240ms ease, transform 240ms ease;
}

.ulp-template .ulp-rail-contact a:hover .ulp-rail-contact-text,
.ulp-template .ulp-rail-contact a:focus-visible .ulp-rail-contact-text {
	opacity: 1;
	transform: none;
}

@media (max-width: 1000px) {
	.ulp-template .ulp-rail-contact { margin-top: 21px; }
}

/* Below the wide layout the rail is a horizontal band with no room beneath the
 * marks, so the labels sit inline instead of being revealed under them. Gated
 * on width as well as pointer type: a resized desktop window and a tablet with
 * a mouse both get the stacked band without matching (hover: none). */
@media (max-width: 1000px), (hover: none) {
	.ulp-template .ulp-rail-contact {
		position: static;
		flex-direction: column;
		gap: 10px;
	}

	.ulp-template .ulp-rail-contact a {
		display: flex;
		align-items: center;
		gap: 10px;
	}

	.ulp-template .ulp-rail-contact-text {
		position: static;
		opacity: 1;
		transform: none;
		pointer-events: auto;
	}
}

/* A dropdown answers one short thing, so it takes the width of its longest
 * option rather than the whole column. */
.ulp-template .ulp-formrow-narrow { max-width: 420px; }

/* Two lines for a short supporting note, growing from there as it is typed. */
.ulp-template .ulp-form textarea.ulp-textarea-short { min-height: 4.1em; }

/* A single link under the page's opening line, sending a reader straight to
 * the part of the page they came for. Set on the page's own left edge, with
 * the same inset the statement above it uses. */
.ulp-template .ulp-onward-jump {
	margin: 0;
	padding: 0 0 21px;
}

/* A line that introduces the list directly beneath it, so the two read as one
 * unit rather than as a paragraph followed by an unrelated list. Bound to the
 * case it was written for: the same class on a line followed by a paragraph
 * would pull that paragraph closer than every other pair on the page. */
.ulp-template .ulp-prose-lead:has(+ ul) { margin-bottom: -8px; }

/* A source link closes a section, so it carries no bottom spacing of its own.
 * Cited mid-section, the paragraph after it takes the gap a section's first
 * paragraph takes, since the prose-to-prose rule cannot reach across it. */
.ulp-template .ulp-source-link + .ulp-prose { padding-top: 21px; }

/* One line a section turns on, set between body and heading size so it carries
 * weight without competing with the heading above it. The measure matches the
 * body prose beside it: capped tighter, a longer line stacked into a narrow
 * column of its own and read as stranded rather than emphasised. */
.ulp-template .ulp-pull {
	margin: 34px 0 0;
	max-width: 54ch;
	font-size: clamp(21px, 1.6vw, 27px);
	line-height: 1.25;
	letter-spacing: -0.01em;
	text-wrap: balance;
	color: var(--ulp-charcoal);
}

/* The paragraph after it takes the gap the prose-to-prose rule cannot supply
 * across a different element. */
.ulp-template .ulp-pull + .ulp-prose { padding-top: 21px; }

/* A colon line that opens the sentence the display line finishes: bound to it,
 * the way a lead line is bound to the list it introduces, so the pair reads as
 * one thought rather than as two separated statements. */
.ulp-template .ulp-prose-lead + .ulp-pull { margin-top: 10px; }

/* A short pathway read left to right, one word a step, for a sequence that is
 * a route rather than three stages with descriptions. */
.ulp-template .ulp-flowsteps {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 10px 16px;
	margin: 34px 0 0;
	padding: 0;
	list-style: none;
	font-size: 17px;
	letter-spacing: 0.02em;
}

.ulp-template .ulp-flowsteps li {
	display: flex;
	align-items: center;
	gap: 16px;
	color: var(--ulp-charcoal);
}

.ulp-template .ulp-flowsteps li + li::before {
	content: "\2192";
	color: var(--ulp-grey);
}

/* A section that belongs to one audience only: out of the page until that
 * audience is chosen, rather than shown by default like a cell that names no
 * audience. */
.ulp-template [data-sector-only] { display: none; }
.ulp-template [data-sector-only].is-shown { display: block; }
.ulp-template .ulp-row-pair[data-sector-only].is-shown { display: grid; }

/* A line of links closing a run of product tiles needs more air than the feed's
 * standard row gap: that gap is measured between text rows, and a full-bleed
 * tile has no internal space of its own for the links to sit clear of. */
.ulp-template .ulp-row-sprouts + .ulp-row-full { padding-top: 42px; }

/* The audience-assignment panel: a tool for deciding the SPROUTS split, shown
 * only with ?tweaks=1 and never part of the published page. Deliberately plain
 * rather than styled as site furniture, so it cannot be mistaken for content. */
.ulp-template .ulp-tweaks {
	position: fixed;
	right: 21px;
	bottom: 96px;
	z-index: 1200;
	width: min(320px, calc(100vw - 42px));
	/* The cap has to account for the offset the panel sits at: 96px clearing
	 * the chat launcher plus the 21px inset above it, or a tall panel is pushed
	 * off the top of the window where scrolling inside it cannot reach. */
	max-height: calc(100vh - 117px);
	overflow-y: auto;
	padding: 21px;
	border: 1px solid rgba(0, 0, 0, 0.18);
	background: var(--ulp-white);
	box-shadow: 0 18px 44px rgba(0, 0, 0, 0.14);
	font-size: 15px;
}

.ulp-template .ulp-tweaks-head {
	font-size: 13px;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--ulp-grey);
}

.ulp-template .ulp-tweaks-note {
	margin: 12px 0 18px;
	font-size: 14px;
	line-height: 1.45;
	color: var(--ulp-grey);
}

.ulp-template .ulp-tweaks-row {
	padding: 12px 0;
	border-top: 1px solid rgba(0, 0, 0, 0.1);
}

.ulp-template .ulp-tweaks-label {
	display: block;
	margin-bottom: 8px;
	color: var(--ulp-charcoal);
}

.ulp-template .ulp-tweaks-choices { display: flex; gap: 6px; }

.ulp-template .ulp-tweaks-btn {
	flex: 1;
	padding: 7px 4px;
	border: 1px solid rgba(0, 0, 0, 0.24);
	background: var(--ulp-white);
	color: var(--ulp-grey);
	font: inherit;
	font-size: 13px;
	cursor: pointer;
}

.ulp-template .ulp-tweaks-btn[aria-pressed="true"] {
	background: var(--ulp-charcoal);
	border-color: var(--ulp-charcoal);
	color: var(--ulp-white);
}

.ulp-template .ulp-tweaks-copy {
	width: 100%;
	margin-top: 18px;
	padding: 11px;
	border: 1px solid currentColor;
	background: rgba(0, 0, 0, 0.1);
	box-shadow: inset 1px 0 0 currentColor;
	color: var(--ulp-charcoal);
	font: inherit;
	cursor: pointer;
}

/* A meta value still awaiting a fact from ULP. Marked so it cannot be mistaken
 * for a confident claim on a client-facing page, and so it is easy to find
 * before launch. Remove the class when the real value is set. */
.ulp-template .ulp-story-meta-todo {
	color: var(--ulp-grey);
	font-style: italic;
	text-decoration: underline dotted currentColor;
	text-underline-offset: 4px;
}

/* The product code beneath a Playform product's name: a reference for quoting
 * and procurement, set small and quiet so it never competes with the name. */
.ulp-template .ulp-product-code {
	margin: 14px 0 0;
	font-size: 13px;
	letter-spacing: 0.16em;
	color: var(--ulp-grey);
}

/* The code inside an open SPROUTS product: tighter to its title than on a
 * product page, where the code sits under a full page heading. */
.ulp-template .ulp-sprout-copy .ulp-product-code { margin: -8px 0 18px; }


/* The product code in the corner of a tile: readable at rest rather than only
 * on hover, and held above the panel so it stays put when the panel comes up.
 * Set on the photograph, so it carries its own shadow for legibility. */
.ulp-template .ulp-card-code {
	position: absolute;
	top: var(--ulp-inset);
	right: var(--ulp-inset);
	z-index: 2;
	font-size: 13px;
	letter-spacing: 0.16em;
	color: var(--ulp-white);
	text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
	pointer-events: none;
}

/* On an empty frame there is no photograph to sit against, so it takes the
 * page's own ink. */
.ulp-template .ulp-block-slot .ulp-card-code {
	color: var(--ulp-grey);
	text-shadow: none;
}

/* On hover the panel's flat colour fills the tile and the photograph is gone,
 * so the code exchanges ink the way the corner title on a Careers card does:
 * charcoal over a light ground, white over a dark one, and no shadow either
 * way now that there is no photograph beneath it. */
.ulp-template .ulp-block:has(.ulp-panel-light):hover .ulp-card-code,
.ulp-template .ulp-block:has(.ulp-panel-light):focus .ulp-card-code,
.ulp-template .ulp-block:has(.ulp-panel-light):focus-visible .ulp-card-code,
.ulp-template .ulp-block:has(.ulp-panel-light):focus-within .ulp-card-code {
	color: var(--ulp-charcoal);
	text-shadow: none;
}

.ulp-template .ulp-block:has(.ulp-panel):hover .ulp-card-code,
.ulp-template .ulp-block:has(.ulp-panel):focus .ulp-card-code,
.ulp-template .ulp-block:has(.ulp-panel):focus-visible .ulp-card-code,
.ulp-template .ulp-block:has(.ulp-panel):focus-within .ulp-card-code { text-shadow: none; }

/* The product code on a shortlist row, so a visitor can quote it and the
 * printed or emailed brief carries the same reference the team orders against. */
.ulp-template .ulp-planner-code {
	margin: 4px 0 0;
	font-size: 13px;
	letter-spacing: 0.16em;
	color: var(--ulp-grey);
}

/* ------------------------------------------------------- article bodies */

/* An article body written in the block editor. The blocks are core; these
 * rules give them the approved treatment, so a writer edits words and the
 * design stays fixed. The selectors match what the editor emits, and the block
 * styles registered in functions.php are the three cases core has no
 * equivalent for. */
.ulp-template .ulp-article > * { margin: 0; }

.ulp-template .ulp-article > h2 {
	margin: var(--ulp-row) 0 0;
	max-width: none;
	font-size: clamp(24px, 2vw, 34px);
	font-weight: 400;
	line-height: 1.15;
	letter-spacing: -0.01em;
	text-wrap: pretty;
}

.ulp-template .ulp-article > h2:first-child { margin-top: 0; }

.ulp-template .ulp-article > p {
	margin: 21px 0 0;
	max-width: 54ch;
	font-size: 19px;
	line-height: 1.62;
	text-wrap: pretty;
}

.ulp-template .ulp-article > h2 + p { margin-top: 21px; }

/* The direct answer: the line an extraction quotes, set at statement size. */
.ulp-template .ulp-article > p.is-style-ulp-answer {
	margin: 0 0 34px;
	max-width: 34ch;
	font-size: clamp(28px, 3.4vw, 62px);
	line-height: 1.14;
	letter-spacing: -0.02em;
	color: var(--ulp-charcoal);
}

/* One line a section turns on. */
.ulp-template .ulp-article > p.is-style-ulp-emphasis {
	margin: 34px 0 0;
	max-width: 54ch;
	font-size: clamp(21px, 1.6vw, 27px);
	line-height: 1.25;
	letter-spacing: -0.01em;
	text-wrap: balance;
	color: var(--ulp-charcoal);
}

/* A reference to the body that publishes the guidance. */
.ulp-template .ulp-article > p.is-style-ulp-source {
	margin: 14px 0 0;
	max-width: 54ch;
	font-size: 17px;
	line-height: 1.5;
	color: var(--ulp-grey);
}

.ulp-template .ulp-article > ul,
.ulp-template .ulp-article > ol {
	margin: 21px 0 0;
	padding: 0;
	max-width: 54ch;
	list-style: none;
}

.ulp-template .ulp-article > ul > li,
.ulp-template .ulp-article > ol > li {
	padding: 12px 0;
	border-bottom: 1px solid rgba(0, 0, 0, 0.12);
	font-size: 19px;
	line-height: 1.5;
}

.ulp-template .ulp-article > ul:first-of-type > li:first-child { border-top: 1px solid rgba(0, 0, 0, 0.12); }

.ulp-template .ulp-article > figure {
	margin: var(--ulp-row) 0 0;
}

.ulp-template .ulp-article > figure img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 3 / 2;
	object-fit: cover;
}


/* ------------------------------------------- mobile header and scrolling */

/* The sticky band on a phone was holding three stacked blocks: the wordmark,
 * the navigation, and the phone and email marks. Around 250px of a 650px
 * screen, which left the products behind it. The contact marks close the
 * footer on every page, so on a phone they come out of the band and the
 * header keeps the wordmark and one line of navigation.
 *
 * The horizontal scroller was also wrapping all three blocks, so a vertical
 * drag anywhere in that tall region was absorbed by it and the page did not
 * move. The scroller now wraps the navigation alone, and declares which
 * direction it takes, so a drag beginning on the header scrolls the page. */
@media (max-width: 1000px) {
	.ulp-template .ulp-rail {
		padding: 10px 21px 8px;
		box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
	}

	.ulp-template .ulp-logo { width: 124px; }

	.ulp-template .ulp-navwrap {
		margin-top: 6px;
		display: flex;
		align-items: baseline;
		gap: 18px;
		overflow: visible;
		touch-action: pan-y;
	}

	.ulp-template .ulp-navwrap > nav[aria-label="Primary"] {
		min-width: 0;
		overflow-x: auto;
		overscroll-behavior-x: contain;
		-webkit-overflow-scrolling: touch;
		scrollbar-width: none;
		touch-action: pan-x;
	}

	.ulp-template .ulp-navwrap > nav[aria-label="Primary"]::-webkit-scrollbar { display: none; }

	.ulp-template .ulp-rail-brands { margin-top: 0; flex: none; }
	.ulp-template .ulp-rail-planner { white-space: nowrap; }

	/* Already at the foot of every page, where there is room to label them. */
	.ulp-template .ulp-rail-contact { display: none; }
}

/* Landscape on a phone leaves around 390px of height. A sticky header and a
 * single-column footer both assume a tall window, so on a short screen the
 * header scrolls away with the page and the footer keeps its columns. */
@media (max-height: 560px) and (orientation: landscape) {
	.ulp-template .ulp-rail { position: static; }
	.ulp-template .ulp-shell-body { min-height: 0; }
}

@media (max-width: 1000px) and (min-width: 620px) {
	.ulp-template .ulp-footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.ulp-template .ulp-footer { padding: 36px var(--ulp-pad) 32px; }
	.ulp-template .ulp-footer-base { padding-top: 32px; }
}

/* iOS reports 100vh as the height without the browser chrome, so a full-height
 * shell on a phone is taller than the window it sits in. */
@supports (height: 100dvh) {
	.ulp-template .ulp-shell-body { min-height: 100dvh; }
	.ulp-template .ulp-rail { height: 100dvh; }
}

@media (max-width: 1000px) {
	.ulp-template .ulp-rail { height: auto; }
}


/* -------------------------------------- green field: contact marks, names */

/* The phone and email marks take the rail's own ink, which is charcoal. On a
 * green page that reads as dark text on a mid ground, so they take the white
 * the navigation takes there. */
.ulp-template.ulp-field .ulp-rail-contact a,
.ulp-template.ulp-field .ulp-rail-contact-text { color: var(--ulp-white); }

.ulp-template.ulp-field .ulp-rail-contact a:hover,
.ulp-template.ulp-field .ulp-rail-contact a:focus-visible { color: var(--ulp-white); }

/* The marks are drawn with a white fill behind a stroke of the current ink, so
 * on the field the fill becomes the ground and the stroke stays white. */
.ulp-template.ulp-field .ulp-rail-contact svg [fill="#ffffff"] { fill: var(--ulp-green); }

/* On a touch screen there is no hover to reveal a name, so every caption is
 * showing at once and sits over the face it belongs to. Below the portrait
 * instead, where a circular crop leaves the corners free anyway. */
@media (hover: none), (max-width: 1000px) {
	/* The circular crop moves off the figure and onto the portrait itself, so
	 * the figure can grow to hold a caption beneath it without clipping it. */
	.ulp-template .ulp-person {
		position: static;
		aspect-ratio: auto;
		border-radius: 0;
		overflow: visible;
	}

	.ulp-template .ulp-person img,
	.ulp-template .ulp-person .ulp-person-empty {
		height: auto;
		aspect-ratio: 1 / 1;
		border-radius: 50%;
		overflow: hidden;
	}

	.ulp-template .ulp-person figcaption {
		position: static;
		inset: auto;
		padding: 12px 0 0;
		background: none;
		text-align: center;
		opacity: 1;
	}

	.ulp-template .ulp-person-name { font-size: 17px; }
	.ulp-template .ulp-person-role { font-size: 15px; }

	/* The scale-up that framed this one portrait relied on the figure clipping
	 * it. With the crop on the image itself the framing comes from the crop
	 * instead, so nothing sits outside the circle. */
	.ulp-template .ulp-person-tight { transform: none; object-position: 50% 20%; }
}


/* While a field is being typed into on a phone the header stands down, so the
 * keyboard and the form share the window between them rather than the two of
 * them plus a sticky band. Set from the enquiry script on focus. */
.ulp-template .ulp-shell[data-typing] .ulp-rail { position: static; }


/* ------------------------------------- green field: planner and form text */

/* The planning questions were written for a light page and kept their charcoal
 * and grey ink on the green field, where the labels, hints and question text
 * all fell well below a readable contrast. Full-strength white for anything
 * that has to be read, and a light grey only where the reference itself is
 * quieter: the group headings and the question numbers. */
.ulp-template.ulp-field .ulp-detail-body,
.ulp-template.ulp-field .ulp-q-text,
.ulp-template.ulp-field .ulp-check > span,
.ulp-template.ulp-field .ulp-radio > span,
.ulp-template.ulp-field .ulp-disclose-title,
.ulp-template.ulp-field .ulp-qset legend,
.ulp-template.ulp-field .ulp-detail-body label { color: var(--ulp-white); }

.ulp-template.ulp-field .ulp-formhelp,
.ulp-template.ulp-field .ulp-disclose-note,
.ulp-template.ulp-field .ulp-required-note,
.ulp-template.ulp-field .ulp-submitnote,
.ulp-template.ulp-field .ulp-optional,
.ulp-template.ulp-field .ulp-tip { color: rgba(255, 255, 255, 0.82); }

.ulp-template.ulp-field .ulp-detail-group,
.ulp-template.ulp-field .ulp-disclose-kicker,
.ulp-template.ulp-field .ulp-q-num { color: rgba(255, 255, 255, 0.7); }

.ulp-template.ulp-field .ulp-qset,
.ulp-template.ulp-field .ulp-detail-group { border-color: rgba(255, 255, 255, 0.24); }

/* Options are laid out inside the panel too, and the select shares the field
 * chrome the text inputs already take on the green. */
.ulp-template.ulp-field .ulp-formrow select,
.ulp-template.ulp-field .ulp-detail-body select {
	color: var(--ulp-white);
	border-color: rgba(255, 255, 255, 0.58);
	background-color: transparent;
}

/* A native menu paints its own list, which on some systems is light, so the
 * options keep a readable ink of their own rather than inheriting white. */
.ulp-template.ulp-field select option { color: var(--ulp-charcoal); }
