/* Bedshop — the shop's own design tokens and front page.
 *
 * Loaded by wp/Page/FrontPage.php and wp/Page/ConfiguratorPage.php. Kept as one file
 * because it is one design system: the front page and the configurator have to look like
 * the same shop, and a shared :root block is the only way to guarantee that rather than
 * hoping two files agree.
 *
 * Self-hosted fonts. A UK shop loading type from Google's CDN hands every visitor's IP to
 * a third country, which is a live question under UK GDPR and not one worth asking on a
 * page that exists to sell something. Four woff2 files, variable, 200 KB total, no external
 * request. Both families are variable so one file per subset covers every weight.
 *
 * Colours are a warm paper ground with slate ink and a single rust accent. That trio is
 * chosen rather than arrived at: slate and rust are the colours the workshop actually has
 * in the building, and a bed is fabric before it is anything else. Nothing here is a
 * gradient, nothing has a drop shadow, and the radius stays small — this is joinery, not
 * an app.
 */

@font-face {
  font-family: 'Fraunces';
  /* Names must match the files in Assets/fonts/ exactly. These did not, once: the CSS asked
   * for fraunces-latin.woff2 and the file was fraunces-latin-var.woff2, so every face 404'd,
   * the browser silently fell back to Georgia, and the page still looked like a serif site.
   * A wrong font filename is invisible in a screenshot and obvious in document.fonts. */
  src: url('fonts/fraunces-latin-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Fraunces';
  src: url('fonts/fraunces-latin-ext-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Archivo';
  src: url('fonts/archivo-latin-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Archivo';
  src: url('fonts/archivo-latin-ext-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1E00-1EFF,
    U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --bedshop-paper: #faf8f5;
  --bedshop-paper-deep: #f2eee7;
  --bedshop-ink: #1e2328;
  --bedshop-ink-soft: #4d565e;
  --bedshop-ink-faint: #7b848c;
  --bedshop-rule: #ddd6cb;
  --bedshop-rust: #9c4a2f;
  --bedshop-rust-deep: #7d3a24;
  --bedshop-sage: #5f6b5a;

  --bedshop-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --bedshop-body: 'Archivo', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* A 4px scale. Everything is a multiple, so nothing drifts a pixel out of line. */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4rem;
  --s-9: 6rem;

  --bedshop-measure: 34rem;
}

/* --------------------------------------------------------------- base and typography */

/* The width fight, and why these rules exist.
 *
 * Twenty Twenty-Five treats the post-content area as a *constrained* layout: anything inside
 * it is capped at a reading measure — 645px here — and centred. Our page is not a piece of
 * prose, so the cap has to be lifted or every section collapses into a narrow column and the
 * four-across reassurance row becomes a stack of 95px slivers.
 *
 * It has to be lifted on the page AND on each section, because the theme's constraint is
 * applied to descendants individually rather than inherited once. Lifting it only on
 * `.bedshop-front` leaves every section still capped.
 */
.bedshop-front,
.bedshop-configurator {
  color: var(--bedshop-ink);
  font-family: var(--bedshop-body);
  font-size: 1.0625rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  max-width: none;
}

.bedshop-front section,
.bedshop-front .bedshop-shell,
.bedshop-front .bedshop-hero__grid,
.bedshop-front .bedshop-designs,
.bedshop-front .bedshop-steps__list,
.bedshop-front .bedshop-why {
  max-width: none;
}

/* The block theme computes its content measure from these custom properties. Naming them
 * means anything the theme derives from them lands on the width we want rather than on its
 * own prose default. */
.bedshop-front {
  --wp--style--global--content-size: 72rem;
  --wp--style--global--wide-size: 90rem;
  /* The theme's default prose measure, restated as ours. WordPress sets a global line length
     for readable text and the shop inherits it; a lede's natural line at this size is far
     longer than 66 characters, so it is widened rather than left to break mid-sentence. */
  --wp--custom--line-height--body: 1.6;
}

/* The lede paragraph, taken off the theme's narrow measure. It is the second most important
 * sentence on the page and it was setting at roughly 45 characters a line, which puts a hard
 * ragged right edge against a 4rem headline directly above it. */
.bedshop-front .bedshop-hero__lead,
.bedshop-front .bedshop-choose__intro,
.bedshop-front .bedshop-why__intro {
  max-width: 42rem;
  text-wrap: pretty;
}

.bedshop-front *,
.bedshop-configurator * {
  box-sizing: border-box;
}

.bedshop-front h1,
.bedshop-front h2,
.bedshop-front h3 {
  font-family: var(--bedshop-display);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.015em;
  margin: 0;
  text-wrap: balance;
}

.bedshop-front p {
  margin: 0;
}

.bedshop-front a {
  color: inherit;
}

/* One focus treatment everywhere, and it is visible on a phone and not only for a mouse.
 * :focus-visible rather than :focus so a tap does not leave a ring on the screen. */
.bedshop-front a:focus-visible,
.bedshop-configurator :focus-visible {
  outline: 3px solid var(--bedshop-rust);
  outline-offset: 3px;
  border-radius: 2px;
}

.bedshop-shell {
  width: 100%;
  max-width: 72rem;
  margin: 0 auto;
  padding: 0 var(--s-5);
}

@media (max-width: 640px) {
  .bedshop-shell {
    padding: 0 var(--s-4);
  }
}

/* An eyebrow: the small uppercase line above a heading. Used to name a section, not to
 * decorate one, so it always says what the thing below it actually is. */
.bedshop-eyebrow {
  font-family: var(--bedshop-body);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bedshop-ink-faint);
  margin: 0 0 var(--s-3);
}

/* ------------------------------------------------------------------- the front page */

.bedshop-hero {
  padding: var(--s-8) 0 var(--s-7);
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-hero__grid {
  display: grid;
  gap: var(--s-6);
  align-items: end;
}

@media (min-width: 900px) {
  .bedshop-hero__grid {
    grid-template-columns: 1.05fr 0.95fr;
    gap: var(--s-8);
    align-items: start;
  }
}

/* The hero's second column: a photograph of a real Bed Design above the price panel.
 *
 * A bed shop whose front door has no photograph in it has told a visitor nothing about what it
 * sells, which is the one thing a photograph does that a sentence cannot. The picture is the
 * first Bed Design on sale that has one — so it is always something the shop can actually make
 * — and it is wrapped in a link to that bed's own page with its name under it, so it is a way
 * into a product rather than decoration.
 *
 * 4:3 rather than square, and for the same reason as every other photograph on this page: a
 * bed is a wide, low object, and a square frame crops the headboard off — which is the part
 * being sold. The same ratio as `.bedshop-design__photo`, so the hero and the cards crop the
 * same way and the page reads as one set of pictures.
 */
.bedshop-hero__media {
  display: block;
  position: relative;
  overflow: hidden;
  border-radius: 4px;
  background: var(--bedshop-paper-deep);
  text-decoration: none;
  margin-bottom: var(--s-4);
}

.bedshop-hero__photo {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform 400ms ease;
}

.bedshop-hero__media:hover .bedshop-hero__photo,
.bedshop-hero__media:focus-visible .bedshop-hero__photo {
  transform: scale(1.03);
}

/* The name on the picture, over a scrim. The same reason as the department tiles: the image is
 * whatever the bed happens to be photographed on, so the text cannot assume it is dark in the
 * bottom third and needs its own ground to sit on.
 *
 * Two spans, not one string: the name and the from-price wrap as units, so a narrow column
 * breaks between them rather than mid-price ("£350.00" never splits across lines). */
.bedshop-hero__caption {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.25em 0.5em;
  align-items: baseline;
  padding: var(--s-6) var(--s-4) var(--s-3);
  background: linear-gradient(
    to top,
    rgba(30, 35, 40, 0.86) 0%,
    rgba(30, 35, 40, 0.55) 55%,
    rgba(30, 35, 40, 0) 100%
  );
  color: #fff;
  font-family: var(--bedshop-display);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.25;
}

.bedshop-hero__caption-price {
  white-space: nowrap;
  font-size: 0.9375rem;
  font-weight: 500;
  opacity: 0.92;
}

.bedshop-hero__title {
  font-size: clamp(2.5rem, 7vw, 4.25rem);
  letter-spacing: -0.03em;
}

.bedshop-hero__title em {
  font-style: normal;
  color: var(--bedshop-rust);
}

/* The lead paragraph. One job: say what the shop is, in one sentence a Customer can repeat
 * to a friend. It sits at 1.25rem because it is the second most important text on the page
 * and is competing with a 4rem headline. */
.bedshop-hero__lead {
  font-size: 1.25rem;
  line-height: 1.5;
  color: var(--bedshop-ink-soft);
  max-width: var(--bedshop-measure);
  margin-top: var(--s-4);
}

.bedshop-hero__actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--s-3);
  margin-top: var(--s-6);
}

/* One thumb, one job. The primary CTA spans the column on a phone (thumb-sized,
 * 48px+ via .bedshop-btn) and sizes to content on desktop; the browse affordance
 * is a quiet tertiary link beneath it, not a second button competing for the click. */
.bedshop-hero__cta {
  width: 100%;
}

@media (min-width: 900px) {
  .bedshop-hero__cta {
    width: auto;
    align-self: flex-start;
  }
}

.bedshop-hero__browse {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--bedshop-ink-soft);
  text-decoration: underline;
  text-decoration-color: var(--bedshop-rule);
  text-underline-offset: 3px;
}

.bedshop-hero__browse:hover {
  color: var(--bedshop-rust);
  text-decoration-color: var(--bedshop-rust);
}

/* The price panel. Deliberately the only place a figure appears at this size, and it says
 * what it is: the price of the least expensive complete bed, not a promise. */
.bedshop-hero__price {
  background: var(--bedshop-paper-deep);
  border: 1px solid var(--bedshop-rule);
  border-radius: 4px;
  padding: var(--s-5);
}

.bedshop-hero__price dt {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bedshop-ink-faint);
  margin: 0 0 var(--s-2);
}

