/* ==========================================================================
   Yard template - components
   Buttons and the header, then the eight signature components from the plan:
   1 wordmark  2 door marking  3 caption stack  4 plate
   5 range card and the not sure tile  6 size picker
   7 fixed phone bar  8 enquiry panel
   ========================================================================== */


/* --- Buttons ---------------------------------------------------------------
   Square, heavy, one job each. Yellow is the action everywhere.
   On a light surface a yellow fill carries an ink border, because yellow
   against paper is 1.32:1 and a control edge has to be findable.
   ------------------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap);
  padding: var(--space-3) var(--space-5);
  border: var(--edge) solid transparent;
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-weight: var(--w-medium);
  font-size: max(16px, var(--step-0));
  line-height: var(--lh-ui);
  text-decoration: none;
  text-align: center;
  text-wrap: balance;
  cursor: pointer;
  user-select: none;
  position: relative;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              translate var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}

/* --- The lift ----------------------------------------------------------------
   The button rises and leaves a hard black shadow in the space it came out of,
   so it reads as a physical thing lifted off the page rather than a rectangle
   that changed colour. The shadow is exactly --lift deep and has no blur: the
   gap under the button is the shape of the button.

   Pressing puts it back down. The old :active was scale(0.97), which shrank
   the button; with a lift above it, dropping it back into its own shadow is
   the honest opposite of the hover and costs nothing to understand.
   ------------------------------------------------------------------------ */

/* The hit area is extended down by --lift, or the button slides out from under
   the cursor at the bottom edge, un-hovers, drops, re-hovers and oscillates.
   The design standard calls this the doom-flicker and fixes it by transforming
   a child; these buttons have no wrapper to transform, so the target keeps the
   ground it is about to leave. */
.btn::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block: 0 calc(var(--lift) * -1);
}

/* Deliberately NOT inside @media (hover: hover).

   Ben could not see the lift at all, and his machine is why: Chrome on it
   reports pointer: coarse, any-hover: false and maxTouchPoints: 10, so every
   hover block on this site is dead there. That is a touchscreen laptop, and
   it is a whole class of machine, not one odd setup. Gating a hover state on
   `hover: hover` is meant to stop the state sticking after a tap on a phone;
   on a hybrid it throws the state away from the trackpad as well.

   :focus-visible gets the same lift, so the keyboard sees what the mouse
   sees. :active below puts it back down either way, which is also what clears
   it after a tap. */
.btn:hover,
.btn:focus-visible {
  translate: 0 calc(var(--lift) * -1);
  box-shadow: var(--btn-shadow-lift);
}
.btn:active {
  translate: 0 0;
  box-shadow: var(--btn-shadow-press);
  transition-duration: var(--dur-instant);
}
.btn[disabled] { pointer-events: none; opacity: 0.55; }

.btn--block { display: flex; width: 100%; }

/* a.btn needs the colour pinned, or the link colour wins */
/* The fill, the edge and the pressed fill are variables, not fixed colours,
   because they change on the dark bands. See the override in base.css. */
.btn--yellow,
.band--ink a.btn--yellow,
a.btn--yellow {
  background: var(--btn-fill);
  color: var(--btn-text);
  border-color: var(--btn-edge);
}
/* Hover does not change the colour. Ben, 21 September: "the button doesnt
   need to darken when hovered." The lift says "this is live" on its own, and
   darkening as well was two signals carrying one message.

   The darken moves to the press rather than being deleted. It is the only
   colour feedback these buttons had, and a thumb never hovers: on a phone the
   lift is invisible, because the button is at rest until it is touched and
   the press returns it to rest. Without this, tapping a yellow button on a
   phone would do nothing at all until the page changed. */
.btn--yellow:active,
.band--ink a.btn--yellow:active,
a.btn--yellow:active {
  background: var(--btn-fill-press);
  border-color: var(--btn-edge-press);
  color: var(--btn-text);
}

.btn--ink,
.band--yellow a.btn--ink,
a.btn--ink { background: var(--ink); color: var(--on-dark); border-color: var(--ink); }
/* Same again: the lift is the hover. --ink-press on the press was already
   here and stays. */
.btn--ink:active { background: var(--ink-press); border-color: var(--ink-press); }

.text-link { font-weight: var(--w-medium); }


/* --- Header ------------------------------------------------------------------
   Flat charcoal. Wordmark left, four links, the phone number as
   tappable text, the yellow Enquire button far right.
   Under 56rem the links fold into a details menu, which needs no script.
   ------------------------------------------------------------------------ */

.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  background-color: var(--ink);
  color: var(--on-dark);
  transition: box-shadow var(--dur-base) var(--ease-out);
}
.site-header.is-stuck { box-shadow: var(--shadow-header); }

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  min-height: var(--header-h);
}

.site-nav { margin-inline-start: auto; }
.site-nav__list { display: flex; align-items: center; gap: var(--space-5); }

.site-nav a,
.site-header__phone {
  color: var(--on-dark);
  text-decoration: none;
  font-weight: var(--w-medium);
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
}
@media (hover: hover) {
  .site-nav a:hover,
  .site-header__phone:hover { color: var(--yellow); }
}
.site-nav a[aria-current="page"] { box-shadow: inset 0 -3px 0 var(--yellow); }

/* On the enquiry page itself, the header's Enquire button is a link to where
   you already are. Filled, it invites a click that does nothing. Outlined, it
   still marks the page you are on and stops competing with the form below it.
   Yellow on --ink is 11.32:1, so the outline carries at this size. */
.site-header__cta[aria-current="page"] {
  background: transparent;
  border-color: var(--yellow);
  color: var(--yellow);
}
.site-header__cta[aria-current="page"]:active {
  background: transparent;
  border-color: var(--yellow-deep);
  color: var(--yellow-deep);
}

.site-header__phone {
  font-family: var(--font-display);
  font-weight: var(--w-display);
  font-size: var(--step-1);
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.site-header :where(a, summary):focus-visible { outline-color: var(--focus-on-dark); }

/* The folded menu */
.menu { display: none; margin-inline-start: auto; }
.menu > summary {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap);
  padding-inline: var(--space-4);
  border: var(--edge) solid var(--mist);
  font-weight: var(--w-medium);
  cursor: pointer;
  list-style: none;
  user-select: none;
}
/* A closed panel is laid out, not just invisible: Chrome still gives it a box,
   shrink wrapped to the summary. Its links then measure about 42px wide and
   the tap target gate fails on a menu nobody can see. It passed before only
   because the old, larger summary happened to be wide enough to carry them.
   A closed dropdown should not be in the layout at all. */
.menu:not([open]) .menu__panel { display: none; }

.menu > summary::-webkit-details-marker { display: none; }
/* Open is a pressed state, so it takes the pressed fill rather than the
   resting one: on the dark header that is --mist, a step down from the white
   of the Enquire button inside the panel it has just opened. It used to
   hardcode --yellow, which left it the only yellow object in the header once
   the buttons there went white. */
.menu[open] > summary {
  background: var(--btn-fill-press);
  color: var(--btn-text);
  border-color: var(--btn-edge-press);
}

/* The menu button lifts like the rest. It is the only other thing on the site
   shaped like a button: bordered, discrete, one job.

   It does NOT lift while the menu is open, because it is then the lid on a
   panel that is attached to it, and a lid that floats above its own box is
   wrong. Open is a pressed state, so it sits down. */