.bedshop-hero__price dd {
  margin: 0;
  font-family: var(--bedshop-display);
  font-size: clamp(2rem, 5vw, 2.75rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1;
}

.bedshop-hero__price-note {
  font-size: 0.9375rem;
  color: var(--bedshop-ink-soft);
  margin: var(--s-3) 0 0;
}

.bedshop-hero__price-note strong {
  font-weight: 600;
  color: var(--bedshop-ink);
}

/* Buttons. One primary, one quiet. No third.
 *
 * `color` is set on every variant, not just the primary. The theme's global `a { color }`
 * is more specific than a single class in places, so the primary would render dark text on
 * a dark ground — an invisible button that is still perfectly clickable and looks broken.
 * Setting it in both states is the fix, and setting `background` on the base rule means the
 * quiet variant cannot inherit the primary's fill.
 */
.bedshop-front .bedshop-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 var(--s-5);
  background: transparent;
  color: var(--bedshop-ink);
  border: 1px solid var(--bedshop-ink);
  border-radius: 3px;
  font-family: var(--bedshop-body);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}

.bedshop-front .bedshop-btn--primary {
  background: var(--bedshop-ink);
  color: var(--bedshop-paper);
}

.bedshop-front .bedshop-btn--primary:hover {
  background: var(--bedshop-rust);
  border-color: var(--bedshop-rust);
  color: var(--bedshop-paper);
}

.bedshop-front .bedshop-btn--quiet:hover {
  background: var(--bedshop-paper-deep);
  color: var(--bedshop-ink);
}

/* -------------------------------------------------------------- why choose us */

/* Four things a buyer of a made-to-order bed wants to know before they start configuring.
 * No invented badges and no star ratings — these are facts the shop can already stand behind,
 * and they are now the body of a section with a heading over them rather than a bare strip of
 * four labels with nothing to say what they are for.
 *
 * The cells keep the `.bedshop-reassure__label` / `__text` names they have always had: they are
 * the same four promises in the same words, they are just under a heading now, and infra/
 * phone_check.py asserts those four labels are present and legible on a 390px screen. Renaming
 * them for tidiness would break that check for no gain.
 *
 * The grid is on the section and the columns are restated on the shell inside it, because
 * `.bedshop-shell` is the wrapper rather than a grid item — putting the columns on the shell
 * alone made the shell the only item and the row collapsed to one column.
 */
.bedshop-why {
  padding: var(--s-7) 0;
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-why__title {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  margin-bottom: var(--s-2);
}

.bedshop-why__intro {
  color: var(--bedshop-ink-soft);
  max-width: 42rem;
  text-wrap: pretty;
  margin-bottom: var(--s-6);
}

.bedshop-why__grid {
  display: grid;
  gap: var(--s-5);
  grid-template-columns: 1fr;
}

.bedshop-why__point {
  min-width: 0;
  padding-left: var(--s-4);
  border-left: 2px solid var(--bedshop-rule);
}

.bedshop-reassure__label {
  font-family: var(--bedshop-body);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bedshop-rust);
  margin: 0 0 var(--s-2);
}

/* At desktop the four sit side by side and a wrapped eyebrow looks broken. Once the row
 * stacks on a phone the eyebrow has the full width and can wrap without looking wrong, so the
 * no-wrap is scoped to the widths where it is actually needed. */
@media (min-width: 560px) {
  .bedshop-reassure__label {
    text-wrap: nowrap;
  }
}

.bedshop-reassure__text {
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--bedshop-ink-soft);
  margin: 0;
}