.menu > summary {
  position: relative;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              translate var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
.menu:not([open]) > summary:hover,
.menu:not([open]) > summary:focus-visible {
  translate: 0 calc(var(--lift) * -1);
  box-shadow: var(--btn-shadow-lift);
}
.menu > summary:active,
.menu[open] > summary {
  translate: 0 0;
  box-shadow: var(--btn-shadow-press);
}

.menu__panel {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 100%;
  padding: var(--space-4) var(--page-gutter) var(--space-6);
  background-color: var(--ink);
  border-block-start: 1px solid var(--rule-on-dark);
  box-shadow: var(--shadow-header);
}
/* :not(.btn) matters. Without it this rule paints the Enquire button's label
   in the light type colour, on yellow, at 1.32:1. */
.menu__panel a:not(.btn) {
  display: flex;
  align-items: center;
  min-height: 3.25rem;
  color: var(--on-dark);
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: var(--w-display);
  font-size: var(--step-2);
  border-block-end: 1px solid var(--rule-on-dark);
}
.menu__panel .btn { margin-block-start: var(--space-5); }

@media (max-width: 55.99rem) {
  .site-nav, .site-header__phone, .site-header__cta { display: none; }
  .menu { display: block; }
}


/* --- 1. Wordmark -------------------------------------------------------------
   Live text, never an image, so it reskins by changing two strings.
   The name sits on a solid --red-text plate with --on-dark type (5.35:1),
   like the data plate riveted to a container door. Red text on charcoal
   cleared only 3.54:1 and vanished in greyscale; a red fill holds on any
   band. In the header the plate runs the full height of the bar.
   ------------------------------------------------------------------------ */

.wordmark {
  display: inline-flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0.15em;
  padding: var(--space-2) var(--space-3);
  background: var(--red-text);
  text-decoration: none;
  line-height: 1;
}
/* Ben's drawn wordmark, out of the sprite. It was set type until 21 September,
   in Work Sans Bold, which is all it could be once Big Shoulders came out on
   the 19th: the one piece of the identity that should never have been the body
   face was being set in it.

   It comes through <use> rather than an <img> for one reason. An <img> is an
   opaque document and cannot inherit anything, so the mark would be stuck in
   whatever colour it was exported as, which here is black, which is invisible
   on the charcoal header. Through <use> the paths inherit `color` off this
   link, the way the stars and the Facebook mark already do. One mark, every
   colour the site needs, no second file. */
.wordmark__mark {
  display: block;
  width: var(--wordmark-mark);
  /* The viewBox is the artwork's own bounding box, so this ratio is the
     letters themselves. There is no padding baked into the file to allow for
     and no descender, so the shape's edges are the lockup's edges. */
  aspect-ratio: 640.7 / 183.2;
  height: auto;
  fill: currentColor;
}
.wordmark__line {
  font-family: var(--font-body);
  font-weight: var(--w-medium);
  font-size: var(--wordmark-line);
  letter-spacing: 0.01em;
  /* Ben's note, 21 September: the strapline sits to the width of the name.
     The column stretches it to the mark's width, and justifying the last (and
     only) line pushes "Container" and "Sales" out to the two ends, so the
     lockup is one rectangle rather than a shape with a short line under it.
     `text-align: justify` is the fallback for anything without
     `text-align-last`; on a single line it does nothing, and the strapline
     simply sits left, which is where it was before. */
  text-align: justify;
  text-align-last: justify;
}
/* One scale factor for the whole lockup, not one per part. The strapline is
   justified out to the mark's width, so if the mark grows and the strapline
   does not, the space between "Container" and "Sales" takes up the whole
   difference and the lockup reads as broken. Both are multiplied by the same
   number and the gap holds its proportion. */
.wordmark--lg { --wordmark-scale: 1.8; padding: var(--space-4) var(--space-5); }
.wordmark--lg .wordmark__mark { width: calc(var(--wordmark-mark) * var(--wordmark-scale)); }
.wordmark--lg .wordmark__line { font-size: calc(var(--wordmark-line) * var(--wordmark-scale)); }

/* Pinned, or a band's link colour wins. Light type on --red-text on every band. */
.wordmark,
a.wordmark,
.band--ink a.wordmark,
.band--yellow a.wordmark { color: var(--on-dark); }
@media (hover: hover) {
  a.wordmark:hover,
  .band--ink a.wordmark:hover { background: var(--red-press); color: var(--on-dark); }
}
a.wordmark:focus-visible { outline-color: var(--focus-on-light); }

.site-header .wordmark {
  align-self: stretch;
  padding-block: var(--space-3) var(--space-2);
}
/* Bigger in the header since 25 October. Jen: the homepage H1 was bigger
   than the logo. At 1.6 the letters stand about 55px, level with the 58px
   H1 at its widest. Phones get 1.25, because the size picker still has to
   clear the call bar on a 667px screen. Same scale on both parts, for the
   reason given at .wordmark--lg. It never shrinks: squeezed by the nav it
   broke "Container Sales" onto two lines. Under 1280px the full nav is
   already tight, so the full 1.6 waits for room, and from 896px to 1023px,
   where the full nav first appears, there is no room at all and the logo
   stays at its old size. --header-h follows the header's height in
   tokens.css. */
.site-header .wordmark { --wordmark-scale: 1.25; flex-shrink: 0; }
.site-header .wordmark__mark { width: calc(var(--wordmark-mark) * var(--wordmark-scale)); }
.site-header .wordmark__line { font-size: calc(var(--wordmark-line) * var(--wordmark-scale)); }
@media (min-width: 56rem) and (max-width: 63.99rem) {
  .site-header .wordmark { --wordmark-scale: 1; }
}
@media (min-width: 80rem) {
  .site-header .wordmark { --wordmark-scale: 1.6; }
}
.site-header a.wordmark:focus-visible { outline-color: var(--focus-on-dark); outline-offset: -4px; }


/* --- 2. Door marking ---------------------------------------------------------
   The signature move. Data labels set the way a container door is stencilled:
   Products and photos only. There are no section eyebrows anywhere in this
   template.
   ------------------------------------------------------------------------ */

/* Sentence case since 19 September. These carry a product's facts and they
   appear on nearly every card, row and plate on the site. As letterspaced
   condensed capitals, forty of them read as forty things shouting; the page
   had no quiet level at all. Now they are small, grey and set in the body
   face, and they sit under the name instead of competing with it. */
.marking {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--w-medium);
  font-size: var(--step--1);
  line-height: 1.4;
  letter-spacing: 0;
  text-transform: none;
  font-variant-numeric: tabular-nums;
  color: var(--steel);
  max-width: none;
}
/* Secondary type on dark is --mist, never --steel. */
.band--ink .marking,
.plate .marking,
.range-tile .marking { color: var(--mist); }
.marking--lg { font-size: var(--step-1); }
.marking--sm { font-size: var(--step--1); }   /* the floor. Never smaller. */

/* --- The spec line ---------------------------------------------------------
   Added 20 September, as the one visual idea that belongs to containers.

   Every shipping container carries its figures stencilled on the right hand
   door: capitals, a fixed width for every digit so the columns line up, and a
   hairline boxing them off from everything else. That is the language this
   business already speaks, and it was the only thing on the page that could
   not have belonged to a joiner or a tyre fitter.

   This is deliberately narrow. Section 10 took forty letterspaced markings a
   page down to sentence case because the page had no quiet level, and that was
   right. Capitals come back on the lines that carry figures and nothing else,
   which is about five a page: a card's dimensions, not a photo caption, not a
   heading, not a button.
   -------------------------------------------------------------------------- */
.marking--spec {
  padding-block-start: var(--space-3);
  border-block-start: 1px solid;
  border-color: color-mix(in srgb, currentColor 30%, transparent);
  text-transform: uppercase;
  letter-spacing: var(--ls-marking);
  font-variant-numeric: tabular-nums;
}

/* A door plate never splits a figure from its unit. Each fact is a span
   that holds together, with its dot inside it, so a line only breaks
   between facts: "20FT · 6.06 M LONG ·" then "2.44 M WIDE". */
.marking > span { white-space: nowrap; }

/* Five drawn stars. A row of stars is recognised before it is read.
   --ink on light, --yellow on dark. Never yellow on a light surface. */
.stars {
  display: inline-flex;
  gap: 0.08em;
  vertical-align: -0.1em;
  color: var(--ink);
}
.stars svg { width: 0.95em; height: 0.95em; }

/* The Facebook f next to the score, so the source of the five stars is read
   before it is read. Their mark, pointing only at his own page. */
.fb-mark {
  display: inline-block;
  width: 1.15em;
  height: 1.15em;
  vertical-align: -0.22em;
  margin-inline-end: 0.3em;
}
/* No nowrap. At 768px the trust strip runs two up and "from 8 Facebook
   reviews" is wider than its half, so holding it on one line pushed the page
   49px sideways. */
.fb-link { white-space: normal; }
.band--ink .stars { color: var(--yellow); }

/* --- Where the score can be checked -----------------------------------------
   Two marks beside the five stars, one per platform, each linking out. Until
   21 September this was the words "from 8 Facebook reviews"; a Google profile
   turned up with 6 more and naming both platforms in words did not fit the
   trust strip. Ben's call: total the count, let the marks say where.

   So these are not decoration. They are the only thing on the page that says
   where 14 comes from, which is why both are links and neither is
   aria-hidden. The accessible name is on the link, not the svg, because a
   mark with no name is a link with no name.
   ------------------------------------------------------------------------ */

.src-links {
  display: inline-flex;
  align-items: center;
  gap: 0;
  /* The row is --tap tall for the hit areas below. Without this the line it
     sits on inherits that height and the strip grows by 20px. */
  margin-block: calc(var(--tap) / -2);
  /* Each mark carries about 10px of its own hit area as padding on the left,
     so without this the pair starts a step away from "reviews". This cancels
     most of that first slab, and the word space does the rest. It was -0.85rem
     while the marks were bare letterforms; a disc carries its own edge much
     further out, so the same figure buried the f in the last "s". */
  margin-inline-start: -0.15rem;
  vertical-align: middle;
}
.src-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44px of hit area. This is the one number here that is not a visual
     decision: a mark drawn at 24px is not a 24px target on a phone.

     It is kept even though scripts/qa.js would exempt these, because it
     exempts `display: inline` links inside running text and these are
     inline-flex. An icon is not running text, and switching the display to
     duck the check would be fixing the gate rather than the page. */
  min-width: var(--tap);
  min-height: var(--tap);
  /* The same colour as the stars, not the grey of the line the marks sit on.
     They belong to the score, and inheriting the quiet grey left them looking
     like two things that had drifted in from somewhere else. */
  color: var(--ink);
}
.band--ink .src-link { color: var(--yellow); }
.src-mark {
  /* Drawn at about 23px, not 18px. At 18px each mark sat in the middle of a
     44px box with 13px of dead air on either side, so the pair floated away
     from the line and from each other. Ben, 21 September: "the icons look
     disconnected." Filling more of the box is what closes the gap, and a disc
     at this size carries the same weight as a star beside it. */
  width: 1.4em;
  height: 1.4em;
  fill: currentColor;
}
/* The marks carry no underline: an underline under a glyph reads as a fault
   rather than as a link. The hover is on the mark itself. */
.src-link { text-decoration: none; }
@media (hover: hover) {
  .src-link:hover .src-mark { fill: var(--red-text); }
  .band--ink .src-link:hover .src-mark { fill: var(--yellow); }
}