@media (min-width: 560px) {
  .bedshop-why__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 900px) {
  .bedshop-why__grid {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* ------------------------------------------------------------------- choosing a bed */

.bedshop-choose {
  padding: var(--s-7) 0;
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-choose__title {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  margin-bottom: var(--s-2);
}

.bedshop-choose__intro {
  color: var(--bedshop-ink-soft);
  max-width: var(--bedshop-measure);
  margin-bottom: var(--s-6);
}

/* The bed designs. A card per design, and a card that cannot yet have a photograph says so
 * honestly rather than showing a grey box that reads as a broken image.
 */
/* The cards.
 *
 * A fixed number of columns per breakpoint rather than `auto-fill` with a floor, because the
 * page has to read as one grid rather than as a collection of boxes. Measured against the page
 * this layout is modelled on, every category tile and every product card is exactly 202.5px in
 * a four-column track with a 30px gutter — the same grid used twice — and that consistency is
 * most of why that page scans quickly: the eye learns the rhythm in the first section and does
 * not have to re-learn it at every shelf below.
 *
 * `auto-fill` with a 20rem floor gave two 382px cards at a 788px content width, which is the
 * opposite problem: cards large enough that only two fit, so a shelf of eight beds became four
 * screens of scrolling and the page lost its shelves entirely. The floor is 18rem, which
 * puts three cards across on a desktop, two on a tablet and one on a phone, and lets the
 * photography do the selling rather than reading as swatches.
 *
 * `auto-fill` rather than `auto-fit` still: auto-fit collapses empty tracks, so a lone card
 * would stretch across the whole 72rem and look like a formatting error rather than a product.
 * auto-fill keeps the track widths and leaves the empty ones empty, so one card sits at a
 * readable size, and a Bed Design added tomorrow has somewhere to go.
 */
.bedshop-designs {
  display: grid;
  gap: var(--s-6);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
}

.bedshop-design {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--bedshop-rule);
  border-radius: 4px;
  overflow: hidden;
  background: #fff;
  transition: border-color 0.2s ease;
}

.bedshop-design:hover,
.bedshop-design:focus-within {
  border-color: var(--bedshop-ink);
}

.bedshop-design__photo {
  aspect-ratio: 4 / 3;
  width: 100%;
  /* The width/height attributes WordPress prints on the <img> are mapped to CSS as a
   * presentational hint (height: 910px here). A presentational hint loses to any author
   * declaration of the same property — but this rule declared none, so the hint won,
   * aspect-ratio could not take effect, and every card rendered as a tall crop of the
   * photograph. Auto hands the height back to the ratio. */
  height: auto;
  object-fit: cover;
  display: block;
  background: var(--bedshop-paper-deep);
  transition: transform 0.5s ease;
}

.bedshop-design:hover .bedshop-design__photo,
.bedshop-design:focus-within .bedshop-design__photo {
  transform: scale(1.04);
}

@media (prefers-reduced-motion: reduce) {
  .bedshop-design__photo {
    transition: none;
  }

  .bedshop-design:hover .bedshop-design__photo,
  .bedshop-design:focus-within .bedshop-design__photo {
    transform: none;
  }
}

/* A photograph-shaped hole. 16:10 rather than 4:3 because a bed is a wide, low object and a
 * squarer frame crops the headboard off, which is the part being sold. */
.bedshop-design__placeholder {
  aspect-ratio: 16 / 10;
  display: grid;
  place-items: center;
  padding: var(--s-5);
  text-align: center;
  background: var(--bedshop-paper-deep);
  border-bottom: 1px solid var(--bedshop-rule);
  position: relative;
  overflow: hidden;
}

/* A woven line pattern, drawn in CSS rather than shipped as an image: it stands in for the
 * texture of the thing itself, costs nothing to load, and is the visual hint that this space
 * is waiting for a fabric. */
.bedshop-design__placeholder::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(
      90deg,
      var(--bedshop-rule) 0 1px,
      transparent 1px 7px
    ),
    repeating-linear-gradient(0deg, var(--bedshop-rule) 0 1px, transparent 1px 7px);
  opacity: 0.5;
}

.bedshop-design__placeholder p {
  position: relative;
}

.bedshop-design__placeholder p {
  font-size: 0.9375rem;
  color: var(--bedshop-ink-faint);
  max-width: 18rem;
  margin: 0;
}

.bedshop-design__body {
  padding: var(--s-5);
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  flex: 1;
}

.bedshop-design__name {
  font-family: var(--bedshop-display);
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* The editorial price: eyebrow + big serif number + faint VAT suffix, in the same
 * language as the hero's FROM £290.00 block. Thumbs compare prices across a 36-bed
 * shelf without reading every name; the saving, when there is one, shares the eyebrow
 * line so comparison stays a single scan line. */
.bedshop-design__price {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
}

.bedshop-design__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--bedshop-body);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bedshop-ink-faint);
}

.bedshop-design__amount {
  font-family: var(--bedshop-display);
  font-size: 1.75rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--bedshop-ink);
  line-height: 1.1;
}

.bedshop-design__vat {
  font-family: var(--bedshop-body);
  font-size: 0.8125rem;
  color: var(--bedshop-ink-faint);
}

/* The discount, when there is one. Rendered only when the manufacturer's RRP is above the
 * price (ADR-0017), so this markup exists on the page only when the saving did too — there is
 * no style that could make an absent badge visible.
 *
 * The strike-through sits on the old figure and the saving is the loud part, because the number
 * a shopper should read is the one they pay. Both are set smaller than the price itself so the
 * price still wins the eye at a glance.
 */
.bedshop-design__was {
  color: var(--bedshop-ink-faint);
  font-size: 0.875rem;
  margin-right: var(--s-1);
}

.bedshop-design__save {
  display: inline-block;
  margin-right: var(--s-2);
  padding: 0.05em 0.5em;
  border: 1px solid var(--bedshop-rust);
  border-radius: 2px;
  background: var(--bedshop-rust);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.6;
  text-transform: uppercase;
  vertical-align: 0.15em;
  white-space: nowrap;
}

/* The way in. Solid ink like the hero's Configure action, full-width on the card so
 * a thumb gets a 48px+ target, one short line so a 36-bed shelf aligns. Hover and
 * keyboard focus darken to rust; focus-within on the card already draws the ink
 * border, so keyboard users get the same cue as hover.
 *
 * One link per card: the photo and the name are plain markup, so there is a single
 * tab stop to each bed's page and no nested or duplicate links. */
.bedshop-design__cta {
  margin-top: auto;
  align-self: stretch;
  justify-content: center;
  min-height: 48px;
}

a.bedshop-design__cta:hover {
  background: var(--bedshop-rust-deep);
  border-color: var(--bedshop-rust-deep);
}

a.bedshop-design__cta:focus-visible {
  outline: 2px solid var(--bedshop-rust);
  outline-offset: 2px;
}

.bedshop-design__unavailable {
  font-size: 0.9375rem;
  color: var(--bedshop-ink-faint);
  margin: 0;
}

/* -------------------------------------------------------- how the configurator works */

/* A genuine sequence — five steps, in order, each one depending on the last — so this is
 * the one place on the page where numbering carries information rather than decoration. */
.bedshop-steps {
  padding: var(--s-7) 0;
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-steps__title {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  margin-bottom: var(--s-6);
}

.bedshop-steps__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-5);
  grid-template-columns: 1fr;
  counter-reset: bedshop-step;
}

@media (min-width: 640px) {
  .bedshop-steps__list {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1000px) {
  .bedshop-steps__list {
    grid-template-columns: repeat(5, 1fr);
  }
}

.bedshop-step {
  counter-increment: bedshop-step;
  padding-top: var(--s-4);
  border-top: 2px solid var(--bedshop-rule);
}

.bedshop-step::before {
  content: counter(bedshop-step);
  display: block;
  font-family: var(--bedshop-display);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--bedshop-rust);
  margin-bottom: var(--s-2);
}

.bedshop-step__name {
  font-weight: 600;
  margin: 0 0 var(--s-1);
}

.bedshop-step__text {
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--bedshop-ink-soft);
  margin: 0;
}

/* -------------------------------------------------------------------- closing band */

.bedshop-closer {
  padding: var(--s-7) 0;
  text-align: left;
}

@media (min-width: 900px) {
  .bedshop-closer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--s-6);
  }
}

.bedshop-closer__title {
  font-size: clamp(1.5rem, 3.5vw, 2rem);
  margin-bottom: var(--s-2);
}

.bedshop-closer__text {
  color: var(--bedshop-ink-soft);
  max-width: 30rem;
}

.bedshop-closer .bedshop-btn {
  margin-top: var(--s-5);
  flex-shrink: 0;
}

@media (min-width: 900px) {
  .bedshop-closer .bedshop-btn {
    margin-top: 0;
  }
}

/* ------------------------------------------------------------- the configurator page */

/* Carried over from ticket 02 and restated here so both files agree on the type scale and
 * the price panel, which are the two things that must not drift between the front door and
 * the room it leads to. */

.bedshop-configurator {
  max-width: 46rem;
  margin: 0 auto;
}

/* The page's own H1, since the block theme's page title is suppressed here. Sized below the
 * front page's hero because this is a working page, not a landing one: the Customer has
 * arrived to do something and the heading is a signpost, not a statement. */
.bedshop-configurator__title {
  font-family: var(--bedshop-display);
  font-size: clamp(1.875rem, 5vw, 2.75rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 var(--s-3);
  text-wrap: balance;
}

.bedshop-intro {
  color: var(--bedshop-ink-soft);
  margin-bottom: var(--s-5);
}

.bedshop-dimensions {
  display: grid;
  gap: var(--s-5);
}

.bedshop-dimension {
  border: 1px solid var(--bedshop-rule);
  border-radius: 4px;
  padding: var(--s-4);
  margin: 0;
  background: #fff;
}

.bedshop-dimension legend {
  font-family: var(--bedshop-display);
  font-size: 1.25rem;
  font-weight: 600;
  padding: 0 var(--s-2);
}

.bedshop-option {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: var(--s-1) 0;
  /* A radio row is a control, not a line of text, so it gets a thumb-sized target. Ticket
     03's phone check measured these at 26px, under the 44px a thumb can reliably hit, and
     this is the control a Customer presses five times to buy a bed. */
  min-height: 44px;
}

.bedshop-option input[type='radio'] {
  width: 20px;
  height: 20px;
  margin: 0;
  flex-shrink: 0;
  accent-color: var(--bedshop-rust);
}

.bedshop-option label {
  cursor: pointer;
  /* The whole row is the target, not just the 20px box: tapping the words has to work. */
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  flex: 1;
}

.bedshop-option__price {
  color: var(--bedshop-ink-faint);
  font-variant-numeric: tabular-nums;
}

.bedshop-refusals {
  margin-top: var(--s-5);
  padding: var(--s-4);
  border-left: 3px solid var(--bedshop-rust);
  background: #fbf1ed;
  border-radius: 0 3px 3px 0;
}

.bedshop-refusal {
  margin: 0 0 var(--s-2);
}

.bedshop-refusal:last-child {
  margin-bottom: 0;
}

.bedshop-noscript {
  margin-top: var(--s-4);
  font-size: 0.9375rem;
  color: var(--bedshop-ink-soft);
}

/* ------------------------------------------------------------ the buy page
 *
 * Two columns: the bed on the left, the decision on the right. The photographs are what the
 * Customer is deciding about, so they are the thing that does not move and does not scroll
 * away while they are choosing, and the choices sit beside them under the price where the
 * decision is being made. Under 960px it is one column, photographs first — the order that
 * makes sense on a phone is "what is it, what does it cost", and that is the order the markup
 * already is.
 */
.bedshop-buy {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: var(--s-6);
  align-items: start;
  margin: var(--s-5) 0 var(--s-6);
}

/* The active theme constrains every direct child of the post content to its "content size" —
   `.entry-content > * { max-width: var(--wp--style--global--content-size) }` — which is a
   sensible reading measure and about two thirds of a laptop screen. This page is not a
   column of prose: a bed and its choices side by side need more than that, and left alone it
   rendered two 300px columns on a 1440px screen with a third of the page empty.

   The `.entry-content >` part is not decoration. It is what makes this rule beat the theme's
   `.entry-content > *`: without the class in the selector, specificity ties and load order
   decides, which is exactly the kind of thing that works until the theme's stylesheet is
   reordered. `margin-inline: 0` undoes the theme's centring, and 84rem is a ceiling rather
   than a width so the page still works on a very wide monitor. */
.entry-content > .bedshop-buy {
  max-width: min(100%, 84rem);
  margin-inline: 0;
}

.bedshop-buy__media {
  min-width: 0;
}

.bedshop-buy__panel {
  min-width: 0;
  position: sticky;
  top: var(--s-4);
}

.bedshop-buy__title {
  font-family: var(--bedshop-display);
  font-size: clamp(1.75rem, 3.2vw, 2.5rem);
  line-height: 1.12;
  color: var(--bedshop-ink);
  margin: 0 0 var(--s-3);
}

.bedshop-buy__from {
  font-family: var(--bedshop-body);
  font-size: 1.375rem;
  color: var(--bedshop-ink-soft);
  margin: 0 0 var(--s-5);
  padding-bottom: var(--s-4);
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-buy__from strong {
  font-family: var(--bedshop-display);
  font-size: 1.6em;
  color: var(--bedshop-ink);
}

.bedshop-buy__from span {
  font-size: 0.8125rem;
  color: var(--bedshop-ink-faint);
}

/* ---------------------------------------------------------------- gallery */

.bedshop-gallery__main {
  background: var(--bedshop-paper-deep);
  border-radius: 2px;
  overflow: hidden;
}

/* No aspect-ratio and no object-fit here, deliberately.
 *
 * The photographs come from another shop and are not all the same shape: beds are shot
 * portrait, a mattress is shot landscape on white. Forcing a 4:5 box and cropping to fill it
 * cut the top off the mattress and left a white band above it that was indistinguishable
 * from empty page. Cropping a product photograph is the one thing a shop should never do —
 * a Customer cannot tell what they are being sold if part of it is missing — so the hero is
 * shown whole, at whatever shape it actually is, and the column simply varies in height from
 * bed to bed. The thumbnails keep a fixed square because a chip is a chip.
 */
.bedshop-gallery__hero {
  display: block;
  width: 100%;
  height: auto;
}

.bedshop-gallery__thumbs {
  display: flex;
  gap: var(--s-2);
  margin-top: var(--s-2);
  padding: 0;
  overflow-x: auto;
  scrollbar-width: thin;
}

.bedshop-gallery__thumb {
  flex: 0 0 auto;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 2px;
  background: none;
  cursor: pointer;
  line-height: 0;
  opacity: 0.72;
  transition: opacity 120ms ease, border-color 120ms ease;
}

.bedshop-gallery__thumb:hover,
.bedshop-gallery__thumb:focus-visible {
  opacity: 1;
}

.bedshop-gallery__thumb.is-active {
  border-color: var(--bedshop-rust);
  opacity: 1;
}

.bedshop-gallery__thumbimage {
  display: block;
  width: 68px;
  height: 68px;
  object-fit: cover;
  border-radius: 1px;
}

/* ---------------------------------------------------------------- choices */

.bedshop-choices {
  display: grid;
  gap: var(--s-5);
  margin: 0;
}

.bedshop-choice {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

.bedshop-choice__label {
  display: block;
  font-family: var(--bedshop-body);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--bedshop-ink-faint);
  margin-bottom: var(--s-2);
  padding: 0;
}

/* Dropdown */
.bedshop-select {
  width: 100%;
  font-family: var(--bedshop-body);
  font-size: 1rem;
  color: var(--bedshop-ink);
  background: var(--bedshop-paper);
  border: 1px solid var(--bedshop-rule);
  border-radius: 2px;
  padding: 0.7em 2.2em 0.7em 0.8em;
  min-height: 44px;
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--bedshop-ink-soft) 50%),
    linear-gradient(135deg, var(--bedshop-ink-soft) 50%, transparent 50%);
  background-position: calc(100% - 18px) 52%, calc(100% - 12px) 52%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}

.bedshop-select:focus-visible {
  outline: 3px solid var(--bedshop-rust);
  outline-offset: 1px;
}

.bedshop-select.is-filtered {
  border-color: var(--bedshop-ink-faint);
}

/* Short list of cards: sizes, bases */
.bedshop-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: var(--s-2);
}

.bedshop-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.7em 0.8em;
  border: 1px solid var(--bedshop-rule);
  border-radius: 2px;
  background: var(--bedshop-paper);
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}

.bedshop-card:hover {
  border-color: var(--bedshop-ink-faint);
}

.bedshop-card:has(input:checked) {
  border-color: var(--bedshop-rust);
  background: var(--bedshop-paper-deep);
}

.bedshop-card:has(input:focus-visible) {
  outline: 3px solid var(--bedshop-rust);
  outline-offset: 1px;
}

.bedshop-card input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.bedshop-card__name {
  font-size: 0.9375rem;
  color: var(--bedshop-ink);
}

/* Swatches: the fabric, as cloth */
/* ------------------------------------------------------- the chosen fabric
 *
 * The chosen cloth, shown large above the grid. A fabric is a colour, and a colour is chosen
 * by looking at it; the grid's chips are ~5.5rem, which is too small to tell aubergine from
 * claret on a phone in a dim room. This enlarges the real swatch to a size where the choice
 * is obvious. The name is given a min-height so the grid does not jump down the page the
 * first time a colour is picked — the same care the size-filtered dropdown takes.
 *
 * The whole panel is decorative: the radios remain the single source of truth, the cloth is
 * aria-hidden (it duplicates the chosen radio's own label), and the name is a polite live
 * region so a screen-reader user hears the colour they just picked.
 */