/* The full block, for the 20ft page. Reads like the data panel on a door. */
.marking-block {
  display: grid;
  grid-template-columns: auto 1fr 1fr;
  margin: 0;
  border: var(--edge) solid currentColor;
  font-family: var(--font-display);
  font-weight: var(--w-display);
  font-size: var(--step-0);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}
/* A figure never splits from its unit. "1,170 cu ft" was breaking after "cu"
   in the middle column on a phone, which made that row a line taller than the
   rest and the table read as misaligned. */
.marking-block > * {
  white-space: nowrap;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-block-end: 1px solid currentColor;
}
.marking-block > :nth-last-child(-n + 3) { border-block-end: 0; }
.marking-block dt { font-weight: var(--w-medium); opacity: 1; }
.marking-block dd { text-align: end; }
.marking-block__note {
  margin-block-start: var(--space-3);
  font-size: var(--step--1);
  color: var(--steel);
}


/* --- 3. Caption stack --------------------------------------------------------
   Four door marking lines on charcoal blocks, the last one yellow.
   It overlaps the corner of the hero photo.
   ------------------------------------------------------------------------ */

.caption-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
  margin: 0;
  max-width: none;
  font-family: var(--font-display);
  font-weight: var(--w-display);
  font-size: clamp(1.125rem, 0.9rem + 1vw, 1.75rem);
  line-height: 1.1;
}
.caption-stack > span {
  padding: 0.22em 0.55em 0.18em;
  background: var(--ink);
  color: var(--on-dark);
}
.caption-stack > .caption-stack__last { color: var(--yellow); }


/* --- 4. Plate -----------------------------------------------------------------
   An empty photo slot. Every slot on the build is empty: the studio cut-outs
   came off on 19 September and the yard photos have not arrived.

   A plate is a flat charcoal box with a cross corner to corner and a label
   naming the photo it is waiting for. The cross is the point. The earlier
   plates carried a to scale line drawing of the container, which looked like
   content and read as a finished illustration rather than as a gap, so nobody
   could tell at a glance which slots were still outstanding. A cross can only
   mean one thing.
   ------------------------------------------------------------------------ */

.plate {
  position: relative;
  display: grid;
  align-items: end;
  justify-items: start;
  aspect-ratio: var(--ratio, 4 / 3);
  overflow: hidden;
  background-color: var(--ink-2);
  color: var(--mist);
}
.plate > picture, .plate > img {
  position: absolute; inset: 0; width: 100%; height: 100%;
}
.plate img { width: 100%; height: 100%; object-fit: cover; }

/* The cross. Two corner to corner rules and a box, drawn with gradients so it
   costs no request and no markup. `to top right` and `to bottom right` run
   between actual corners, so the diagonals stay true at any ratio. */
.plate::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--plate-line);
  background-image:
    linear-gradient(to top right,
      transparent calc(50% - 0.5px), var(--plate-line) calc(50% - 0.5px),
      var(--plate-line) calc(50% + 0.5px), transparent calc(50% + 0.5px)),
    linear-gradient(to bottom right,
      transparent calc(50% - 0.5px), var(--plate-line) calc(50% - 0.5px),
      var(--plate-line) calc(50% + 0.5px), transparent calc(50% + 0.5px));
  pointer-events: none;
}
/* A photo covers the cross. The cross says "no photo yet", so the moment one
   arrives it has to go, cut-out or not: a diagonal running behind a container
   reads as a fault, not as a frame. */
.plate:has(img)::before { display: none; }

.plate__label {
  position: relative;
  font-size: var(--step--1);
  margin: var(--space-4);
  padding: 0.3em 0.6em 0.25em;
  background: var(--ink);
  color: var(--on-dark);
}

/* --- The cut-outs -----------------------------------------------------------
   Jen's four studio shots, knocked out to transparency by
   scripts/make_cutouts.py. They are not yard photos, so they do not fill the
   frame the way a yard photo will: they sit on the charcoal as objects, and
   the plate stays visible around them.

   Trimmed of their white these units run 1.12 to 0.63 on the long side against
   a 4/3 frame, so `cover` would saw the ends off the container. `contain` is
   not optional here.
   ------------------------------------------------------------------------ */

.plate--cutout img {
  object-fit: contain;
  box-sizing: border-box;
  /* Percentages, not the space tokens. This padding has to hold its proportion
     across two frames of very different sizes: a 632px row on the range page
     and a third-width card on the homepage grid. Percentage padding resolves
     against the width on all four sides, so one rule serves both. The deeper
     bottom is clearance for the caption. */
  padding: 5% 5% 16%;
}

/* The house grade, from assets/README.md. One pass over every photo on the
   build, so that pictures taken on different days read as one afternoon. It
   goes on the cut-outs now so Anthony's yard photos land beside them already
   matching. */