.bedshop-fabric-preview {
  margin: 0 0 var(--s-4);
}

.bedshop-fabric-preview__frame {
  position: relative;
  width: 100%;
  max-width: 18rem;
  aspect-ratio: 1;
  background: var(--bedshop-paper-deep);
  border: 1px solid var(--bedshop-rule);
  border-radius: 2px;
  overflow: hidden;
}

.bedshop-fabric-preview__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 150ms ease;
}

.bedshop-fabric-preview__image.is-visible {
  opacity: 1;
}

.bedshop-fabric-preview__empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: var(--s-4);
  text-align: center;
  font-size: 0.875rem;
  color: var(--bedshop-ink-faint);
}

.bedshop-fabric-preview.has-fabric .bedshop-fabric-preview__empty {
  display: none;
}

.bedshop-fabric-preview__name {
  margin: var(--s-3) 0 0;
  min-height: 1.4em;
  font-family: var(--bedshop-display);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--bedshop-ink);
}

.bedshop-choice--swatches .bedshop-swatches {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
  gap: var(--s-2);
}

.bedshop-swatch {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 0.35rem;
  border: 2px solid transparent;
  border-radius: 2px;
  cursor: pointer;
  transition: border-color 120ms ease;
}

.bedshop-swatch:hover .bedshop-swatch__picture {
  outline: 1px solid var(--bedshop-ink-faint);
}

.bedshop-swatch:has(input:checked) {
  border-color: var(--bedshop-rust);
}

.bedshop-swatch:has(input:focus-visible) {
  outline: 3px solid var(--bedshop-rust);
  outline-offset: 1px;
}

.bedshop-swatch input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.bedshop-swatch__picture {
  display: block;
  aspect-ratio: 1;
  background: var(--bedshop-paper-deep);
  border-radius: 1px;
  overflow: hidden;
}

.bedshop-swatch__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.bedshop-swatch__missing {
  display: block;
  width: 100%;
  height: 100%;
  background: repeating-linear-gradient(45deg, var(--bedshop-paper-deep) 0 6px, var(--bedshop-rule) 6px 12px);
}

.bedshop-swatch__name {
  font-size: 0.75rem;
  line-height: 1.25;
  color: var(--bedshop-ink-soft);
}

.bedshop-swatch .bedshop-option__price {
  font-size: 0.6875rem;
  color: var(--bedshop-ink-faint);
}

/* The chosen swatch also gets a tick, because a rust border on a photograph of aubergine is
   not the strongest signal in the world and colour-blind Customers deserve better. */
.bedshop-swatch:has(input:checked)::after {
  content: '';
  position: absolute;
  top: 0.7rem;
  right: 0.7rem;
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 50%;
  background: var(--bedshop-rust) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 6.5l2.5 2.5L10 3.5' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 0.75rem no-repeat;
}

/* ---------------------------------------------------------------- total
 *
 * The live total, which sits between the "From" figure and the choices. It is the one thing
 * on the page that changes as the Customer works, so it is boxed and given air rather than
 * being a line of grey text that could be mistaken for the delivery note under it.
 */
.bedshop-quote {
  background: var(--bedshop-paper-deep);
  border: 1px solid var(--bedshop-rule);
  border-left: 3px solid var(--bedshop-rust);
  border-radius: 2px;
  padding: var(--s-4) var(--s-4) var(--s-3);
  margin: 0 0 var(--s-5);
}

.bedshop-quote p {
  margin: 0;
}

.bedshop-price {
  font-family: var(--bedshop-display);
  font-size: 1.875rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--bedshop-ink);
}

.bedshop-price__label {
  display: block;
  font-family: var(--bedshop-body);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--bedshop-ink-faint);
  margin-bottom: 0.25em;
}

.bedshop-vat,
.bedshop-ready {
  font-family: var(--bedshop-body);
  font-size: 0.8125rem;
  color: var(--bedshop-ink-faint);
  margin: 0.35em 0 0;
}

.bedshop-ready strong {
  color: var(--bedshop-ink-soft);
  font-weight: 600;
}

.bedshop-quote .bedshop-add {
  margin: var(--s-4) 0 0;
}

.bedshop-quote .bedshop-add .bedshop-btn {
  width: 100%;
  min-height: 44px;
}

.bedshop-quote .bedshop-add .bedshop-btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.bedshop-delivery {
  font-family: var(--bedshop-body);
  font-size: 0.8125rem;
  color: var(--bedshop-ink-faint);
  margin: var(--s-5) 0 0;
  padding-top: var(--s-3);
  border-top: 1px solid var(--bedshop-rule);
}

/* ---------------------------------------------------------------- delivery step */

.bedshop-deliverystep {
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--bedshop-rule);
}

.bedshop-postcode {
  width: 100%;
  max-width: 16em;
  min-height: 44px;
  padding: 10px 12px;
  font-family: var(--bedshop-body);
  font-size: 1rem;
  text-transform: uppercase;
  border: 1px solid var(--bedshop-rule);
  border-radius: 4px;
  background: #fff;
}

.bedshop-choice--assembly {
  margin-top: var(--s-3);
}

.bedshop-assembly {
  display: flex;
  align-items: center;
  gap: var(--s-2, 0.5rem);
  min-height: 44px;
  font-family: var(--bedshop-body);
  font-size: 0.9375rem;
  color: var(--bedshop-ink-soft);
  cursor: pointer;
}

.bedshop-assembly input {
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
}

/* The delivery and assembly figures, shown as their own lines under the total. */
.bedshop-delivery-lines {
  margin: var(--s-3) 0 0;
  padding-top: var(--s-3);
  border-top: 1px solid var(--bedshop-rule);
  font-family: var(--bedshop-body);
  font-size: 0.875rem;
}

.bedshop-delivery-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-3);
  margin: 0;
  padding: 2px 0;
}

.bedshop-delivery-line dt {
  color: var(--bedshop-ink-soft);
  margin: 0;
}

.bedshop-delivery-line dd {
  margin: 0;
  font-variant-numeric: tabular-nums;
  color: var(--bedshop-ink);
  font-weight: 600;
  white-space: nowrap;
}

.bedshop-delivery-line__transit {
  display: block;
  font-size: 0.75rem;
  color: var(--bedshop-ink-faint);
}

.bedshop-refusals {
  margin: 0 0 var(--s-4);
}

/* ---------------------------------------------------------------- description */

.bedshop-description {
  margin-top: var(--s-5);
  border-top: 1px solid var(--bedshop-rule);
  padding-top: var(--s-4);
}

.bedshop-description > summary {
  cursor: pointer;
  font-family: var(--bedshop-body);
  font-size: 0.9375rem;
  color: var(--bedshop-ink);
  list-style: none;
  display: flex;
  align-items: center;
  gap: 0.5em;
  min-height: 44px;
}

.bedshop-description > summary::-webkit-details-marker {
  display: none;
}

.bedshop-description > summary::before {
  content: '+';
  font-size: 1.25em;
  color: var(--bedshop-rust);
  line-height: 1;
}

.bedshop-description[open] > summary::before {
  content: '\2212';
}

.bedshop-description__body {
  max-width: var(--bedshop-measure);
  color: var(--bedshop-ink-soft);
  line-height: 1.65;
  padding-top: var(--s-3);
}

.bedshop-description__body h2,
.bedshop-description__body h3,
.bedshop-description__body h4 {
  font-family: var(--bedshop-display);
  color: var(--bedshop-ink);
  margin: var(--s-4) 0 var(--s-2);
  line-height: 1.2;
}

.bedshop-description__body h2:first-child,
.bedshop-description__body h3:first-child {
  margin-top: 0;
}

.bedshop-description__body table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--s-3) 0;
  font-size: 0.9375rem;
}

.bedshop-description__body th,
.bedshop-description__body td {
  text-align: left;
  padding: 0.5em 0.7em;
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-description__body th {
  color: var(--bedshop-ink);
  font-weight: 600;
}

/* ---------------------------------------------------------------- closed */

.bedshop-closed {
  text-align: center;
  padding: var(--s-7) 0;
  max-width: var(--bedshop-measure);
  margin: 0 auto;
}

@media (max-width: 960px) {
  .bedshop-buy {
    grid-template-columns: minmax(0, 1fr);
  }

  .bedshop-buy__panel {
    position: static;
  }
}

/* --------------------------------------------------------------- reduced motion */

/* Respected rather than treated as an edge case: the shop's whole motion budget is a price
 * that changes as you choose, and someone who has asked the operating system for less
 * movement should get the price and none of the transition. */
@media (prefers-reduced-motion: reduce) {
  .bedshop-front *,
  .bedshop-configurator * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------- category banner */

/* The homepage's departments, shown as pictures — the thing a bed shop's front door is expected
 * to have. Each card is a link to that category's beds further down the page, so the banner is
 * navigation, not decoration, and every card lands on a real group of beds rather than a page
 * that does not exist yet. The picture is the category's first bed, so a card is never blank. */
.bedshop-categories {
  padding: var(--s-7) 0;
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-categories__head {
  margin-bottom: var(--s-6);
}

.bedshop-categories__title {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  margin: 0;
}

/* Every section on this page announces itself the same way: a title, then one sentence under it
 * capped at a reading measure. On the page this layout is modelled on the same block repeats
 * six times — a title, then a subtitle capped at 420px and centred — and repeating one shape
 * is what stops a long page reading as a stack of unrelated sections.
 *
 * Capped rather than centred, because the sentence is read rather than scanned. Centring caps
 * the measure anyway and gives a ragged left edge against a full-width heading above it. */
.bedshop-categories__intro,
.bedshop-browse__intro {
  max-width: 34rem;
  margin-top: var(--s-2);
  color: var(--bedshop-ink-soft);
  text-wrap: pretty;
}

.bedshop-categories__head,
.bedshop-browse__lead {
  margin-bottom: var(--s-6);
}

.bedshop-browse__title-main {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  margin: 0;
}

/* auto-fill with a floor, like the bed cards: five departments fit a row on desktop, four and
 * then three and then two as the screen narrows, and one on a phone. A single card stays at a
 * readable size rather than stretching across the whole width. */
.bedshop-categories__grid {
  display: grid;
  gap: var(--s-5);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
}

/* The tiles are pictures first and text second, in the way a showroom wall is: the department
 * is a photograph with its name on it, not a bordered card with a header above an image. The
 * name sits on the picture over a scrim rather than in a panel under it, which is what lets the
 * tile run to its own edge with no border and no white strip — the grid gap is the only thing
 * separating them.
 *
 * The scrim is the load-bearing part of that. The picture underneath is whatever the first bed
 * in the department happens to be photographed on, so the text cannot rely on the image being
 * dark in the bottom third; a bottom-weighted gradient to 88% of the ink colour is dark enough
 * for white text over any photograph *and* over the pale striped placeholder a category with no
 * photograph yet gets, which is the case that would otherwise have failed contrast.
 *
 * What did not change: each tile is still a link to `#cat-<slug>`, still says how many beds are
 * in the department, and still says nothing at all when it has no picture to show.
 */
.bedshop-category {
  position: relative;
  display: flex;
  flex-direction: column;
  border: 0;
  border-radius: 0;
  overflow: hidden;
  background: var(--bedshop-paper-deep);
  color: #fff;
  text-decoration: none;
  transition: transform 150ms ease, box-shadow 150ms ease;
}

.bedshop-category:hover,
.bedshop-category:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 8px 22px rgba(30, 35, 40, 0.28);
}

/* Slightly taller than the old 4:3. A department tile is a shop window rather than a thumbnail,
 * and at 4:3 the overlaid name sat on a band too shallow to hold two lines of text without
 * crowding the picture. */
.bedshop-category__media {
  display: block;
  aspect-ratio: 5 / 6;
  background: var(--bedshop-paper-deep);
  overflow: hidden;
}

.bedshop-category__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 400ms ease;
}

.bedshop-category:hover .bedshop-category__img {
  transform: scale(1.04);
}

/* The one case a card has no photograph to lead with — a category whose beds have none yet. A
 * flat tint keeps the card's shape so the grid does not break, and it is labelled so it reads as
 * deliberate rather than a broken image. */
.bedshop-category__placeholder {
  display: block;
  width: 100%;
  height: 100%;
  background:
    repeating-linear-gradient(45deg, var(--bedshop-paper-deep) 0 12px, var(--bedshop-rule) 12px 13px);
}

/* Over the picture rather than under it, so the tile has no white strip and no rule to break. */
.bedshop-category__body {
  position: absolute;
  inset: auto 0 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  padding: var(--s-6) var(--s-4) var(--s-4);
  background: linear-gradient(
    to top,
    rgba(30, 35, 40, 0.88) 0%,
    rgba(30, 35, 40, 0.72) 45%,
    rgba(30, 35, 40, 0) 100%
  );
}

.bedshop-category__name {
  font-family: var(--bedshop-display);
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.2;
  color: #fff;
  text-shadow: 0 1px 2px rgba(30, 35, 40, 0.45);
}

.bedshop-category__count {
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.82);
}

/* ----------------------------------------------------------------- the beds */

/* The whole range, grouped by category. Each group is an anchor the banner jumps to, so the
 * heading is the landmark a customer lands on when they pick a department. The count sits beside
 * the title rather than under it, so a long category name does not push the number onto its own
 * line. */
.bedshop-browse {
  padding: var(--s-7) 0;
}

.bedshop-browse__group {
  padding-top: var(--s-7);
}

.bedshop-browse__group + .bedshop-browse__group {
  border-top: 1px solid var(--bedshop-rule);
  margin-top: var(--s-7);
}

/* Room to breathe under a sticky header when the banner jumps to a group, so the category
 * heading is not hidden behind it. */
.bedshop-browse__group:target {
  scroll-margin-top: var(--s-6);
}

.bedshop-browse__head {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  margin-bottom: var(--s-5);
  padding-bottom: var(--s-3);
  border-bottom: 2px solid var(--bedshop-rule);
}

.bedshop-browse__title {
  font-size: clamp(1.5rem, 3vw, 2rem);
  margin: 0;
}

.bedshop-browse__count {
  font-size: 0.875rem;
  color: var(--bedshop-ink-faint);
  margin-left: auto;
}

/* Smooth, respectful scrolling for the banner's anchor jumps, and off for anyone who has asked
 * the OS for less motion — the same rule the configurator's price transition follows. */
html {
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}



/* ------------------------------------------------------------- customer reviews */

/* Shown only when the shop has real reviews to show — FrontPage renders nothing here at all
 * when it has none, so an empty section is never a possibility and there is no risk of the
 * heading implying reviews that do not exist. The rating is stars above the quote, the
 * attribution under it, and the source's own date beside the name — see FrontPage::reviews()
 * for why the date is the source's and never the import day. */