img.graded { filter: saturate(0.82) contrast(1.06) brightness(1.02) sepia(0.08); }


/* --- 5. Range card and the not sure tile ------------------------------------
   Six cards, all the same size. Three across, then two, then two on a phone.
   Every card is identical: plate, name, spec line, button.

   The grid has run four tracks twice, with the 20ft one trip and the tile
   each spanning two, and it has been taken back to six equal cards twice:
   on 19 September and again on 20 September, both on Ben's eye at full
   width. The spans do stop six cards looking like a template, and they also
   make one card's photo three times the area of its neighbours', which reads
   as a sale rather than a range. The page is a list of sizes and its job is
   to let a buyer find theirs and press a button. Leave it flat.
   ------------------------------------------------------------------------ */

.range-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-6);
}

@media (max-width: 63.99rem) {
  .range-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 35.99rem) {
  /* ONE column, not two. Two cards across a 390px screen leaves each one
     163px wide, and the card's contents do not fit in 163px: the spec line is
     letterspaced capitals and broke over six lines, the button label over
     four, and "See the 20ft page" over two. A card that is mostly wrapped
     text is not a card. One column gives the spec one line, the button one
     line, and a plate big enough to see the container in. */
  .range-grid { grid-template-columns: 1fr; gap: var(--space-5); }
  /* A letterbox, not a 4/3 square-ish frame. One column makes the card 358px
     wide, and at 4/3 that is a 268px deep plate six times over, which put the
     homepage 200px past its phone length budget on its own. At 16/9 the plate
     is 201px and still far bigger than the 122px it had at two columns, so
     the photograph gained and the page lost nothing it needed. */
  .range-card > .plate { --ratio: 16 / 9; }
  .range-card__name { font-size: var(--step-1); }
  .range-card .marking > span { white-space: normal; }
  .range-card .btn {
    display: flex;
    width: 100%;
    padding-inline: var(--space-2);
    font-size: max(16px, 1rem);
    min-height: var(--picker-h);
  }
  /* The label and the tighter cut-out padding below were both written for a
     163px card. At one column the card is 358px and there is room for the
     caption again, so it comes back. */
  .range-card__body { padding: var(--space-4); }
}

.range-card,
.range-tile {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-block-start: var(--edge) solid var(--ink);
}
.range-card__body,
.range-tile {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: var(--space-3);
  padding: var(--space-5);
}
.range-card__name { font-size: var(--step-2); max-width: none; }
.range-card__who  { color: var(--steel); }
/* Under the button on the two 20ft cards. The button asks for the enquiry,
   this offers the detail first, for the buyer who is not ready to ask yet. */
.range-card__link { margin: 0; text-align: center; font-size: var(--step--1); }
/* Optional. One "from" price per card, only when the lead sheet gives prices.
   Leave the element out and nothing shows: there is no empty state to style.
   If prices go on, delete the pound rule in scripts/qa.js. */
.range-card__price {
  font-weight: var(--w-black);
  font-size: var(--step-2);
  line-height: var(--lh-heading);
  font-variant-numeric: tabular-nums;
}
.range-card__price small {
  font-weight: var(--w-medium);
  font-size: var(--step--1);
  color: var(--steel);
}
.range-card .btn,
.range-tile .btn {
  margin-block-start: auto;            /* footers line up */
  min-height: var(--card-btn-h);
  padding-inline: var(--space-3);
  font-size: max(16px, 1rem);
}
.range-card__body > .marking { color: var(--steel); }

/* The not sure tile is the same card with a dark fill. It used to be double
   width with its own type scale, which made it compete with the containers
   for attention when all it does is catch the people who cannot pick one. */
.range-tile {
  background-color: var(--ink);
  color: var(--on-dark);
  border-block-start: var(--edge) solid var(--yellow);
}
/* Its own dark surface, so it carries the dark band's link rules whether or
   not the markup adds band--ink. Red text on charcoal is 2.79:1. */
.range-tile a:not(.btn) { color: var(--on-dark); }
@media (hover: hover) { .range-tile a:not(.btn):hover { color: var(--yellow); } }
.range-tile__title { font-size: var(--step-2); max-width: none; }
.range-tile p { color: var(--mist); }
.range-tile .btn { border-color: var(--yellow); }
.range-tile :where(a):focus-visible { outline-color: var(--focus-on-dark); }


/* --- 6. Size picker ----------------------------------------------------------
   The hero's primary action. Four plain links, so it works with scripts off.
   Each one opens the enquiry page with that size already ticked.
   ------------------------------------------------------------------------ */