.bedshop-reviews {
  padding: var(--s-7) 0;
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-reviews__title {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  margin-bottom: var(--s-6);
}

/* The measured strip, as the caption to the list below it. Sits under the heading with room
 * before the reviews, so it reads as a summary of what follows rather than as another review.
 * On a phone the two halves of the line wrap onto two lines and the stars stay on their own. */
.bedshop-reviews__rating {
  margin-bottom: var(--s-5);
}

/* One column on a phone, two at tablet, three at desktop. Explicit counts rather than
 * minmax() so the theme's own grid variables do not decide how many fit — the same reason
 * the reassurance and steps rows set their own. */
.bedshop-reviews__list {
  display: grid;
  gap: var(--s-5);
  grid-template-columns: 1fr;
  margin: 0;
}

@media (min-width: 640px) {
  .bedshop-reviews__list {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 1000px) {
  .bedshop-reviews__list {
    grid-template-columns: repeat(3, 1fr);
  }
}

.bedshop-review {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: var(--s-5);
  background: var(--bedshop-paper-deep);
  border: 1px solid var(--bedshop-rule);
}

/* The stars. The glyphs are aria-hidden and carry the number in the container's accessible
 * name, so these are purely visual; colour alone distinguishes filled from empty, which is why
 * the filled ones are also the rust accent and the empty ones the faint rule colour. */
.bedshop-review__stars {
  display: inline-flex;
  gap: 2px;
  font-size: 1.125rem;
  line-height: 1;
  letter-spacing: 0.05em;
}

.bedshop-review__star {
  color: var(--bedshop-rule);
}

.bedshop-review__star.is-on {
  color: var(--bedshop-rust);
}

.bedshop-review__body {
  margin: 0;
  color: var(--bedshop-ink);
  font-size: 1rem;
  line-height: 1.6;
}

.bedshop-review__body p {
  margin: 0;
}

/* The attribution, pushed to the foot of the card so the quotes line up even when one is a
 * sentence and the next is a paragraph. The name is plain text — it does not link anywhere —
 * and the source is quiet next to it. */
.bedshop-review__who {
  margin-top: auto;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--bedshop-ink-soft);
}

.bedshop-review__source {
  color: var(--bedshop-ink-faint);
}

/* The verified-reviews banner, under the list and above the section's bottom border. A tick
 * and a sentence, in the sage accent rather than the rust of the stars so it reads as a caption
 * rather than another call to action. It says what these reviews are and where they were
 * checked; the count is the profile's total, so it does not imply the handful shown are all. */
.bedshop-reviews__verified {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: var(--s-6) 0 0;
  padding-top: var(--s-5);
  border-top: 1px solid var(--bedshop-rule);
  font-size: 0.9375rem;
  color: var(--bedshop-ink-soft);
}

.bedshop-reviews__verified strong {
  color: var(--bedshop-ink);
}

.bedshop-reviews__tick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.375rem;
  height: 1.375rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--bedshop-sage);
  color: var(--bedshop-paper);
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1;
}

/* --------------------------------------------------------- the department strip */

/* HOME and the departments, as a bar under the header, sticky so the way about the shop stays
 * one reach away while the page runs long. On a phone the items scroll sideways rather than
 * wrap to four rows; from 900px they wrap, because a scrolling main nav on a desktop is a menu
 * that hides itself. The transparent bottom border is on every item (link or summary) so the
 * "More soon" disclosure cannot shift the row by a pixel. */
.bedshop-catnav {
  position: sticky;
  top: 0;
  z-index: 10;
  margin: 0;
  max-width: none;
  background: #fff;
  border-bottom: 1px solid var(--bedshop-rule);
}

.bedshop-catnav__inner {
  display: flex;
  align-items: center;
  gap: var(--s-5);
  padding-top: var(--s-3);
  padding-bottom: var(--s-3);
  overflow-x: auto;
  scrollbar-width: none;
}

.bedshop-catnav__inner::-webkit-scrollbar {
  display: none;
}

.bedshop-catnav__item {
  flex: 0 0 auto;
  padding-bottom: 2px;
  border-bottom: 2px solid transparent;
  color: var(--bedshop-ink);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.01em;
  text-decoration: none;
  white-space: nowrap;
}

a.bedshop-catnav__item:hover,
a.bedshop-catnav__item:focus-visible,
summary.bedshop-catnav__item:hover,
summary.bedshop-catnav__item:focus-visible {
  color: var(--bedshop-rust);
  border-bottom-color: var(--bedshop-rust);
}

/* "More soon": the single disclosure for departments with no stock yet.
 *
 * A <details> so it works with JavaScript off and a screen reader gets the
 * open/closed state from the element itself. The summary reads as one more strip
 * item (same type, same underline affordance, pointer cursor); the list opens as a
 * paper panel below the row rather than pushing content. Four muted pills would eat
 * ~40% of a phone strip — this keeps the honesty in one reach.
 */
.bedshop-catnav__soon {
  position: relative;
  flex: 0 0 auto;
}

.bedshop-catnav__summary {
  cursor: pointer;
  list-style: none;
}

.bedshop-catnav__summary::-webkit-details-marker {
  display: none;
}

.bedshop-catnav__summary::after {
  content: ' ▾';
  color: var(--bedshop-ink-faint);
}

.bedshop-catnav__soon-list {
  position: absolute;
  top: calc(100% + var(--s-2));
  right: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 12rem;
  padding: var(--s-4);
  background: var(--bedshop-paper);
  border: 1px solid var(--bedshop-rule);
  border-radius: 4px;
}

/* Not a link: the shop has nothing to put behind this name yet. Muted rather than hidden,
 * because the strip is meant to show what the shop is going to carry, and muted rather than
 * linked, because a link to nothing is the one thing it must not be. */
.bedshop-catnav__item.is-soon {
  color: var(--bedshop-ink-faint);
  font-weight: 500;
  cursor: default;
}

.bedshop-catnav__soon-tag {
  margin-left: 0.35em;
  padding: 0 0.4em;
  border: 1px solid var(--bedshop-rule);
  border-radius: 999px;
  color: var(--bedshop-sage);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  vertical-align: 0.35em;
}

@media (min-width: 900px) {
  .bedshop-catnav__inner {
    flex-wrap: wrap;
    row-gap: var(--s-2);
    overflow-x: visible;
  }
}

/* Room under the sticky strip when an anchor jumps to a section, so the heading the customer
 * asked for is not hidden behind the bar they asked for it from. This supersedes the earlier
 * per-group rule above and covers the banner card targets and the contact anchor too. */
.bedshop-browse__group:target,
.bedshop-categories:target,
.bedshop-contact:target {
  scroll-margin-top: 5rem;
}

/* ------------------------------------------------------------- the rating strip */

/* "5.0 out of 5 — from our Google reviews", sitting directly under the sticky department strip.
 *
 * The strip is short on purpose: it is a figure and the sentence that says where the figure came
 * from, not a claims bar. It names no total review count, because the average is measured over
 * the reviews stored in this shop and the Google profile's larger total was never measured — the
 * two numbers are not the same measurement and must not be printed as though they were.
 *
 * Left-aligned and quiet rather than centred and loud, because this is an editorial page and the
 * hero is already the loudest thing on it.
 */
.bedshop-rating-strip {
  border-bottom: 1px solid var(--bedshop-rule);
  background: #fff;
}

.bedshop-rating-strip .bedshop-shell {
  padding-top: var(--s-3);
  padding-bottom: var(--s-3);
}

.bedshop-rating {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2) var(--s-3);
}

/* The glyphs are aria-hidden and the number is in the container's accessible name, so these are
 * purely visual — filled against empty carries the score a second time for anyone who cannot
 * see the text. Same colour pairing as the per-review stars. */
.bedshop-rating__stars {
  display: inline-flex;
  gap: 2px;
  font-size: 1.0625rem;
  line-height: 1;
  letter-spacing: 0.05em;
}

.bedshop-rating__star {
  color: var(--bedshop-rule);
}

.bedshop-rating__star.is-on {
  color: var(--bedshop-rust);
}

.bedshop-rating__text {
  font-size: 0.9375rem;
  color: var(--bedshop-ink-soft);
}

.bedshop-rating__text strong {
  color: var(--bedshop-ink);
  font-weight: 600;
}

/* ---------------------------------------------------------------- the trust badges */

/* Six badges, and the set is closed (ADR-0017). Each one is a thing the shop can be held to;
 * nothing here is a claim about how popular the business is or what it might offer later.
 *
 * Sequencing, not volume: the star strip sits above the hero and earns the scroll; this
 * band sits *below* the hero as the receipts after the promise and the action. On a phone
 * it becomes a 2-column grid of tappable-size rows so the hero + Configure CTA reach the
 * first viewport instead of a six-item wrap-wall pushing them below the fold. The page
 * still has a "Why choose us" section further down where four of these same facts are
 * argued properly rather than listed.
 */