.picker { margin: 0; container-type: inline-size; }
.picker__label {
  margin-block-end: var(--space-3);
  font-weight: var(--w-medium);
  color: var(--on-dark);
}
/* Two by two until the picker itself is wide enough for four in a row.
   A container query, so it answers to the column it sits in, not the screen. */
.picker__list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}
@container (min-width: 36rem) {
  .picker__list { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* The marking under each size used to be one word or one figure, so four
   buttons came out the same height by luck. "One trip or second hand" wraps,
   so the height is pinned properly instead: the list item stretches to the
   tallest in the row and the button fills it. */
.picker__list > li { display: flex; }
.picker__list > li > .picker__btn { flex: 1 1 auto; }
/* Filled, not outlined. Four thin outlines were the quietest shapes in the
   hero and lost the squint test to the header button. Each is a door plate:
   the size big, a marking under it with a fact from the lead sheet. */
.picker__btn,
.band--ink a.picker__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: var(--picker-h);
  padding: var(--space-2) var(--space-3);
  background: var(--btn-fill);
  border: var(--edge) solid var(--btn-edge);
  color: var(--btn-text);
  font-family: var(--font-display);
  font-weight: var(--w-display);
  text-decoration: none;
  text-align: center;
  line-height: 1;
  position: relative;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out),
              translate var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
/* The size picker lifts like every other button. It is not a .btn, so it
   carries its own copy of the rule and its own extended hit area. */
.picker__btn::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block: 0 calc(var(--lift) * -1);
}
.picker__size {
  font-size: var(--step-1);
  letter-spacing: 0.01em;
  white-space: nowrap;          /* four buttons, one height */
}
/* .picker__mark is unused on the pages since 20 September: the buttons carry
   the size and nothing else. The rule stays for the template, where a second
   line may earn its place on a business with fewer obvious sizes. */
.picker__mark {
  font-size: var(--step--1);
  font-weight: var(--w-body);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
}
/* Ungated, for the reason written against .btn:hover above. The colour stays
   put on hover and only the lift happens, as everywhere else. */
.picker__btn:hover,
.picker__btn:focus-visible,
.band--ink a.picker__btn:hover {
  translate: 0 calc(var(--lift) * -1);
  box-shadow: var(--btn-shadow-lift);
}
/* AFTER the hover rule, not before it. These carry the same specificity, so
   source order decides, and while :active is also :hover the later one wins.
   With this block above the hover, pressing a picker button darkened it but
   left it hovering 6px up on its shadow instead of dropping back down. */
.picker__btn:active,
.band--ink a.picker__btn:active {
  background: var(--btn-fill-press); border-color: var(--btn-edge-press); color: var(--btn-text);
  translate: 0 0;
  box-shadow: var(--btn-shadow-press);
  transition-duration: var(--dur-instant);
}
/* The ring sits clear of the fill, so it is seen against the charcoal. */
.picker__btn:focus-visible { outline: 2px solid var(--focus-on-dark); outline-offset: 4px; }


/* --- 7. Fixed phone bar ------------------------------------------------------
   Call and Enquire under the thumb on every scroll position. 64px, under 8%
   of a phone screen. Its height is reserved on body in base.css.
   ------------------------------------------------------------------------ */

.phone-bar { display: none; }

@media (max-width: 47.99rem) {
  .phone-bar {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: var(--z-bar);
    display: grid;
    grid-template-columns: 1fr 1fr;
    padding-block-end: env(safe-area-inset-bottom, 0px);
    background: var(--ink-2);
    border-block-start: 1px solid var(--rule-on-dark);
  }
  .phone-bar--call-only { grid-template-columns: 1fr; }
  .phone-bar a {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: var(--bar-h);
    font-weight: var(--w-medium);
    text-decoration: none;
  }
  .phone-bar__call    { background: var(--ink-2);  color: var(--on-dark); }
  .phone-bar__enquire { background: var(--yellow); color: var(--ink); }
  /* The two halves of this bar do NOT lift, and it is the one deliberate
     exception to "every button lifts".

     It is fixed to the bottom edge of the screen. There is nothing under it
     to leave a shadow on, so a lift would open a 6px gap onto whatever is
     scrolling past underneath and the bar would look unstuck. It is also
     phone only, where there is no cursor to lift it with. Darkening on press
     is the right feedback for a thumb. */
  .phone-bar__call:active    { background: var(--ink-press); }
  .phone-bar__enquire:active { background: var(--yellow-deep); }
  .phone-bar a:focus-visible { outline: 2px solid var(--focus-on-dark); outline-offset: -4px; }
  .phone-bar__enquire:focus-visible { outline-color: var(--ink); }
}


/* --- 8. Enquiry panel --------------------------------------------------------
   Four required answers: size, postcode, name, phone. Labels above every
   field and always visible. The panel is boxed, and one line of proof sits
   inside the box under the button.
   ------------------------------------------------------------------------ */

.enquiry {
  display: grid;
  gap: var(--space-5);
  padding: clamp(var(--space-5), 4vw, var(--space-7));
  background: var(--surface);
  border: var(--edge) solid var(--ink);
  color: var(--ink);
}
.enquiry fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
.enquiry legend,
.enquiry label.field__label {
  display: block;
  padding: 0;
  margin-block-end: var(--space-2);
  font-weight: var(--w-medium);
}
.field__optional { font-weight: var(--w-body); color: var(--steel); }
/* Above the box, not under it, since 20 September: a hint you read after you
   have already answered is not a hint. */
.field__help { margin-block: 0 var(--space-2); font-size: var(--step--1); color: var(--steel); }

.enquiry input[type="text"],
.enquiry input[type="tel"],
.enquiry textarea {
  display: block;
  width: 100%;
  min-height: 3rem;
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border: var(--edge) solid var(--field);
  border-radius: var(--radius);
  color: var(--ink);
}
.enquiry textarea { min-height: 6.5rem; resize: vertical; }
/* A postcode is eight characters. A full width box for it tells the person
   filling it in that something longer is expected, and then looks wrong when
   they type TR16 5DZ into it. */
.enquiry input#f-postcode { width: 10rem; }
.enquiry input:focus-visible,
.enquiry textarea:focus-visible { border-color: var(--ink); }
.enquiry [aria-invalid="true"] { border-color: var(--invalid); }
.field__error { margin-block-start: var(--space-2); color: var(--invalid); font-weight: var(--w-medium); }

.enquiry__row { display: grid; gap: var(--space-5); }
@media (min-width: 40rem) { .enquiry__row { grid-template-columns: 1fr 1fr; } }

/* Tick buttons: a real radio underneath, so it works without scripts. */
.ticks { display: flex; flex-wrap: wrap; gap: var(--space-2); }
/* The five sizes on an even grid, three then two, rather than a wrapped row
   where the widths fall wherever the words end. */
.ticks--grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-2);
}
.ticks--grid > .tick:nth-child(4),
.ticks--grid > .tick:nth-child(5) { grid-column: span 1; }
@media (max-width: 30rem) {
  .ticks--grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.ticks--grid .tick { display: flex; }
.ticks--grid .tick span { flex: 1; justify-content: center; text-align: center; }
/* "Not sure yet" was the only one of the five long enough to wrap, so it sat
   two lines tall beside four one line chips and the grid looked broken. */
.ticks--grid .tick span { white-space: nowrap; }
.tick { position: relative; }
.tick input { position: absolute; opacity: 0; inset: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
/* Set like the hero picker, same face and height, so the size chosen there
   visibly carries through to this panel. */
.tick span {
  display: inline-flex;
  align-items: center;
  min-height: var(--picker-h);
  padding: var(--space-2) var(--space-4);
  border: var(--edge) solid var(--field);
  font-family: var(--font-display);
  font-weight: var(--w-medium);
  font-size: var(--step-1);
  letter-spacing: 0.01em;
  transition: background-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out);
}
/* A ticked chip is a yellow fill, a charcoal border and a drawn tick, not a
   colour swap alone. Colour on its own fails anyone who cannot separate these
   two, and on a form where one of five must be chosen the answer has to be
   obvious at a glance. */
.tick input:checked + span {
  background: var(--yellow);
  color: var(--ink);
  border-color: var(--ink);
  font-weight: var(--w-display);
}
.tick input:checked + span::before {
  content: "";
  flex: 0 0 auto;
  width: 0.85em;
  height: 0.5em;
  margin-inline-end: 0.5em;
  border-inline-start: 3px solid currentColor;
  border-block-end: 3px solid currentColor;
  rotate: -45deg;
  translate: 0 -0.15em;
}
.tick input:focus-visible + span { outline: 2px solid var(--focus-on-light); outline-offset: 3px; }
@media (hover: hover) { .tick input:not(:checked):hover + span { border-color: var(--ink); } }

.enquiry__foot { display: grid; gap: var(--space-3); }
/* The score moved inside the panel on 20 September, under the button, where
   it is read at the moment of deciding to press it rather than in a box off
   to the side. */
.enquiry__stars { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.enquiry__proof { font-size: var(--step--1); color: var(--steel); }
.enquiry__error {
  padding: var(--space-3) var(--space-4);
  border: 2px solid var(--ink);
  background: var(--surface);
  color: var(--ink);
  font-weight: var(--w-medium);
}
.enquiry__error[hidden] { display: none; }

.enquiry__done { display: none; }
.enquiry.is-sent > :not(.enquiry__done) { display: none; }
.enquiry.is-sent > .enquiry__done { display: grid; gap: var(--space-4); }
.enquiry__done h2 { font-size: var(--step-4); }