.bedshop-trust {
  border-bottom: 1px solid var(--bedshop-rule);
  background: var(--bedshop-paper);
}

.bedshop-trust__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  column-gap: var(--s-5);
  row-gap: var(--s-2);
  margin: 0;
  padding-top: var(--s-3);
  padding-bottom: var(--s-3);
  list-style: none;
}

/* The separator is drawn here rather than written into the markup, so it can never reach the
 * text a screen reader reads out — six facts in a row are six facts, not one string with
 * pipes in it. It is suppressed on the last item so the row does not end in a dangling rule. */
.bedshop-trust__item + .bedshop-trust__item {
  padding-left: var(--s-5);
  border-left: 1px solid var(--bedshop-rule);
}

.bedshop-trust__item {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
  color: var(--bedshop-ink-soft);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.3;
}

.bedshop-trust__item:last-child {
  padding-left: 0;
  border-left: 0;
}

/* The marks are sized by width/height on the element rather than by a font glyph, so they line
 * up with the text baseline on every platform instead of inheriting whatever box the font's
 * star character happens to occupy. */
.bedshop-trust__icon {
  flex: 0 0 auto;
  color: var(--bedshop-rust);
}

.bedshop-trust__label {
  min-width: 0;
}

/* On a phone six badges do not fit on one line, and a wrapped row breaks the hairlines: a
 * separator drawn as "every item after the first" lands at the start of a wrapped line, so the
 * rule leads a line instead of sitting between two facts. Which items share a line is not
 * knowable from the stylesheet — it depends on how each label measures at the width it is
 * given — so the separators are dropped below the width where the row fits, and the strip
 * becomes a plain centred wrap of six short facts.
 *
 * Dropped rather than recomputed with nth-child because a wrong separator is worse than none:
 * a stray rule beside an unrelated fact reads as a divider between two related things.
 */
/* A phone: receipts become a 2-column grid of 44px rows rather than a centred wrap.
 * The separators are dropped (see note above) and each fact gets room to breathe —
 * peripheral reassurance after the hero, not a wall before it.
 */
@media (max-width: 900px) {
  .bedshop-trust__item + .bedshop-trust__item {
    padding-left: 0;
    border-left: 0;
  }

  .bedshop-trust__list {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-2) var(--s-4);
    justify-content: stretch;
  }

  .bedshop-trust__item {
    min-height: 44px;
  }
}

/* ---------------------------------------------------- the rest of a long department */

/* The expander under a department with a pile behind it. A <details>, so it works with
 * JavaScript off and a screen reader gets the open/closed state from the element itself
 * rather than from an aria-expanded someone has to remember to keep in sync. The chevron
 * flips with the state; the label stays the same because it describes what is inside. */
.bedshop-more {
  margin-top: var(--s-5);
}

.bedshop-more__toggle {
  display: inline-block;
  list-style: none;
  cursor: pointer;
  font-family: var(--bedshop-body);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--bedshop-ink);
  background: #fff;
  border: 1px solid var(--bedshop-rule);
  border-radius: 4px;
  padding: var(--s-3) var(--s-5);
}

.bedshop-more__toggle::-webkit-details-marker {
  display: none;
}

.bedshop-more__toggle::after {
  content: ' \25BE';
  margin-left: 0.5em;
  color: var(--bedshop-ink-faint);
}

.bedshop-more[open] .bedshop-more__toggle::after {
  display: inline-block;
  transform: rotate(180deg);
}

.bedshop-more__toggle:hover,
.bedshop-more__toggle:focus-visible {
  border-color: var(--bedshop-ink);
}

.bedshop-more > .bedshop-designs {
  margin-top: var(--s-5);
}

/* The eyebrow names the range section; the first group's padding-top exists to separate
 * groups from each other, not to separate the section's heading from its own first group. */
.bedshop-eyebrow + .bedshop-browse__group {
  padding-top: var(--s-4);
}

/* --------------------------------------------------------------------- contact */

/* The closing band, and the anchor "Contact Us" lands on. Two links that work — a tel: and a
 * mailto: — rather than a form; the details are the business's own, the same ones on its
 * existing site, and the strip above points here, which is what makes that nav item honest. */
.bedshop-contact {
  padding: var(--s-7) 0 var(--s-8);
  background: var(--bedshop-paper-deep);
}

.bedshop-contact__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
}

.bedshop-contact__title {
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  margin: 0 0 var(--s-2);
}

.bedshop-contact__lead {
  margin: 0;
  max-width: var(--bedshop-measure);
  color: var(--bedshop-ink-soft);
}

.bedshop-contact__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}


/* ------------------------------------------------------------------- the basket */

.bedshop-basket {
  font-family: var(--bedshop-body);
  color: var(--bedshop-ink);
  max-width: 46rem;
  margin: 0 auto;
}

.bedshop-basket__title {
  font-family: var(--bedshop-display);
  font-size: 2rem;
  font-weight: 600;
  margin: 0 0 var(--s-5);
}

.bedshop-basket__lines {
  list-style: none;
  margin: 0 0 var(--s-5);
  padding: 0;
}

.bedshop-basket__line {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  justify-content: space-between;
  align-items: flex-start;
  padding: var(--s-4) 0;
  border-top: 1px solid var(--bedshop-rule);
}

.bedshop-basket__line-main {
  flex: 1 1 18rem;
}

.bedshop-basket__name {
  display: block;
  font-family: var(--bedshop-display);
  font-size: 1.25rem;
  font-weight: 600;
}

.bedshop-basket__price {
  display: block;
  margin: 0.35rem 0 0;
  font-size: 1.05rem;
}

.bedshop-basket__price span {
  font-size: 0.8125rem;
  color: var(--bedshop-ink-faint);
}

.bedshop-basket__spec {
  list-style: none;
  margin: var(--s-3) 0 0;
  padding: 0;
  font-size: 0.875rem;
  color: var(--bedshop-ink-soft);
}

.bedshop-basket__spec li {
  display: inline;
}

.bedshop-basket__spec li + li::before {
  content: " · ";
  color: var(--bedshop-ink-faint);
}

.bedshop-basket__postcode {
  margin: var(--s-3) 0 0;
  font-size: 0.8125rem;
  color: var(--bedshop-ink-faint);
}

.bedshop-basket__remove {
  flex: 0 0 auto;
}

.bedshop-basket__removebutton {
  min-height: 44px;
  padding: 0 var(--s-4);
  background: none;
  border: 1px solid var(--bedshop-rule);
  border-radius: 2px;
  font: inherit;
  font-size: 0.875rem;
  color: var(--bedshop-ink-soft);
  cursor: pointer;
}

.bedshop-basket__removebutton:hover {
  border-color: var(--bedshop-ink-soft);
  color: var(--bedshop-ink);
}

.bedshop-basket__totals {
  border-top: 2px solid var(--bedshop-ink);
  padding-top: var(--s-3);
  margin: 0 0 var(--s-4);
}

.bedshop-basket__totals > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-4);
}

.bedshop-basket__totals dt {
  font-size: 0.9375rem;
}

.bedshop-basket__totals dd {
  margin: 0;
  font-family: var(--bedshop-display);
  font-size: 1.5rem;
  font-weight: 600;
}

.bedshop-basket__totals > div + div dt,
.bedshop-basket__totals > div + div dd {
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--bedshop-ink-faint);
}

.bedshop-basket__note {
  font-size: 0.8125rem;
  color: var(--bedshop-ink-faint);
  margin: 0 0 var(--s-5);
}

.bedshop-basket__actions {
  margin: var(--s-5) 0 0;
}

.bedshop-basket__actions .bedshop-btn {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
