/*
Theme Name: Lomond
Theme URI: https://lomondfurniture.co.uk/
Author: Lomond Furniture & Homeware
Description: Editorial retail theme for Lomond Furniture & Homeware. Brand tokens are sampled from the supplied logo, never approximated.
Version: 0.1.0-staging
Requires at least: 6.0
Tested up to: 7.0
Text Domain: lomond
*/

/* --------------------------------------------------------------------------
   BRAND TOKENS — sampled from the supplied logo, never approximated.
   Re-sampled 2026-09-01 from the owner's updated transparent PNG (attachment
   #220). Values come from FULLY OPAQUE pixels only: including semi-transparent
   antialiased edges drags the mean darker and yields a colour that is in the
   file but not in the mark.

     Navy   #00142E   62,865 px  ·  18.43:1 on white
     Taupe  #655145   12,492 px  ·   7.46:1 on white

   The previous logo sampled at #091D36 / #81736D. The taupe change matters
   beyond aesthetics: the old value cleared AA for body text by a hair (4.56:1),
   so a darkened derivative had to carry copy. The new taupe is comfortably
   readable at 7.46:1 and is used directly.
   -------------------------------------------------------------------------- */
:root {
  --lf-navy:        #00142E;
  --lf-navy-80:     #1B2E45;
  --lf-navy-60:     #44546A;
  --lf-taupe:       #655145;   /* 7.46:1 — safe for text */
  --lf-taupe-deep:  #4E3F35;
  --lf-taupe-mid:   #8A7A6C;   /* 4.60:1 — de-emphasised text only, still AA */
  --lf-taupe-pale:  #E2DAD2;
  --lf-taupe-wash:  #F2EDE8;

  --lf-ivory:       #FBF9F6;
  --lf-stone:       #F5F2EE;
  /* Two warmer surfaces, used ONLY by the New Arrivals row and the Timeless
     strip. The rest of the page keeps ivory/stone; these exist so those two
     sections read as one warm editorial passage rather than as two more
     interchangeable panels. */
  --lf-cream:       #FAF7F1;
  --lf-cream-deep:  #F2ECE3;

  /* Antique gold — DETAIL ONLY, and only in the Timeless strip. Never a
     background, never a heading, never body copy: navy stays the voice and gold
     is the punctuation.

     #8D6A3A is chosen over the lighter candidates because it is the only tone
     in the range that clears WCAG AA as TEXT on this palette — 4.61:1 on
     --lf-cream, where #98713E manages 4.11:1 and #A17C45 about 3.7:1. The
     eyebrow it carries is 11.5px, so it is small text and needs the full 4.5:1;
     a lighter gold would have meant either failing the check or restricting
     gold to decoration and leaving the eyebrow taupe. */
  --lf-gold:        #8D6A3A;
  /* The same antique gold, one step lighter, for use ON navy. #8D6A3A manages
     only 3.5:1 against --lf-navy and goes muddy; #A17C45 reaches 4.5:1 and
     still reads as the same accent beside it on the light panels. */
  --lf-gold-on-navy:#A17C45;
  /* Brighter again, for gold sitting ON PHOTOGRAPHY. A scrim over a photograph
     is never as dark as a flat navy fill and it varies picture to picture, so
     the accent needs more lift than #A17C45 to stay legible — this reaches
     roughly 5.4:1 over the darkest part of the tile gradients. */
  --lf-gold-light:  #C9A063;
  /* A fourth gold, for a solid gold AREA sitting on the PAGE GROUND rather than
     on navy or on a photograph — currently only the merchandising tag's backing
     sheet. The two values either side of it were both tried against it and both
     fail for the opposite reason: #A17C45 is tuned to sit ON navy and goes
     muddy where it emerges onto cream, and #C9A063 is tuned for a thin mark
     over photography and reads sandy rather than gold when spread across a
     solid 3px band. Decorative only — nothing is ever set in it. */
  --lf-gold-sheet:  #B8904F;
  --lf-gold-line:   rgba(141, 106, 58, .24);
  --lf-gold-rule:   rgba(141, 106, 58, .5);
  --lf-white:       #FFFFFF;
  --lf-charcoal:    #2B2A28;

  --lf-line:        #E7E1DA;
  --lf-line-strong: #D4CABF;

  /* Cool navy tints. The palette is deliberately warm everywhere else; these
     exist so SELECTION reads as a different kind of signal from decoration,
     and they are used nowhere but the bundle builder's chosen state, its
     saving chip and its total. */
  --lf-navy-wash:   #EEF2F7;
  --lf-navy-tint:   #DEE6F0;
  --lf-navy-line:   #B9C6D8;

  --lf-serif: "Cormorant Garamond", "Times New Roman", Times, serif;
  --lf-sans:  "Jost", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  --lf-max: 1440px;
  --lf-gutter: clamp(1.25rem, 3vw, 3rem);
  --lf-ease: cubic-bezier(.22,.61,.36,1);
}

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

html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--lf-white);
  color: var(--lf-charcoal);
  font-family: var(--lf-sans);
  font-size: 16px;
  line-height: 1.65;
  font-weight: 300;
  letter-spacing: .005em;
  /*
   * Horizontal overflow is a named QA failure; this is the structural guard.
   * `clip` rather than `hidden`: `overflow-x: hidden` silently turns <body>
   * into a scroll container, and every `position: sticky` descendant then
   * sticks to a container that never scrolls — which is to say, not at all.
   * `clip` contains the overflow without creating that scroll container.
   */
  overflow-x: clip;
}
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }

h1, h2, h3, .lf-serif {
  font-family: var(--lf-serif);
  font-weight: 500;
  color: var(--lf-navy);
  letter-spacing: -.005em;
  line-height: 1.12;
  margin: 0 0 .5em;
}
h1 { font-size: clamp(2.4rem, 5vw, 4rem); }
h2 { font-size: clamp(1.9rem, 3.4vw, 2.9rem); }
h3 { font-size: clamp(1.25rem, 2vw, 1.6rem); }
p  { margin: 0 0 1.1em; }

.lf-wrap { max-width: var(--lf-max); margin-inline: auto; padding-inline: var(--lf-gutter); }
.lf-wrap--narrow { max-width: 860px; }

.lf-eyebrow {
  font-size: .72rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--lf-taupe); font-weight: 400; margin: 0 0 1rem;
}

/* --------------------------------------------------------------- buttons */
.lf-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6rem;
  min-height: 48px; padding: 0 1.9rem;
  font-family: var(--lf-sans); font-size: .82rem; font-weight: 400;
  letter-spacing: .14em; text-transform: uppercase;
  border: 1px solid var(--lf-navy); background: var(--lf-navy); color: #fff;
  cursor: pointer; transition: background .3s var(--lf-ease), color .3s var(--lf-ease), border-color .3s var(--lf-ease);
}
.lf-btn:hover { background: var(--lf-navy-80); border-color: var(--lf-navy-80); }
.lf-btn--ghost { background: transparent; color: var(--lf-navy); }
.lf-btn--ghost:hover { background: var(--lf-navy); color: #fff; }
.lf-btn--wide { width: 100%; }
/* PROBLEM 8. The primary control was the same 48px as every secondary button on
   the page, so it dominated nothing. On the product page it is the one thing the
   column exists for: taller, wider tracking, and a hair more weight. The
   wishlist keeps its own height, so the two are no longer peers. */
.lf-pdp__buy .lf-btn--wide {
  min-height: 58px; font-size: .88rem; letter-spacing: .18em;
}
a:focus-visible, button:focus-visible, select:focus-visible, input:focus-visible, summary:focus-visible {
  outline: 2px solid var(--lf-navy); outline-offset: 3px;
}

/* --------------------------------------------------------------- utility bar */
.lf-utility {
  background: var(--lf-navy); color: rgba(255,255,255,.86);
  font-size: .74rem; letter-spacing: .1em;
}
.lf-utility ul {
  display: flex; gap: 2.5rem; justify-content: center; align-items: center;
  list-style: none; margin: 0; padding: .6rem 0; flex-wrap: wrap;
  line-height: 1.35;
}
/*
 * The bar is one line from 1024 up. Below that the three claims stack, and the
 * ROW gap is what made the stack dominant: at 2.5rem between rows the bar
 * measured 98px on a tablet and 108px on a phone — 13% of a 844px viewport
 * spent before the shopper sees anything. The claims themselves are untouched;
 * only the space between them is. Column gap is preserved for the widths that
 * still fit two on a line.
 */
@media (max-width: 1023px) {
  .lf-utility ul { gap: .45rem 2rem; padding: .55rem 0; }
}
.lf-utility li { display: flex; align-items: center; gap: .5rem; }
/* The utility icons inherit no size of their own and rendered far larger than
   the 12px text beside them, especially once the bar wrapped on mobile. */
.lf-utility svg { width: 15px; height: 15px; flex: none; stroke: currentColor; fill: none; stroke-width: 1.3; }

/* --------------------------------------------------------------- header
 * TWO ROWS: an identity row (logo / utilities) over a navigation row.
 *
 * The single-row grid gave the nav a 928px centre column at every width from
 * 1440 up, and the eight labels need 965px. That 37px is the whole of the
 * "messy header" — three labels wrapped, and because every link was top-aligned
 * inside a stretched row, a wrapped label's first line sat 3px above the
 * single-line labels beside it. Shrinking the type until it fitted would have
 * treated the symptom. Giving the nav the container's full width removes the
 * constraint: the same labels now occupy about half the row, so nothing wraps,
 * the gaps can breathe, and every label sits on one baseline because every
 * label is one line.
 * ------------------------------------------------------------------------- */
.lf-header {
  position: sticky; top: 0; z-index: 60;
  background: rgba(255,255,255,.96);
  backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid var(--lf-line);
  transition: box-shadow .3s var(--lf-ease);
}
/*
 * THE SCROLLED STATE CHANGES COLOUR, NEVER GEOMETRY.
 *
 * A `position: sticky` element still occupies its space in normal flow, so
 * shrinking the header on scroll shrinks the document with it. Measured on the
 * live page: condensing from 138px to 110px moved every section 28px up the
 * document and cut 28px off the body height — the page sliding under the reader
 * mid-scroll. The height is therefore constant at every scroll position, and
 * the "settled" cue is carried by the backdrop going fully opaque and the rule
 * beneath it strengthening. Both are paint-only.
 */
.lf-header.is-scrolled {
  background: #fff;
  border-bottom-color: var(--lf-line-strong);
  box-shadow: 0 1px 18px rgba(9, 29, 54, .05);
}

/* ---- row 1: brand · search · utilities ----
 * Three zones sized by the grid, not by whatever is left over. The previous
 * `1fr auto` split put the logo against the left edge, the controls against the
 * right, and roughly a thousand pixels of nothing between them. The centre
 * column is now the site's search, which is the one thing a catalogue header
 * should never make a shopper hunt for.
 */
.lf-header__inner {
  display: grid;
  /* EQUAL outer columns, not `auto`. With `auto … auto` the centre column is
     centred between the logo and the utilities, and since those are 105px and
     168px wide the field landed 31px left of the page's centre line — visibly
     out of step with the nav row underneath, which IS page-centred. Two `1fr`
     columns put the field's midpoint exactly on the nav's. */
  grid-template-columns: 1fr minmax(320px, var(--lf-hsearch-max, 520px)) 1fr;
  align-items: center;
  gap: clamp(1.25rem, 3.5vw, 3.5rem);
  /* The row is sized by the logo plus a hairline of space, not by generous
     padding: 54px of logo inside a 64px row. */
  padding-block: 5px;
}
/* `justify-self: start` is load-bearing. As a stretched grid item the logo link
   took the whole column — an invisible click target across most of the header. */
.lf-logo { display: flex; align-items: center; justify-self: start; }
.lf-actions--utility { justify-self: end; }
/* The supplied lockup is stacked (monogram over wordmark over descriptor,
   aspect ~1.95), so it is sized by HEIGHT; 54px renders ~105px wide, the
   confident end of the range without the descriptor line closing up. */
.lf-logo img { height: 54px; width: auto; max-width: 220px; }

/* ---- the persistent search field ----
 * A rectangle, not a pill: 2px of radius, a warm hairline and the site's own
 * ivory rather than a grey input fill. It has to read as somewhere to type at a
 * glance, which rules out a bare underline on white; and it must not read as a
 * marketplace, which rules out a filled capsule with a button on the end.
 */
.lf-hsearch {
  position: relative; display: flex; align-items: center;
  min-width: 0; height: 42px;
  background: var(--lf-ivory);
  border: 1px solid var(--lf-line);
  /* 9px. A 2px radius on a 42px box reads as an unstyled input; half the box
     height reads as a pill, and a pill in a furniture header reads as a search
     engine. 9px is the value where the corner is clearly deliberate and the
     field still reads as a rectangle — roughly a fifth of its height, the same
     relationship the site's other soft corners use. */
  border-radius: 9px;
  /* No padding on the control itself: the button has to reach the border, so
     the field's own inset moves onto the icon and the input instead. */
  padding: 0;
  transition: border-color .18s var(--lf-ease), background .18s var(--lf-ease),
              box-shadow .18s var(--lf-ease);
}
.lf-hsearch > svg {
  flex: none; align-self: center;
  width: 17px; height: 17px; margin: 0 11px 0 17px;
  stroke: var(--lf-navy); fill: none; stroke-width: 1.5;
}
.lf-hsearch__input {
  flex: 1 1 auto; min-width: 0; height: 100%;
  border: 0; background: none; padding: 0; margin: 0;
  font-family: var(--lf-sans); font-size: .875rem; letter-spacing: .01em;
  color: var(--lf-navy); -webkit-appearance: none; appearance: none;
}
.lf-hsearch__input::placeholder { color: var(--lf-taupe-mid); opacity: 1; }
.lf-hsearch__input:focus { outline: none; }
.lf-hsearch__input::-webkit-search-cancel-button { -webkit-appearance: none; }
/* THE BUTTON IS PART OF THE FIELD, not a control parked beside it.
 *
 * It was previously hidden until focused, on the reasoning that Enter already
 * submits. That is true and still true — but it assumes the shopper knows it,
 * and a furniture buyer is not necessarily a keyboard-shortcut user. The
 * primary action is now stated.
 *
 * Negative margins pull it over the field's own 1px border on three sides, so
 * the navy meets the field's outer edge with no hairline of ivory between them
 * and no gap where the two meet. Its right corners carry the field's 9px; its
 * left corners are square, which is what makes the pair read as one object. */
.lf-hsearch__submit {
  flex: none; width: 100px; align-self: stretch;
  margin: -1px -1px -1px 0; padding: 0; border: 0;
  border-radius: 0 9px 9px 0;
  background: var(--lf-navy); color: #fff;
  font-family: var(--lf-sans); font-size: .7rem; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: background .18s var(--lf-ease);
}
.lf-hsearch__submit:hover { background: var(--lf-navy-80); }
/* The ring sits outside the control, where it is legible against the header's
   white rather than against the button's own navy. */
.lf-hsearch__submit:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }
.lf-hsearch:hover { border-color: var(--lf-line-strong); }
/* Focus is carried by the FIELD, so the whole control responds as one object
   rather than sprouting a ring around the input inside it. Gold, because the
   palette reserves gold for the thing being acted on. */
.lf-hsearch:focus-within {
  border-color: var(--lf-navy); background: var(--lf-white);
  /* Navy, and a 3px wash of navy outside the hairline rather than a second
     border inside it. The halo keeps the field's own geometry — nothing moves
     on focus — and reads as the control waking up rather than as a browser
     glow. Deliberately not the gold used elsewhere for accent: this is the
     brand's voice colour saying "you are typing here". */
  box-shadow: 0 0 0 3px rgba(0, 20, 46, .10);
}
/* The toggle only exists where the field cannot fit. Doubled class: the generic
   `.lf-actions button` rule below is (0,1,1) and would otherwise win on source
   order and put a second search entry point beside the first. */
.lf-actions .lf-actions__searchtoggle { display: none; }

/* ---- row 2: primary navigation ----
   A hairline above it, so the two rows read as one stack rather than as a bar
   with something underneath. The nav itself carries the wrap, so its links are
   measured against the container's full width, not against what is left over
   between the logo and the icons. */
.lf-header__navrow { border-top: 1px solid var(--lf-line); }
.lf-nav > ul {
  display: flex; justify-content: center; align-items: stretch;
  gap: clamp(1.5rem, 3vw, 3.25rem);
  list-style: none; margin: 0; padding: 0;
}
.lf-nav a {
  display: flex; align-items: center; justify-content: center;
  /* 44px, not less. The composition wants 38-44 and this is the top of it,
     because the theme's own accessibility rule floors nav links at a 44px
     touch target (see REFINEMENTS / L-015) and quietly undercutting that to
     win a pixel would be trading a real rule for a cosmetic one. The row is
     therefore 45px: 44 plus its hairline. */
  height: 44px; padding: 0; line-height: 1;
  /* One line, always. The row has roughly twice the width the labels need, so
     this can never truncate — it is here to make wrapping impossible rather
     than merely unlikely if a label is ever renamed. */
  white-space: nowrap;
  font-size: .8rem; letter-spacing: .13em;
  text-transform: uppercase; color: var(--lf-navy); position: relative;
  transition: color .25s var(--lf-ease);
}
/* The underline sits on the row's own baseline rather than on each link's box,
   so it is the same distance below every label. */
/* The hover rule is GOLD, not navy: it is the page's accent doing the one job
   the palette reserves for it — marking the thing you are pointing at — and it
   separates "hovered" from "current" without adding a second navy line. */
.lf-nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 9px; height: 1px;
  background: var(--lf-gold); transform: scaleX(0); transform-origin: center;
  transition: transform .18s var(--lf-ease);
}
.lf-nav a:hover::after, .lf-nav a:focus-visible::after,
.lf-nav__item.is-open > a::after { transform: scaleX(1); }

/* ---- utilities ----
   One optical size, one stroke weight, one target size. The glyphs themselves
   were redrawn to a common grid (see `lomond_icon()`); this only has to keep
   them on it. */
/* A real gap between the controls. At `gap: 0` the three 42px targets abutted,
   so the glyphs were 23px apart with nothing between them and the group read as
   one crowded cluster rather than three separate things to click. */
.lf-actions { display: flex; gap: 4px; justify-content: flex-end; align-items: center; }
/* The target is 44px of whitespace around a 21px glyph — comfortably clickable
   without precision, and invisible as a control. No circle, no plate, no
   bordered box at rest. */
.lf-actions button, .lf-actions a {
  background: none; border: 0; padding: 0; color: var(--lf-navy);
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; cursor: pointer; border-radius: 8px;
  position: relative;
  transition: color .18s var(--lf-ease), background-color .18s var(--lf-ease);
}
/* Colour carries the hover; the ground behind it is a 4% navy wash, which is
   enough to show WHICH target you are in without becoming a bubble on a
   background that is itself white. */
.lf-actions button:hover, .lf-actions a:hover {
  color: var(--lf-gold); background-color: rgba(0, 20, 46, .04);
}
/* The header heart says whether anything is saved, using the same gold the
   product card's own wishlist button already uses for its pressed state —
   one state, one colour, wherever it appears. The count is the source of
   truth: the script unhides it exactly when the list is non-empty. */
.lf-header__wish:has(.lf-header__wishcount:not([hidden])) svg {
  /* A WASH, not a fill. The product card's own wishlist button turns solid gold
     when pressed, but that is a 38px control with one job; at 21px in a row of
     line glyphs a solid gold heart becomes the loudest thing in the header
     and says a second time what the counter beside it already says. The outline
     stays navy so the glyph still reads as part of the set. */
  fill: var(--lf-gold-line);
}
/* 21px at 1.6, up from 19 at 1.5. The set was drawn to one optical box, so a
   single size and a single stroke keep all three at identical visual weight —
   the increase is applied to the family, never to one glyph. */
.lf-actions svg {
  width: 21px; height: 21px; stroke: currentColor; fill: none; stroke-width: 1.6;
  transition: fill .18s var(--lf-ease), stroke .18s var(--lf-ease);
}

/* The search control reads as a field on desktop and as a glyph where there is
   no room for the word. `clip` rather than `display:none` so the word stays in
   the accessible name at every width. */
.lf-burger { display: none; }

/* Condensed once the page moves: the identity row gives up a little height and
   the nav row keeps all of its own, so the bar stays useful without dominating
   a scrolled page. The script republishes --lf-headh on every scroll, so the
   sticky filter toolbar that offsets against it follows automatically. */
.lf-header { transition: background .3s var(--lf-ease), border-color .3s var(--lf-ease),
                         box-shadow .3s var(--lf-ease); }

/* --------------------------------------------------------------- hero */
.lf-hero { background: var(--lf-stone); position: relative; overflow: hidden; }
/*
 * PAIRED hero — a text panel beside the photograph, not text on top of it.
 *
 * The first attempt overlaid the headline on the image. Rendered, the words sat
 * directly across the coffee table's glass top and the supporting sentence was
 * illegible: measured worst-case contrast in the text area was 1.01:1. The fix
 * is not a heavier scrim, which would destroy the photograph we went to some
 * trouble to find. It is to stop putting text over the subject.
 *
 * The design direction allows either: "Overlay OR PAIR it with restrained
 * editorial copy." Pairing is the honest answer for photography whose subject
 * fills the frame.
 */
.lf-hero--image { background: var(--lf-navy); }
.lf-hero--image .lf-hero__frame {
  /* Image first in the DOM, so column one is the photograph. It gets the larger
     share — the panel only needs enough width for the copy to set well. */
  display: grid; grid-template-columns: 1.3fr 1fr; align-items: stretch;
  min-height: min(72vh, 680px);
}
.lf-hero--image .lf-hero__inner {
  display: flex; align-items: center; background: var(--lf-navy);
  padding: clamp(2.5rem, 5vw, 4.5rem) clamp(1.5rem, 4vw, 4rem);
  max-width: none; margin: 0;
}
.lf-hero--image .lf-hero__copy { max-width: 30rem; }
.lf-hero--image .lf-hero__bg { position: relative; overflow: hidden; }
.lf-hero--image .lf-hero__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 58% 46%; }
/* A whisper of navy at the seam so the panel and the photograph read as one
   composition rather than two boxes butted together. */
.lf-hero--image .lf-hero__bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(9,29,54,.55) 0%, rgba(9,29,54,.10) 14%, transparent 30%);
}
.lf-hero--image h1 { color: #fff; font-size: clamp(2.3rem, 3.4vw, 3.5rem); }
.lf-hero--image p { color: rgba(255,255,255,.82); }
.lf-hero--image .lf-eyebrow { color: var(--lf-taupe-mid); }
.lf-hero--image .lf-btn { background: #fff; border-color: #fff; color: var(--lf-navy); }
.lf-hero--image .lf-btn:hover { background: transparent; color: #fff; }
.lf-hero--image .lf-btn--ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,.55); }
.lf-hero--image .lf-btn--ghost:hover { background: #fff; color: var(--lf-navy); }

/*
 * THE TWO HERO BUTTONS, WHEN THEY WRAP.
 *
 * `.lf-hero__cta` had no rule at all: a plain block containing two inline-flex
 * anchors, so their separation was whatever the whitespace between the two tags
 * happened to collapse to. Side by side that is about 4px. Stacked it is ZERO —
 * measured at 390, 430 and 1024, where the two buttons meet edge to edge and
 * read as one 96px slab rather than as a primary action and a secondary one.
 *
 * 1024 IS AFFECTED TOO, and not obviously: the hero is a two-column grid there,
 * so the copy column is 363px and the buttons need 430px. They wrap on a
 * desktop-width screen.
 *
 * `row-gap` alone is the fix. `column-gap` is set to the 4px the inline
 * whitespace was already producing, because a flex container ignores that
 * whitespace and leaving it unset would close the side-by-side gap to nothing —
 * changing the desktop arrangement, which this is not allowed to do.
 *
 * `align-items: center` preserves the current behaviour rather than adopting
 * flex's default: `stretch` would make a wrapped label grow its neighbour to
 * match, which inline-flex on a line box does not do. Both buttons are 48px
 * today, so nothing moves.
 */
.lf-hero__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px 4px;          /* row, column */
}

@media (max-width: 860px) {
  /* Mobile is designed, not stacked: photograph first, then a full-width panel.
     The image keeps a landscape crop so the product stays recognisable. */
  .lf-hero--image .lf-hero__frame { grid-template-columns: 1fr; min-height: 0; }
  .lf-hero--image .lf-hero__bg { aspect-ratio: 4 / 3; }
  .lf-hero--image .lf-hero__bg::after { background: none; }
  .lf-hero--image .lf-hero__inner { padding: clamp(2rem, 8vw, 3rem) var(--lf-gutter) clamp(2.5rem, 9vw, 3.5rem); }
  .lf-hero--image .lf-hero__copy { max-width: none; }
}

/* --------------------------------------------------------------- sections */
.lf-section { padding-block: clamp(3.5rem, 7vw, 6.5rem); }
.lf-section--stone { background: var(--lf-ivory); }
.lf-section__head { display: flex; align-items: end; justify-content: space-between; gap: 2rem; margin-bottom: clamp(1.8rem, 3vw, 3rem); }
.lf-section__head p { color: var(--lf-taupe-deep); margin: .4rem 0 0; max-width: 46ch; }
.lf-link {
  font-size: .78rem; letter-spacing: .14em; text-transform: uppercase; color: var(--lf-navy);
  border-bottom: 1px solid var(--lf-line-strong); padding-bottom: .3rem; white-space: nowrap;
  transition: border-color .3s var(--lf-ease);
}
.lf-link:hover { border-color: var(--lf-navy); }

/* -------------------------------------------------- shop by room (asymmetric) */

/* --------------------------------------------------------------- product cards */
/* Column tiers are sized for the eventual 175-product catalogue, not for the ten
   staging products. Row gap is larger than column gap so rows separate without
   the grid looking sparse horizontally. */
.lf-grid { display: grid; grid-template-columns: repeat(4, 1fr); column-gap: clamp(1rem, 1.6vw, 1.9rem); row-gap: clamp(2rem, 3vw, 3.2rem); }
.lf-grid--3 { grid-template-columns: repeat(3, 1fr); }
@media (min-width: 1600px) { .lf-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 1240px) { .lf-grid { grid-template-columns: repeat(3, 1fr); } }
.lf-card { display: flex; flex-direction: column; }
.lf-card__media {
  position: relative; display: block; background: var(--lf-stone);
  /* 1:1 rather than 4:5. Supplier photography is predominantly landscape, and a
     portrait frame letterboxed almost every product — the item ended up
     occupying about half its own card. */
  aspect-ratio: 1 / 1; overflow: hidden; margin-bottom: .9rem;
}
.lf-card__media img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  /* `contain` always: a furniture proportion must never be cropped or stretched.
     Padding cut from 8% to 3% so the product actually fills its frame. */
  object-fit: contain; padding: 3%; mix-blend-mode: multiply;
  transition: transform .7s var(--lf-ease), opacity .5s var(--lf-ease);
}
.lf-card__media img.is-alt { opacity: 0; }
/* Hover-only behaviour is gated: on a touch device the state sticks after a tap
   and the card is left showing its secondary image (ANTI_PATTERNS, "sticky
   hover on touch"). */
@media (hover: hover) and (pointer: fine) {
  .lf-card:hover .lf-card__media img.is-primary { opacity: 0; }
  .lf-card:hover .lf-card__media img.is-alt { opacity: 1; }
  .lf-card:hover .lf-card__media img { transform: scale(1.03); }
}
.lf-card__media:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }
.lf-card__range { font-size: .66rem; letter-spacing: .18em; text-transform: uppercase; color: var(--lf-taupe); margin: 0 0 .3rem; }
.lf-card__title { font-family: var(--lf-serif); font-size: 1.14rem; line-height: 1.28; margin: 0 0 .3rem; color: var(--lf-navy); }
.lf-card__title a:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }
.lf-card__meta { font-size: .76rem; color: var(--lf-taupe); margin: 0 0 .55rem; }
/* Price is the second thing read after the name, so it steps up in weight and
   size rather than sitting level with the metadata. */
.lf-card__price { font-size: 1.02rem; color: var(--lf-navy); font-weight: 400; letter-spacing: .01em; margin: 0; }
.lf-card__price .from { font-size: .66rem; color: var(--lf-taupe); text-transform: uppercase; letter-spacing: .14em; margin-right: .3rem; font-weight: 400; }

/* --------------------------------------------------------------- editorial feature */

/* --------------------------------------------------------------- brand story */
.lf-story { background: var(--lf-navy); color: rgba(255,255,255,.86); }
.lf-story h2 { color: #fff; }
.lf-story .lf-eyebrow { color: var(--lf-taupe-mid); }
.lf-story .lf-btn { border-color: rgba(255,255,255,.5); background: transparent; color: #fff; }
.lf-story .lf-btn:hover { background: #fff; color: var(--lf-navy); border-color: #fff; }

/* --------------------------------------------------------------- service row */
.lf-service { display: grid; grid-template-columns: repeat(4, 1fr); gap: 2rem; border-top: 1px solid var(--lf-line); padding-top: 2.5rem; }
.lf-service div { display: flex; gap: .9rem; align-items: flex-start; }
.lf-service svg { width: 22px; height: 22px; stroke: var(--lf-taupe); fill: none; stroke-width: 1.2; flex: none; margin-top: 2px; }
.lf-service strong { display: block; font-weight: 400; color: var(--lf-navy); font-size: .92rem; margin-bottom: .15rem; }
.lf-service span { font-size: .82rem; color: var(--lf-taupe-deep); }

/* ================================================ KLARNA, ON THE PRODUCT PAGE
   A fact about the price, set beside the price. Pale stone, one hairline, a
   small wordmark and two lines of 13px — noticeable at the moment of the
   decision without becoming the thing the page is about.

   NOT the pink advertising box the category is full of: the only pink is the
   wordmark chip itself, at 44x22, because that is Klarna's identifier and
   rendering it in Lomond's navy would be passing it off as ours.            */

/*
 * PROBLEM 6: it read as a technical notification, not as merchandising.
 *
 * The content was right and the SIZE was wrong — 57px tall against a 48px
 * button, with a 13px lede. It is now a proper card: roughly half again the
 * height, a larger wordmark, a 15px lede in navy, and a chevron on the right
 * that gives it the shape of a retail finance panel rather than a system
 * message. The surface stays stone with a single hairline, so it gains
 * presence without becoming the pink advertising box the brief rules out.
 */
/*
 * PINK, BECAUSE THE APPROVED DESIGN IS PINK.
 *
 * Earlier passes made this stone-grey on the reasoning that a tinted panel
 * would read as a promotional box. The approved design settles it: finance is
 * MERCHANDISING on a furniture PDP, and the customer recognises the colour
 * before they read the words. The restraint is in the value of the tint — a 12%
 * wash of Klarna's own pink rather than the full brand colour — and in the fact
 * that nothing else on the page is pink.
 */
.lf-klarna {
  margin: 1.35rem 0 0;
  background: #FFF0F4;
  border: 1px solid #F7CEDC;
  /* 4px, not 8: the buying column's other surfaces (the confidence grid, the
     rewards panel, the swatches) all sit at 3-4px, and a rounder finance card
     reads as a SaaS notification pinned to a retail page. */
  border-radius: 4px;
}
/*
 * THE WHOLE BAND IS THE CONTROL, so the chevron is part of the interaction
 * rather than an ornament beside it — and the target is the full 618x64 rather
 * than a 16px arrow.
 */
.lf-klarna__row {
  display: flex; align-items: center; width: 100%;
  gap: clamp(1rem, 1.9vw, 1.35rem);
  min-height: 64px;
  padding: .7rem clamp(1.15rem, 2.1vw, 1.5rem);
  background: none; border: 0; border-radius: inherit;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
.lf-klarna__row:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }

/* Klarna's own pink pill, at the size the wordmark stays a wordmark. */
.lf-klarna__mark {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 88px; height: 38px; padding: 0 .55rem;
  background: #FFB3C7; border-radius: 4px;
}
.lf-klarna__wordmark { display: block; width: 100%; height: auto; }
.lf-klarna__wordfallback {
  font-family: var(--lf-sans); font-size: .95rem; font-weight: 600;
  color: #17120F; letter-spacing: .005em;
}

.lf-klarna__copy { flex: 1 1 auto; display: flex; flex-direction: column; gap: .16rem; min-width: 0; }
/* 15.5px semibold. The finance offer is a selling line, and it was previously
   set at the weight of body copy, which is what made a pink panel read as a
   pale notification. */
.lf-klarna__lede {
  font-family: var(--lf-sans); font-size: .97rem; font-weight: 600; line-height: 1.3;
  color: var(--lf-navy); letter-spacing: .005em;
}
/* The hedge, deliberately legible rather than small print: it is the honest
   part of the claim, not a disclaimer to be hidden. */
.lf-klarna__note {
  font-family: var(--lf-sans); font-size: .8rem; line-height: 1.35;
  color: #86677180; color: #7E626C; text-wrap: pretty;
}
.lf-klarna__more { flex: none; color: #B07C90; line-height: 0; transition: transform .3s var(--lf-ease); }
.lf-klarna__more svg { width: 20px; height: 20px; display: block; }
.lf-klarna__row[aria-expanded="true"] .lf-klarna__more { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) { .lf-klarna__more { transition: none; } }

.lf-klarna__detail {
  padding: 0 clamp(1.15rem, 2.1vw, 1.5rem) 1rem;
  /* The pill's width plus the row gap, so the paragraph starts under the copy
     rather than under the mark. */
  padding-left: calc(clamp(1.15rem, 2.1vw, 1.5rem) + 88px + clamp(1rem, 1.9vw, 1.35rem));
}
.lf-klarna__detail p {
  margin: 0; font-family: var(--lf-sans); font-size: .82rem; line-height: 1.5;
  color: #7E626C; text-wrap: pretty;
}
@media (max-width: 560px) {
  .lf-klarna__detail { padding-left: clamp(1.15rem, 2.1vw, 1.5rem); }
}

/* ---- the payment reassurance row, under the basket button */
.lf-paysafe {
  display: flex; align-items: center; flex-wrap: wrap;
  /* 10px between marks, 14px before them. The row was a 24px strip of .8rem
     grey under a 58px button and read as a caption on the button rather than as
     reassurance in its own right. */
  gap: .5rem .875rem; margin: 1.1rem 0 0;
  font-family: var(--lf-sans); font-size: .875rem; line-height: 1.4;
  color: var(--lf-taupe-deep);
}
/* The real brand marks, from the Stripe gateway plugin's own licensed assets —
   no wordmark is redrawn and nothing is shown that the checkout cannot take. */
.lf-paysafe__marks { display: inline-flex; align-items: center; gap: .45rem; }
.lf-klarna__badge {
  display: block; flex: 0 0 auto; width: 42px; height: 42px;
  border-radius: 6px;
}
/* Fixed BOX, contained artwork. The scheme files do not share an aspect —
   Visa and Mastercard are 40x25-ish, Klarna's is a 32x32 square — so sizing by
   height alone put a square mark beside two landscape ones, and letting the box
   follow the file squashed the square one. A uniform box with `contain` keeps
   the row even and never distorts a brand mark, which is the one thing a
   licensed asset may not do. */
.lf-paysafe__mark {
  /* 44x28 rather than 38x24 — the marks have to be recognisable at reading
     distance, which is the entire job of the row. `contain` inside a uniform
     box keeps them even without distorting any of them. */
  display: block; width: 44px; height: 28px;
  object-fit: contain; object-position: center;
  border: 1px solid var(--lf-line); border-radius: 3px; background: #fff;
  padding: 2px;
}
.lf-paysafe__lock { flex: none; line-height: 0; color: var(--lf-taupe-deep); }
.lf-paysafe__lock svg { width: 16px; height: 16px; display: block; stroke: currentColor; fill: none; stroke-width: 1.5; }
.lf-paysafe__label { color: var(--lf-navy); }
/* The middot separated two runs of WORDS ("Secure checkout · Card · Klarna").
   Now that the methods render as marks, it dangles between a sentence and a row
   of images, punctuating nothing. It comes back on its own if the marks ever
   fail to load, because that is the branch that still prints words. */
.lf-paysafe:has(.lf-paysafe__methods) .lf-paysafe__label::after {
  content: "·"; margin-left: .55rem; color: var(--lf-taupe-mid);
}
.lf-paysafe__methods { color: var(--lf-taupe); }

/* ---- the product reference, under the title */
.lf-pdp__sku {
  margin: .5rem 0 0;
  font-family: var(--lf-sans); font-size: .78rem; letter-spacing: .06em;
  color: var(--lf-taupe-mid);
}
.lf-pdp__sku span { color: var(--lf-taupe-deep); letter-spacing: .04em; }

@media (max-width: 560px) {
  .lf-klarna { gap: .7rem; padding: .7rem .8rem; }
  .lf-klarna__mark { min-width: 46px; font-size: .7rem; }
  .lf-klarna__lede { font-size: .84rem; }
  .lf-klarna__note { font-size: .76rem; }
}

/* --------------------------------------------------------------- signup
   THE "STAY IN TOUCH" BAND — a full-width surface carrying a contained grid.

   TWO ELEMENTS, TWO JOBS, AND THAT SEPARATION IS THE WHOLE LAYOUT.

     .lf-signup         the SURFACE. Full width, edge to edge, no max-width and
                        no padding. It is the beige, the two hairlines, and
                        nothing else.
     .lf-signup__inner  the CONTENT. A centred container on exactly the site's
                        own measurements — `--lf-max` and `--lf-gutter`, the
                        same two values `.lf-wrap` uses — so the photograph's
                        left edge lands on the same vertical as the "Complete
                        the room" heading below it, and the card's right edge
                        on the same vertical as the last product card.

   WHAT THIS REPLACES. The grid used to be full-bleed too, so the photograph ran
   to the viewport edge and only the RIGHT edge was pulled back onto the page
   grid, by a `max()` inset. That made the band's content sit on a different
   grid from every other section on the page — the thing that read as drifting.
   The inset variable is gone with it; a container that is genuinely centred
   needs no arithmetic to find its own edges.

   The band takes no block padding: the columns supply their own, because the
   photograph still has to reach the top and bottom of the band. */
/* THE EDGES ARE WARM, NOT NEUTRAL. `--lf-line` is calibrated against white and
   reads as a grey scratch where beige meets the white product rails above and
   below. A warmer hairline makes the change of surface look decided. */
.lf-signup {
  background: var(--lf-taupe-wash);
  border-top: 1px solid #E4DCD2;
  border-bottom: 1px solid #E4DCD2;
  /* The photograph bleeds past this element's left edge on purpose (below).
     `clip` rather than `hidden` because `hidden` makes the band a scroll
     container, which would let a focused control inside it scroll the band
     sideways. Both are declared so a browser without `clip` still contains it. */
  overflow: hidden;
  overflow: clip;
}
.lf-signup__inner {
  display: grid;
  /* 22 / 33 / 45 of the CONTAINER, plus the photograph's bleed on top of its
     column. The picture was 21% and then lost a further 42% of THAT to its own
     fades — about 164px of real photograph on a 1440 screen, which is what made
     it read as a strip. It is now 341px with a fade on one edge only: roughly
     double the effective picture, taken from the column AND from the page
     margin it now covers.
     Measured, not chosen: 25% broke the heading onto two lines and 22% squeezed
     the card until its action row wrapped and the band grew 70px. 21/32/47 is
     the split where the heading holds one line, the card's button and link hold
     one row, and the photograph still gains half as much again as it had. */
  grid-template-columns: minmax(0, 21%) minmax(0, 32%) minmax(0, 47%);
  align-items: stretch;
  min-height: 320px;
  max-width: var(--lf-max);
  margin-inline: auto;
  padding-inline: var(--lf-gutter);
}
/* Two areas only, when there is no programme and no list to invite anyone to. */
.lf-signup--nopanel .lf-signup__inner { grid-template-columns: minmax(0, 22%) minmax(0, 1fr); }
.lf-signup--novisual .lf-signup__inner { grid-template-columns: minmax(0, 38%) minmax(0, 62%); }
.lf-signup--novisual.lf-signup--nopanel .lf-signup__inner { grid-template-columns: 1fr; }

/* ---- the photograph
   A CSS CROP, NOT A NEW UPLOAD. `IMAGE_DERIVATIVE_POLICY.md` measured inodes,
   not disk, as the account's binding constraint, and one upload costs up to ten
   files. `transform-origin` is held to the same point as `object-position` so
   the zoom pulls in towards the focal point instead of drifting off it. */
/*
 * THE PHOTOGRAPH REACHES THE EDGE OF THE PAGE.
 *
 * The copy and the card stay on the site's centred grid — that is what makes
 * the band line up with everything above and below it. The photograph does not
 * want to be on that grid: it is the band's LEFT SIDE, and a picture that stops
 * 43px short of the window with beige either side of it reads as a rectangle
 * dropped into a section rather than as the section's own background.
 *
 * So it is pulled back out by exactly the distance the container is inset:
 * `(100vw - max)/2` above 1440px, where the container is centred, plus the
 * gutter at every width. `100vw` includes the scrollbar, so on a scrolling page
 * this over-reaches by a few pixels — which is why the band clips. Over-reaching
 * into a clip is flush; under-reaching would be a sliver of beige.
 */
.lf-signup__visual {
  position: relative; overflow: hidden;
  margin-left: calc(-1 * (max(0px, (100vw - var(--lf-max)) / 2) + var(--lf-gutter)));
  /* The band's own colour, not a tint: any flash before the photograph decodes
     is then invisible rather than a taupe rectangle. */
  background: var(--lf-taupe-wash);
}
.lf-signup__visual img {
  position: absolute; inset: 0; display: block;
  width: 100%; height: 100%; max-width: none;
  /* Less zoom than before: the column is half as wide again, so the same crop
     scale would have pushed the room out of frame and left only the vase. */
  object-fit: cover; object-position: 72% 72%;
  transform: scale(1.42); transform-origin: 72% 72%;
}

/*
 * THE PHOTOGRAPH EMERGES FROM THE BAND — a mask, not an overlay.
 *
 * It used to be an overlay: a gradient from transparent to `--lf-taupe-wash`
 * painted over the right-hand edge. That works only while the thing behind the
 * photograph is EXACTLY that colour, and it did nothing at all for the left
 * edge, which since the content was brought onto the centred grid has been a
 * hard vertical cut against the beige. A mask fades the photograph to genuine
 * transparency instead, so whatever is behind it shows through — the band's own
 * background, at whatever value it happens to be, with no colour to keep in
 * step and no seam possible.
 *
 * ON THE WRAPPER, NOT THE IMAGE, AND THAT IS NOT A STYLE CHOICE. The `img`
 * carries `transform: scale(1.78)` for its crop. A mask is applied in the
 * element's own coordinate space and is transformed along with it, so a mask on
 * the image would be blown up by 1.78 about the crop's origin and its soft
 * edges would land far outside the visible box. The wrapper is untransformed
 * and clips, so masking it fades the clipped result exactly where it is seen.
 *
 * THE SUBJECT STAYS CRISP. The fade takes the outer ~20% at each vertical edge
 * and nothing is faded in between: about 58% of the photograph's width — the
 * vase, the flowers and the books — is untouched, at full opacity and full
 * sharpness. This is a dissolve at the boundary, not a vignette over the
 * picture.
 */
@supports (mask-image: linear-gradient(#000, #000)) or (-webkit-mask-image: linear-gradient(#000, #000)) {
  /*
   * ONE EDGE FADES, AND ONLY ONE.
   *
   * The previous mask tapered BOTH vertical edges — 20% off the left and 22%
   * off the right of a 284px column. Nearly half the photograph was being
   * dissolved, which is why it looked washed out and insubstantial: the fade
   * had become the treatment rather than the join.
   *
   * Three of the four edges no longer need anything. The left runs off the side
   * of the window. The top and bottom meet the band's own hairlines, which are
   * the section's edges rather than a boundary with the beige. That leaves the
   * right edge, where the photograph meets the copy, and that is the only place
   * a seam could show.
   *
   * 84% of the picture is therefore at FULL opacity and full colour — the vase,
   * the flowers, the books, the sideboard — and the last 16% carries the whole
   * transition. Two stops rather than one so it eases out instead of ramping
   * linearly, which is what stops a soft edge from reading as a gradient.
   */
  .lf-signup__visual {
    -webkit-mask-image: linear-gradient(to right, #000 0%, #000 84%, rgba(0,0,0,.55) 93%, transparent 100%);
            mask-image: linear-gradient(to right, #000 0%, #000 84%, rgba(0,0,0,.55) 93%, transparent 100%);
  }
}

/*
 * THE FALLBACK, for a browser with no mask support: the old overlay, on the one
 * edge where a flat colour is guaranteed to match. Scoped behind `@supports not`
 * so the two can never both apply and fade the same edge twice.
 */
@supports not ((mask-image: linear-gradient(#000, #000)) or (-webkit-mask-image: linear-gradient(#000, #000))) {
  .lf-signup__visual::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(to right, rgba(242,237,232,0) 62%, var(--lf-taupe-wash) 100%);
  }
}

/* ---- the editorial copy */
/*
 * ASYMMETRIC PADDING, AND MEASURED RATHER THAN CHOSEN.
 *
 * With equal padding the copy started 37px from the edge of the photograph and
 * ended ~110px short of the card: crowded against the image on one side and
 * adrift from the card on the other. The left inset is therefore the larger of
 * the two — the photograph is a hard visual edge and needs more clearance than
 * a card that supplies its own.
 */
.lf-signup__editorial {
  display: flex; flex-direction: column; justify-content: center;
  /* The left inset is smaller than it was: it existed to hold the copy off a
     HARD photographic edge, and there is no longer one — the picture dissolves
     over its last 16%, which is clearance of its own. */
  padding: clamp(2rem, 3vw, 2.75rem) clamp(1.5rem, 2.2vw, 2.3rem)
           clamp(2rem, 3vw, 2.75rem) clamp(1.75rem, 2.8vw, 2.75rem);
}
/* NOT `--lf-gold`. That token is calibrated against white and the near-white
   surfaces (#FBF9F6, #FAF7F1); on this band's #F2EDE8 it measures 4.24:1, and
   the eyebrow is 11.5px text, so it needs 4.5:1. #835F33 measures 4.95:1 on
   the band and 5.48:1 on the panel, and is the same hue a shade deeper. */
.lf-signup__eyebrow { color: #835F33; margin-bottom: 1.15rem; }
/* SIZED TO HOLD "A little more inspiration." ON ONE LINE at 1440 in the 28%
   column, which is how the approved composition reads it. At 2.9rem it broke
   after "more" and the band gained a line it did not need. */
.lf-signup__title { margin: 0; font-size: clamp(1.7rem, 2.35vw, 2.15rem); line-height: 1.16; }
.lf-signup__intro { margin: 1.3rem 0 0; color: var(--lf-taupe-deep); max-width: 31ch; font-size: .95rem; line-height: 1.78; }
/* The short decorative rule under the copy. A `span`, not an `hr`: it separates
   nothing, so it has no business in the accessibility tree. */
/* THE RULE IS PLACED, NOT LEFT OVER. It sits far enough below the paragraph to
   read as the block's closing mark rather than as an underline that missed, it
   is shorter than before so it reads as a mark rather than as a divider, and it
   fades at its right-hand end so it stops rather than being cut off. */
.lf-signup__flourish {
  display: block; width: 46px; height: 1px; margin-top: 2.6rem;
  background: linear-gradient(to right, var(--lf-gold-sheet), rgba(184, 144, 79, 0));
}
/* The fallback aside, used only when there is no panel at all. */
.lf-signup__editorial--aside { justify-content: center; }

/* ---- the rewards panel's outer box lives here, its contents in rewards.css,
   because the box has to hold its shape on a page where `rewards.css` is not
   enqueued at all. */
/* THE CARD READS AS AN OBJECT ON THE BAND, not as a lighter patch of it.
   Four things do that work together, and none of them alone:
     surface   a shade warmer and a shade lighter than --lf-ivory, so it lifts
               off #F2EDE8 without going clinical white
     border    one warm hairline, slightly stronger than --lf-line, which is
               tuned for white and disappears against beige
     shadow    two layers — a 1px contact shadow that seats the edge, and a wide
               soft one at low opacity that suggests height without casting a box
     radius    12px: enough to read as a card, well short of a pill */
.lf-rwband {
  margin: clamp(1.25rem, 1.95vw, 1.75rem) 0;
  padding: clamp(1.5rem, 2vw, 1.85rem) clamp(1.5rem, 2.3vw, 2.15rem);
  background: #FCFAF7;
  border: 1px solid #E5DDD3;
  border-radius: 12px;
  /* So `.lf-rwband__sep` can ask how wide THIS is, rather than how wide the
     window is. `inline-size` contains the inline axis only, so the card's
     height still follows its content. */
  container-type: inline-size;
  /* The wide layer had a -30px spread, which cancelled almost all of it: at 2x
     the card had no perceptible lift at all. -24px and a little more opacity
     keeps it well under "floating" while making the edge sit ON the band. */
  box-shadow: 0 1px 2px rgba(0, 20, 46, .045), 0 16px 36px -24px rgba(0, 20, 46, .24);
  display: flex; flex-direction: column; justify-content: center;
}

@media (max-width: 1180px) {
  /* TABLET: the photograph becomes a shallow full-width visual across the top
     and the two text areas sit side by side. It reduces; the panel does not. */
  .lf-signup__inner,
  .lf-signup--nopanel .lf-signup__inner,
  .lf-signup--novisual .lf-signup__inner { grid-template-columns: minmax(0, 42%) minmax(0, 58%); }
  /* THE STRIP STAYS INSIDE THE CONTAINER, like everything else in the band.
     It was breaking out to the viewport edge, which meant the photograph sat
     on the page grid at desktop and off it at tablet — the same element
     obeying two different rules depending on the width, which is exactly the
     drift this container was introduced to remove. */
  .lf-signup__visual { grid-column: 1 / -1; height: clamp(150px, 20vw, 200px); }
  /* A WIDE, SHORT BOX TAKES A HORIZONTAL SLICE, so the Y position is what
     chooses the subject, not the X. At 58% the slice ran through the lamp
     shade and the middle of the canvas — an arbitrary band of wall. 78% puts
     the sideboard top in it: the vase, the books and the lantern, which is the
     same still life the desktop column crops to. */
  .lf-signup__visual img { transform: none; object-position: 56% 78%; }

  /*
   * STACKED, THE STRIP SPANS THE WINDOW AND ONLY ITS FOOT NEEDS A BLEND.
   *
   * It used to sit inside the container with beige either side, so both of its
   * vertical edges were exposed and both had to be tapered — which on a strip
   * only 120-200px tall meant most of its width was in a fade. Bleeding it to
   * both edges removes those two boundaries entirely rather than disguising
   * them, and leaves exactly one: the foot, where the copy begins.
   *
   * One gradient, no compositing, and 74% of the strip at full colour.
   */
  .lf-signup__visual {
    margin-inline: calc(-1 * (max(0px, (100vw - var(--lf-max)) / 2) + var(--lf-gutter)));
    -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 74%, rgba(0,0,0,.5) 89%, transparent 100%);
            mask-image: linear-gradient(to bottom, #000 0%, #000 74%, rgba(0,0,0,.5) 89%, transparent 100%);
  }
  .lf-signup__editorial { padding-inline: 0 clamp(1.25rem, 2.4vw, 2rem); }
  .lf-rwband { margin-block: clamp(1.25rem, 2.4vw, 2rem); }
}

@media (max-width: 860px) {
  /* MOBILE: one column, in DOM order — visual, copy, panel. */
  .lf-signup__inner,
  .lf-signup--nopanel .lf-signup__inner,
  .lf-signup--novisual .lf-signup__inner { grid-template-columns: 1fr; min-height: 0; }
  .lf-signup__visual { height: clamp(120px, 30vw, 170px); }
  /* The container carries the gutter now. Repeating it here doubled it — 40px
     of inset on a 390px phone instead of the 20px the rest of the page uses. */
  .lf-signup__editorial { padding: 1.85rem 0 0; }
  /* The eyebrow is a letterspaced label rather than body copy, but 11.5px is
     mean on a phone. It takes the same step up the panel's copy does. */
  .lf-signup__eyebrow { font-size: .78rem; }
  .lf-signup__intro { max-width: 42ch; }
  .lf-signup__flourish { margin-top: 1.25rem; }
  .lf-rwband { margin: 1.5rem 0 2rem; padding: 1.5rem 1.35rem 1.6rem; }
}

/* --------------------------------------------------------------- footer */
.lf-footer { background: var(--lf-ivory); border-top: 1px solid var(--lf-line); padding-block: clamp(3rem, 5vw, 4.5rem) 2rem; }
/* Four columns, not five: the "About Lomond" column held three placeholders
   for pages nobody has planned, and it has gone. */
.lf-footer__cols { display: grid; grid-template-columns: 1.4fr repeat(3, 1fr); gap: 2.5rem; }
.lf-footer h3 { font-family: var(--lf-sans); font-size: .74rem; letter-spacing: .18em; text-transform: uppercase; color: var(--lf-navy); margin: 0 0 1.1rem; font-weight: 400; }
.lf-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }
.lf-footer a { font-size: .88rem; color: var(--lf-taupe-deep); }
.lf-footer a:hover { color: var(--lf-navy); }
.lf-footer__brand p { font-size: .88rem; color: var(--lf-taupe-deep); max-width: 26ch; }
.lf-footer__base { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--lf-line); display: flex; justify-content: space-between; gap: 1rem 2rem; flex-wrap: wrap; font-size: .78rem; color: var(--lf-taupe); }
/* The agency credit sits quietly: same size as the copyright line, no accent
   colour, and it underlines only on interaction. */
.lf-footer__credit a { color: var(--lf-taupe-deep); border-bottom: 1px solid transparent; transition: border-color .25s var(--lf-ease); }
.lf-footer__credit a:hover, .lf-footer__credit a:focus-visible { border-bottom-color: var(--lf-taupe); }
@media (max-width: 640px) { .lf-footer__base { justify-content: flex-start; flex-direction: column; gap: .5rem; } }

/* --------------------------------------------------------------- breadcrumb */
.lf-crumbs { font-size: .76rem; color: var(--lf-taupe); letter-spacing: .04em; padding-block: 1.25rem; }
.lf-crumbs a { color: var(--lf-taupe-deep); }
.lf-crumbs a:hover { color: var(--lf-navy); }
.lf-crumbs span + span::before { content: "/"; margin: 0 .55rem; color: var(--lf-taupe-mid); }

/* --------------------------------------------------------------- staging ribbon */
.lf-staging {
  background: #7A2E2E; color: #fff; text-align: center;
  font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; padding: .5rem 1rem;
}

/* --------------------------------------------------------------- responsive */
@media (max-width: 900px) {
  .lf-grid { grid-template-columns: repeat(2, 1fr); }
  .lf-footer__cols { grid-template-columns: 1fr 1fr 1fr; }
  .lf-service { grid-template-columns: 1fr 1fr; }
}
/*
 * THE NAV HANDS OVER TO THE BURGER AT 1100px, NOT 860px.
 *
 * Adding Mattresses and Home Office took the bar from six items to eight, and
 * eight no longer fit beside the logo and the icons below about 1180px: the
 * page overflowed by 56px at 1024 and 148px at 900. The two categories are not
 * the problem — being unreachable was — so the breakpoint moves instead, and
 * the band just above it is tightened so the bar is never merely surviving.
 */
/*
 * BELOW THE DESKTOP BREAKPOINT the field cannot sit beside the logo without
 * being crushed, so it is summoned instead of crowded: the toggle returns to
 * the utilities and the same form — not a second copy of it — drops to a
 * full-width row beneath the header when opened. Closed, it is `display: none`,
 * so the header is exactly as tall as it was before the field existed and there
 * is no ghost row of any kind.
 */
@media (max-width: 1099px) {
  .lf-header__inner { grid-template-columns: auto 1fr auto; }
  .lf-header__navrow { display: none; }
  .lf-burger { display: inline-flex; }
  /* Centred in its own column, not shunted up against the burger. */
  .lf-logo { justify-self: center; }
  .lf-logo img { height: 46px; }
  .lf-actions .lf-actions__searchtoggle { display: inline-flex; }

  .lf-hsearch { display: none; }
  .lf-header.is-searching .lf-hsearch {
    display: flex;
    grid-column: 1 / -1; grid-row: 2;
    height: 44px; margin-top: 8px;
  }
  .lf-header.is-searching .lf-header__inner { padding-bottom: 10px; }
}
/*
 * NO TIGHTENING BAND. There used to be a 1100-1279px tier that dropped the nav
 * to 12.16px and 21.6px gaps. Measured on the live row after the nav took its
 * own full-width row, that tier had 330px of slack it did not need, so it was
 * shrinking the type for nothing and breaking the rhythm between 1279 and 1280.
 * One size, one tracking, one gap curve across the whole desktop range; the
 * narrowest desktop width still clears the labels by ~108px.
 */
@media (max-width: 860px) {
  .lf-hero__grid { grid-template-columns: 1fr; min-height: 0; }
  .lf-hero__media { order: -1; }
  .lf-hero__media img { aspect-ratio: 5 / 4; }
  .lf-section__head { flex-direction: column; align-items: flex-start; }
}
@media (max-width: 560px) {
  .lf-grid { grid-template-columns: 1fr 1fr; gap: 1rem; }
  .lf-card__title { font-size: 1rem; }
  .lf-footer__cols { grid-template-columns: 1fr 1fr; }
  .lf-service { grid-template-columns: 1fr; }
  .lf-utility ul { gap: .4rem 1.2rem; font-size: .68rem; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* ============================================================ PRODUCT PAGE */
/*
 * NO TRAILING PADDING ON THE PDP.
 *
 * `padding-block`'s second value used to be clamp(3rem, 6vw, 5rem) — 80px at
 * 1440 — and it predates the recommendation rails. Measured on the rendered
 * page it was 80 of the 107px between the last recommendation and the
 * newsletter, and worse than the size was the COLOUR: `main` is transparent, so
 * those 80px painted a white stripe between the ivory rail above them and the
 * cream newsletter below, which reads as a hole rather than as spacing. That is
 * the "large white gap".
 *
 * The closing space now belongs to the last rail — see `.lf-reco--close`,
 * which carries it (the tint that once went with it is gone; see that rule).
 * Safe unconditionally rather than behind `:has()`: if a page ever ended
 * without rails it would end at `.lf-pinfo`, which carries its own
 * clamp(2.5rem, 4vw, 3.5rem) of bottom padding.
 */
.lf-pdp { padding-block: clamp(1rem, 3vw, 2rem) 0; }
/* THE SPLIT, MEASURED AGAINST THE APPROVED MOCKUP rather than chosen. The
   mockup's own columns measure 510 : 467 — a ratio of 1.09 — and this grid was
   already at 1.15, so the composition was close before this pass and the work
   was NOT in the ratio. It moves to 1.22 to give the photograph the extra
   weight the brief asks for, and the gap tightens so the purchase column loses
   nothing: at 1440 the gallery gains ~40px and the panel holds its width. */
/*
 * THE SPLIT AND THE GUTTER ARE THE MOCKUP'S, MEASURED.
 *
 * Taken off the approved design at its own scale and expressed as fractions of
 * the content width: gallery 49.8%, gutter 4.6%, purchase column 45.6%. That is
 * a 1.09 : 1 track ratio, not the 1.22 : 1 this carried — which rendered
 * 53.0 / 3.6 / 43.4 at a 1440 viewport, a gallery three points too wide and a
 * purchase column two points too narrow, closing the gutter to compensate.
 *
 * The purchase column is the one that suffers: it carries price, finance,
 * variants, the confidence grid, the CTA, the trust row and rewards, and every
 * point taken off it tightens all seven.
 *
 * `minmax(0, …)` on both tracks is load-bearing — without it a wide image or a
 * long unbroken product code pushes its own track past the fraction.
 */
.lf-pdp__grid { display: grid; grid-template-columns: minmax(0, 1.09fr) minmax(0, 1fr); gap: clamp(1.75rem, 4.6vw, 3.9rem); align-items: start; }

.lf-gallery { position: sticky; top: 110px; align-self: start; }
/* Set by the viewer when the column is taller than the space it would stick
   in — see `stickyFit()`. */
.lf-gallery--nostick { position: static; }
/* 1:1 rather than 4:5. Supplier product photography is predominantly landscape,
   and a portrait frame left a third of the panel empty above and below it. */
/*
 * THE CROP BUG, and why it was not a cropping rule.
 *
 * This was `aspect-ratio: 4/3` with `display: grid; place-items: center` and an
 * image at `width:100%; height:100%`. `place-items: center` stops the item
 * stretching, so the grid row is sized BY the image — which makes the image's
 * own `height: 100%` circular. It resolved to auto, the image took its natural
 * square shape at 686px wide inside a 514px-tall frame, and `overflow: hidden`
 * quietly removed 86px from the top and bottom of every tall product. Nothing
 * in the stylesheet said "crop"; `contain` was set and did nothing, because the
 * element it was containing was already larger than the frame.
 *
 * The frame is now absolutely positioned, so no percentage height depends on a
 * box that depends on it, and the ratio comes from the product's own measured
 * subject rather than from a fixed 4:3.
 */
.lf-gallery__main {
  position: relative; overflow: hidden;
  aspect-ratio: var(--lf-gal-ar, 1);
  background: #FBFAF8; border: 1px solid var(--lf-line);
  cursor: zoom-in;
}
.lf-gallery__main img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; padding: 4.5%;
  mix-blend-mode: multiply;
}
/* A rail, not a wrapping block: six images must not push the buying controls
   down a second row. */
.lf-gallery__thumbs {
  display: flex; gap: .55rem; margin-top: .7rem; flex-wrap: nowrap;
  overflow-x: auto; scrollbar-width: thin; padding-bottom: .2rem;
  /*
   * `overflow-x: auto` alone does not contain this strip.
   *
   * A flex or grid item defaults to `min-width: auto`, which refuses to shrink
   * below its content — so seven 74px thumbnails pushed the whole PAGE 117px
   * wide at 390px instead of scrolling inside their own row. The overflow
   * declaration was already correct; it simply never got the chance to apply.
   */
  min-width: 0;
  /* A deliberate swipe, and it settles on a thumbnail rather than mid-image. */
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.lf-gallery__thumbs button { scroll-snap-align: start; flex: 0 0 auto; }
/* Same reason: the gallery column must be allowed to be narrower than its
   widest child. */
.lf-gallery { min-width: 0; }
.lf-gallery__thumbs button {
  /* Padding in PERCENT resolves against the containing block's width, not the
     button's own. At 6% of a ~660px row that was ~40px each side on a 72px
     button, collapsing the image to zero width — six blank boxes. */
  width: 74px; height: 92px; padding: 6px; background: var(--lf-stone);
  border: 1px solid var(--lf-line); cursor: pointer;
  transition: border-color .25s var(--lf-ease);
  display: grid; place-items: center;
}
.lf-gallery__thumbs button:hover { border-color: var(--lf-taupe); }
.lf-gallery__thumbs button[aria-current="true"] { border-color: var(--lf-navy); }
.lf-gallery__thumbs img { width: 100%; height: 100%; object-fit: contain; mix-blend-mode: multiply; }

.lf-pdp__title { font-size: clamp(1.9rem, 3vw, 2.6rem); margin: .4rem 0 .8rem; }
/* 1.5rem read as a large body figure rather than as the price. */
.lf-pdp__price { font-size: clamp(1.65rem, 2.1vw, 1.85rem); color: var(--lf-navy); font-family: var(--lf-sans); font-weight: 400; letter-spacing: -.005em; margin: 0 0 .45rem; }
.lf-pdp__price .from { font-size: .7rem; letter-spacing: .14em; text-transform: uppercase; color: var(--lf-taupe); margin-right: .4rem; }
.lf-pdp__vat { font-size: .78rem; color: var(--lf-taupe); margin: 0 0 1.4rem; }
.lf-pdp__summary { color: var(--lf-taupe-deep); font-size: 1rem; margin-bottom: 1.6rem; }
.lf-pdp__pack {
  display: inline-block; font-size: .74rem; letter-spacing: .12em; text-transform: uppercase;
  background: var(--lf-taupe-wash); color: var(--lf-taupe-deep); padding: .45rem .8rem; margin-bottom: 1.2rem;
}
.lf-pdp__buy { border-top: 1px solid var(--lf-line); padding-top: 1.6rem; margin-top: .5rem; }
.lf-pdp__note { font-size: .78rem; color: var(--lf-taupe); margin-top: .9rem; }
/*
 * PROBLEM 10, and the first attempt at it missed.
 *
 * It targeted `.lf-buyline`, which does not exist — the delivery and
 * change-of-mind lines carry `.lf-buydel`, and the rule matched nothing. Worth
 * recording rather than quietly correcting: a CSS selector that matches nothing
 * fails silently, looks plausible in a diff, and is only caught by rendering the
 * page and finding the thing unchanged.
 *
 * The two lines and the policy links now sit together on one quiet surface
 * under a hairline, so they close the buying panel instead of trailing off it.
 */
.lf-pdp__buy .lf-buydel { margin: 0; }
.lf-pdp__buy .lf-buydel + .lf-buydel { margin-top: .55rem; }
.lf-pdp__buy .lf-buydel:first-of-type {
  margin-top: clamp(1.1rem, 2vw, 1.4rem);
  padding-top: clamp(1rem, 1.8vw, 1.3rem);
  border-top: 1px solid var(--lf-line);
}

/* Variation selector — deliberately not WooCommerce's default <select> row. */
.lf-variations { display: grid; gap: 1.3rem; margin-bottom: 1.5rem; }
.lf-variations__label { font-size: .76rem; letter-spacing: .16em; text-transform: uppercase; color: var(--lf-taupe-deep); margin: 0 0 .8rem; }
.lf-swatches { display: flex; gap: .7rem; flex-wrap: wrap; }
/*
 * A RETAIL SWATCH, NOT A FORM CONTROL.
 *
 * The selected state used to be a filled navy button, which made the chosen
 * finish the heaviest thing in the column — heavier than Add to Basket — and
 * made the unchosen ones read as disabled. The approved design selects with a
 * 2px navy OUTLINE on white: the choice is unmistakable, the CTA keeps its
 * primacy, and a colour name is never printed white-on-navy where it competes
 * with the actual swatch colour it describes.
 *
 * The border is drawn with `box-shadow: inset` rather than by changing
 * `border-width`, so selecting never shifts the button's box by a pixel and the
 * row does not reflow as the customer clicks along it.
 */
.lf-swatch {
  min-height: 52px; min-width: 56px; padding: 0 1.35rem;
  border: 1px solid var(--lf-line-strong); border-radius: 3px;
  background: #fff; color: var(--lf-navy);
  font-family: var(--lf-sans); font-size: .94rem; font-weight: 400; letter-spacing: .015em;
  cursor: pointer;
  transition: border-color .25s var(--lf-ease), box-shadow .25s var(--lf-ease);
}
.lf-swatch:hover { border-color: var(--lf-taupe); }
.lf-swatch[aria-pressed="true"] {
  border-color: var(--lf-navy); background: #fff; color: var(--lf-navy); font-weight: 500;
  box-shadow: inset 0 0 0 1px var(--lf-navy);
}

.lf-spec { border-top: 1px solid var(--lf-line); }
.lf-spec details { border-bottom: 1px solid var(--lf-line); }
.lf-spec summary {
  cursor: pointer; list-style: none; padding: 1.15rem 0; display: flex; justify-content: space-between;
  align-items: center; font-size: .82rem; letter-spacing: .14em; text-transform: uppercase; color: var(--lf-navy);
}
.lf-spec summary::-webkit-details-marker { display: none; }
.lf-spec summary::after { content: "+"; font-size: 1.2rem; color: var(--lf-taupe); transition: transform .3s var(--lf-ease); }
.lf-spec details[open] summary::after { content: "–"; }
.lf-spec__body { padding-bottom: 1.4rem; color: var(--lf-taupe-deep); font-size: .94rem; }
.lf-spec__body h2 { font-size: 1.1rem; margin: 1.2rem 0 .5rem; }
.lf-spec__body ul { margin: 0 0 1rem; padding-left: 1.1rem; }
.lf-spec__body li { margin-bottom: .35rem; }
.lf-spec table { width: 100%; border-collapse: collapse; font-size: .9rem; }
.lf-spec th, .lf-spec td { text-align: left; padding: .55rem 0; border-bottom: 1px solid var(--lf-line); font-weight: 400; }
.lf-spec th { color: var(--lf-taupe); width: 46%; }
.lf-spec__scroll { overflow-x: auto; }

@media (max-width: 900px) {
  .lf-pdp__grid { grid-template-columns: 1fr; }
  .lf-gallery { position: static; }
  /* Sticky buy bar earns its place on mobile: the CTA is otherwise a long scroll away. */
  .lf-stickybuy {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 70;
    background: rgba(255,255,255,.97); border-top: 1px solid var(--lf-line);
    padding: .7rem var(--lf-gutter); display: flex; gap: 1rem; align-items: center; justify-content: space-between;
    box-shadow: 0 -2px 20px rgba(9,29,54,.08);
  }
  /* `is-armed` is added by the script, so a page without JS keeps the bar it
     always had. `is-visible` is the reveal. */
  .lf-stickybuy.is-armed {
    transform: translateY(102%); opacity: 0;
    transition: transform .32s var(--lf-ease), opacity .24s var(--lf-ease);
    pointer-events: none;
  }
  .lf-stickybuy.is-armed.is-visible { transform: none; opacity: 1; pointer-events: auto; }
  .lf-stickybuy span { font-size: 1rem; color: var(--lf-navy); }
  .lf-stickybuy .lf-btn { flex: 1 1 auto; max-width: 60%; }
  body.single-product { padding-bottom: 78px; }
}
@media (min-width: 901px) { .lf-stickybuy { display: none; } }
@media (max-width: 900px) {
  /* Clearance for the fixed buy bar. Without it the bar sits on top of whatever
     is last in the column — here the staging notice, but on a live store it
     would be the returns links — and a focused control could end up underneath
     it with no way to scroll further. */
  .lf-main { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }
}

/* ============================================================ ARCHIVE */
/* The header band was taller than its content needed and left the right half of
   a 1440px screen empty. Tightened, and the copy sits at a readable measure
   beside the heading rather than under it on wide screens. */
.lf-archive__hero { background: var(--lf-ivory); padding-block: clamp(1.75rem, 3vw, 2.75rem); }
.lf-archive__hero h1 { margin-bottom: .4rem; }
.lf-archive__hero p { color: var(--lf-taupe-deep); max-width: 58ch; margin: 0; font-size: .95rem; }
.lf-archive__head { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(1rem, 4vw, 4rem); align-items: end; }
@media (max-width: 900px) { .lf-archive__head { grid-template-columns: 1fr; gap: .75rem; } }
.lf-crumbs { padding-block: 1rem .35rem; }
.lf-archive__bar { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding-block: 1.5rem; border-bottom: 1px solid var(--lf-line); flex-wrap: wrap; }
.lf-archive__count { font-size: .8rem; color: var(--lf-taupe); letter-spacing: .06em; }
.lf-filters { display: flex; gap: .5rem; flex-wrap: wrap; }
.lf-filters span {
  font-size: .74rem; letter-spacing: .1em; text-transform: uppercase; color: var(--lf-taupe-deep);
  border: 1px solid var(--lf-line-strong); padding: .45rem .85rem;
}
.lf-empty { padding: 4rem 0; color: var(--lf-taupe-deep); }
.screen-reader-text {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.lf-mobilenav { border-top: 1px solid var(--lf-line); background: #fff; }
.lf-mobilenav ul { list-style: none; margin: 0; padding: .5rem var(--lf-gutter) 1rem; display: grid; gap: .2rem; }
.lf-mobilenav a { display: block; padding: .85rem 0; font-size: .9rem; letter-spacing: .1em; text-transform: uppercase; color: var(--lf-navy); border-bottom: 1px solid var(--lf-line); }

/* ============================================================ FILTERS
   The previous treatment was a row of static <span> chips: elegant, but they
   looked identical whether or not anything was selected and nothing indicated
   they could be clicked. Kept restrained — no WooCommerce sidebar — but they
   are now real controls with visible state.                                  */
.lf-filterbar { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.lf-filter { position: relative; }
.lf-filter__toggle {
  display: inline-flex; align-items: center; gap: .55rem;
  min-height: 44px; padding: 0 .95rem;
  font-family: var(--lf-sans); font-size: .74rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--lf-taupe-deep); background: #fff;
  border: 1px solid var(--lf-line-strong); cursor: pointer;
  transition: border-color .25s var(--lf-ease), color .25s var(--lf-ease);
}
.lf-filter__toggle:hover { border-color: var(--lf-taupe); color: var(--lf-navy); }
.lf-filter__toggle[aria-expanded="true"] { border-color: var(--lf-navy); color: var(--lf-navy); }
.lf-filter__toggle .count { color: var(--lf-taupe-mid); font-size: .7rem; }
.lf-filter__toggle .chev {
  width: 9px; height: 9px; border-right: 1px solid currentColor; border-bottom: 1px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px); transition: transform .3s var(--lf-ease);
}
.lf-filter__toggle[aria-expanded="true"] .chev { transform: rotate(225deg) translate(-2px, -2px); }
/* A filter holding a selection must be unmistakable from one that is not. */
.lf-filter__toggle[data-active="true"] {
  border-color: var(--lf-navy); background: var(--lf-navy); color: #fff;
}
.lf-filter__toggle[data-active="true"] .count { color: rgba(255,255,255,.7); }

.lf-filter__panel {
  /* Anchored to the RIGHT edge: the filter bar sits right-aligned, so a panel
     anchored left ran off the viewport and produced up to 106px of horizontal
     overflow at 1024px and 1440px. */
  position: absolute; z-index: 40; top: calc(100% + 6px); right: 0; min-width: 15rem;
  max-width: min(20rem, calc(100vw - 2rem));
  background: #fff; border: 1px solid var(--lf-line-strong);
  padding: .9rem; display: grid; gap: .1rem;
  box-shadow: 0 12px 34px rgba(9,29,54,.10);
  max-height: 18rem; overflow-y: auto;
}
/*
 * `display: grid` on the panel silently defeats the browser's own
 * `[hidden] { display: none }`, so every panel rendered open at once and they
 * overlapped each other. Any element given an explicit display value needs the
 * hidden case restated.
 */
.lf-filter__panel[hidden] { display: none; }
.lf-filter__panel label {
  display: flex; align-items: center; gap: .6rem; min-height: 40px;
  padding: 0 .35rem; font-size: .86rem; color: var(--lf-charcoal); cursor: pointer;
}
.lf-filter__panel label:hover { color: var(--lf-navy); }
.lf-filter__panel input { width: 15px; height: 15px; accent-color: var(--lf-navy); flex: none; }
.lf-filter__panel input:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }

.lf-filter__clear {
  min-height: 44px; padding: 0 .8rem; background: none; border: 0; cursor: pointer;
  font-family: var(--lf-sans); font-size: .74rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--lf-taupe); border-bottom: 1px solid transparent;
}
.lf-filter__clear:hover { color: var(--lf-navy); border-bottom-color: var(--lf-navy); }
.lf-filter__clear[hidden] { display: none; }
/*
 * On desktop the chip row already carries "Clear all", right under the
 * toolbar. The one inside the filter form is for the mobile drawer, where
 * there is no chip row on screen while the drawer is open — showing both at
 * once put two identical controls a few centimetres apart.
 */
@media (min-width: 861px) {
  .lf-filterbar > .lf-filter__clear[data-lf-filter-clear] { display: none; }
}

/* Mobile: a drawer, because a dropdown anchored to a chip is unusable at 390px. */
.lf-filter__trigger { display: none; }
@media (max-width: 860px) {
  .lf-filter__trigger {
    display: inline-flex; align-items: center; gap: .5rem; min-height: 44px; padding: 0 1rem;
    background: #fff; border: 1px solid var(--lf-line-strong); cursor: pointer;
    font-family: var(--lf-sans); font-size: .76rem; letter-spacing: .12em; text-transform: uppercase; color: var(--lf-navy);
  }
  .lf-filterbar {
    position: fixed; inset: auto 0 0 0; z-index: 90; background: #fff;
    border-top: 1px solid var(--lf-line-strong); box-shadow: 0 -8px 30px rgba(9,29,54,.14);
    padding: 1rem var(--lf-gutter) 1.25rem; display: grid; gap: .5rem;
    transform: translateY(101%); transition: transform .35s var(--lf-ease);
    max-height: 80vh; overflow-y: auto;
  }
  .lf-filterbar[data-open="true"] { transform: translateY(0); }
  .lf-filter { position: static; }
  .lf-filter__toggle { width: 100%; justify-content: space-between; }
  .lf-filter__panel { position: static; box-shadow: none; border: 0; border-left: 2px solid var(--lf-line); padding: .35rem 0 .35rem .9rem; min-width: 0; }
  .lf-filterbar__head { display: flex; justify-content: space-between; align-items: center; }
  .lf-filterbar__head strong { font-family: var(--lf-serif); font-size: 1.25rem; color: var(--lf-navy); font-weight: 500; }
}
@media (min-width: 861px) { .lf-filterbar__head { display: none; } }

.lf-archive__bar { align-items: center; }
.lf-card--hidden { display: none; }
.lf-noresults { padding: 3rem 0; color: var(--lf-taupe-deep); }
.lf-noresults[hidden] { display: none; }

/* ============================================================ REFINEMENTS
   Accessibility, touch targets and the remaining loose ends.              */

/* L-015: compact nav links default well under the 44px touch minimum. */
.lf-mobilenav a { min-height: 48px; display: flex; align-items: center; }
.lf-nav a { min-height: 44px; display: flex; align-items: center; }

/*
 * A footer entry whose page is not published yet: shown, and not a link.
 *
 * The "Coming soon" note that used to sit under each list is gone — it was
 * attached to every list carrying the attribute rather than to lists with
 * something pending, so it appeared under Help where all three pages were
 * live. The item itself stays: removing it took the whole Legal column with it
 * on staging, where all three pages are drafts.
 *
 * Muted and unclickable is the whole treatment. Nothing announces itself as
 * pending, because an entry that is plainly not a link already says so.
 */
.lf-footer__pending { color: var(--lf-taupe-mid); font-size: .88rem; cursor: default; }

/* The service row sizes to how many claims are actually true today. */
.lf-service[data-count="2"] { grid-template-columns: repeat(2, 1fr); max-width: 46rem; }
.lf-service[data-count="3"] { grid-template-columns: repeat(3, 1fr); }

/* A related row with fewer than four keeps card scale rather than stretching
   two products across the full width. */
.lf-grid--sparse { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1240px) { .lf-grid--sparse { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 900px) { .lf-grid--sparse { grid-template-columns: repeat(2, 1fr); } }

/* Gallery: never letterbox a landscape product shot into a portrait frame, and
   never stretch. The frame adapts; the image is always `contain`. */
/* `max-width: none` is load-bearing, not tidying: the subject-fill geometry
   sizes the image PAST the frame on purpose, and the global `img { max-width:
   100% }` would silently clamp it straight back — the same trap recorded as
   L-044. The overflow is the file's own white margin, which the frame clips. */
.lf-gallery__main img { max-width: none; }
.lf-gallery__thumbs button:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }

/* Focus must be visible on every interactive control, including inside panels. */
.lf-filter__toggle:focus-visible, .lf-filter__clear:focus-visible,
.lf-filter__trigger:focus-visible, .lf-swatch:focus-visible {
  outline: 2px solid var(--lf-navy); outline-offset: 2px;
}

/* Swatches: clearly interactive without becoming chunky. */
.lf-swatch { min-height: 52px; }
.lf-swatch[aria-pressed="true"]::after {
  content: ""; position: absolute; inset: -4px; border: 1px solid var(--lf-navy); pointer-events: none;
}
.lf-swatch { position: relative; }

/* Reduce the header's visual weight at small sizes without shrinking targets. */
@media (max-width: 560px) {
  /* Same 5-6px as every other width; .75rem here was a leftover from the tall
     header and put the phone row 14px above the tablet one for no reason. */
  .lf-header__inner { padding-block: 6px; gap: .5rem; }
  .lf-actions { gap: .25rem; }
  .lf-utility ul { padding: .5rem 0; }
}


/* WCAG 2.5.8 sets a 24x24 minimum target size. Text links inside card headings
   measured 22px and breadcrumb links 18px — both marginally under. Padding is
   added to the link box rather than changing the type, so nothing moves. */
.lf-card__title a { display: inline-block; padding-block: 2px; }
.lf-crumbs a { display: inline-block; padding-block: 4px; }
.lf-link { display: inline-block; padding-block: 4px; }
.lf-footer a { display: inline-block; padding-block: 3px; }


/* The burger IS the .lf-actions element, not a child of one, so the 44px rule
   written for `.lf-actions button` never applied to it — it measured 36x26. */
.lf-burger {
  min-width: 48px; min-height: 48px; align-items: center; justify-content: center;
  background: none; border: 0; padding: 0; color: var(--lf-navy); cursor: pointer;
}
.lf-burger svg { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 1.3; }

/* The checkbox is 15px but the label is the real target; it needs the height. */
.lf-filter__panel label { min-height: 44px; }
.lf-filter__panel input { width: 16px; height: 16px; }

/* Breadcrumb separators and short links still need a 24px minimum box. */
.lf-crumbs span { display: inline-block; }

/* ============================================================ CONFIGURATOR
   Complete your bed. Editorial, not a plugin widget: hairline rules instead of
   cards, no shadows, no rounded corners, serif headings, and the price the only
   thing allowed to be emphatic.                                             */
/* =============================================================== NEW ARRIVALS
   A commercial row, not a vague "curated" one: the heading states what the
   products are, the badge states why they are here, and the card carries one
   dense meta line instead of two thin ones.                                  */

.lf-new { background: var(--lf-cream); }

.lf-new__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 2rem; margin-bottom: clamp(1.9rem, 3vw, 2.5rem);
}
.lf-new__head h2 {
  font-family: var(--lf-serif); font-size: clamp(2.1rem, 3.9vw, 3.4rem); font-weight: 400;
  line-height: 1.02; letter-spacing: -.02em; color: var(--lf-navy); margin: .3rem 0 0;
}
.lf-new__head > div > p:last-child {
  margin: .55rem 0 0; color: var(--lf-taupe-deep); font-size: .95rem; max-width: 44ch;
}
.lf-new__all {
  display: inline-flex; align-items: center; gap: .55rem; flex: none;
  font-size: .74rem; letter-spacing: .18em; text-transform: uppercase; color: var(--lf-navy);
  padding-bottom: .45rem; border-bottom: 1px solid var(--lf-line-strong);
  transition: border-color .25s var(--lf-ease), gap .25s var(--lf-ease);
}
.lf-new__all svg {
  width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.3;
  transition: transform .25s var(--lf-ease);
}
.lf-new__all:hover { border-color: var(--lf-navy); gap: .8rem; }
.lf-new__all:hover svg { transform: translateX(2px); }
.lf-new__all:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 4px; }

/*
 * THE IMAGE STAGE
 *
 * Supplier photography is a wide, flat product centred on a square white sheet:
 * measured across the catalogue the item fills 84-100% of the file's width but
 * only 28-95% of its height. Fitting the SHEET to the frame — plain
 * `object-fit: contain`, which is what every other grid on the site does — puts
 * the product at roughly 45% of the frame's height and hands the rest of the
 * card to empty canvas.
 *
 * So this row fits the PRODUCT to the frame instead. `lomond_stage_style()`
 * scales and offsets each file by its measured content box, so the product
 * itself fills up to 94% of the frame's width and 92% of its height, whichever
 * binds first, and sits optically centred. The file keeps its own aspect ratio
 * throughout — nothing is cropped into and nothing is stretched — and the frame
 * clips only white canvas.
 *
 * The frame is 1.14:1, matching the concept. It is deliberately NOT taller: a
 * bed photographed straight on is a 2.2:1 subject, and every pixel of extra
 * frame height is empty space it can never fill. The card gains its weight from
 * the product being larger and the text block being tighter, not from a taller
 * empty box.
 */
.lf-grid--new { gap: clamp(1.25rem, 2.2vw, 1.9rem) clamp(1.1rem, 1.6vw, 1.5rem); }
.lf-grid--new .lf-card { height: 100%; }
/* Four across, then two — never three. The row holds exactly four products, so
   a three-column tier would strand one card on a line of its own. */
@media (max-width: 1240px) { .lf-grid--new { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 1024px) { .lf-grid--new { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.lf-grid--new .lf-card__media {
  aspect-ratio: var(--lf-stage-ar, 1.14); margin-bottom: 1.05rem;
  /* A backdrop rather than a box: a barely-there warm gradient so the space
     around a flat product reads as lit studio floor, not as a gap. */
  background:
    linear-gradient(180deg, #FCFAF7 0%, var(--lf-stone) 62%, #EFEAE3 100%);
}
/* `max-width: none` is load-bearing, not tidying. The global `img { max-width:
   100% }` silently clamps the computed stage width back to the frame, which
   defeats the geometry above for exactly the wide, flat products it exists to
   enlarge — the overflow is white canvas the frame clips. */
.lf-grid--new .lf-card__media img { padding: 0; max-width: none; }
.lf-grid--new .lf-card__range { font-size: .64rem; letter-spacing: .19em; margin-bottom: .38rem; }
.lf-grid--new .lf-card__title {
  font-size: 1.18rem; line-height: 1.26; margin-bottom: .34rem;
  /* Two lines, so a long supplier name cannot push one card's price out of
     line with the row. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.lf-grid--new .lf-card__meta { font-size: .77rem; margin-bottom: .8rem; }
/* Price last, pushed to the card's floor, so the four prices sit on one line
   across the row however long the names above them run. */
.lf-grid--new .lf-card__price { font-size: 1.06rem; margin-top: auto; }

/* ==================================================== MERCHANDISING TAG (LAYERED)
 * A printed label laid over the foot of the photograph — two physical layers,
 * not a coloured rectangle.
 *
 * WHY THE BOTTOM EDGE. `lomond_stage_style()` stands every product on a floor
 * line near the foot of its frame and puts ALL the leftover height above it.
 * Measured on the live row, that is 71-111px of empty backdrop at the TOP of
 * every frame and none at the bottom. A tag anywhere along the top edge is
 * therefore guaranteed to sit on nothing, whatever it is made of; a tag at the
 * foot sits where the furniture actually is. This is the one position in the
 * frame that the row's own composition makes correct.
 *
 * WHY IT IS IN FLOW. The tag straddles the image's bottom edge, so it belongs
 * to both boxes and can be positioned by neither alone. As a flex item pulled
 * up by a negative top margin it overlaps the picture by design and still sets
 * its own clearance to the eyebrow beneath — one declaration governs both, and
 * the overlap pays for most of the space it takes. The media's own bottom gap
 * is handed over rather than added to, so a badged card is ~17px taller than an
 * unbadged one, not 36px taller.
 *
 * THE TWO LAYERS. `::before` is an antique-gold sheet offset 3px down and
 * right; `::after` is the navy face over it. Both carry the same chamfer, so
 * the gold reads as a second sheet of card beneath the first rather than as an
 * outline — letterpress, not a 3D button. The drop shadow is a `filter`, not a
 * `box-shadow`, because a clipped silhouette needs a shadow that follows the
 * silhouette; at 12% it registers as layering before it registers as a shadow.
 *
 * THE MARK. Gold, ~6px, and never load-bearing: the word says what it means.
 * A four-point star ahead of "Just in", a short rule after "New" — one system,
 * two states, and the gold stays punctuation.
 *
 * WEIGHT. 500, not 600: the theme ships Jost 300/400/500 only, and a declared
 * 600 resolves to the 500 face (measured — identical advance width), so asking
 * for 600 would be a lie in the stylesheet.
 * ------------------------------------------------------------------------- */
.lf-card__badge {
  position: relative; z-index: 3; align-self: flex-start;
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  height: 38px; padding: 0 23px;
  /* ONE tag width for the whole row, set by the longest label. A row of labels
     that each shrink-wrap their own word reads as text that happens to have a
     background; a row of identical plates reads as printed stock. The value is
     the natural width of the longest label at this type size — shorter labels
     centre inside it, longer ones grow past it rather than being clipped. */
  min-width: 118px;
  /* The overlap is unchanged from the version that was approved: the tag is
     38px tall and pulled up 24px, so exactly the same 14px hangs below the
     image edge as before, and the clearance to the eyebrow is still 20px. */
  margin: -24px 0 20px;
  border: 0; background: none;
  color: var(--lf-ivory);
  font-family: var(--lf-sans); font-size: 12.5px; font-weight: 500;
  letter-spacing: .12em; line-height: 1; text-transform: uppercase;
  white-space: nowrap;
  filter: drop-shadow(0 5px 14px rgba(0, 20, 45, .12));
  transition: filter .2s var(--lf-ease);
}
/* The media hands its bottom gap to the tag rather than the tag adding to it.
   Scoped with `:has()` so a card with no tag keeps its own spacing exactly. */
.lf-card__media:has(+ .lf-card__badge) { margin-bottom: 0; }

/* Both sheets share one silhouette. The chamfer is 9px on the bottom-right
   corner only — enough to read as a cut corner on a printed label, not enough
   to read as a ribbon or a supermarket price flag. */
.lf-card__badge::before,
.lf-card__badge::after {
  content: ""; position: absolute; inset: 0;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 9px), calc(100% - 9px) 100%, 0 100%);
}
.lf-card__badge::before {
  z-index: -2; translate: 3px 3px;
  background: var(--lf-gold-sheet);
  transition: translate .2s var(--lf-ease);
}
.lf-card__badge::after {
  z-index: -1; background: var(--lf-navy);
  /* A 1px ivory highlight along the top edge only — the light side of a sheet
     of card. It also gives the face an edge on a near-black photograph, where
     navy on black has none. */
  box-shadow: inset 0 1px 0 rgba(251, 249, 246, .14);
}

/* The mark. One empty element in both tones; only its shape changes.
 *
 * It takes `--lf-gold-light` where the sheet behind takes `--lf-gold-on-navy`,
 * and the difference is deliberate: a 100px sheet of gold carries its colour at
 * 4.8:1, but a shape whose arms are barely a pixel across does not, and at
 * 7px in the darker gold the star silted up into a plus sign. 7.6:1 is what a
 * hairline needs to read as the shape it is. Decoration either way — it is
 * aria-hidden, and the word beside it carries the whole meaning. */
.lf-card__badge-mark {
  flex: none; width: 8px; height: 8px; background: var(--lf-gold-light);
  clip-path: polygon(50% 0, 57% 43%, 100% 50%, 57% 57%,
                     50% 100%, 43% 57%, 0 50%, 43% 43%);
}
/* "New" takes a short upright rule where "Just in" takes the star — same place,
   same gold, same clear space, different shape. Tried as a trailing rule after
   the word first and rejected on the render: at the tag's right edge it read as
   a stray hyphen rather than as the star's counterpart. */
/* The rule is DRAWN 2px wide but keeps the star's 8px box, so the gap, the
   text's optical position and the tag's metrics are identical in both tones —
   the only difference between them is the shape itself. */
.lf-card__badge:not(.lf-card__badge--accent) .lf-card__badge-mark {
  height: 12px; clip-path: inset(0 calc(50% - 1px));
}

/* Hovering the CARD, never the tag on its own: the gold sheet slides out by a
   further pixel and the shadow deepens a little. Nothing moves that a shopper
   would notice moving — it reads as the label settling, not as an animation. */
@media (hover: hover) and (pointer: fine) {
  .lf-card:hover .lf-card__badge { filter: drop-shadow(0 7px 18px rgba(0, 20, 45, .18)); }
  .lf-card:hover .lf-card__badge::before { translate: 4px 4px; }
}
@media (prefers-reduced-motion: reduce) {
  .lf-card__badge, .lf-card__badge::before { transition: none; }
  .lf-card:hover .lf-card__badge::before { translate: 3px 3px; }
}

/* ============================================================ TIMELESS DESIGN
   One editorial strip in three panels — photograph, statement, value grid —
   run edge to edge with no section padding of its own, so the panels themselves
   set the rhythm and the photograph reaches the viewport edge.               */

.lf-timeless { background: var(--lf-cream); padding-block: 0; }
.lf-timeless__grid {
  display: grid;
  grid-template-columns: minmax(0, .64fr) minmax(0, .78fr) minmax(0, 1fr);
  align-items: stretch;
  max-width: 1800px; margin-inline: auto;
}
.lf-timeless__media { position: relative; overflow: hidden; background: var(--lf-stone); min-height: 27rem; }
.lf-timeless__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }

.lf-timeless__copy {
  background: var(--lf-cream);
  padding: clamp(2.5rem, 4.4vw, 4.5rem) clamp(1.75rem, 3.4vw, 3.75rem);
  display: flex; flex-direction: column; justify-content: center;
}
/* Gold is scoped to this section by descent, never applied to `.lf-eyebrow`
   globally — every other eyebrow on the page stays taupe. */
.lf-timeless .lf-eyebrow { color: var(--lf-gold); }
/* A short editorial rule above the eyebrow: the one piece of pure ornament in
   the section, and the smallest one that reads. */
.lf-timeless__copy .lf-eyebrow::before {
  content: ""; display: block; width: 34px; height: 1px;
  background: var(--lf-gold-rule); margin-bottom: 1.15rem;
}
.lf-timeless__copy h2 {
  font-family: var(--lf-serif); font-size: clamp(1.9rem, 2.9vw, 2.7rem); font-weight: 400;
  line-height: 1.1; letter-spacing: -.018em; color: var(--lf-navy); margin: .35rem 0 0;
}
.lf-timeless__copy > p:not(.lf-eyebrow) {
  margin: 1.15rem 0 0; color: var(--lf-taupe-deep); line-height: 1.72; font-size: .95rem; max-width: 34ch;
}
/* The label stays navy and carries the meaning; the rule and the arrow are the
   gold. Reversing that — a gold label — would put the accent on the one thing
   in the section that has to be read. */
.lf-timeless__link {
  display: inline-flex; align-items: center; gap: .55rem; margin-top: 1.9rem; align-self: flex-start;
  font-size: .74rem; letter-spacing: .18em; text-transform: uppercase; color: var(--lf-navy);
  padding-bottom: .4rem; border-bottom: 1px solid var(--lf-gold-rule);
  transition: gap .25s var(--lf-ease), border-color .25s var(--lf-ease);
}
.lf-timeless__link svg {
  width: 16px; height: 16px; fill: none; stroke: var(--lf-gold); stroke-width: 1.3;
}
.lf-timeless__link:hover { gap: .85rem; border-bottom-color: var(--lf-gold); }
.lf-timeless__link:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 4px; }

/* The value panel carries the section's one tonal step. Separators are hairlines
   between cells only — no outer border, so it reads as a panel rather than as
   four boxes. */
.lf-timeless__values {
  list-style: none; margin: 0; padding: 0;
  background: var(--lf-cream-deep);
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
}
.lf-timeless__values li {
  padding: clamp(1.6rem, 2.6vw, 2.4rem) clamp(1.4rem, 2.2vw, 2.1rem);
  display: flex; flex-direction: column;
}
.lf-timeless__values li:nth-child(-n+2) { border-bottom: 1px solid var(--lf-gold-line); }
.lf-timeless__values li:nth-child(odd)  { border-right: 1px solid var(--lf-gold-line); }
/* The icons are aria-hidden ornament, so gold here is a free win: it warms the
   deeper panel without putting the accent anywhere a reader has to decode. */
.lf-timeless__icon svg {
  width: 24px; height: 24px; fill: none; stroke: var(--lf-gold); stroke-width: 1.15;
}
.lf-timeless__vtitle {
  margin: 1rem 0 .5rem; font-size: .69rem; letter-spacing: .17em;
  text-transform: uppercase; color: var(--lf-navy);
}
.lf-timeless__vbody { margin: 0; font-size: .845rem; line-height: 1.6; color: var(--lf-taupe-deep); }

@media (max-width: 1180px) {
  /* Photograph beside the statement, values across the full width beneath both:
     the panel keeps its three parts without squeezing any of them. */
  .lf-timeless__grid { grid-template-columns: minmax(0, .82fr) minmax(0, 1fr); }
  .lf-timeless__values { grid-column: 1 / -1; }
  .lf-timeless__media { min-height: 22rem; }
}

@media (max-width: 860px) {
  .lf-timeless__grid { grid-template-columns: minmax(0, 1fr); }
  .lf-timeless__media { min-height: 0; aspect-ratio: 4 / 3; }
  .lf-timeless__copy { padding-block: clamp(2.25rem, 7vw, 3rem); }
  /* Stacked, the statement has the full column to itself; the desktop measure
     leaves it stranded against the left edge of an empty panel. */
  .lf-timeless__copy > p:not(.lf-eyebrow) { max-width: 46ch; }
}

@media (max-width: 720px) {
  .lf-new__head { flex-direction: column; align-items: flex-start; gap: 1.1rem; }
  /* One step down, never a different object: same corner, same rectangle, same
     rule. Only the height and the side padding give way. */
  /* One step down, never a different object: same two sheets, same chamfer,
     same overlap. Only the height, the padding and the gold offset give way. */
  .lf-card__badge {
    height: 34px; padding: 0 18px; font-size: 11.5px; gap: 8px;
    letter-spacing: .11em; min-width: 104px;
    margin: -21px 0 18px;            /* 13px below the edge, as before */
  }
  .lf-card__badge::before { translate: 2px 2px; }
  .lf-card:hover .lf-card__badge::before { translate: 3px 3px; }
  .lf-grid--new .lf-card__title { font-size: 1.02rem; }
  .lf-grid--new .lf-card__meta { font-size: .74rem; margin-bottom: .65rem; }
  .lf-grid--new .lf-card__price { font-size: .98rem; }
}

@media (max-width: 520px) {
  /* One column, so tighter cells: four stacked items at desktop padding turn
     the panel into a page of its own on a phone. */
  .lf-timeless__values { grid-template-columns: minmax(0, 1fr); }
  .lf-timeless__values li { padding: 1.35rem 1.25rem; }
  .lf-timeless__icon svg { width: 21px; height: 21px; }
  .lf-timeless__vtitle { margin-top: .7rem; }
  .lf-timeless__values li:nth-child(odd)  { border-right: 0; }
  .lf-timeless__values li:not(:last-child) { border-bottom: 1px solid var(--lf-gold-line); }
}

/* ============================================================== SHOP BY ROOM
   Five equal editorial tiles, replacing an asymmetric mosaic.

   Deliberately its OWN class namespace (.lf-roomrow / .lf-roomcard) rather than
   reusing .lf-room: that class still drives a second room block further down the
   homepage, and restyling it here would silently redesign a section this task
   was told not to touch.

   The image IS the card. No padded white box, no shadow — the photography
   carries the section and everything else stays out of its way.            */

.lf-section--rooms { padding-block: clamp(3.5rem, 7vw, 6rem) 0; background: var(--lf-white); }

.lf-roomrow__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 2rem; margin-bottom: clamp(2rem, 4vw, 3rem);
}
.lf-roomrow__head h2 {
  font-family: var(--lf-serif); font-size: clamp(1.9rem, 3.4vw, 3rem); font-weight: 400;
  line-height: 1.08; letter-spacing: -.015em; color: var(--lf-navy); margin: .35rem 0 0;
  max-width: 22ch;
}
.lf-roomrow__all {
  display: inline-flex; align-items: center; gap: .55rem; flex: none;
  font-size: .74rem; letter-spacing: .18em; text-transform: uppercase; color: var(--lf-navy);
  padding-bottom: .3rem; border-bottom: 1px solid var(--lf-line-strong);
  transition: border-color .25s var(--lf-ease), gap .25s var(--lf-ease);
}
.lf-roomrow__all svg {
  width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.3;
  transition: transform .25s var(--lf-ease);
}
.lf-roomrow__all:hover { border-color: var(--lf-navy); gap: .8rem; }
.lf-roomrow__all:hover svg { transform: translateX(2px); }
.lf-roomrow__all:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 4px; }

/* ------------------------------------------------------------------- tiles */
.lf-roomrow { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: clamp(.6rem, 1.1vw, 1rem); }

.lf-roomcard {
  position: relative; display: block; overflow: hidden;
  aspect-ratio: 4 / 5; border-radius: 4px; background: var(--lf-stone);
  isolation: isolate;
}
.lf-roomcard__media { position: absolute; inset: 0; display: block; }
.lf-roomcard__media img {
  width: 100%; height: 100%; object-fit: cover; object-position: center;
  display: block; transition: transform .32s var(--lf-ease);
}
/* The gradient exists ONLY so the label stays legible — it covers the lower
   third and leaves the photograph itself bright. */
.lf-roomcard::after {
  content: ''; position: absolute; inset: auto 0 0 0; height: 55%;
  background: linear-gradient(to bottom, rgba(0,20,46,0) 0%, rgba(0,20,46,.18) 45%, rgba(0,20,46,.62) 100%);
  transition: opacity .32s var(--lf-ease); z-index: 1;
}
.lf-roomcard__label {
  position: absolute; left: clamp(1rem, 1.6vw, 1.5rem); bottom: clamp(1rem, 1.6vw, 1.4rem);
  z-index: 2; color: #fff; font-family: var(--lf-serif);
  font-size: clamp(1.4rem, 1.78vw, 1.85rem); font-weight: 500; line-height: 1.15;
  letter-spacing: -.005em; text-shadow: 0 1px 12px rgba(0, 20, 46, .35);
  transition: transform .32s var(--lf-ease);
}
.lf-roomcard:hover .lf-roomcard__media img { transform: scale(1.022); }
.lf-roomcard:hover::after { opacity: .88; }
.lf-roomcard:hover .lf-roomcard__label { transform: translateY(-2px); }
.lf-roomcard:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }

/* ---------------------------------------------------------- confidence strip
   A compact bar, not a second content section. */
.lf-trust {
  margin-top: clamp(3rem, 6vw, 4.5rem);
  background: var(--lf-stone); border-block: 1px solid var(--lf-line);
}
.lf-trust__grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
}
.lf-trust__item {
  display: flex; align-items: flex-start; gap: .85rem;
  padding: clamp(1.5rem, 2.4vw, 2rem) clamp(1rem, 2vw, 1.75rem);
}
.lf-trust__item + .lf-trust__item { border-left: 1px solid var(--lf-line-strong); }
.lf-trust__icon { flex: none; margin-top: .1rem; }
.lf-trust__icon svg {
  width: 20px; height: 20px; fill: none; stroke: var(--lf-taupe); stroke-width: 1.2;
}
.lf-trust__title {
  margin: 0 0 .3rem; font-size: .7rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--lf-navy);
}
.lf-trust__body { margin: 0; font-size: .84rem; line-height: 1.5; color: var(--lf-taupe-deep); }

@media (max-width: 1100px) {
  /* Three then two, rather than five squeezed tiles. The last card spans the
     remaining columns so the row never ends with a ragged gap. */
  .lf-roomrow { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .lf-roomcard { grid-column: span 2; aspect-ratio: 4 / 5; }
  .lf-roomcard:nth-child(4) { grid-column: span 3; aspect-ratio: 16 / 11; }
  .lf-roomcard:nth-child(5) { grid-column: span 3; aspect-ratio: 16 / 11; }
  .lf-trust__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lf-trust__item:nth-child(3) { border-left: 0; }
  .lf-trust__item:nth-child(n+3) { border-top: 1px solid var(--lf-line-strong); }
}

@media (max-width: 720px) {
  .lf-roomrow__head { flex-direction: column; align-items: flex-start; gap: 1rem; }
  .lf-roomrow__head h2 { max-width: none; }
  /* Two columns, with Home Accessories taking the full width — a fifth tile
     alone on a row reads as an accident otherwise. */
  .lf-roomrow { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .6rem; }
  .lf-roomcard, .lf-roomcard:nth-child(4) { grid-column: span 1; aspect-ratio: 4 / 5; }
  .lf-roomcard:nth-child(5) { grid-column: 1 / -1; aspect-ratio: 16 / 9; }
  .lf-trust { margin-top: 2.5rem; }
  .lf-trust__grid { grid-template-columns: minmax(0, 1fr); }
  .lf-trust__item { padding: 1.1rem .25rem; }
  .lf-trust__item + .lf-trust__item { border-left: 0; border-top: 1px solid var(--lf-line-strong); }
  .lf-trust__item:nth-child(3) { border-left: 0; }
}

/* ============================================================ BUNDLE BUILDER
   "Complete your bed" — mattress merchandising, not a settings form.

   The whole card is the interaction target: the <label> wraps a real radio, so
   pointer, keyboard and screen reader all drive the same native control and the
   large tap area comes for free rather than from a click handler on a div.

   FOUR STEPS OF TONE, and the gaps between them are deliberately wider than a
   first pass would make them. Too little separation and the whole thing reads
   as one pale wash; too much and it stops being calm.

     page          #FFFFFF   white
     panel         #F0EAE2   warm stone, a full step down from the page
     card          #FFFFFF   back to white, so it lifts without a shadow
     image well    #EAE2D7   deeper again, so the product sits IN something

   Selection is the ONLY place a cool colour appears anywhere in this palette.
   Everything else Lomond uses is warm, so a navy-tinted card cannot be mistaken
   for decoration — it can only mean "this is the one I chose".                */

.lf-bundle {
  /* Was 2.5rem. The buying column now carries configuration, a summary, a
     confidence strip, a CTA and a wishlist — every generous gap between them
     compounds, and this one sat on top of the panel's own padding. */
  margin-top: 1.6rem;
  --lfb-panel:  #F0EAE2;
  --lfb-well:   #EAE2D7;
  --lfb-border: #DCD3C7;
}

/* The panel groups the whole decision: heading, help text, options, opt-out. */
.lf-bundle__panel {
  background: var(--lfb-panel);
  border: 1px solid var(--lfb-border);
  border-radius: 11px;
  padding: clamp(1rem, 2vw, 1.35rem);
}

.lf-bundle__head { margin-bottom: 1rem; }
.lf-bundle__title {
  font-family: var(--lf-serif); font-size: clamp(1.3rem, 1.8vw, 1.55rem); font-weight: 500;
  line-height: 1.12; letter-spacing: -.008em; color: var(--lf-navy); margin: 0;
}
.lf-bundle__intro {
  margin: .35rem 0 0; font-size: .86rem; line-height: 1.45;
  color: var(--lf-taupe-deep); max-width: 46ch;
}

/* ------------------------------------------------------------- bunk steps */
/* A bunk is two separate decisions. The number says so before any styling
   does, and it is a quiet marker rather than a badge — the size beneath it is
   the fact the customer actually needs. */
.lf-bundle__surface + .lf-bundle__surface {
  margin-top: 1.5rem; padding-top: 1.35rem; border-top: 1px solid var(--lfb-border);
}
.lf-bundle__step { display: flex; align-items: baseline; gap: .7rem; margin: 0 0 .85rem; }
.lf-bundle__stepnum {
  flex: none; font-family: var(--lf-serif); font-size: 1.15rem; line-height: 1;
  color: var(--lf-navy-60); font-variant-numeric: lining-nums tabular-nums;
}
.lf-bundle__stepnum::after { content: '.'; }
.lf-bundle__stepbody { min-width: 0; }
.lf-bundle__steptitle {
  font-family: var(--lf-serif); font-size: 1.18rem; font-weight: 500; line-height: 1.2;
  color: var(--lf-navy); margin: 0;
}
.lf-bundle__stepsize {
  margin: .25rem 0 0; font-size: .74rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--lf-taupe);
}

/* Two across. One column of full-width rows is what made four mattresses read
   as a page of its own; side by side they read as a comparison, which is what
   choosing between them actually is. */
.lf-bundle__options { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .6rem; }
/* The overflow list and the opt-out both span the pair. */
.lf-bundle__more, .lf-bundle__none { grid-column: 1 / -1; }
.lf-bundle__moreinner { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .6rem; }

/* ------------------------------------------------------------ mattress card */
.lf-mattress {
  position: relative; display: grid;
  /* Three columns, two rows: the control and the picture run down the side and
     the price moves UNDER the name rather than into a fourth column. At half
     the previous width there is no room for a price rail, and stacking it is
     also how a customer reads a card this size. */
  grid-template-columns: 20px 62px minmax(0, 1fr);
  grid-template-rows: auto auto;
  align-items: start; column-gap: .7rem; row-gap: .2rem;
  padding: .75rem .85rem; cursor: pointer;
  background: var(--lf-white);
  border: 1px solid var(--lfb-border);
  border-radius: 9px;
  /* Just enough shadow to sit the card ON the panel rather than in it. Any
     more and four of these in a column start to float. */
  box-shadow: 0 1px 2px rgba(0, 20, 46, .04);
  transition: border-color .18s var(--lf-ease), background-color .18s var(--lf-ease),
              box-shadow .18s var(--lf-ease), transform .18s var(--lf-ease);
}
.lf-mattress:hover {
  border-color: var(--lf-line-strong);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 20, 46, .07);
}
.lf-mattress:has(input:focus-visible) { outline: 2px solid var(--lf-navy); outline-offset: 3px; }

/* SELECTED. Two pixels of navy, delivered as 1px border + 1px inset shadow so
   nothing reflows when the customer changes their mind — plus the tint, the
   filled control and the word "Selected". Four signals, none of them loud. */
.lf-mattress:has(input:checked), .lf-mattress.is-selected {
  border-color: var(--lf-navy);
  box-shadow: inset 0 0 0 1px var(--lf-navy), 0 2px 10px rgba(0, 20, 46, .08);
  background: var(--lf-navy-wash);
}
.lf-mattress:has(input:checked):hover, .lf-mattress.is-selected:hover {
  transform: none;
  box-shadow: inset 0 0 0 1px var(--lf-navy), 0 2px 10px rgba(0, 20, 46, .08);
}
.lf-mattress:has(input:disabled), .lf-mattress:has(input:disabled):hover {
  opacity: .5; cursor: not-allowed; background: var(--lf-white);
  border-color: var(--lfb-border); transform: none;
  box-shadow: 0 1px 2px rgba(0, 20, 46, .04);
}

/* The radio stays a real, focusable control — moved out of sight, never
   display:none, which would remove it from the accessibility tree. */
.lf-mattress__input {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; border: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
}

/* The caption hangs BELOW the control, out of flow. Sizing the column to fit
   the word "Selected" cost the product name ~36px and pushed the longest one
   onto two lines — and it would have done so on every card, selected or not,
   to accommodate a label only one card ever shows. */
.lf-mattress__control {
  grid-column: 1; grid-row: 1; align-self: center;
  position: relative; width: 22px; display: block;
}
.lf-mattress__tick {
  width: 22px; height: 22px;
  border: 1px solid var(--lf-line-strong); border-radius: 50%; background: var(--lf-white);
  display: grid; place-items: center;
  transition: border-color .18s var(--lf-ease), background-color .18s var(--lf-ease);
}
.lf-mattress__tick::after {
  content: ''; width: 10px; height: 5px; margin-top: -2px;
  border-left: 1.75px solid #fff; border-bottom: 1.75px solid #fff;
  transform: rotate(-45deg) scale(.4); opacity: 0;
  transition: opacity .15s var(--lf-ease), transform .15s var(--lf-ease);
}
.lf-mattress__selected {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  margin-top: .35rem; white-space: nowrap;
  font-size: .54rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--lf-navy); opacity: 0; transition: opacity .15s var(--lf-ease);
}
.lf-mattress:hover .lf-mattress__tick { border-color: var(--lf-taupe-mid); }
.lf-mattress:has(input:checked) .lf-mattress__tick,
.lf-mattress.is-selected .lf-mattress__tick {
  border-color: var(--lf-navy); background: var(--lf-navy);
}
.lf-mattress:has(input:checked) .lf-mattress__tick::after,
.lf-mattress.is-selected .lf-mattress__tick::after { opacity: 1; transform: rotate(-45deg) scale(1); }
.lf-mattress:has(input:checked) .lf-mattress__selected,
.lf-mattress.is-selected .lf-mattress__selected { opacity: 1; }

/* The image well. Supplier photography is wildly inconsistent — different
   backgrounds, crops and framing — so every mattress is placed in the same
   container, padded, and CONTAINED rather than cropped. Deeper than the card
   on purpose: a frame only reads as a frame if you can see it. */
.lf-mattress__media {
  grid-column: 2; grid-row: 1 / -1; align-self: center;
  display: flex; align-items: center; justify-content: center;
  width: 62px; height: 62px; padding: 7px;
  background: var(--lfb-well); border-radius: 7px;
  transition: background-color .18s var(--lf-ease);
}
.lf-mattress__media img {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  object-fit: contain; border-radius: 5px; display: block;
}
/* On a selected card the well goes white, so the product lifts forward instead
   of sinking into the tint. */
.lf-mattress:has(input:checked) .lf-mattress__media,
.lf-mattress.is-selected .lf-mattress__media { background: var(--lf-white); }

.lf-mattress__body {
  grid-column: 3; grid-row: 1; display: grid; gap: .1rem; min-width: 0;
  align-self: end; padding-block: 0;
}
.lf-mattress__top { display: flex; align-items: baseline; gap: .55rem; flex-wrap: wrap; }
.lf-mattress__name {
  font-family: var(--lf-serif); font-size: 1rem; font-weight: 600;
  line-height: 1.2; letter-spacing: -.005em; color: var(--lf-navy);
}
.lf-mattress__badge {
  font-size: .58rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--lf-taupe-deep); background: var(--lf-taupe-wash);
  border: 1px solid var(--lf-taupe-pale); border-radius: 3px;
  padding: .2rem .45rem; white-space: nowrap; transform: translateY(-1px);
}
.lf-mattress__desc {
  font-size: .77rem; color: var(--lf-taupe-deep); line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden;
}
/* Attributes and size share one quiet line each. Both are optional and both
   collapse to nothing, so a card with neither has no empty rows to explain. */
.lf-mattress__specs { font-size: .74rem; color: var(--lf-taupe-deep); margin-top: 0; }
.lf-mattress__size { font-size: .74rem; color: var(--lf-taupe); }

/* ---------------------------------------------------------------- price block */
/* Anchored, not floated: the block gets its own hairline rule on the left so
   the number reads as a deliberate column rather than text that drifted right. */
.lf-mattress__price {
  grid-column: 3; grid-row: 2; align-self: start;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: .45rem;
  justify-items: start; text-align: left;
  padding-left: 0; margin-left: 0; border-left: 0; min-height: 0;
}
.lf-mattress:has(input:checked) .lf-mattress__price,
.lf-mattress.is-selected .lf-mattress__price { border-left-color: var(--lf-navy-line); }
.lf-mattress__was {
  font-size: .84rem; color: var(--lf-taupe-mid);
  text-decoration-thickness: 1px; text-underline-offset: 2px;
}
.lf-mattress__now {
  font-size: 1.32rem; color: var(--lf-navy); white-space: nowrap; line-height: 1.25;
  letter-spacing: -.01em;
}
.lf-mattress__with { font-size: .7rem; color: var(--lf-taupe); white-space: nowrap; }
/* A chip, not a shout. Pale on an unselected card; solid navy once chosen, so
   it stays legible against the tint and reinforces the choice. */
.lf-mattress__save {
  margin-top: .45rem; font-size: .63rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--lf-navy); background: var(--lf-navy-wash);
  border: 1px solid var(--lf-navy-line); border-radius: 3px;
  padding: .25rem .55rem; white-space: nowrap;
}
.lf-mattress:has(input:checked) .lf-mattress__save,
.lf-mattress.is-selected .lf-mattress__save {
  background: var(--lf-navy); border-color: var(--lf-navy); color: #fff;
}

/* The overflow disclosure: a quiet control, not a call to action. Two options
   are shown first; this reveals the rest in place. */
.lf-bundle__more { margin-top: .1rem; }
.lf-bundle__more > summary {
  /* 44px, not 48: still a comfortable touch target, and three of these gaps
     between here and the CTA is where the column length came from. */
  list-style: none; cursor: pointer; min-height: 44px;
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .8rem; font-weight: 500; letter-spacing: .1em; text-transform: uppercase;
  color: var(--lf-navy); border-bottom: 1px solid var(--lf-navy-line);
  width: fit-content; padding: 0 .1rem .25rem;
  transition: border-color .18s var(--lf-ease), opacity .18s var(--lf-ease);
}
.lf-bundle__more > summary::-webkit-details-marker,
.lf-bundle__more > summary::marker { display: none; content: ''; }
.lf-bundle__more > summary:hover { border-color: var(--lf-navy); opacity: .78; }
.lf-bundle__more > summary:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 4px; }
.lf-bundle__chev { flex: none; transition: transform .18s var(--lf-ease); }
.lf-bundle__more[open] .lf-bundle__chev { transform: rotate(180deg); }
/* While the disclosure holds the chosen mattress it cannot be collapsed —
   hiding the customer's own selection would be the worst outcome here — so it
   stops advertising itself as a control. */
.lf-bundle__more.is-locked > summary {
  cursor: default; border-bottom-color: transparent; opacity: .45;
}
.lf-bundle__more.is-locked .lf-bundle__chev { display: none; }
.lf-bundle__more[open] > summary { margin-bottom: .85rem; }
.lf-bundle__moreinner { display: grid; gap: .6rem; }

@media (max-width: 620px) {
  /* One column. Two cards across a phone left each one about 150px wide, which
     both overflowed the viewport and stopped the names being readable — and a
     comparison you cannot read is not a comparison. The card keeps its compact
     one-row shape, so stacking costs height only, not the compression. */
  .lf-bundle__options, .lf-bundle__moreinner { grid-template-columns: minmax(0, 1fr); }
  .lf-mattress { grid-template-columns: 20px 56px minmax(0, 1fr); }
  .lf-mattress__media { width: 56px; height: 56px; }
}

/* Bed-frame-only: a considered opt-out, deliberately not merchandised. A real
   control and real spacing so it does not read as a stray radio button — but
   no card, no image and no price. It is not competing for the sale. */
.lf-bundle__none {
  display: flex; align-items: center; gap: .85rem; min-height: 42px;
  margin-top: .3rem; padding: .5rem .25rem 0; cursor: pointer;
  border-top: 1px solid var(--lfb-border);
  font-size: .94rem; color: var(--lf-taupe-deep);
  transition: color .18s var(--lf-ease);
}
.lf-bundle__none:hover { color: var(--lf-navy); }
.lf-bundle__none input {
  appearance: none; -webkit-appearance: none; width: 22px; height: 22px; flex: none; margin: 0;
  border: 1px solid var(--lf-line-strong); border-radius: 50%; background: var(--lf-white);
  display: grid; place-items: center; cursor: pointer;
  transition: border-color .18s var(--lf-ease), background-color .18s var(--lf-ease);
}
.lf-bundle__none input::after {
  content: ''; width: 8px; height: 8px; border-radius: 50%;
  background: #fff; transform: scale(0); transition: transform .15s var(--lf-ease);
}
.lf-bundle__none input:checked { border-color: var(--lf-navy); background: var(--lf-navy); }
.lf-bundle__none input:checked::after { transform: scale(1); }
.lf-bundle__none input:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }
.lf-bundle__none:has(input:checked) { color: var(--lf-navy); }

/* ------------------------------------------------------------- guidance state
   A top bunk with no manufacturer-stated depth limit is offered NOTHING, and
   that is a safety rule, not a gap in the data. So it is presented the way a
   good salesperson would say it — a titled note in the warm palette — rather
   than as a red-bordered failure the page is apologising for.                */
.lf-bundle__guidance {
  background: var(--lf-white); border: 1px solid var(--lfb-border);
  border-radius: 10px; padding: 1.1rem 1.25rem;
}
.lf-bundle__guidancetitle {
  margin: 0 0 .35rem; font-size: .95rem; font-weight: 500;
  font-family: var(--lf-serif); color: var(--lf-navy);
}
.lf-bundle__guidancebody {
  margin: 0; font-size: .88rem; line-height: 1.55; color: var(--lf-taupe-deep); max-width: 52ch;
}

/* ------------------------------------------------------------------ summary */
/* Sits OUTSIDE the panel, on the page's own white, because it is no longer a
   choice — it is the statement of what will be bought. */
.lf-bundle__summary { margin-top: 1.1rem; }
.lf-bundle__summarytitle {
  font-size: .74rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--lf-navy); margin: 0 0 .6rem;
}
.lf-bundle__lines { margin: 0; display: grid; gap: .45rem; }
.lf-bundle__line {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1.25rem; font-size: .96rem;
}
.lf-bundle__line dt { color: var(--lf-charcoal); margin: 0; }
.lf-bundle__line dd { margin: 0; color: var(--lf-navy); white-space: nowrap; }
.lf-bundle__line dd s { color: var(--lf-taupe-mid); margin-right: .35rem; }
.lf-bundle__line--saving {
  margin-top: .2rem; padding: .7rem .9rem;
  background: var(--lf-navy-wash); border-radius: 6px;
}
.lf-bundle__line--saving dt {
  color: var(--lf-navy); font-size: .74rem; letter-spacing: .14em; text-transform: uppercase;
}
.lf-bundle__line--saving dd { color: var(--lf-navy); font-size: .98rem; }
.lf-bundle__total {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  margin-top: .8rem; padding-top: .75rem; border-top: 2px solid var(--lf-navy);
}
.lf-bundle__total span {
  font-size: .76rem; letter-spacing: .18em; text-transform: uppercase; color: var(--lf-navy);
}
.lf-bundle__total strong {
  font-family: var(--lf-serif); font-size: 1.6rem; font-weight: 600;
  color: var(--lf-navy); line-height: 1; letter-spacing: -.01em;
}

.lf-bundle__status {
  margin: .85rem 0 0; font-size: .88rem; line-height: 1.5; padding: .8rem 1rem;
  background: var(--lf-navy-wash); border: 1px solid var(--lf-navy-line);
  border-radius: 8px; color: var(--lf-navy);
}
.lf-bundle__status.is-error {
  background: var(--lf-taupe-wash); border-color: var(--lf-taupe-pale); color: var(--lf-taupe-deep);
}
.lf-bundle__status[hidden] { display: none; }

/* ====================================================== PRODUCT INFORMATION
   Full-width tabs on desktop, accordions on mobile — one copy of the content.

   The two presentations need genuinely different ARIA (a tab must be a child of
   a tablist; an accordion header must sit directly above its region), so the
   small control labels exist twice and CSS decides which set is live. The
   breakpoint is the same 900px the rest of the product page uses.

   Editorial, not administrative: rules rather than boxes, navy for structure,
   and a reading measure on prose even though the section itself is full width. */

/*
 * WHITE. The canvas stays white the whole way down the product page.
 *
 * A warm ground was tried here to tie the tab content to its tab, and it was
 * the wrong instrument: washing a full-width section cream dulls the page and
 * costs the clean contrast the rest of Lomond is built on. Separation comes
 * from the hairline above, the whitespace, and the components inside — the
 * at-a-glance card and the FAQ panel carry the warmth between them.
 */
.lf-pinfo {
  /*
   * NO BORDER-TOP. The seam between the buying area and the product
   * information is now carried by `lomond_editorial_divider()`, which sits in
   * the template immediately above this section. A hairline here as well would
   * be the same transition stated twice — and the plain full-bleed rule is
   * exactly what the divider replaces.
   *
   * The top margin goes with it: the divider brings its own vertical rhythm,
   * and leaving this would have opened a 160px gap where the design shows one
   * pause.
   */
  padding-block: clamp(2rem, 4vw, 3.25rem) clamp(2.5rem, 4vw, 3.5rem);
  background: #FFFFFF;
}

/* ------------------------------------------------------------------- tabs */
.lf-pinfo__tabs {
  display: flex; gap: clamp(1.5rem, 3.5vw, 3rem); align-items: stretch;
  border-bottom: 1px solid var(--lf-line);
  overflow: visible;
}
.lf-pinfo__tab {
  appearance: none; background: none; border: 0; cursor: pointer;
  padding: 0 0 1rem; margin-bottom: -1px;
  font-family: var(--lf-sans); font-size: .82rem; font-weight: 400;
  letter-spacing: .16em; text-transform: uppercase; color: var(--lf-taupe);
  border-bottom: 2px solid transparent;
  transition: color .18s var(--lf-ease), border-color .18s var(--lf-ease);
  white-space: nowrap;
}
.lf-pinfo__tab:hover { color: var(--lf-navy-80); }
.lf-pinfo__tab[aria-selected="true"] { color: var(--lf-navy); border-bottom-color: var(--lf-navy); }
.lf-pinfo__tab:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 4px; }

/* Mobile controls, off until the breakpoint. */
.lf-pinfo__acch { display: none; margin: 0; }

/* Bottom padding is the SECTION's job now that it has a ground of its own;
   keeping it here too stacked 104px of nothing under the last question. */
.lf-pinfo__panel { padding-block: clamp(2rem, 4vw, 3rem) 0; }
.lf-pinfo__panel[hidden] { display: none; }

/* --------------------------------------------------------- details layout */
/*
 * THE VOID, and what caused it.
 *
 * The prose carried `max-width: 68ch` inside a grid column that was 961px wide,
 * so 349px of that column was empty by construction and the measured gap to the
 * at-a-glance card was 422px. The reading measure was right; putting it in a
 * column two-thirds wider than itself was not. The column is now sized to the
 * measure instead, and the panel beside it takes the width that frees up.
 */
.lf-pinfo__editorial {
  /* 64 / 5 / 31 of the content width. The previous split ran the card wider and
     the channel between them narrower, which read as two things placed near
     each other rather than one composition — a wider gap and a tighter card
     is the pairing that reads as deliberate. */
  display: grid; grid-template-columns: minmax(0, 64fr) minmax(0, 31fr);
  column-gap: clamp(2rem, 4.6vw, 4.25rem); row-gap: clamp(1.75rem, 3vw, 2.5rem);
  align-items: start;
}
.lf-pinfo__prose { max-width: none; }
.lf-pinfo__eyebrow { color: var(--lf-gold); margin-bottom: .7rem; }
/* The lede names the product and is the largest thing in the column; the
   generated section headings step down from it so the order of importance is
   legible before a word is read. */
.lf-pinfo__lede {
  font-family: var(--lf-serif); font-size: clamp(1.4rem, 1.85vw, 1.65rem); font-weight: 500;
  color: var(--lf-navy); margin: 0 0 .8rem; letter-spacing: -.012em; line-height: 1.2;
}
/* `:not(.lf-pinfo__lede)` is load-bearing. The lede IS an h3 — correctly, it is
   a section heading — so this rule outranked `.lf-pinfo__lede` on specificity
   and flattened both to the same 20px. The hierarchy has to be excluded from
   the rule it sits above, not just declared before it. */
.lf-pinfo__prose h3:not(.lf-pinfo__lede) {
  font-family: var(--lf-serif); font-size: 1.28rem; font-weight: 500; color: var(--lf-navy);
  /* 3.4rem, not 2.5rem. The gold rule that has just been removed sat inside the
     heading and carried a 0.9rem margin of its own, so deleting it silently
     took ~15px out of every subsection gap. The margin absorbs that so the
     rendered rhythm is unchanged — only the decoration has gone. */
  margin: 3.4rem 0 .75rem; letter-spacing: -.005em;
}
/* The first subsection gets a little more air than the rest: it is where the
   overview stops and the specifics begin, which is a bigger step than moving
   from one specific to the next. */
.lf-pinfo__lede + p + h3:not(.lf-pinfo__lede) { margin-top: 4.05rem; }
.lf-pinfo__prose h3:not(.lf-pinfo__lede):first-of-type { margin-top: 0; }
.lf-pinfo__lede + p { margin-top: 0; }
/* The measure stays — 70ch is still comfortable reading — but the HEADINGS and
   the dimension figures use the full column, so the paragraphs stopping short
   reads as a text block rather than as the void it used to. */
.lf-pinfo__prose p { margin: 0; color: var(--lf-charcoal); line-height: 1.75; font-size: .96rem; max-width: 70ch; }

/* ---- dimension figures ---- */
/* Measurements as figures, not as a dashboard: hairline separators and no
   boxes, so they read as part of the editorial rather than a widget dropped
   into it. */
.lf-dims {
  /* Sized to the figures, not to the column: rules running 550px past the last
     number read as an unfinished table rather than a measured detail. */
  display: inline-flex; flex-wrap: wrap; margin: 0 0 1.1rem;
  border-top: 1px solid var(--lf-gold-line); border-bottom: 1px solid var(--lf-gold-line);
}
.lf-dims__item { padding: .85rem clamp(1.1rem, 2.2vw, 2rem) .85rem 0; }
.lf-dims__item + .lf-dims__item {
  border-left: 1px solid var(--lf-gold-line); padding-left: clamp(1.1rem, 2.2vw, 2rem);
}
.lf-dims__label {
  display: block; font-size: .615rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--lf-taupe); margin-bottom: .3rem;
}
.lf-dims__value {
  display: block; font-family: var(--lf-serif); font-size: 1.75rem; font-weight: 500;
  line-height: 1; color: var(--lf-navy);
}
.lf-dims__value em { font-style: normal; font-size: .85rem; margin-left: .18rem; color: var(--lf-taupe); }

.lf-pinfo__jump {
  /* 24px minimum for the same reason as `.lf-conf__link` — a standalone link
     acting as a control, not a link inside a sentence. */
  display: inline-flex; align-items: center; gap: .45rem; margin-top: .9rem;
  min-height: 24px; padding-block: .25rem .2rem;
  font-size: .68rem; letter-spacing: .15em; text-transform: uppercase; color: var(--lf-navy);
  border-bottom: 1px solid rgba(141, 106, 58, .5);
  transition: gap .25s var(--lf-ease), border-color .25s var(--lf-ease);
}
.lf-pinfo__jump svg { width: 14px; height: 14px; }
.lf-pinfo__jump:hover { gap: .7rem; border-bottom-color: var(--lf-gold); }
.lf-pinfo__jump:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }

/* ---- at a glance ---- */
.lf-pinfo__side {
  /* Stone rather than cream: against a cream section the lighter tint was
     enough, against white it all but disappeared. This is the one panel in the
     details area that is deliberately not white. */
  background: var(--lf-stone); border: 1px solid var(--lf-line);
  border-radius: 11px; padding: 1.35rem clamp(1.25rem, 1.8vw, 1.6rem) .6rem;
  box-shadow: 0 18px 42px -38px rgba(0, 20, 46, .35);
}
.lf-pinfo__side h3 {
  font-size: .655rem; letter-spacing: .19em; text-transform: uppercase;
  color: var(--lf-taupe); margin: 0 0 .35rem; font-family: var(--lf-sans); font-weight: 400;
}
.lf-glance { margin: 0; }
/* Problem 7 in the brief, and it was measurable rather than a matter of taste:
   the labels rendered at 9.8px and the icons at 18px inside a component whose
   job is buying confidence. Every dimension here goes up by roughly a fifth. */
.lf-glance__row {
  display: grid; grid-template-columns: 22px minmax(0, 1fr);
  column-gap: .95rem; align-items: start; padding: 1.15rem 0;
  border-top: 1px solid var(--lf-gold-line);
}
/* The first row's rule doubles the card's own top spacing. */
.lf-glance__row:first-child { border-top: 0; padding-top: .35rem; }
.lf-glance__icon { grid-row: 1 / span 2; padding-top: 3px; }
.lf-glance__icon svg {
  width: 21px; height: 21px; fill: none; stroke: var(--lf-gold); stroke-width: 1.25;
}
.lf-glance dt {
  font-size: .7rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--lf-taupe); margin: 0 0 .35rem;
}
.lf-glance dd { margin: 0; font-size: 1.08rem; line-height: 1.42; color: var(--lf-navy); font-weight: 500; }

/* ================================================== THE SPECIFICATION SHEET
   An architectural spec sheet, not a card. The earlier version put an ivory
   panel around everything and a second cream panel around the measurements
   inside it — a box in a box, which is what made a page of eight short facts
   feel heavy and inserted rather than composed.

   There is no outer container now. The section sits on the page's own white,
   and its structure is carried by THREE THINGS ONLY: a shared three-column
   grid, two horizontal rules, and the change of surface under the dimensions.

   THE ONE MOVE THAT TIES IT TOGETHER: the dimension band and the specification
   grid share the same three columns, the same gutter and the same left
   alignment, so a value in the band sits directly above a value in the grid.
   Previously the band was centred and the grid was left-aligned, which read as
   two components that happened to be adjacent — the "separated from the rest"
   problem. Same grid, same alignment, different surface and different scale:
   one system, with the measurements as its loudest voice.                    */

.lf-spec {
  /* Shared by the band and the grid, so the two can never disagree. */
  --lf-spec-cols: repeat(3, minmax(0, 1fr));
  --lf-spec-gap: clamp(1.5rem, 3vw, 3rem);
  /* The icon column, stated once. Everything with no icon of its own — the
     reference strip — is indented by it so the LABEL column is continuous down
     the whole sheet. A spec sheet is read down its labels; one of them starting
     34px left of the others is the kind of small break that makes a layout feel
     assembled rather than set. */
  --lf-spec-indent: calc(20px + .8rem);
}

/* ---- the heading: introduces, does not dominate */
.lf-spec__head { margin-bottom: clamp(1.15rem, 2vw, 1.6rem); }
.lf-spec__eyebrow { color: #835F33; margin: 0 0 .4rem; }
.lf-spec__lede {
  margin: 0; font-family: var(--lf-serif);
  font-size: clamp(1.15rem, 1.6vw, 1.4rem); line-height: 1.25; color: var(--lf-navy);
}

/* ---- the dimension band
   A change of SURFACE and a pair of hairlines — no side borders, no radius, no
   shadow. It bleeds slightly wider than the content column so the stone reads
   as a band running under the page rather than as another rectangle, while the
   cells inside it stay exactly on the grid the specifications below use. */
.lf-spec__dims {
  --lf-band-bleed: clamp(1rem, 2vw, 1.75rem);
  list-style: none; margin: 0 calc(var(--lf-band-bleed) * -1);
  padding: clamp(1.35rem, 2.3vw, 1.9rem) var(--lf-band-bleed);
  display: grid; grid-template-columns: var(--lf-spec-cols);
  column-gap: var(--lf-spec-gap);
  background: var(--lf-stone);
  border-top: 1px solid #E4DCD2;
  border-bottom: 1px solid #E4DCD2;
}
/* One measurement should not be stretched across a third of the page, and two
   should not leave a third column of air. */
.lf-spec__dims[data-count="1"] { grid-template-columns: minmax(0, 1fr); }
.lf-spec__dims[data-count="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.lf-spec__dim {
  position: relative;
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "icon label" "icon value";
  column-gap: .8rem; row-gap: .1rem; align-content: center;
}
/* The separator sits in the gutter, inset from both ends and faded — the same
   hairline device the rewards card uses, so the site has one idea of what
   "these are separate" looks like. */
.lf-spec__dim + .lf-spec__dim::before {
  content: ""; position: absolute; top: 4%; bottom: 4%; width: 1px;
  left: calc(var(--lf-spec-gap) / -2);
  background: linear-gradient(to bottom,
    rgba(141,106,58,0), rgba(141,106,58,.24), rgba(141,106,58,0));
}
.lf-spec__dimicon { grid-area: icon; align-self: center; color: var(--lf-gold); line-height: 0; }
/* 20px, exactly as the grid's icons below — the icon column is the label
   column's left edge, and two different icon widths make two label columns. */
.lf-spec__dimicon svg { width: 20px; height: 20px; display: block; }
.lf-spec__dimlabel {
  grid-area: label;
  font-family: var(--lf-sans); font-size: .68rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--lf-taupe);
}
/* Architectural: the number is the largest thing in the section, the unit is
   deliberately smaller and quieter so the figure reads first. */
.lf-spec__dimvalue {
  grid-area: value; display: flex; align-items: baseline; gap: .25rem;
  font-family: var(--lf-serif); color: var(--lf-navy);
}
.lf-spec__num {
  font-size: clamp(1.85rem, 2.9vw, 2.5rem); line-height: 1.08;
  font-weight: 500; letter-spacing: -.01em;
}
.lf-spec__unit { font-size: clamp(.9rem, 1.15vw, 1.05rem); color: var(--lf-taupe-deep); }

/* ---- the specification grid
   The same three columns as the band, ruled rather than tiled. A hairline ABOVE
   each item, so an empty cell renders nothing at all — the failure the earlier
   `auto-fit` + coloured-gap version produced on a six-row product, where four
   empty cells painted a grey block. */
.lf-spec__grid {
  margin: 0; display: grid;
  grid-template-columns: var(--lf-spec-cols);
  column-gap: var(--lf-spec-gap);
}
/*
 * THE CONTENT SITS ON THE GRID LINE; ONLY THE HOVER TINT BLEEDS.
 *
 * The first version gave each item `padding-inline: .8rem` with a matching
 * negative margin, so a hover tint had room to breathe past the text. That also
 * moved every item 12.8px left of the column it was supposed to share with the
 * dimension band above — which is precisely the alignment this layout exists to
 * establish, given away for a hover state. The tint is a pseudo-element now, so
 * it can overhang while the text does not.
 */
.lf-spec__item {
  position: relative; isolation: isolate;
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas: "icon label" "icon value";
  column-gap: .8rem; row-gap: .12rem;
  padding: clamp(1.1rem, 1.9vw, 1.5rem) 0;
  border-top: 1px solid var(--lf-line);
}
.lf-spec__item::before {
  content: ""; position: absolute; inset: 1px -.8rem 0; z-index: -1;
  background: transparent; pointer-events: none;
  transition: background .18s var(--lf-ease);
}
/* The first row's rule would double the band's bottom border. */
.lf-spec__dims + .lf-spec__grid .lf-spec__item:nth-child(-n+3) { border-top: 0; }
.lf-spec__icon {
  grid-area: icon; align-self: center;
  color: var(--lf-taupe-mid); line-height: 0;
  transition: color .18s var(--lf-ease);
}
.lf-spec__icon svg { width: 20px; height: 20px; display: block; }
.lf-spec__label {
  grid-area: label; margin: 0;
  font-family: var(--lf-sans); font-size: .68rem; letter-spacing: .18em;
  text-transform: uppercase; color: var(--lf-taupe);
}
/* Up from 1rem and off the muted greys: these were the weakest thing on the
   sheet, and they are the answers. */
.lf-spec__value {
  grid-area: value; margin: 0;
  font-size: 1.08rem; line-height: 1.4; color: var(--lf-navy); font-weight: 400;
  overflow-wrap: anywhere;
}

/* ---- the reference strip
   Metadata, given its own line and its own space rather than trailing off the
   bottom of the last row. Label above value, on the grid's left edge, under a
   rule that separates it from the specifications proper. */
/* ---- dimensions by size
   The band above answers "how big is it" for a product that has ONE answer. A
   product sold in four sizes has four, and a strip cannot hold them — so they
   are a table, which is what a set of labelled measurements across a set of
   named sizes actually is. It takes the band's stone surface so the two read as
   the same kind of information, and it scrolls inside itself on a narrow
   screen rather than widening the page. */
.lf-spec__sizes {
  --lf-band-bleed: clamp(1rem, 2vw, 1.75rem);
  margin: 0 calc(var(--lf-band-bleed) * -1);
  padding: clamp(1.35rem, 2.3vw, 1.9rem) var(--lf-band-bleed);
  background: var(--lf-stone);
  border-top: 1px solid #E4DCD2;
  border-bottom: 1px solid #E4DCD2;
  overflow-x: auto;
}
/* Two stone bands stacked would show a doubled hairline between them. */
.lf-spec__dims + .lf-spec__sizes { border-top: 0; margin-top: 0; }
.lf-spec__sizeshead {
  margin: 0 0 clamp(.7rem, 1.2vw, 1rem);
  font-family: var(--lf-sans); font-size: .66rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--lf-taupe-mid);
}
.lf-spec__sizetable {
  width: 100%; min-width: 21rem; border-collapse: collapse;
  /* FIXED, and the proportions are the point. Left to itself the browser gave
     the size name every pixel the three measurements did not demand, so "Double"
     sat under a 900px column and "150 cm / 202 cm / 105 cm" were crushed against
     the right edge — three numbers meant to be compared, as far apart as the
     layout could put them. */
  table-layout: fixed;
  font-family: var(--lf-sans); font-size: .92rem; color: var(--lf-navy);
  /* Widths line up down the column, which is the entire point of showing four
     sizes together. */
  font-variant-numeric: tabular-nums;
}
.lf-spec__sizetable th:first-child,
.lf-spec__sizetable td:first-child { width: 34%; }
.lf-spec__sizetable th:not(:first-child),
.lf-spec__sizetable td:not(:first-child) { width: 22%; }
.lf-spec__sizetable th,
.lf-spec__sizetable td {
  padding: .55rem .9rem .55rem 0; text-align: left; vertical-align: baseline;
  border-bottom: 1px solid #E4DCD2;
}
.lf-spec__sizetable tbody tr:last-child th,
.lf-spec__sizetable tbody tr:last-child td { border-bottom: 0; }
.lf-spec__sizetable thead th {
  font-weight: 500; font-size: .66rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--lf-taupe-mid);
}
.lf-spec__sizetable tbody th { font-weight: 500; color: var(--lf-navy); }
.lf-spec__sizetable td:empty::after {
  /* A size the maker has not measured. The cell says so quietly rather than
     leaving a blank that reads as zero. */
  content: "not stated"; color: var(--lf-taupe-mid); font-size: .82rem;
}

.lf-spec__ref {
  display: flex; flex-direction: column; align-items: flex-start; gap: .3rem;
  margin: clamp(1.35rem, 2.3vw, 1.9rem) 0 0;
  padding: clamp(1.15rem, 2vw, 1.5rem) 0 0 var(--lf-spec-indent);
  border-top: 1px solid var(--lf-line);
}
.lf-spec__reflabel {
  font-family: var(--lf-sans); font-size: .66rem; letter-spacing: .2em;
  text-transform: uppercase; color: var(--lf-taupe-mid);
}
.lf-spec__refvalue {
  font-size: .95rem; color: var(--lf-navy); letter-spacing: .03em;
  /* Codes are long, unspaced and hyphenated; a break inside a run is better
     than a panel wider than its column. */
  overflow-wrap: anywhere; min-width: 0; max-width: 100%;
}

/* ---- micro-interaction: a tonal shift, nothing that moves the layout */
@media (hover: hover) and (pointer: fine) {
  .lf-spec__item:hover::before { background: var(--lf-ivory); }
  .lf-spec__item:hover .lf-spec__icon { color: var(--lf-gold); }
}
@media (prefers-reduced-motion: reduce) {
  .lf-spec__item::before, .lf-spec__icon { transition: none; }
}

@media (max-width: 900px) {
  .lf-spec { --lf-spec-gap: clamp(1rem, 3vw, 1.75rem); }
  .lf-spec__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Two columns above, so only the first TWO items meet the band. */
  .lf-spec__dims + .lf-spec__grid .lf-spec__item:nth-child(-n+3) { border-top: 1px solid var(--lf-line); }
  .lf-spec__dims + .lf-spec__grid .lf-spec__item:nth-child(-n+2) { border-top: 0; }
  .lf-spec__num { font-size: clamp(1.6rem, 5vw, 2rem); }
}
@media (max-width: 560px) {
  .lf-spec__grid { grid-template-columns: minmax(0, 1fr); }
  .lf-spec__dims + .lf-spec__grid .lf-spec__item:nth-child(-n+2) { border-top: 1px solid var(--lf-line); }
  .lf-spec__dims + .lf-spec__grid .lf-spec__item:first-child { border-top: 0; }
  /* THE ICON STAYS BESIDE THE LABEL AT EVERY WIDTH.
     Dropping it above the label bought the number a little room and cost the
     sheet its label column: the band's labels went to the page edge while the
     grid's stayed indented by the icon, so the two halves no longer lined up on
     a phone. The number gives up the pixels instead — it is still the largest
     thing on the page at this width. */
  .lf-spec__dimlabel { font-size: .62rem; letter-spacing: .13em; }
  .lf-spec__num { font-size: clamp(1.3rem, 5.6vw, 1.7rem); }

}
@media (max-width: 360px) {
  /* Below this the three numbers genuinely stop fitting. */
  .lf-spec__dims { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 1.25rem; }
  .lf-spec__dim + .lf-spec__dim::before { display: none; }
}
@media (max-width: 380px) {
  .lf-spec__dims { grid-template-columns: minmax(0, 1fr); }
  .lf-spec__dim + .lf-spec__dim::before {
    left: 12%; right: 12%; top: 0; bottom: auto; width: auto; height: 1px;
    background: linear-gradient(to right,
      rgba(141,106,58,0), rgba(141,106,58,.26), rgba(141,106,58,0));
  }
}

/* The old `.lf-specs` definition-list table lived here. Its markup is gone —
   nothing in the theme carries that class any more — so the rules went with it
   rather than being left to accumulate as a second, unreachable spec table. */

/* --------------------------------------------------------- delivery layout */
.lf-pinfo__cols {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: clamp(2rem, 4vw, 3.5rem); align-items: start;
}
.lf-pinfo__cols h3 {
  font-family: var(--lf-serif); font-size: 1.2rem; font-weight: 500; color: var(--lf-navy);
  margin: 0 0 .6rem;
}
.lf-pinfo__cols p { margin: 0; color: var(--lf-charcoal); line-height: 1.7; font-size: .94rem; max-width: 46ch; }

/* ------------------------------------------------------------------ reviews */
.lf-pinfo__empty { max-width: 44ch; }
.lf-pinfo__emptytitle {
  font-family: var(--lf-serif); font-size: 1.3rem; color: var(--lf-navy); margin: 0 0 .5rem;
}
/* WooCommerce's own review markup, brought into the Lomond palette rather than
   replaced — its list, form, moderation and spam handling all stay. */
.lf-pinfo__reviews #reviews { max-width: 60rem; }
.lf-pinfo__reviews .woocommerce-Reviews-title { display: none; }
.lf-pinfo__reviews .woocommerce-noreviews {
  margin: 0 0 1.75rem; font-size: 1.05rem; color: var(--lf-taupe-deep);
}
.lf-pinfo__reviews ol.commentlist { list-style: none; margin: 0 0 2.5rem; padding: 0; display: grid; gap: 1.25rem; }
.lf-pinfo__reviews ol.commentlist li {
  background: var(--lf-white); border: 1px solid var(--lf-line);
  border-radius: 11px; padding: 1.25rem 1.4rem;
}
.lf-pinfo__reviews .comment-text { margin: 0; }
.lf-pinfo__reviews .woocommerce-review__author { font-family: var(--lf-serif); font-size: 1.05rem; color: var(--lf-navy); }
.lf-pinfo__reviews .woocommerce-review__published-date { font-size: .8rem; color: var(--lf-taupe); margin-left: .5rem; }
.lf-pinfo__reviews .comment-form { display: grid; gap: 1rem; max-width: 38rem; }
.lf-pinfo__reviews .comment-form label { font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; color: var(--lf-taupe); }
.lf-pinfo__reviews .comment-form input[type=text],
.lf-pinfo__reviews .comment-form input[type=email],
.lf-pinfo__reviews .comment-form textarea {
  width: 100%; font-family: var(--lf-sans); font-size: .95rem; color: var(--lf-charcoal);
  background: var(--lf-white); border: 1px solid var(--lf-line-strong);
  border-radius: 8px; padding: .7rem .85rem;
}
.lf-pinfo__reviews .comment-form input:focus-visible,
.lf-pinfo__reviews .comment-form textarea:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }
.lf-pinfo__reviews .comment-form .submit {
  appearance: none; cursor: pointer; justify-self: start;
  min-height: 48px; padding: 0 2rem;
  font-family: var(--lf-sans); font-size: .82rem; letter-spacing: .16em; text-transform: uppercase;
  background: var(--lf-navy); border: 1px solid var(--lf-navy); color: #fff; border-radius: 0;
}
.lf-pinfo__reviews .comment-form .submit:hover { background: var(--lf-navy-80); border-color: var(--lf-navy-80); }
.lf-pinfo__reviews .comment-reply-title { font-family: var(--lf-serif); font-size: 1.25rem; color: var(--lf-navy); display: block; margin-bottom: 1rem; }

/* Merchandising blocks below the fold — same card component, honest headings. */
/* ==================================================== PDP RECOMMENDATION RAILS
 * Two rails at the foot of every product page.
 *
 * THE RAIL IS A TRACK, NOT A GRID. The block this replaces used
 * `grid-template-columns: repeat(4, 1fr)` and opened it whatever it had to put
 * inside, so a rail holding one product printed one card and three empty
 * columns — the large white gaps in the brief. `auto-fit` with a max of four
 * means the track is only ever as wide as the cards it actually has, and a
 * short rail ends where its last card ends instead of reserving space for
 * cards that do not exist.
 *
 * Spacing is set ONCE here and nowhere else: no inline margins, no fixed
 * heights, nothing reserving space for absent content. An empty rail renders no
 * element at all (`lomond_reco_rail()` returns early), so it contributes no
 * padding either.
 * ------------------------------------------------------------------------- */
.lf-reco { padding-block: clamp(2rem, 3vw, 2.75rem); background: var(--lf-white); }
/* The first rail carries the separation from the product information above it;
   the pair then reads as one closing passage rather than two loose sections.
   A CLASS, not `:first-of-type` — the product page has several <section>
   siblings before these two, so the pseudo-class never matched and rail one
   silently rendered with the shared padding. */
.lf-reco--lead { padding-top: clamp(2.75rem, 5.5vw, 5rem); }
/* The last rail carries the whole closing space, because it is the last thing
   before the footer and `main` no longer pads beneath it. Measured at 1440:
   76px of padding plus 3px of the final line's descender space = 79px from the
   lowest card content to the band below.

   IT NO LONGER TAKES A TINT, and the modifier is named for what it does rather
   than how it once looked. The ivory existed so that this rail — then sitting
   directly ABOVE the newsletter — stepped into that cream band deliberately
   instead of leaving a white stripe. That reasoning expired when the rail moved
   BELOW the newsletter: it now sits between `.lf-signup` (taupe wash) and
   `.lf-footer`, and `.lf-footer` is `--lf-ivory` — the very same value. Rail and
   footer were painting one continuous beige block with no edge between them.

   White is inherited from `.lf-reco` rather than re-declared here: one
   declaration of the base ground, and a modifier that only adds space. */
.lf-reco--close { padding-bottom: clamp(2.5rem, 5.3vw, 4.75rem); }

.lf-reco__head {
  display: flex; align-items: end; justify-content: space-between;
  gap: 2rem; margin-bottom: clamp(1.4rem, 2.4vw, 2rem);
}
/* Stacked on a phone: side by side the heading wraps to two lines and the link
   sits in the crook of it. */
@media (max-width: 560px) {
  .lf-reco__head { flex-direction: column; align-items: flex-start; gap: .9rem; }
}
.lf-reco__head h2 {
  font-family: var(--lf-serif); font-size: clamp(1.6rem, 2.6vw, 2.2rem);
  font-weight: 400; line-height: 1.08; letter-spacing: -.015em;
  color: var(--lf-navy); margin: 0;
}
.lf-reco__all {
  display: inline-flex; align-items: center; gap: .55rem; flex: none;
  font-size: .72rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--lf-navy); padding-bottom: .4rem;
  border-bottom: 1px solid var(--lf-line-strong);
  transition: border-color .2s var(--lf-ease), gap .2s var(--lf-ease);
}
.lf-reco__all svg {
  width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.3;
}
.lf-reco__all:hover { border-color: var(--lf-navy); gap: .8rem; }
.lf-reco__all:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 4px; }

.lf-reco__rail {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(0, calc((100% - 3 * var(--lf-reco-gap)) / 4)));
  justify-content: start;
  --lf-reco-gap: clamp(1.1rem, 1.6vw, 1.5rem);
  gap: var(--lf-reco-gap);
}
/*
 * BELOW THE DESKTOP GRID: a scrolling rail, not eight full-width cards stacked
 * into a page the length of a receipt, and not a three-column grid either —
 * four cards in three columns prints a 3 + 1 row, which is the same unbalanced
 * shape this whole change exists to remove. Roughly 2.5 cards are in view on a
 * tablet and 1.35 on a phone, so it always reads as a rail that continues.
 * The scroll container is the rail alone, so the PAGE never scrolls sideways.
 */
@media (max-width: 1024px) {
  .lf-reco__rail {
    display: flex; overflow-x: auto; scroll-snap-type: x mandatory;
    scroll-padding-left: var(--lf-gutter);
    /* Full-bleed inside the wrap so the rail runs to the viewport edge and the
       next card is visibly cut off rather than sitting in a tidy box. */
    margin-inline: calc(var(--lf-gutter) * -1);
    padding-inline: var(--lf-gutter);
    -webkit-overflow-scrolling: touch; scrollbar-width: none;
  }
  .lf-reco__rail::-webkit-scrollbar { display: none; }
  .lf-reco__rail > .lf-card { flex: 0 0 40%; scroll-snap-align: start; }
}
@media (max-width: 560px) {
  /* One card and a clear slice of the next, so the rail is obviously scrollable
     without a control telling you so. */
  .lf-reco__rail > .lf-card { flex: 0 0 74%; }
}

.lf-merch + .lf-merch { margin-top: clamp(2.5rem, 5vw, 4rem); }
.lf-merch__head { margin-bottom: 1.5rem; }
.lf-merch__head h2 { font-size: clamp(1.4rem, 2.2vw, 1.9rem); margin: 0; }
.lf-merch__head p { margin: .35rem 0 0; color: var(--lf-taupe); font-size: .88rem; }

@media (max-width: 900px) {
  .lf-bundle { margin-top: 2rem; }
  .lf-bundle__panel { padding: 1.25rem 1.05rem; border-radius: 12px; }
  .lf-bundle__head { margin-bottom: 1.35rem; }

  /* Two rows rather than four columns: control + a still-generous image well +
     the name block on the first row, then the price on its own full-width row.
     The image is 88px, not an icon — an unrecognisable thumbnail is worse than
     no thumbnail at all. */
  .lf-mattress {
    grid-template-columns: auto 88px minmax(0, 1fr);
    column-gap: .85rem; row-gap: .1rem; padding: 1.05rem 1rem;
  }
  /* Top-aligned on mobile so the name sits level with the top of the image
     well. Centred, a body taller than the image floats the product name ABOVE
     the photograph it belongs to, which reads as two unrelated things. */
  .lf-mattress__control { grid-column: 1; grid-row: 1; align-self: start; margin-top: .15rem; gap: .25rem; }
  /* The caption would cost a third of the row's width here; the border, tint
     and filled control carry the signal on their own. */
  .lf-mattress__selected { display: none; }
  .lf-mattress__media {
    grid-column: 2; grid-row: 1; align-self: start;
    width: 88px; height: 88px; padding: 9px;
  }
  .lf-mattress__body { grid-column: 3; grid-row: 1; align-self: start; padding-block: 0; }
  .lf-mattress__name { font-size: 1rem; }
  /* A narrower column needs a third line before it starts truncating. */
  .lf-mattress__desc { font-size: .78rem; -webkit-line-clamp: 2; }
  .lf-mattress__top { gap: .4rem; }
  /* The price stays in the text column beside the picture, not on a full-width
     row of its own under a rule. That rule and its 30px of clearance were most
     of what made a phone card 180px tall — and a price separated from the name
     it belongs to reads as a second thing rather than part of the same card. */
  .lf-mattress__price {
    grid-column: 3; grid-row: 2;
    justify-items: start; align-content: start; text-align: left;
    padding: 0; margin: .1rem 0 0; border: 0; min-height: 0;
    display: flex; align-items: baseline; flex-wrap: wrap; gap: .15rem .45rem;
  }
  .lf-mattress__now { font-size: 1.02rem; }
  /* Keeps the four price elements on one line on a 360px card in most cases;
     when they cannot fit they wrap cleanly rather than being squeezed. */
  .lf-mattress__with { font-size: .66rem; }
  .lf-mattress__save { margin-top: 0; }
  .lf-mattress:hover { transform: none; box-shadow: 0 1px 2px rgba(0, 20, 46, .04); }

  /* Bunk steps stay legible, and the guidance note must not become a slab. */
  .lf-bundle__surface + .lf-bundle__surface { margin-top: 2rem; padding-top: 1.8rem; }
  .lf-bundle__steptitle { font-size: 1.1rem; }
  .lf-bundle__guidance { padding: .95rem 1rem; border-radius: 9px; }
  .lf-bundle__guidancebody { font-size: .85rem; }

  .lf-bundle__total strong { font-size: 1.6rem; }

  /* ---- product information becomes accordions -------------------------- */
  /* The tablist goes away entirely and each panel gets its own header, which
     is why the two control sets exist: an accordion header has to sit directly
     above the region it controls, and a tab has to live inside a tablist. */
  .lf-pinfo { padding-top: clamp(2rem, 6vw, 3rem); margin-top: clamp(2rem, 6vw, 3rem); }
  .lf-pinfo__tabs { display: none; }
  .lf-pinfo__acch { display: block; }
  .lf-pinfo__acc {
    appearance: none; background: none; border: 0; width: 100%; cursor: pointer;
    display: flex; align-items: center; justify-content: space-between; gap: 1rem;
    min-height: 60px; padding: 1rem 0; text-align: left;
    border-top: 1px solid var(--lf-line);
    font-family: var(--lf-sans); font-size: .82rem; font-weight: 400;
    letter-spacing: .14em; text-transform: uppercase; color: var(--lf-navy);
  }
  .lf-pinfo__acch:first-of-type .lf-pinfo__acc { border-top: 0; }
  .lf-pinfo__acc:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: -2px; }
  /* A plus that becomes a minus — one element, no icon font, no swap. */
  .lf-pinfo__pm { position: relative; width: 13px; height: 13px; flex: none; }
  .lf-pinfo__pm::before, .lf-pinfo__pm::after {
    content: ''; position: absolute; background: var(--lf-navy);
    transition: transform .2s var(--lf-ease), opacity .2s var(--lf-ease);
  }
  .lf-pinfo__pm::before { top: 6px; left: 0; width: 13px; height: 1px; }
  .lf-pinfo__pm::after { left: 6px; top: 0; width: 1px; height: 13px; }
  .lf-pinfo__acc[aria-expanded="true"] .lf-pinfo__pm::after { transform: scaleY(0); opacity: 0; }

  /* Enough to breathe, not enough to detach: in accordion mode the panel
     belongs to the header directly above it, so a desktop-sized 48px gap would
     read as content floating free of its own control. */
  .lf-pinfo__panel { padding-block: 1rem 1.75rem; }
  .lf-pinfo__editorial { grid-template-columns: minmax(0, 1fr); gap: 1.75rem; }
  .lf-pinfo__prose h3:not(.lf-pinfo__lede) { font-size: 1.15rem; }
  .lf-pinfo__side { padding: 1.15rem 1.2rem .45rem; border-radius: 10px; }
  .lf-dims__value { font-size: 1.35rem; }
  .lf-pinfo__faq { margin-top: 2rem; }
  .lf-pinfo__faq > h3 { font-size: 1.2rem; }
  /* Specifications stack: label above value, so neither is squeezed. */
  .lf-pinfo__cols { gap: 1.9rem; }
  .lf-pinfo__reviews .comment-form { max-width: none; }
  /* The sticky bar carries the SET total once one is chosen, so the customer
     never scrolls back up to see what they have built. */
  .lf-stickybuy { flex-wrap: wrap; }
  .lf-stickybuy__set { flex: 1 1 100%; font-size: .72rem; letter-spacing: .1em;
    text-transform: uppercase; color: var(--lf-taupe); margin-bottom: .15rem; }
  .lf-stickybuy__set[hidden] { display: none; }
}

/* A merchandising cue, not a badge: same weight as the metadata above it. */
.lf-card__cue { font-size: .72rem; letter-spacing: .06em; color: var(--lf-taupe); margin: -.35rem 0 .55rem; }

/* ============================================================ EDITORIAL
   Long-form content, below the commerce interface. Reading typography rather
   than interface typography: a longer measure, more line height, no chrome.  */
.lf-editorial { padding-block: clamp(3rem, 6vw, 5rem); border-top: 1px solid var(--lf-line); }
.lf-editorial__grid { display: grid; grid-template-columns: minmax(0, 1fr) 17rem; gap: clamp(2rem, 5vw, 5rem); align-items: start; }
.lf-editorial__body { max-width: 68ch; }
.lf-editorial__body h2 {
  font-family: var(--lf-serif); font-size: clamp(1.3rem, 2vw, 1.7rem); font-weight: 500;
  color: var(--lf-navy); margin: 2.2rem 0 .6rem;
}
.lf-editorial__body h2:first-child { margin-top: 0; }
.lf-editorial__body p { font-size: 1rem; line-height: 1.75; color: var(--lf-charcoal); margin: 0 0 1rem; }

/* ------------------------------------------------------------------- FAQ --- */
/* 80% of the content column. Wider than it was, and still well short of the
   at-a-glance card's right edge so it never reads as running underneath it. */
.lf-pinfo__faq { margin-top: clamp(2.5rem, 4.5vw, 3.5rem); max-width: 80%; position: relative; }
/* Not another background: one hairline and the space around it are enough to
   say the editorial has finished and the questions have started. */
.lf-pinfo__faqrule {
  display: block; width: 56px; height: 1px; background: var(--lf-gold);
  margin-bottom: clamp(1.25rem, 2vw, 1.5rem);
}
.lf-pinfo__faq > h3 {
  font-family: var(--lf-serif); font-size: 1.42rem; font-weight: 500;
  color: var(--lf-navy); margin: 0; letter-spacing: -.005em;
}
.lf-pinfo__faqintro { margin: .35rem 0 1.35rem; font-size: .9rem; color: var(--lf-taupe-deep); }

/* A container, so the rows are a block rather than four rules floating in open
   space with nothing holding them together. */
.lf-faq {
  /* White on white: the hairline alone held it together against a warm ground,
     but on white the block needs a trace of depth to read as contained. Broad,
     low and almost invisible — not a floating card. */
  background: #FFFFFF; border: 1px solid var(--lf-line); border-radius: 9px;
  padding: 0 clamp(1rem, 1.6vw, 1.4rem);
  box-shadow: 0 16px 38px -34px rgba(0, 20, 46, .30);
}
.lf-faq details + details { border-top: 1px solid var(--lf-line); }
.lf-faq summary {
  cursor: pointer; list-style: none; padding: 1.2rem 0; display: flex;
  justify-content: space-between; gap: 1.25rem; align-items: center;
  font-size: 1.05rem; font-weight: 500; color: var(--lf-navy); min-height: 48px;
  transition: color .2s var(--lf-ease);
}
.lf-faq summary:hover { color: var(--lf-gold); }
.lf-faq summary::-webkit-details-marker { display: none; }
/* A drawn control rather than a text glyph: a "+" in body type is the almost-
   invisible symbol the brief is describing. */
.lf-faq summary::after {
  content: ""; flex: none; width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--lf-gold-line);
  background:
    linear-gradient(var(--lf-gold), var(--lf-gold)) center/9px 1px no-repeat,
    linear-gradient(var(--lf-gold), var(--lf-gold)) center/1px 9px no-repeat;
  transition: transform .25s var(--lf-ease), border-color .25s var(--lf-ease);
}
.lf-faq details[open] summary::after {
  /* Minus: the vertical stroke rotates away rather than being swapped out. */
  background: linear-gradient(var(--lf-gold), var(--lf-gold)) center/9px 1px no-repeat;
  border-color: var(--lf-gold); transform: rotate(180deg);
}
.lf-faq summary:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }
.lf-faq p { padding: 0 0 1.25rem; margin: 0; color: var(--lf-taupe-deep); font-size: .95rem; line-height: 1.7; max-width: 74ch; }

.lf-editorial__aside { position: sticky; top: 110px; }
.lf-editorial__aside h3 {
  font-family: var(--lf-sans); font-size: .72rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--lf-taupe); font-weight: 400; margin: 0 0 .9rem;
}
.lf-editorial__aside h3 + ul { margin: 0 0 2rem; }
.lf-editorial__aside ul { list-style: none; padding: 0; display: grid; gap: .55rem; }
.lf-editorial__aside a { font-size: .92rem; color: var(--lf-navy); border-bottom: 1px solid transparent; display: inline-block; padding-block: 2px; }
.lf-editorial__aside a:hover { border-bottom-color: var(--lf-taupe); }

@media (max-width: 900px) {
  .lf-editorial__grid { grid-template-columns: 1fr; gap: 2.25rem; }
  .lf-editorial__aside { position: static; border-top: 1px solid var(--lf-line); padding-top: 1.75rem; }
}

/* =========================================================================
   ABOVE-PRODUCT EDITORIAL — category, size landing, collection, guide
   =========================================================================

   The brief for this layer was "premium editorial, not an SEO appendix", and
   the difference between those two things is almost entirely restraint:
   measured line length, real whitespace between ideas, one accent, and no
   component that exists to look busy.

   So there are exactly three treatments here — prose, a card grid, and a link
   list — and each is used only where its shape matches the content. Everything
   in an accordion, or everything in a card, is the appendix look.
   ------------------------------------------------------------------------- */

.lf-editorial--category { background: var(--lf-stone); }

/*
 * Editorial layout.
 *
 * The measured 70ch column is right for reading and wrong on its own: inside a
 * 1440px page it left roughly two thirds of the width empty, which reads as an
 * unfinished layout rather than as restraint. Longer pages therefore pair it
 * with a contents rail, and shorter ones centre it. Neither widens the measure.
 */
.lf-ed { display: grid; gap: clamp(2.75rem, 5vw, 4.25rem); }
.lf-ed__main { display: grid; gap: clamp(2.75rem, 5vw, 4.25rem); min-width: 0; }

/* A guide or a short category page: one centred column, generous margins. */
.lf-ed--single .lf-ed__main { max-width: 74ch; margin-inline: auto; }

@media (min-width: 1000px) {
  .lf-ed--rail {
    grid-template-columns: 14rem minmax(0, 1fr);
    gap: clamp(3rem, 6vw, 6rem);
    align-items: start;
    max-width: 1180px;
    margin-inline: auto;
  }
  .lf-ed--single { max-width: 1180px; margin-inline: auto; }
  /* 110px clears the sticky header; matches the product editorial aside. */
  .lf-ed__toc { position: sticky; top: 110px; }
}
.lf-ed__toch {
  font-family: var(--lf-sans); font-size: .72rem; letter-spacing: .16em;
  text-transform: uppercase; color: var(--lf-taupe); font-weight: 400; margin: 0 0 1rem;
}
.lf-ed__toc ul { list-style: none; padding: 0; margin: 0; display: grid; gap: .1rem; }
.lf-ed__toc a {
  display: block; font-size: .88rem; line-height: 1.4; color: var(--lf-taupe-deep);
  /* 44px minimum target, met through padding rather than a fixed height so a
     two-line entry still grows instead of clipping. */
  padding: .72rem 0; min-height: 44px; border-bottom: 1px solid var(--lf-line);
}
.lf-ed__toc li:last-child a { border-bottom: 0; }
.lf-ed__toc a:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .lf-ed__toc a:hover { color: var(--lf-navy); }
}
/* Below the rail breakpoint the contents list is noise above the content it
   duplicates, and the page is short enough to scroll. */
@media (max-width: 999px) {
  .lf-ed__toc { display: none; }
}
/* An anchor jump must not land the heading under the sticky header. */
.lf-ed__block { scroll-margin-top: 120px; }

/* A single measured column. Editorial prose that runs the full 1440px is
   unreadable regardless of how good the typography is.

   `min-width: 0` is doing real work here, not defensive noise. A grid item
   defaults to `min-width: auto`, which resolves to the MIN-CONTENT width of its
   contents — and the bed-size table sets `min-width: 30rem` so its columns stay
   legible. At 390px that made this block 480px wide, pushed the page into
   110px of horizontal scroll, and defeated the `overflow-x: auto` on the table's
   own wrapper, which could never shrink because its parent never did.

   Measured on staging before the fix: viewport 390, document scrollWidth 500.
   The WordPress admin bar was NOT the cause — it measured 390 on the same run. */
.lf-ed__block { max-width: 70ch; min-width: 0; }
.lf-ed__block:has(.lf-ed__cards) { max-width: none; }
.lf-ed__block h2 {
  font-family: var(--lf-serif); font-weight: 400;
  font-size: clamp(1.35rem, 2.4vw, 1.75rem); line-height: 1.25;
  color: var(--lf-navy); margin: 0 0 .85rem; letter-spacing: -0.01em;
}
.lf-ed__block p {
  font-size: 1rem; line-height: 1.75; color: var(--lf-charcoal); margin: 0 0 1rem;
}
.lf-ed__block p:last-child { margin-bottom: 0; }
.lf-ed__lede { color: var(--lf-taupe-deep); }
.lf-ed__note {
  font-size: .84rem; color: var(--lf-taupe-mid); margin-top: .9rem;
  padding-left: .9rem; border-left: 2px solid var(--lf-line);
}

/* Cards carry a LIST of distinct things — product types, rooms. They are not a
   decorative wrapper for prose, which is why they break the measured column. */
.lf-ed__cards {
  max-width: none;
  display: grid; gap: 1px; margin-top: 1.5rem;
  background: var(--lf-line); border: 1px solid var(--lf-line);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.lf-ed__card { background: var(--lf-white); padding: 1.4rem 1.35rem; }
.lf-ed__card h3 {
  font-family: var(--lf-sans); font-weight: 500; font-size: .82rem;
  letter-spacing: .1em; text-transform: uppercase; color: var(--lf-navy);
  margin: 0 0 .6rem; display: flex; align-items: baseline; gap: .5rem;
}
/* The count is information, not a badge. A filled accent pill on every card is
   the "templated look via colour repetition" anti-pattern. */
.lf-ed__n {
  font-size: .74rem; letter-spacing: .04em; color: var(--lf-taupe-mid);
  font-weight: 400; text-transform: none;
}
.lf-ed__card p {
  font-size: .92rem; line-height: 1.65; color: var(--lf-taupe-deep); margin: 0;
}

/* The size table. Scrolls inside itself so the page body never scrolls sideways. */
.lf-ed__tablewrap { overflow-x: auto; margin-top: 1.35rem; }
.lf-ed__table {
  border-collapse: collapse; width: 100%; min-width: 30rem;
  font-size: .93rem; color: var(--lf-charcoal);
}
.lf-ed__table th, .lf-ed__table td {
  text-align: left; padding: .7rem .9rem .7rem 0; border-bottom: 1px solid var(--lf-line);
}
.lf-ed__table thead th {
  font-family: var(--lf-sans); font-size: .72rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--lf-taupe); font-weight: 400;
}
.lf-ed__table tbody th { font-weight: 500; color: var(--lf-navy); }
.lf-ed__none { color: var(--lf-taupe-mid); }

.lf-ed__links { list-style: none; padding: 0; margin: 1.15rem 0 0; display: grid; gap: .1rem; }
.lf-ed__links li {
  display: flex; align-items: baseline; gap: .75rem;
  padding: .7rem 0; border-bottom: 1px solid var(--lf-line);
}
.lf-ed__links a { color: var(--lf-navy); border-bottom: 1px solid transparent; padding-block: 2px; }
.lf-ed__links a:hover { border-bottom-color: var(--lf-taupe); }
.lf-ed__links em { font-style: normal; font-size: .82rem; color: var(--lf-taupe-mid); margin-left: auto; }

/* A guide is all prose, so it gets the wider gap and no shell tint — it reads
   as an article rather than as a shop page with text underneath. */
.lf-editorial--guide { background: var(--lf-ivory); }
.lf-editorial--guide .lf-ed { gap: clamp(3rem, 5.5vw, 4.75rem); }

/* Visually hidden, for table captions that a screen reader needs and a sighted
   reader already has from the heading above. */
.lf-vh {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (hover: none) {
  .lf-ed__links a:hover { border-bottom-color: transparent; }
}

/* Legal draft scaffolds. Deliberately plain — these are working documents, and
   dressing them up would make an unfinished policy look finished. */
.lf-legal { max-width: 70ch; padding-block: clamp(2rem, 4vw, 3rem); }
.lf-legal__banner {
  background: var(--lf-taupe-wash); border-left: 3px solid var(--lf-taupe);
  padding: 1rem 1.15rem; font-size: .92rem; line-height: 1.65;
  color: var(--lf-taupe-deep); margin: 0 0 2.5rem;
}
.lf-legal__block { margin-bottom: 2.75rem; }
.lf-legal__block h2 {
  font-family: var(--lf-serif); font-weight: 400; font-size: clamp(1.3rem, 2.2vw, 1.6rem);
  color: var(--lf-navy); margin: 0 0 1rem;
}
.lf-legal__block > p { font-size: 1rem; line-height: 1.75; margin: 0 0 1rem; }
.lf-legal__decision {
  border: 1px dashed var(--lf-line-strong); padding: 1.1rem 1.2rem;
  margin: 0 0 1rem; background: var(--lf-ivory);
}
.lf-legal__q { font-size: .98rem; color: var(--lf-navy); margin: 0 0 .5rem; font-weight: 500; }
.lf-legal__why { font-size: .9rem; line-height: 1.65; color: var(--lf-taupe-deep); margin: 0 0 .6rem; }
.lf-legal__id { font-size: .76rem; letter-spacing: .06em; text-transform: uppercase; color: var(--lf-taupe-mid); margin: 0; }
.lf-legal__id code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-transform: none; letter-spacing: 0; }

/* Staging reconciliation note. Plain and quiet — it states a fact about the
   environment, and it disappears on its own once the catalogue is imported. */
.lf-stagingnote {
  font-size: .82rem; line-height: 1.6; color: var(--lf-taupe-mid);
  margin: .85rem 0 0; padding-left: .9rem; border-left: 2px solid var(--lf-line);
  max-width: 70ch;
}

/* Multi-axis selector. Deliberately the same swatch language as the single-axis
   control — this is one more row of buttons, not a second interface. */
.lf-variations--multi { display: grid; gap: 1.15rem; }
.lf-axis__chosen { color: var(--lf-taupe); font-weight: 400; margin-left: .5rem; }
/* An unavailable pairing stays VISIBLE and legible — it tells the customer the
   option exists and does not pair with their other choice. Hiding it would make
   the range look smaller than it is. */
.lf-swatch.is-unavailable {
  opacity: .38; cursor: not-allowed; text-decoration: line-through;
  text-decoration-thickness: 1px;
}
@media (hover: hover) and (pointer: fine) {
  .lf-swatch.is-unavailable:hover { border-color: var(--lf-line); }
}
.lf-variations__status { font-size: .86rem; color: var(--lf-taupe); margin: 0; min-height: 1.2em; }

/* Colour-image availability notice.
   Informational, not an error: a missing photograph is a fact about the option,
   not something the customer did wrong. Muted surface, no red, no icon shouting
   for attention — and never hidden behind a disclosure, because it has to be
   readable at the moment the colour is chosen. */
.lf-imgnote {
  margin: .6rem 0 0;
  padding: .5rem .7rem;
  font-size: .8125rem;
  line-height: 1.4;
  color: var(--lf-muted, #5b6472);
  background: var(--lf-surface-2, #f5f6f8);
  border: 1px solid var(--lf-border, #e3e6ea);
  border-radius: 10px;
}
.lf-gallery__thumbs [hidden] { display: none !important; }

/* Reserve the notice's height so selecting a colour without imagery does not
   push the price and the add-to-basket button down the page mid-read. Reserved
   only on products where a colour can actually raise it. */
.lf-imgnote-slot.is-reserved { min-height: 46px; }
/* flow-root contains the notice's top margin. Without it that margin collapses
   out of the slot and lands on the axis instead, so the reserved height held
   steady while the block above it still grew by ~10px — the reservation looked
   like it had failed when it was the margin escaping. */
.lf-imgnote-slot { display: flow-root; }

/* Reserve the combination-status line where a combination can be out of stock,
   so the message appears without moving the price and the button. */
.lf-variations__status.is-reserved { min-height: 23px; }

/* ============================================================ THE BEDROOM EDIT
   An interlocking editorial composition: one grid, three overlapping areas, no
   absolute positioning and no negative margins anywhere in it.

   The column track is the whole trick. Reading left to right:

     rail | 47fr | 8fr | 3fr | 42fr

   the photograph takes 47+8+3, the panel takes 3+42, and the category strip
   takes 8+3+42 — so the panel laps the photograph's right edge by three units
   and the strip starts back over the photograph, bridging the two. Change only
   these tracks and the whole thing collapses to a stack; nothing is positioned
   out of flow, so there is no mobile behaviour to unpick.                     */

.lf-bedroom-section {
  background: var(--lf-white);
  padding-block: clamp(3.25rem, 6vw, 5.5rem) clamp(3.5rem, 7vw, 6rem);
}

.lf-bedroom {
  display: grid;
  grid-template-columns:
    3.25rem minmax(0, 50fr) minmax(0, 1.5fr) minmax(0, 2.5fr) minmax(0, 4fr) minmax(0, 42fr);
  /* Row 3 is deliberate empty track: it is what lets the photograph carry on
     below the category strip instead of stopping level with it. */
  grid-template-rows: auto auto clamp(2rem, 5.6vw, 5.25rem);
}

/* ---- the vertical editorial mark ---- */
.lf-bedroom__rail {
  grid-column: 1; grid-row: 1 / -1; margin: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  padding-bottom: .25rem;
}
.lf-bedroom__rail span {
  writing-mode: vertical-rl; transform: rotate(180deg); white-space: nowrap;
  font-size: .58rem; letter-spacing: .28em; text-transform: uppercase;
  color: var(--lf-navy-80);
}
.lf-bedroom__rail::after {
  content: ""; width: 1px; margin-top: 1.25rem;
  height: clamp(3rem, 16vw, 12.5rem);
  background: linear-gradient(var(--lf-gold-rule), rgba(141, 106, 58, .12));
}

/* ---- the photograph ---- */
.lf-bedroom__media {
  grid-column: 2 / 5; grid-row: 1 / -1;
  position: relative; z-index: 0; overflow: hidden; background: var(--lf-stone);
  min-height: clamp(20rem, 44vw, 42rem);
}
.lf-bedroom__media img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  /* The source is a 1122x1402 portrait. Held a little above centre, the crop
     keeps the artwork, both bedsides, the wardrobe and the chest of drawers —
     all of which the old 16:11 band cut straight through. */
  object-fit: cover; object-position: 50% 40%; display: block;
}

/* ---- the editorial panel ---- */
.lf-bedroom__panel {
  grid-column: 4 / -1; grid-row: 1;
  position: relative; z-index: 1; background: var(--lf-cream);
  margin-block-start: clamp(1.5rem, 3.4vw, 3.25rem);
  padding: clamp(2rem, 4.2vw, 4rem) clamp(1.75rem, 4vw, 4rem)
           clamp(2rem, 3.4vw, 3.1rem) clamp(2rem, 5vw, 5.25rem);
}
/* The fine gold rule along the panel's own top edge. */
.lf-bedroom__panel::before {
  content: ""; position: absolute; top: 0; left: 0;
  width: clamp(90px, 22%, 165px); height: 2px; background: var(--lf-gold);
}
.lf-bedroom .lf-eyebrow { color: var(--lf-gold); letter-spacing: .26em; margin-bottom: 1.3rem; }
.lf-bedroom__panel h2 {
  font-family: var(--lf-serif); font-weight: 400;
  font-size: clamp(1.95rem, 3.5vw, 3.25rem);
  line-height: 1.12; letter-spacing: -.02em; color: var(--lf-navy); margin: 0;
}
.lf-bedroom__rule {
  display: block; width: 30px; height: 1px;
  background: var(--lf-gold); margin: 1.25rem 0 0;
}
.lf-bedroom__copy {
  margin: 1.2rem 0 0; max-width: 46ch;
  font-size: .96rem; line-height: 1.72; color: var(--lf-taupe-deep);
}

/* ---- the call to action ---- */
.lf-bedroom__cta {
  display: inline-flex; align-items: center; gap: .85rem; align-self: flex-start;
  margin-top: 2rem; padding: 1.05rem 1.6rem; border-radius: 2px;
  background: var(--lf-navy); color: #FFFFFF;
  font-size: .72rem; letter-spacing: .18em; text-transform: uppercase;
  transition: background .25s var(--lf-ease), gap .25s var(--lf-ease);
}
.lf-bedroom__cta svg {
  width: 17px; height: 17px; fill: none; stroke: var(--lf-gold-on-navy); stroke-width: 1.5;
  transition: transform .25s var(--lf-ease), stroke .25s var(--lf-ease);
}
.lf-bedroom__cta:hover { background: #000D1E; gap: 1.05rem; }
.lf-bedroom__cta:hover svg { transform: translateX(3px); stroke: #C0975F; }
.lf-bedroom__cta:focus-visible { outline: 2px solid var(--lf-gold); outline-offset: 3px; }

/* ---- the category strip that bridges photograph and panel ---- */
.lf-bedroom__quick {
  grid-column: 3 / -1; grid-row: 2;
  position: relative; z-index: 2;
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  background: var(--lf-white);
  /* One shadow, and only enough of it to lift the strip off the photograph it
     sits on — the composition does the work, not the elevation. */
  box-shadow: 0 12px 34px -20px rgba(0, 20, 46, .28);
}
.lf-bedroom__quick li { position: relative; }
/* Inset hairlines, not full-height borders: the rule should read as a divider
   between two blocks, not as a box around each one. */
.lf-bedroom__quick li + li::before {
  content: ""; position: absolute; left: 0; top: 20%; bottom: 20%;
  width: 1px; background: var(--lf-gold-line);
}
.lf-bedroom__quick a {
  display: flex; align-items: center; height: 100%;
  gap: clamp(.7rem, 1.1vw, .95rem);
  padding: clamp(1rem, 1.9vw, 1.6rem) clamp(.8rem, 1.2vw, 1.1rem);
  transition: background .25s var(--lf-ease);
}
@media (hover: hover) and (pointer: fine) {
  .lf-bedroom__quick a:hover { background: var(--lf-cream); }
  .lf-bedroom__quick a:hover .lf-bedroom__qgo svg { transform: translateX(3px); }
}
.lf-bedroom__quick a:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: -3px; }
.lf-bedroom__thumb {
  flex: none; display: block; position: relative; overflow: hidden;
  width: clamp(54px, 4.6vw, 68px); aspect-ratio: 1; background: var(--lf-stone);
}
.lf-bedroom__thumb img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; padding: 6%;
  /* Load-bearing: the global `img { max-width: 100% }` otherwise clamps the
     inline subject-filling width straight back to the frame. */
  max-width: none;
}
.lf-bedroom__qtext { display: block; min-width: 0; }
.lf-bedroom__qname {
  display: block; font-size: .655rem; letter-spacing: .115em; text-transform: uppercase;
  color: var(--lf-navy); line-height: 1.35;
}
.lf-bedroom__qgo {
  display: inline-flex; align-items: center; gap: .4rem; margin-top: .45rem;
  font-size: .74rem; color: var(--lf-taupe);
}
.lf-bedroom__qgo svg {
  width: 14px; height: 14px; fill: none; stroke: var(--lf-gold); stroke-width: 1.5;
  transition: transform .25s var(--lf-ease);
}

@media (max-width: 1100px) {
  /* The overlap is abandoned rather than squeezed: below this width the panel
     and the strip have to give up so much padding to keep their columns that
     the layering stops reading as deliberate. Photograph, panel, strip. */
  .lf-bedroom { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto auto; }
  .lf-bedroom__rail { display: none; }
  .lf-bedroom__media { grid-column: 1; grid-row: 1; min-height: 0; aspect-ratio: 4 / 3; }
  .lf-bedroom__panel { grid-column: 1; grid-row: 2; margin-block-start: 0; }
  .lf-bedroom__quick { grid-column: 1; grid-row: 3; }
  .lf-bedroom__copy { max-width: 56ch; }
}

@media (max-width: 720px) {
  .lf-bedroom__media { aspect-ratio: 5 / 4; }
  .lf-bedroom__quick { grid-template-columns: minmax(0, 1fr); box-shadow: none; border: 1px solid var(--lf-gold-line); }
  .lf-bedroom__quick li + li::before { left: 5%; right: 5%; top: 0; bottom: auto; width: auto; height: 1px; }
  /* Full width for the touch target, but the label and arrow stay together —
     flung to opposite edges they read as two unrelated controls. */
  .lf-bedroom__cta { width: 100%; justify-content: center; }
}

@media (max-width: 430px) {
  /* The two-line headline is the point, so the type steps down far enough that
     "considered bedroom." stays on one line rather than breaking after a word. */
  .lf-bedroom__panel h2 { font-size: 1.72rem; }
  .lf-bedroom__panel { padding-inline: clamp(1.25rem, 6vw, 1.75rem); }
}

/* ============================================================ MORE TO EXPLORE
   Four category destinations as one composition.

   The asymmetry is not hardcoded — it FALLS OUT of the two columns having
   different intrinsic heights. The left column is a heading block above a
   square photograph; the right is a landscape photograph above a pair of
   near-square ones. The left is naturally the taller of the two, so
   `align-self: end` on the right column drops it to the shared baseline and
   leaves its top edge sitting up beside the heading. Nothing is offset by hand,
   so a heading that wraps to another line at some width simply moves the seam
   rather than breaking the layout.                                           */

.lf-more { background: var(--lf-cream); }

.lf-more__grid {
  display: grid;
  grid-template-columns: minmax(0, 46fr) minmax(0, 52fr);
  grid-template-rows: auto minmax(0, 1fr);
  column-gap: clamp(.8rem, 1.5vw, 1.45rem);
  row-gap: clamp(1.5rem, 2.6vw, 2.5rem);
}
.lf-more__head   { grid-area: 1 / 1; align-self: start; }
.lf-more__right  { grid-area: 1 / 2 / -1 / -1; align-self: end;
                   display: grid; grid-template-rows: auto auto;
                   gap: clamp(.6rem, 1.1vw, 1.05rem); }
.lf-more__pair   { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
                   gap: clamp(.6rem, 1.1vw, 1.05rem); }

/* ---- heading block ---- */
.lf-more__head .lf-eyebrow { color: var(--lf-gold); margin-bottom: 1.15rem; }
/* The concept's short rule runs on from the eyebrow rather than sitting under
   it — a continuation of the line of type, not a second element. */
.lf-more__head .lf-eyebrow::after {
  content: ""; display: inline-block; vertical-align: middle;
  width: 34px; height: 1px; margin-left: .9rem; background: var(--lf-gold-rule);
}
.lf-more__head h2 {
  font-family: var(--lf-serif); font-weight: 400;
  font-size: clamp(2rem, 3.9vw, 3.6rem);
  line-height: 1.06; letter-spacing: -.02em; color: var(--lf-navy); margin: 0;
}
.lf-more__head > p:not(.lf-eyebrow) {
  margin: 1.35rem 0 0; max-width: 40ch;
  font-size: .96rem; line-height: 1.7; color: var(--lf-taupe-deep);
}

/* ---- the tiles ---- */
.lf-more__tile {
  position: relative; display: block; overflow: hidden;
  background: var(--lf-stone); border-radius: 2px; color: #FFFFFF;
}
.lf-more__tile--dining { grid-area: 2 / 1; align-self: start; aspect-ratio: 1 / 1; }
.lf-more__tile--living { aspect-ratio: 5 / 3; }
.lf-more__pair .lf-more__tile { aspect-ratio: 21 / 20; }

.lf-more__media { position: absolute; inset: 0; display: block; }
.lf-more__media img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .4s var(--lf-ease);
}
/* Each photograph is held where its subject is, not at its own centre. */
.lf-more__tile--dining .lf-more__media img      { object-position: 50% 58%; }
.lf-more__tile--sofas .lf-more__media img       { object-position: 50% 55%; }
.lf-more__tile--accessories .lf-more__media img { object-position: 55% 50%; }

/* The overlay is a NAVY tint, not a neutral fade. A grey scrim over warm
   photography reads as fog sitting on top of the picture; a dark navy one reads
   as the shadowed part of the room, and it is the palette's own colour. */
.lf-more__tile::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(to top,
    rgba(4, 16, 31, .88) 0%,
    rgba(4, 16, 31, .74) 12%,
    rgba(4, 16, 31, .40) 28%,
    rgba(4, 16, 31, .10) 48%,
    rgba(4, 16, 31, 0)   68%);
  transition: opacity .4s var(--lf-ease);
}

.lf-more__label {
  position: absolute; z-index: 1; left: 0; right: 0; bottom: 0;
  display: block; padding: clamp(1.05rem, 1.9vw, 1.75rem);
  transition: transform .4s var(--lf-ease);
}
.lf-more__kicker {
  display: block; font-size: .625rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--lf-gold-light); margin-bottom: .45rem;
}
.lf-more__name {
  display: block; font-family: var(--lf-serif); font-weight: 400;
  font-size: clamp(1.3rem, 1.85vw, 1.7rem); line-height: 1.15; color: #FFFFFF;
}
.lf-more__arrow {
  display: block; width: 34px; height: 12px; margin-top: .75rem;
  fill: none; stroke: var(--lf-gold-light); stroke-width: 1.5;
  transition: transform .4s var(--lf-ease);
}

@media (hover: hover) and (pointer: fine) {
  .lf-more__tile:hover .lf-more__media img { transform: scale(1.03); }
  .lf-more__tile:hover::after { opacity: 1.12; }
  .lf-more__tile:hover .lf-more__label { transform: translateY(-2px); }
  .lf-more__tile:hover .lf-more__arrow { transform: translateX(4px); }
}
.lf-more__tile:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }

@media (max-width: 1100px) {
  /* Two-up, twice. `display: contents` dissolves the right-hand wrapper so its
     children join the outer grid directly — the alternative is a nested grid
     whose rows cannot line up with the ones beside it. */
  .lf-more__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: auto; }
  .lf-more__head { grid-area: auto; grid-column: 1 / -1; }
  .lf-more__right { display: contents; }
  .lf-more__pair { grid-column: 1 / -1; }
  .lf-more__tile--dining { grid-area: auto; }
  .lf-more__tile--dining, .lf-more__tile--living { aspect-ratio: 4 / 3; }
  .lf-more__pair .lf-more__tile { aspect-ratio: 4 / 3; }
  .lf-more__head > p:not(.lf-eyebrow) { max-width: 52ch; }
}

@media (max-width: 640px) {
  /* Four full-width cards. A two-across grid at this width turns four room
     photographs into four thumbnails, which is the failure the new photography
     was chosen to end. */
  .lf-more__grid { grid-template-columns: minmax(0, 1fr); }
  .lf-more__pair { grid-template-columns: minmax(0, 1fr); }
  .lf-more__tile--dining, .lf-more__tile--living,
  .lf-more__pair .lf-more__tile { aspect-ratio: 3 / 2; }
  .lf-more__name { font-size: 1.45rem; }
  /* A shorter tile puts the label higher up the gradient, where the desktop
     ramp has barely started — so the kicker was landing on a bright window in
     two of the four photographs. The scrim is rebalanced rather than the type
     given a shadow: the label has to be legible over ANY photograph put in
     this slot later, not just today's four. */
  .lf-more__tile::after {
    background: linear-gradient(to top,
      rgba(4, 16, 31, .90) 0%,
      rgba(4, 16, 31, .80) 18%,
      rgba(4, 16, 31, .52) 38%,
      rgba(4, 16, 31, .16) 58%,
      rgba(4, 16, 31, 0)   78%);
  }
}

/* ============================================================ FEATURED PIECES
   The homepage's closing merchandising panel: an editorial column and three
   product cards, between the warm newsletter above and the ivory footer below.

   The framing is carried by TONE, not by lines. An earlier pass drew a border
   round the panel, another round each card and a third round each image stage —
   three nested rectangles, which is what made a showroom read as a grid
   component. Now the panel is a cleaner white than the ground it sits on, the
   image stages are a shade warmer than the panel, and nothing has an outline at
   all.                                                                        */

.lf-show {
  background: var(--lf-cream);
  /* The newsletter above already ends with a full section's padding, so this
     one only needs enough of its own to separate the two grounds. */
  padding-block: clamp(1.35rem, 2.4vw, 2.25rem) clamp(1.6rem, 2.8vw, 2.5rem);
}

.lf-show__panel {
  background: #FFFFFF; border-radius: 2px;
  /* Deliberately tight. Panel padding is width the product row does not get,
     and this row's cards were coming out NARROWER than the four-across New
     Arrivals cards higher up the same page — the clearest possible tell that
     the composition was over-padded rather than short of space. */
  padding: clamp(1rem, 1.7vw, 1.5rem);
  display: grid;
  grid-template-columns: minmax(0, 24fr) minmax(0, 76fr);
  column-gap: clamp(1.5rem, 2.8vw, 2.5rem);
  row-gap: clamp(1.5rem, 3vw, 2.25rem);
  align-items: center;
  /* One broad, almost invisible shadow instead of a hairline — enough to seat
     the white panel on the warm ground, not enough to read as elevation. */
  box-shadow: 0 2px 3px -2px rgba(0, 20, 46, .05),
              0 26px 60px -44px rgba(0, 20, 46, .30);
}

/* ---- editorial column ---- */
.lf-show__intro { padding-left: clamp(.25rem, 1vw, 1.15rem); }
.lf-show__intro .lf-eyebrow { color: var(--lf-taupe); letter-spacing: .24em; margin-bottom: 1.2rem; }
.lf-show__intro h2 {
  font-family: var(--lf-serif); font-weight: 400;
  font-size: clamp(1.7rem, 2.6vw, 2.35rem);
  line-height: 1.12; letter-spacing: -.018em; color: var(--lf-navy); margin: 0;
}
.lf-show__rule {
  display: block; width: 46px; height: 1px;
  background: var(--lf-gold); margin: 1.5rem 0 0;
}
.lf-show__copy {
  margin: 1.4rem 0 0; max-width: 27ch;
  font-size: .94rem; line-height: 1.82; color: var(--lf-taupe-deep);
}
.lf-show__cta {
  display: inline-flex; align-items: center; gap: .65rem; margin-top: 1.9rem;
  font-size: .735rem; letter-spacing: .19em; text-transform: uppercase; color: var(--lf-navy);
  padding-bottom: .42rem; border-bottom: 1px solid rgba(141, 106, 58, .55);
  transition: gap .3s var(--lf-ease), border-color .3s var(--lf-ease);
}
.lf-show__cta svg {
  width: 17px; height: 17px; fill: none; stroke: var(--lf-gold); stroke-width: 1.4;
  transition: transform .3s var(--lf-ease);
}
.lf-show__cta:hover { gap: .95rem; border-bottom-color: var(--lf-gold); }
.lf-show__cta:hover svg { transform: translateX(3px); }
.lf-show__cta:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 4px; }

/* ---- product cards ---- */
.lf-show__grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(.7rem, 1.3vw, 1.15rem);
}
.lf-show__card { display: block; }
.lf-show__link { display: flex; flex-direction: column; height: 100%; background: transparent; }
.lf-show__link:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }

.lf-show__stage {
  display: block; position: relative; overflow: hidden;
  /* PORTRAIT, and it must match the ratio passed to lomond_stage_style().
     See that call for why a taller frame makes the product bigger rather than
     smaller on this catalogue's near-square cut-outs. */
  aspect-ratio: 0.86;
  background: #FAF8F4;
}
.lf-show__stage img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain;
  /* Load-bearing: the global `img { max-width: 100% }` otherwise clamps the
     inline subject-filling width back to the frame. */
  max-width: none;
  /* The cut-outs carry WHITE canvas, and the subject-filling geometry pushes
     that canvas past the frame — so without this the sheet paints over the warm
     plinth and each stage renders as irregular patches of white and tint rather
     than one surface. Multiply drops the white into the plinth colour; the
     plinth is light enough that the product itself is unchanged. */
  mix-blend-mode: multiply;
  transition: transform .4s var(--lf-ease);
}
@media (hover: hover) and (pointer: fine) {
  .lf-show__link:hover .lf-show__stage { background: #F7F4EF; }
  .lf-show__link:hover .lf-show__stage img { transform: scale(1.02); }
  .lf-show__link:hover .lf-show__title { text-decoration: underline; text-underline-offset: 3px; }
}

.lf-show__body {
  padding: clamp(1rem, 1.5vw, 1.35rem) clamp(.15rem, .5vw, .5rem) 0;
  display: flex; flex-direction: column; flex: 1 1 auto;
}
.lf-show__range {
  margin: 0 0 .55rem; font-size: .625rem; letter-spacing: .19em;
  text-transform: uppercase; color: var(--lf-taupe);
}
.lf-show__title {
  margin: 0; font-family: var(--lf-serif); font-weight: 400;
  font-size: clamp(1.08rem, 1.35vw, 1.2rem); line-height: 1.32; color: var(--lf-navy);
}
/* Price on the card's floor, so three names of different lengths still leave
   three prices on one line across the row. */
.lf-show__price {
  margin: .7rem 0 0; font-size: 1.04rem; color: var(--lf-navy); margin-top: auto;
  padding-top: .7rem;
}
.lf-show__price .from {
  font-size: .625rem; color: var(--lf-taupe); text-transform: uppercase;
  letter-spacing: .14em; margin-right: .32rem;
}

@media (max-width: 1100px) {
  /* The editorial column stops being a column: at this width it would be
     narrower than its own two-line heading wants to be. */
  .lf-show__panel { grid-template-columns: minmax(0, 1fr); }
  .lf-show__intro { padding-left: 0; }
  .lf-show__copy { max-width: 54ch; }
}

@media (max-width: 980px) and (min-width: 641px) {
  /* Two large cards and one, rather than three narrow ones: below this width a
     third column costs each product about a third of its size, which is the
     opposite of what this section is for.
     Flex rather than grid purely so the odd third card CENTRES on its own row.
     Left-aligned in a two-column grid it sat beside an empty cell, which reads
     as a missing product rather than as a deliberate arrangement. */
  .lf-show__grid { display: flex; flex-wrap: wrap; justify-content: center; }
  .lf-show__card { flex: 0 1 calc(50% - clamp(.7rem, 1.3vw, 1.15rem) / 2); }
}

@media (max-width: 640px) {
  .lf-show__grid { grid-template-columns: minmax(0, 1fr); }
  .lf-show__stage { aspect-ratio: 1.05; }
  .lf-show__panel {
    padding: clamp(.85rem, 3.5vw, 1.15rem);
    /* The shadow is doing nothing at this width except costing a paint. */
    box-shadow: none;
  }
  .lf-show__body { padding-inline: .25rem; }
}

/* ====================================================== PRODUCT IMAGE VIEWER */

.lf-gallery__main.is-zooming { cursor: crosshair; }
/*
 * THE IMAGE MAGNIFIES ITSELF. No clone, no overlay, no blend.
 *
 * This previously placed a copy of the photograph on top of the original and
 * composited it with `mix-blend-mode: multiply`. Multiply does not cover — it
 * multiplies the two pictures together — so hovering produced the magnified
 * copy AND the original showing through it, offset, as a stack of translucent
 * ghosts. The duplication was the design, so the design is gone.
 *
 * Transitioning `transform` gives a smooth zoom in and out. `transform-origin`
 * is deliberately NOT transitioned: animating it would make the magnifier lag
 * behind the cursor instead of tracking it.
 */
[data-lf-gallery-main] {
  transition: transform .22s var(--lf-ease);
  will-change: transform;
}
.lf-gallery__main.is-zooming [data-lf-gallery-main] {
  /* The stage already clips; nothing can escape the frame. */
  cursor: crosshair;
}
@media (prefers-reduced-motion: reduce) {
  [data-lf-gallery-main] { transition: none; }
}

/* Controls sit ABOVE the image so they stay reachable while inspecting. */
.lf-gallery__expand {
  position: absolute; z-index: 3; right: .85rem; top: .85rem;
  width: 40px; height: 40px; display: grid; place-items: center;
  background: rgba(255, 255, 255, .92); color: var(--lf-navy);
  border: 1px solid var(--lf-line); border-radius: 2px;
  transition: background .25s var(--lf-ease), border-color .25s var(--lf-ease);
}
.lf-gallery__expand svg { width: 17px; height: 17px; }
.lf-gallery__expand:hover { background: #FFFFFF; border-color: var(--lf-line-strong); }
.lf-gallery__expand:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }

.lf-gallery__hint {
  position: absolute; z-index: 3; left: .95rem; bottom: .85rem; margin: 0;
  font-size: .625rem; letter-spacing: .15em; text-transform: uppercase;
  color: var(--lf-taupe); background: rgba(255, 255, 255, .86);
  padding: .4rem .6rem; border-radius: 2px;
  transition: opacity .3s var(--lf-ease);
}
/* Guidance, not furniture: it goes once the customer has understood it. */
.lf-gallery__hint.is-faded { opacity: 0; }

.lf-gallery__thumbs button {
  flex: 0 0 auto; width: 74px; height: 74px; padding: 5px;
  background: #FBFAF8; border: 1px solid var(--lf-line); border-radius: 2px;
  position: relative; transition: border-color .25s var(--lf-ease);
}
.lf-gallery__thumbs button[aria-current="true"] { border-color: var(--lf-navy); }
/* The gold underline is what makes the selected thumbnail unmistakable at a
   glance; the navy border alone reads as "hovered" on a warm page. */
.lf-gallery__thumbs button[aria-current="true"]::after {
  content: ""; position: absolute; left: 8px; right: 8px; bottom: -5px;
  height: 2px; background: var(--lf-gold);
}

/* ------------------------------------------------------------- lightbox --- */
html.lf-lb-open { overflow: hidden; }

.lf-lightbox {
  /* Above every other fixed layer on the site — the announcement bar and the
     sticky header both sit in the thousands, and a viewer with the page's own
     furniture poking through the top of it is not a viewer. */
  position: fixed; inset: 0; z-index: 100000;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  /* The picture row takes every pixel the caption does not. Auto rows sized the
     frame to the image's own fit and left the bottom half of a phone screen
     empty. */
  grid-template-rows: minmax(0, 1fr) auto;
  align-items: center; gap: clamp(.25rem, 2vw, 1.5rem);
  padding: clamp(.75rem, 3vw, 2.5rem);
  /* OPAQUE. At 96% a white product page transmits enough light to read the
     header, the thumbnails and the price straight through the backdrop — which
     on a phone made the viewer look as though it had failed to cover the page
     at all. Inspecting furniture wants no competition behind it. */
  background: #050D18;
  overscroll-behavior: contain;
}
.lf-lightbox[hidden] { display: none; }

.lf-lightbox__frame {
  grid-column: 2; justify-self: center; align-self: center;
  width: 100%; height: 100%; display: grid; place-items: center;
  overflow: hidden; touch-action: none;
}
.lf-lightbox__frame img {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  object-fit: contain; display: block;
  /* Most of this catalogue is cut-outs on white canvas, which on a dark
     backdrop would otherwise read as an accidental white rectangle. Painting
     the plate white makes the canvas and the mount the same surface, so the
     picture reads as a mounted print; a lifestyle shot covers it entirely. */
  background: #FFFFFF;
  box-shadow: 0 30px 80px -40px rgba(0, 0, 0, .8);
  transform-origin: center center;
  transition: transform .22s var(--lf-ease);
  cursor: zoom-in;
}
.lf-lightbox.is-zoomed .lf-lightbox__frame img { cursor: grab; transition: none; }

.lf-lightbox__close,
.lf-lightbox__nav {
  display: grid; place-items: center; color: #FFFFFF;
  background: rgba(255, 255, 255, .08); border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 2px; transition: background .25s var(--lf-ease), border-color .25s var(--lf-ease);
}
.lf-lightbox__close:hover,
.lf-lightbox__nav:hover { background: rgba(255, 255, 255, .16); border-color: rgba(201, 160, 99, .6); }
.lf-lightbox__close:focus-visible,
.lf-lightbox__nav:focus-visible { outline: 2px solid var(--lf-gold-light); outline-offset: 3px; }

.lf-lightbox__close {
  position: absolute; top: clamp(.75rem, 2vw, 1.5rem); right: clamp(.75rem, 2vw, 1.5rem);
  z-index: 2; width: 48px; height: 48px;
}
.lf-lightbox__close svg { width: 20px; height: 20px; }
.lf-lightbox__nav { width: 48px; height: 78px; }
.lf-lightbox__nav svg { width: 22px; height: 22px; }
.lf-lightbox__nav--prev { grid-column: 1; }
.lf-lightbox__nav--next { grid-column: 3; }
.lf-lightbox__nav[hidden] { visibility: hidden; display: grid; }

.lf-lightbox__meta {
  grid-column: 1 / -1; margin: 0; text-align: center;
  display: flex; align-items: center; justify-content: center; gap: .9rem;
  font-size: .68rem; letter-spacing: .16em; text-transform: uppercase;
  color: rgba(255, 255, 255, .62);
}
.lf-lightbox__count { color: var(--lf-gold-light); }

@media (max-width: 720px) {
  /* Arrows would eat a third of a phone's width beside the picture. Swipe and
     the counter carry navigation here; the close control stays large. */
  .lf-lightbox { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; }
  .lf-lightbox__nav { display: none; }
  .lf-lightbox__frame { grid-column: 1; }
  .lf-lightbox__meta { grid-column: 1; }
  .lf-gallery__hint { display: none; }
  .lf-gallery__thumbs button { width: 62px; height: 62px; }
}

/* ------------------------------------------------------------------ legal
   Policy pages are still Lomond: the same navy, the same measure, the same
   restraint. A legal page that looks like a default WordPress page tells the
   customer the care stopped at the shop. Readability leads — long-form prose at
   a comfortable measure, generous leading, and a quiet contents list once a
   page is long enough to need one. */
.lf-legal { max-width: 46rem; margin: 0 auto; }

.lf-legal__banner {
  margin: 0 0 2.5rem;
  padding: .9rem 1.1rem;
  font-size: .875rem;
  line-height: 1.55;
  color: var(--lf-ink, #1b2431);
  background: var(--lf-surface-2, #f5f6f8);
  border-left: 3px solid var(--lf-accent, #9a8c78);
  border-radius: 0 10px 10px 0;
}

.lf-legal__toc {
  margin: 0 0 3rem;
  padding: 1.25rem 1.5rem;
  background: var(--lf-surface-2, #f5f6f8);
  border-radius: 14px;
}
.lf-legal__toc-title {
  margin: 0 0 .6rem;
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--lf-muted, #5b6472);
}
.lf-legal__toc ol { margin: 0; padding-left: 1.1rem; }
.lf-legal__toc li { margin: .3rem 0; font-size: .9375rem; }
.lf-legal__toc a { color: var(--lf-ink, #1b2431); text-decoration: none; border-bottom: 1px solid transparent; }
.lf-legal__toc a:hover,
.lf-legal__toc a:focus-visible { border-bottom-color: currentColor; }

.lf-legal__block { margin: 0 0 3rem; scroll-margin-top: 6rem; }
.lf-legal__block h2 {
  margin: 0 0 .9rem;
  font-size: clamp(1.25rem, 1.1rem + .6vw, 1.5rem);
  line-height: 1.25;
  letter-spacing: -.01em;
}
.lf-legal__block p { margin: 0 0 1rem; line-height: 1.7; }

/* An unanswered question must never read as finished prose. */
.lf-legal__decision {
  margin: 0 0 1.25rem;
  padding: 1rem 1.15rem;
  background: #fffaf2;
  border: 1px dashed #d8c49a;
  border-radius: 12px;
}
.lf-legal__q { margin: 0 0 .35rem; font-weight: 600; }
.lf-legal__why { margin: 0 0 .5rem; font-size: .9375rem; color: var(--lf-muted, #5b6472); }
.lf-legal__id { margin: 0; font-size: .8125rem; color: var(--lf-muted, #5b6472); }
.lf-legal__id code { font-size: .8125rem; }

.lf-legal__identity {
  margin: 3rem 0 0;
  padding-top: 1.5rem;
  border-top: 1px solid var(--lf-border, #e3e6ea);
  font-size: .875rem;
  color: var(--lf-muted, #5b6472);
}

@media (max-width: 600px) {
  .lf-legal__toc { padding: 1rem 1.15rem; }
  .lf-legal__block { margin-bottom: 2.25rem; }
}

/* Business identification in the footer base — present because the law asks for
   it, weighted so it never competes with the brand. */
.lf-footer__legal-id { opacity: .75; }

/* Checkout consent line — quiet, legible, never a wall of small print. */
.lf-checkout__consent {
  margin: 0 0 1rem;
  font-size: .875rem;
  line-height: 1.6;
  color: var(--lf-muted, #5b6472);
}
.lf-checkout__consent a { color: inherit; text-decoration: underline; }

/* ==================================================== BUYER CONFIDENCE AREA */

/* ---- review summary (renders only when reviews genuinely exist) ---- */
.lf-pdp__rating { display: inline-flex; align-items: baseline; gap: .55rem; margin: 0 0 .35rem; }
.lf-stars {
  font-size: .95rem; letter-spacing: .1em; line-height: 1;
  background: linear-gradient(90deg, var(--lf-gold) var(--lf-stars, 0%), var(--lf-taupe-pale) var(--lf-stars, 0%));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.lf-pdp__rating-num { font-size: .9rem; color: var(--lf-navy); }
.lf-pdp__rating-count { font-size: .8rem; color: var(--lf-taupe); border-bottom: 1px solid var(--lf-line-strong); }
.lf-pdp__rating:hover .lf-pdp__rating-count { border-bottom-color: var(--lf-navy); }

.lf-pdp__pack {
  margin: .1rem 0 0; font-size: .78rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--lf-navy);
}

/* ---- the confidence strip ----
   Was a tall stack of full-width rows in a beige card, which read as a third
   large panel in a column that already had two. The same facts now sit side by
   side as one quick-glance answer: cells, hairlines, no card. */
.lf-conf {
  margin: 1.25rem 0 1.1rem;
  background: #FCFAF6; border: 1px solid var(--lf-line-strong); border-radius: 4px;
  display: grid; gap: 0;
  /* The gold is one hairline at the top edge, not a fill. */
  box-shadow: inset 0 2px 0 -1px var(--lf-gold-line);
}
.lf-conf[data-cells="1"] { grid-template-columns: minmax(0, 1fr); }
.lf-conf[data-cells="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.lf-conf[data-cells="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* Four facts stop fitting across a 596px column, so they fold rather than
   shrink the type. */
.lf-conf[data-cells="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* 15px of internal air, against 12.8. Four cells of tiny grey type in a thin
   box was the "technically present, visually absent" failure — the panel has to
   carry the weight of the objections it answers. */
.lf-conf__cell { padding: .95rem clamp(.85rem, 1.25vw, 1.05rem); min-width: 0; }
/* Hairlines BETWEEN cells only — a border on each would rebuild the boxes. */
.lf-conf[data-cells="2"] .lf-conf__cell + .lf-conf__cell,
.lf-conf[data-cells="3"] .lf-conf__cell + .lf-conf__cell {
  border-left: 1px solid var(--lf-gold-line);
}
.lf-conf[data-cells="4"] .lf-conf__cell:nth-child(even) { border-left: 1px solid var(--lf-gold-line); }
.lf-conf[data-cells="4"] .lf-conf__cell:nth-child(n+3) { border-top: 1px solid var(--lf-gold-line); }

/* ICON -> LABEL -> VALUE -> SUPPORTING DETAIL, and each step visibly a step.
   The label was 9.6px at the taupe mid-tone, which is below the size at which a
   caption reads as a heading at all. */
.lf-conf__label {
  display: flex; align-items: center; gap: .5rem; margin: 0 0 .38rem;
  font-size: .7rem; font-weight: 500; letter-spacing: .13em; text-transform: uppercase;
  color: var(--lf-taupe-deep);
}
/* 22px, up from 14. These are the only icons in the purchase column and they
   carry the meaning of the cell before the label is read. */
.lf-conf__label svg {
  flex: none; width: 22px; height: 22px; fill: none; stroke: var(--lf-gold); stroke-width: 1.35;
}
.lf-conf__value { margin: 0; font-size: .95rem; line-height: 1.4; color: var(--lf-navy); }
.lf-conf__note { margin: .22rem 0 0; font-size: .78rem; line-height: 1.4; color: var(--lf-taupe-deep); }
/*
 * WCAG 2.5.8 — 24x24 CSS pixels.
 *
 * Both of these are standalone links doing a button's job, so the inline-text
 * exception does not cover them: they measured 15px and 16px tall. The visual
 * rule stays exactly where it was — the target grows around the text with
 * padding, rather than the type growing, so nothing about the design changes.
 */
/* "Full dimensions →" has to look like something you would click. At .62rem
   uppercase it read as another caption in a panel already full of them. */
.lf-conf__link {
  display: inline-flex; align-items: center; gap: .35rem; margin-top: .4rem;
  min-height: 24px; padding-block: .3rem .18rem;
  font-size: .82rem; font-weight: 500; letter-spacing: .01em; color: var(--lf-navy);
  border-bottom: 1px solid rgba(141, 106, 58, .65);
}
.lf-conf__link svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.6; }
.lf-conf__link:hover { border-bottom-color: var(--lf-gold); }
.lf-conf__link:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }

@media (max-width: 560px) {
  /* Three tiny cells across a phone is unreadable; two is not. */
  .lf-conf[data-cells="3"], .lf-conf[data-cells="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lf-conf[data-cells="3"] .lf-conf__cell + .lf-conf__cell { border-left: 0; }
  .lf-conf[data-cells="3"] .lf-conf__cell:nth-child(even) { border-left: 1px solid var(--lf-gold-line); }
  .lf-conf[data-cells="3"] .lf-conf__cell:nth-child(n+3) { border-top: 1px solid var(--lf-gold-line); }
}

/* ---- wishlist ---- */
.lf-wish {
  display: inline-flex; align-items: center; justify-content: center; gap: .6rem;
  width: 100%; margin-top: .7rem; min-height: 48px; padding: .8rem 1rem;
  background: transparent; color: var(--lf-navy);
  border: 1px solid var(--lf-line-strong); border-radius: 2px;
  font-size: .72rem; letter-spacing: .17em; text-transform: uppercase;
  transition: border-color .25s var(--lf-ease), background .25s var(--lf-ease);
}
.lf-wish svg { width: 17px; height: 17px; transition: fill .25s var(--lf-ease), stroke .25s var(--lf-ease); }
.lf-wish:hover { border-color: var(--lf-navy); }
.lf-wish:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }
/* The saved state is carried by aria-pressed, so the control's accessible state
   and its appearance cannot drift apart. */
.lf-wish .lf-wish__on { display: none; }
.lf-wish[aria-pressed="true"] .lf-wish__on { display: inline; }
.lf-wish[aria-pressed="true"] .lf-wish__off { display: none; }
.lf-wish[aria-pressed="true"] svg { fill: var(--lf-gold); stroke: var(--lf-gold); }
.lf-wish[aria-pressed="true"] { border-color: rgba(141, 106, 58, .55); }

.lf-wish--compact {
  position: absolute; z-index: 2; top: .6rem; right: .6rem;
  width: 38px; height: 38px; min-height: 0; padding: 0; margin: 0;
  background: rgba(255, 255, 255, .92); border-color: var(--lf-line);
}
.lf-card { position: relative; }

.lf-pdp__links {
  display: flex; flex-wrap: wrap; gap: 1.25rem; margin: 1.1rem 0 0;
}
.lf-pdp__links a {
  font-size: .82rem; color: var(--lf-taupe-deep);
  border-bottom: 1px solid var(--lf-gold-line); padding-bottom: .18rem;
}
.lf-pdp__links a:hover { color: var(--lf-navy); border-bottom-color: var(--lf-navy); }

/* ---- header heart ---- */
.lf-header__wish, .lf-header__bag { position: relative; display: inline-flex; }
/* `display: grid` on an author rule BEATS the user-agent's `[hidden]
   { display: none }`, so the empty badge rendered as a navy dot beside the
   wishlist icon on every page of the site — a permanent notification for
   nothing. The attribute selector has to win, and it has to be declared for
   both badges. */
.lf-header__wishcount[hidden], .lf-header__bagcount[hidden] { display: none; }
/* Small, round, and set in the ivory the rest of the header uses for reversed
   type. Positioned against the ICON rather than the link box, so it kisses the
   glyph's corner instead of floating in the link's padding. */
.lf-header__wishcount, .lf-header__bagcount {
  /* Sized against the GLYPH, not against the tap target. At 16px with a 2px
     ring the badge was 20px on a 21px icon and read as a second object of equal
     weight; 13px with a 1.5px ring reads as a count on an icon. */
  /* Sat on the glyph's top-right CORNER, not over its middle: centred on the
     corner it overlaps only the icon's empty quadrant, so the heart's lobe and
     the bag's handle both stay whole. Absolute throughout, so a count appearing
     or changing never moves the icon or the row. */
  /* PUSHED OUT PAST THE CORNER, not centred on it. The glyph is 21px inside a
     44px box, so its top-right corner is 11.5px in from both edges. A disc
     centred there is mathematically tidy and visually wrong: at 15px plus a
     ring it then covers a quarter of a 21px glyph, and it was hiding the
     heart's lobe and the bag's handle — the exact shapes this pass exists to
     make clearer. Sat at 2px it overlaps the glyph by about 5px in each
     direction, which is enough to read as attached and little enough to leave
     the icon whole. The 44px target gives it that room to move into. */
  position: absolute; top: 2px; right: 2px;
  min-width: 15px; height: 15px; padding: 0 4px;
  display: grid; place-items: center;
  background: var(--lf-navy); color: #fff; border-radius: 999px;
  font-family: var(--lf-sans); font-size: .58rem; font-weight: 500;
  line-height: 1; letter-spacing: .02em;
  /* A ring in the header's own white separates the disc from the glyph beneath
     it, so the two never read as one shape. 1.5px, because every extra pixel of
     ring is another pixel of glyph covered. */
  box-shadow: 0 0 0 1.5px #fff;
}

/* ---- wishlist page ---- */
.lf-wish-page { padding-block: clamp(2.5rem, 5vw, 4.5rem); }
.lf-wish-page__title {
  font-family: var(--lf-serif); font-weight: 400; color: var(--lf-navy);
  font-size: clamp(2rem, 3.6vw, 3rem); line-height: 1.08; margin: 0 0 clamp(1.75rem, 3vw, 2.5rem);
}
.lf-wish-page__empty {
  margin: 0; padding: clamp(2rem, 4vw, 3.5rem) 0; color: var(--lf-taupe-deep); font-size: .95rem;
}
.lf-wish-page__empty a { color: var(--lf-navy); border-bottom: 1px solid var(--lf-gold); padding-bottom: .1rem; }

@media (max-width: 720px) {
  .lf-conf { margin-block: 1.35rem 1.1rem; }
  .lf-conf__row { padding-block: .9rem; }
}

/* A disabled CTA must LOOK disabled. `disabled(!$hasConfig)` was already
   setting the attribute, so the button was correctly inert for assistive tech
   and the keyboard while still reading as a live navy call to action to
   everyone else — the one combination that wastes a customer's click. */
.lf-btn:disabled,
.lf-btn[disabled] {
  background: var(--lf-taupe-pale); border-color: var(--lf-taupe-pale);
  color: var(--lf-taupe-deep); cursor: not-allowed;
}
.lf-btn:disabled:hover,
.lf-btn[disabled]:hover { background: var(--lf-taupe-pale); border-color: var(--lf-taupe-pale); }

/* The panel is the last thing read before the decision, so it sits closer to
   the button than to the copy above it. */
.lf-pdp__buy { margin-top: .35rem; }

@media (max-width: 520px) {
  /* Three figures across a phone leaves each one about 90px; two wraps to a
     second row cleanly and keeps the numbers at a readable size. */
  .lf-dims__item { padding-right: 1.1rem; }
  .lf-dims__item:nth-child(3) { border-left: 0; padding-left: 0; }
}

@media (max-width: 900px) {
  .lf-pinfo__lede { font-size: 1.4rem; }
}

/* ==================================================================== basket
   The basket is part of the shop, not a form bolted onto it: same navy, same
   measure, same restraint. Two columns on desktop — the things you chose, and
   what they come to — collapsing to one on narrow screens with the summary
   last, because on a phone you scroll past what you bought to reach the total. */
.lf-basket { margin: 0 0 4rem; }
.lf-basket__grid {
  display: grid; gap: 3rem;
  grid-template-columns: minmax(0, 1fr) 22rem;   /* minmax(0,…): see L-022 */
  align-items: start;
}
.lf-basket__lines { min-width: 0; }
.lf-basket__lines-title {
  font-family: var(--lf-sans); font-size: .75rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--lf-taupe);
  margin: 0 0 1.2rem; padding-bottom: .9rem; border-bottom: 1px solid var(--lf-line);
}
.lf-basket__list { list-style: none; margin: 0; padding: 0; }

.lf-basket__item {
  display: grid; gap: 1.4rem; align-items: start;
  grid-template-columns: 104px minmax(0, 1fr) auto;
  padding: 1.6rem 0; border-bottom: 1px solid var(--lf-line);
}
/* A mattress chosen for a bed is shown as belonging to it, not as a second
   unrelated purchase. */
.lf-basket__item.is-linked { border-left: 2px solid var(--lf-line); padding-left: 1.2rem; }

.lf-basket__media { width: 104px; }
.lf-basket__media img {
  width: 100%; height: auto; aspect-ratio: 1; object-fit: contain;
  background: var(--lf-stone); mix-blend-mode: multiply;
}
.lf-basket__detail { min-width: 0; }
.lf-basket__link-note {
  margin: 0 0 .3rem; font-size: .75rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--lf-taupe);
}
.lf-basket__link-note span { color: var(--lf-navy); }
.lf-basket__name { margin: 0 0 .4rem; font-size: 1.05rem; line-height: 1.35; }
.lf-basket__name a { color: var(--lf-navy); text-decoration: none; }
.lf-basket__name a:hover { text-decoration: underline; }
.lf-basket__detail dl,
.lf-basket__detail .variation { margin: .3rem 0 .6rem; font-size: .85rem; color: var(--lf-taupe-deep); }
.lf-basket__detail dt { font-weight: 500; display: inline; }
.lf-basket__detail dd { display: inline; margin: 0 .8rem 0 .25rem; }
.lf-basket__detail dd p { display: inline; margin: 0; }

.lf-basket__controls { display: flex; align-items: center; gap: 1rem; margin-top: .7rem; }
.lf-basket__controls .quantity input {
  width: 4.2rem; padding: .45rem .5rem; text-align: center;
  border: 1px solid var(--lf-line); background: #fff; font: inherit; font-size: .9rem;
}
.lf-basket__remove {
  font-size: .8rem; color: var(--lf-taupe); text-decoration: none;
  /*
   * A standalone control, so it has to be reachable: WCAG 2.5.8 asks for at
   * least 24x24 CSS pixels and the text alone came to 44x22. Inline-flex with a
   * min-height gives it the target without moving anything around it. (Links
   * inside a sentence are exempt — this is not one.)
   */
  display: inline-flex; align-items: center;
  min-height: 24px; padding-block: 1px;
  border-bottom: 1px solid transparent;
}
.lf-basket__remove:hover, .lf-basket__remove:focus-visible {
  color: var(--lf-navy); border-bottom-color: currentColor;
}
.lf-basket__price { margin: 0; font-size: 1rem; white-space: nowrap; text-align: right; }

.lf-basket__actions {
  display: flex; align-items: center; gap: 1.4rem; flex-wrap: wrap; margin-top: 1.6rem;
}
/* 24px minimum — it sits beside a button, so it is a control, not a link in a
   sentence. It measured 14px tall. */
.lf-basket__continue {
  display: inline-flex; align-items: center; min-height: 24px;
  font-size: .875rem; color: var(--lf-taupe); text-decoration: underline;
}
.lf-basket__continue:hover { color: var(--lf-navy); }

/* ---- summary ---- */
.lf-basket__summary { min-width: 0; position: sticky; top: 6rem; }
.lf-summary { background: var(--lf-stone); padding: 1.75rem; }
.lf-summary__title {
  font-family: var(--lf-sans); font-size: .75rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--lf-taupe);
  margin: 0 0 1.1rem;
}
.lf-summary__rows { margin: 0 0 1.1rem; }
.lf-summary__row { display: flex; justify-content: space-between; gap: 1rem; padding: .45rem 0; }
.lf-summary__row dt { margin: 0; color: var(--lf-taupe-deep); font-size: .92rem; }
.lf-summary__row dd { margin: 0; font-size: .92rem; }
.lf-summary__row--total {
  border-top: 1px solid var(--lf-line); margin-top: .5rem; padding-top: .9rem;
}
.lf-summary__row--total dt, .lf-summary__row--total dd { font-size: 1.1rem; color: var(--lf-navy); }
.lf-summary__note { margin: 0 0 1.2rem; font-size: .78rem; line-height: 1.5; color: var(--lf-taupe); }
.lf-summary__cta { display: block; width: 100%; text-align: center; }

.lf-basket-empty { text-align: center; padding: 4rem 0 5rem; }
.lf-basket-empty h2 { margin: 0 0 .6rem; }
.lf-basket-empty p { margin: 0 auto 1.6rem; max-width: 34rem; color: var(--lf-taupe-deep); }

/* ---- checkout ---- */
.lf-checkout__gate {
  margin: 0 0 2rem; padding: .9rem 1.1rem; font-size: .875rem; line-height: 1.55;
  background: var(--lf-stone); border-left: 3px solid var(--lf-taupe);
}
.lf-checkout__gate p { margin: 0; }

@media (max-width: 900px) {
  .lf-basket__grid { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .lf-basket__summary { position: static; }
}
@media (max-width: 560px) {
  .lf-basket__item { grid-template-columns: 76px minmax(0, 1fr); gap: 1rem; }
  .lf-basket__media { width: 76px; }
  /* The price moves under the details rather than squeezing a third column. */
  .lf-basket__price { grid-column: 2; text-align: left; margin-top: .5rem; }
}

/* ================================================================== checkout
   Two columns: what we need from you, and what you are buying. The summary is
   sticky on desktop so the total stays visible while the form is filled, and
   drops below the form on narrow screens — nobody fills an address on a phone
   while looking at a price rail. */
.woocommerce-checkout .lf-wrap > h1 { margin-bottom: 2rem; }

form.checkout.woocommerce-checkout {
  display: grid;
  column-gap: 3rem; row-gap: .75rem;
  grid-template-columns: minmax(0, 1fr) 23rem;
  /*
   * Row 1 hugs the summary heading. Without an explicit size, the details
   * column — which spans both rows — distributes its considerable height across
   * them, inflating row 1 and stranding the summary ~280px below its own title.
   */
  grid-template-rows: min-content 1fr;
  align-items: start;
}
/*
 * Explicit placement. The three children arrive in DOM order — details,
 * heading, review — so on a two-column grid the heading landed in row 1 of the
 * right column and the review fell to row 2, leaving the summary marooned far
 * below its own title. The details span both rows; the heading and its panel
 * sit together.
 */
.woocommerce-checkout #customer_details { min-width: 0; grid-column: 1; grid-row: 1 / span 2; }
.woocommerce-checkout #order_review_heading { grid-column: 2; grid-row: 1; min-width: 0; }
.woocommerce-checkout #order_review { grid-column: 2; grid-row: 2; min-width: 0; }
.woocommerce-checkout #order_review_heading {
  font-family: var(--lf-sans); font-size: .75rem; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase; color: var(--lf-taupe);
  margin: 0 0 1rem;
}
.woocommerce-checkout #order_review { position: sticky; top: 6rem; background: var(--lf-stone); padding: 1.75rem; align-self: start; }

.woocommerce-checkout h3 {
  font-size: 1.15rem; margin: 0 0 1.1rem; padding-bottom: .8rem;
  border-bottom: 1px solid var(--lf-line);
}
.woocommerce-checkout .form-row { margin: 0 0 1.1rem; display: block; }
.woocommerce-checkout .form-row label {
  display: block; font-size: .8rem; letter-spacing: .04em; color: var(--lf-taupe-deep);
  margin-bottom: .35rem;
}
.woocommerce-checkout .form-row .required { color: var(--lf-navy); text-decoration: none; }
.woocommerce-checkout .input-text,
.woocommerce-checkout select,
.woocommerce-checkout .select2-selection {
  width: 100%; padding: .7rem .8rem; font: inherit; font-size: .95rem;
  border: 1px solid var(--lf-line); background: #fff; border-radius: 0;
  transition: border-color .2s var(--lf-ease);
}
.woocommerce-checkout .input-text:focus,
.woocommerce-checkout select:focus { outline: 2px solid var(--lf-navy); outline-offset: 1px; border-color: var(--lf-navy); }
/* Two-up on the fields that genuinely pair. */
@media (min-width: 700px) {
  .woocommerce-checkout .form-row-first,
  .woocommerce-checkout .form-row-last { display: inline-block; width: calc(50% - .55rem); }
  .woocommerce-checkout .form-row-first { margin-right: 1rem; }
}

.woocommerce-checkout .shop_table { width: 100%; border-collapse: collapse; font-size: .92rem; }
.woocommerce-checkout .shop_table th,
.woocommerce-checkout .shop_table td { padding: .55rem 0; text-align: left; vertical-align: top; }
.woocommerce-checkout .shop_table td:last-child,
.woocommerce-checkout .shop_table th:last-child { text-align: right; white-space: nowrap; }
.woocommerce-checkout .shop_table thead th {
  font-size: .72rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--lf-taupe); border-bottom: 1px solid var(--lf-line); padding-bottom: .7rem;
}
.woocommerce-checkout .shop_table .order-total th,
.woocommerce-checkout .shop_table .order-total td {
  border-top: 1px solid var(--lf-line); padding-top: .9rem; font-size: 1.1rem; color: var(--lf-navy);
}
.woocommerce-checkout .shop_table .variation { font-size: .8rem; color: var(--lf-taupe); margin: .2rem 0 0; }

.woocommerce-checkout #payment { background: transparent; margin-top: 1.4rem; }
.woocommerce-checkout #payment .woocommerce-info,
.woocommerce-checkout .woocommerce-notice--info {
  background: #fff; border: 1px solid var(--lf-line); padding: .85rem 1rem;
  font-size: .85rem; line-height: 1.55; color: var(--lf-taupe-deep); margin: 0 0 1rem;
}
.woocommerce-checkout #place_order {
  width: 100%; margin-top: .5rem; padding: .95rem 1.2rem;
  background: var(--lf-navy); color: #fff; border: 0; cursor: pointer;
  font-family: var(--lf-sans); font-size: .8rem; letter-spacing: .14em; text-transform: uppercase;
  transition: background .25s var(--lf-ease);
}
.woocommerce-checkout #place_order:hover:not(:disabled) { background: #0d1b2a; }
.woocommerce-checkout #place_order:disabled { opacity: .45; cursor: not-allowed; }
.woocommerce-checkout .woocommerce-terms-and-conditions-wrapper { margin: 1rem 0 0; font-size: .85rem; }

@media (max-width: 900px) {
  form.checkout.woocommerce-checkout { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .woocommerce-checkout #customer_details { grid-column: 1; grid-row: auto; }
  .woocommerce-checkout #order_review_heading,
  .woocommerce-checkout #order_review { grid-column: 1; grid-row: auto; position: static; }
}

@media (max-width: 900px) {
  /* Smaller, but still intentional: the same rhythm compressed, not abandoned. */
  .lf-pinfo__prose h3:not(.lf-pinfo__lede) { margin-top: 2.6rem; }
  .lf-pinfo__lede + p + h3:not(.lf-pinfo__lede) { margin-top: 3rem; }
  .lf-pinfo__faq { margin-top: 2.75rem; }
}

/* --------------------------------------------------------------------------
   ORDER TRACKER  (Phase 13)

   Five steps, shown on the confirmation page and on the My Account order view.

   NOT COLOUR-ALONE. The current step is marked three ways — a filled dot, a
   heavier weight, and the words "where your order is now" — because the whole
   point of the component is to answer a question, and a customer who cannot
   distinguish the navy dot from the taupe one must still get the answer.

   No dates appear anywhere in it, by design: a date beside a future step is a
   delivery promise however quietly it is styled, and no lead time has been
   agreed with the supplier.
   -------------------------------------------------------------------------- */
.lf-track {
  margin: 0 0 2rem; padding: 1.5rem 1.6rem 1.35rem;
  background: var(--lf-ivory); border: 1px solid var(--lf-taupe-pale);
}
.lf-track__title {
  font-family: var(--lf-sans); font-size: .74rem; letter-spacing: .18em;
  text-transform: uppercase; font-weight: 400; color: var(--lf-taupe);
  margin: 0 0 1.15rem;
}
.lf-track__steps { list-style: none; margin: 0 0 1.1rem; padding: 0; display: grid; gap: .55rem; }
.lf-track__step {
  position: relative; padding-left: 1.9rem; min-height: 24px;
  font-family: var(--lf-sans); font-size: .93rem; line-height: 1.5;
  color: var(--lf-taupe-mid);
}
.lf-track__dot {
  position: absolute; left: 0; top: .34rem;
  width: 11px; height: 11px; border-radius: 50%;
  border: 1px solid var(--lf-taupe-mid); background: var(--lf-white);
}
/* The rule joining the steps, drawn from each dot to the next. */
.lf-track__step + .lf-track__step .lf-track__dot::before {
  content: ""; position: absolute; left: 50%; bottom: 100%;
  width: 1px; height: .55rem; transform: translateX(-50%);
  background: var(--lf-taupe-pale);
}
.lf-track__step.is-done { color: var(--lf-navy); }
.lf-track__step.is-done .lf-track__dot { background: var(--lf-taupe-mid); border-color: var(--lf-taupe-mid); }
.lf-track__step.is-current { color: var(--lf-navy); font-weight: 500; }
.lf-track__step.is-current .lf-track__dot {
  background: var(--lf-navy); border-color: var(--lf-navy);
  box-shadow: 0 0 0 3px rgba(0, 20, 46, .12);
}
.lf-track__now { color: var(--lf-taupe); font-weight: 400; font-size: .86rem; }
.lf-track__text, .lf-track__off {
  font-family: var(--lf-sans); font-size: .93rem; line-height: 1.6;
  color: var(--lf-navy-60); margin: 0;
}
.lf-track__off { color: var(--lf-navy); font-size: 1.05rem; margin: 0 0 .5rem; }
.lf-track__ref {
  font-family: var(--lf-sans); font-size: .88rem; color: var(--lf-taupe);
  margin: .55rem 0 0;
}
.lf-track a { color: var(--lf-navy); }

/* From the tablet breakpoint the five steps read better across than down —
   but only where all five genuinely fit, hence a five-column grid rather than
   flex wrapping, which would strand one step on a line of its own. */
@media (min-width: 48rem) {
  .lf-track__steps { grid-template-columns: repeat(5, 1fr); gap: 0; }
  .lf-track__step { padding: 1.5rem .6rem 0 0; min-height: 0; }
  .lf-track__dot { top: 0; left: 0; }
  /* The connector spans the GAP BETWEEN two dots, so it has to be measured
     against the step (one grid column wide), not against the 11px dot. Hung on
     the dot, `width: calc(100% + .6rem)` resolved to about 21px and drew a
     short dash floating beside each step instead of a joined track. */
  .lf-track__step + .lf-track__step .lf-track__dot::before { content: none; }
  .lf-track__step + .lf-track__step::before {
    content: ""; position: absolute; top: 5px; height: 1px;
    left: calc(-100% + 15px); width: calc(100% - 19px);
    background: var(--lf-taupe-pale);
  }
  .lf-track__step.is-done + .lf-track__step::before,
  .lf-track__step.is-current::before { background: var(--lf-taupe-mid); }
  .lf-track__now { display: block; }
}

/* --------------------------------------------------------------------------
   MY ACCOUNT  (Phase 13)

   Not a redesign of the account area — it had no design at all. WooCommerce's
   markup was rendering raw: the navigation as a bulleted list, the order
   history as an unstyled table, and the order number inside a <mark>, which
   browsers paint highlighter-yellow. Phase 13 made these pages part of the
   customer's answer to "where is my order?", so they have to look like the
   shop they belong to.

   Everything below styles WooCommerce's own classes. No markup was replaced.
   -------------------------------------------------------------------------- */
.woocommerce-MyAccount-navigation ul {
  list-style: none; margin: 0; padding: 0;
  border-top: 1px solid var(--lf-taupe-pale);
}
.woocommerce-MyAccount-navigation li { margin: 0; border-bottom: 1px solid var(--lf-taupe-pale); }
.woocommerce-MyAccount-navigation a {
  display: block; padding: .85rem .2rem;
  font-family: var(--lf-sans); font-size: .95rem; color: var(--lf-navy-60);
  text-decoration: none;
}
.woocommerce-MyAccount-navigation a:hover,
.woocommerce-MyAccount-navigation a:focus-visible { color: var(--lf-navy); }
.woocommerce-MyAccount-navigation .is-active a { color: var(--lf-navy); font-weight: 500; }

.woocommerce-MyAccount-content {
  /* min-width:0 so the content column may shrink inside the grid; overflow-x
     so the order table scrolls INSIDE it rather than pushing the page sideways.
     The order history carries a total, an item count and an action in one row,
     which is wider than a 390px screen however the padding is tuned. */
  min-width: 0; overflow-x: auto;
}
.woocommerce-MyAccount-content p,
.woocommerce-MyAccount-content li { font-family: var(--lf-sans); color: var(--lf-navy-60); }

/* The order number arrives inside a <mark>. Left alone it is highlighter-yellow. */
.woocommerce-account mark, .woocommerce-order-details mark, .lf-track mark {
  background: none; color: var(--lf-navy); font-weight: 500;
}

/* Order history, addresses and downloads all use this one table class. */
.woocommerce-account table.woocommerce-orders-table,
.woocommerce-account table.shop_table,
.woocommerce-order-details table.shop_table {
  width: 100%; border-collapse: collapse; margin: 0 0 1.6rem;
  font-family: var(--lf-sans); font-size: .95rem;
}
.woocommerce-account table.shop_table th,
.woocommerce-order-details table.shop_table th,
.woocommerce-account table.woocommerce-orders-table th {
  text-align: left; padding: .7rem .8rem .7rem 0;
  font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  font-weight: 400; color: var(--lf-taupe);
  border-bottom: 1px solid var(--lf-navy);
}
.woocommerce-account table.shop_table td,
.woocommerce-order-details table.shop_table td,
.woocommerce-account table.woocommerce-orders-table td {
  padding: .95rem .8rem .95rem 0; vertical-align: top;
  border-bottom: 1px solid var(--lf-taupe-pale); color: var(--lf-navy);
}
.woocommerce-account table.shop_table tfoot th,
.woocommerce-order-details table.shop_table tfoot th { border-bottom: none; border-top: 1px solid var(--lf-taupe-pale); }

/* The action column is a link doing a button's job — give it the target size. */
.woocommerce-orders-table__cell-order-actions a,
.woocommerce-MyAccount-content .button, .woocommerce-MyAccount-content .woocommerce-Button {
  display: inline-flex; align-items: center; min-height: 40px;
  padding: 0 1.1rem; border: 1px solid var(--lf-navy);
  font-family: var(--lf-sans); font-size: .82rem; letter-spacing: .02em;
  color: var(--lf-navy); text-decoration: none; background: none;
}
.woocommerce-orders-table__cell-order-actions a:hover,
.woocommerce-MyAccount-content .button:hover { background: var(--lf-navy); color: var(--lf-white); }

/* Chosen options under an order line — the same quiet treatment as the basket. */
.woocommerce-order-details .wc-item-meta,
.woocommerce-account .wc-item-meta {
  list-style: none; margin: .35rem 0 0; padding: 0;
  font-size: .86rem; color: var(--lf-taupe);
}
.woocommerce-order-details .wc-item-meta li { margin: 0 0 .1rem; }
.woocommerce-order-details .wc-item-meta p, .woocommerce-order-details .wc-item-meta strong {
  display: inline; margin: 0; font-weight: 400;
}

.woocommerce-customer-details address {
  font-style: normal; font-family: var(--lf-sans); font-size: .95rem;
  line-height: 1.7; color: var(--lf-navy-60);
  padding: 1rem 1.15rem; border: 1px solid var(--lf-taupe-pale); background: var(--lf-ivory);
}

.woocommerce-message, .woocommerce-info, .woocommerce-error, .woocommerce-notice {
  font-family: var(--lf-sans); font-size: .93rem; line-height: 1.6;
  padding: .95rem 1.15rem; margin: 0 0 1.4rem;
  border: 1px solid var(--lf-taupe-pale); background: var(--lf-ivory); color: var(--lf-navy);
  list-style: none;
}
.woocommerce-error { border-color: #B3261E; background: #FDF3F2; }

/* Two columns from the tablet breakpoint: a quiet rail, then the content. */
@media (min-width: 48rem) {
  .woocommerce-account .woocommerce {
    display: grid; grid-template-columns: 13rem minmax(0, 1fr); gap: 3rem; align-items: start;
  }
  .woocommerce-account .woocommerce-MyAccount-navigation { grid-column: 1; }
  .woocommerce-account .woocommerce-MyAccount-content { grid-column: 2; }
}

/* ================================================== CATEGORY ARCHIVE (pilot)
   Hero, subcategory navigation, sort, active-filter chips, pagination.
   The grid, cards and filter drawer are the existing components — nothing
   below restyles them.                                                      */

.lf-archive__head { align-items: end; }
.lf-archive__title { min-width: 0; }
.lf-archive__head .lf-eyebrow { color: var(--lf-gold); margin-bottom: .7rem; }
.lf-archive__head h1 { margin-bottom: 0; }
.lf-archive__tagline {
  font-family: var(--lf-serif); font-weight: 400; color: var(--lf-navy);
  font-size: clamp(1.15rem, 1.8vw, 1.5rem); line-height: 1.2; margin: .45rem 0 0;
  letter-spacing: -.01em;
}
.lf-archive__intro { margin-top: .9rem; }
.lf-archive__intro p { margin: 0; max-width: 62ch; }

/* ---- shop by type ---- */
.lf-subcats { padding-block: clamp(1.75rem, 3vw, 2.75rem) 0; }
.lf-subcats__label {
  margin: 0 0 1rem; font-size: .655rem; letter-spacing: .19em;
  text-transform: uppercase; color: var(--lf-taupe);
}
/* A FIXED four-up track. `auto-fit` stretched a two-child category into two
   half-page tiles 660px tall — the row is navigation, not a feature panel, so
   the tile size must not depend on how many children happen to exist. */
.lf-subcats__grid {
  list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(.7rem, 1.3vw, 1.15rem);
}
@media (max-width: 1100px) { .lf-subcats__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 720px)  { .lf-subcats__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.lf-subcats__grid a {
  display: block; background: #FFFFFF; border: 1px solid var(--lf-line);
  border-radius: 3px; overflow: hidden; height: 100%;
  transition: border-color .25s var(--lf-ease);
}
.lf-subcats__media {
  display: block; position: relative; overflow: hidden;
  aspect-ratio: 1.35; background: #FBFAF8;
}
.lf-subcats__media img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; max-width: none; mix-blend-mode: multiply;
  transition: transform .4s var(--lf-ease);
}
.lf-subcats__body { display: block; padding: .85rem clamp(.75rem, 1.2vw, 1rem) 1rem; }
.lf-subcats__name {
  display: block; font-family: var(--lf-serif); font-size: 1.02rem;
  color: var(--lf-navy); line-height: 1.25;
}
.lf-subcats__count {
  display: block; margin-top: .3rem; font-size: .68rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--lf-taupe);
}
@media (hover: hover) and (pointer: fine) {
  .lf-subcats__grid a:hover { border-color: var(--lf-line-strong); }
  .lf-subcats__grid a:hover .lf-subcats__media img { transform: scale(1.03); }
}
.lf-subcats__grid a:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 3px; }

/* ---- sort ---- */
.lf-sort { display: inline-flex; align-items: center; gap: .55rem; margin-left: auto; }
.lf-sort label {
  font-size: .655rem; letter-spacing: .17em; text-transform: uppercase; color: var(--lf-taupe);
}
.lf-sort select {
  font-family: var(--lf-sans); font-size: .82rem; color: var(--lf-navy);
  background: #FFFFFF; border: 1px solid var(--lf-line-strong); border-radius: 2px;
  padding: .55rem 2rem .55rem .7rem; min-height: 44px; cursor: pointer;
  appearance: none; -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--lf-navy) 50%),
                    linear-gradient(135deg, var(--lf-navy) 50%, transparent 50%);
  background-position: calc(100% - 15px) 50%, calc(100% - 10px) 50%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.lf-sort select:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }

/* ---- active filter chips ---- */
.lf-chips { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1rem 0 0; }
.lf-chips[hidden] { display: none; }
.lf-chip {
  display: inline-flex; align-items: center; gap: .45rem; min-height: 34px;
  padding: .35rem .7rem; border-radius: 2px;
  background: var(--lf-cream); border: 1px solid var(--lf-gold-line);
  font-size: .76rem; color: var(--lf-navy);
  transition: border-color .2s var(--lf-ease);
}
.lf-chip svg { width: 12px; height: 12px; stroke: var(--lf-gold); }
.lf-chip:hover { border-color: var(--lf-gold); }
.lf-chip:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }
.lf-chip--clear { background: transparent; border-color: transparent; color: var(--lf-taupe-deep); text-decoration: underline; }
/* The chips are links now, not buttons a script built. */
.lf-chip[href] { cursor: pointer; text-decoration: none; }
.lf-chip[href] span[aria-hidden] { color: var(--lf-gold); font-size: .95em; line-height: 1; }

/* ---- filter option that would return nothing ----
   Disabled rather than removed: an option that disappears when you tick its
   neighbour reads as a fault, and the count still tells the truth. */
.lf-filter__panel label.is-unavailable { opacity: .38; cursor: not-allowed; }
.lf-filter__panel label.is-unavailable input { cursor: not-allowed; }

/* While the server is answering. Deliberately faint — the results are usually
   back before it is perceptible, and a spinner on a 40ms request is noise. */
.lf-filterbar.is-loading { cursor: progress; }
[data-lf-resultsregion][aria-busy="true"] { opacity: .55; transition: opacity .18s var(--lf-ease); }

/* ---- empty state ---- */
.lf-noresults { padding: clamp(2.5rem, 5vw, 4rem) 0; text-align: center; }
.lf-noresults p { margin: 0 0 1.1rem; color: var(--lf-taupe-deep); }
.lf-noresults .lf-btn { display: inline-flex; width: auto; }

/* ---- pagination ---- */
.lf-pagination {
  display: flex; flex-wrap: wrap; justify-content: center; gap: .4rem;
  margin-top: clamp(2.5rem, 4vw, 3.5rem);
}
.lf-pagination .page-numbers {
  display: grid; place-items: center; min-width: 44px; min-height: 44px;
  padding: 0 .7rem; border: 1px solid var(--lf-line); border-radius: 2px;
  font-size: .85rem; color: var(--lf-navy);
  transition: border-color .2s var(--lf-ease), background .2s var(--lf-ease);
}
.lf-pagination .page-numbers:hover { border-color: var(--lf-line-strong); }
.lf-pagination .page-numbers.current {
  background: var(--lf-navy); border-color: var(--lf-navy); color: #FFFFFF;
}
.lf-pagination .page-numbers:focus-visible { outline: 2px solid var(--lf-navy); outline-offset: 2px; }

@media (max-width: 860px) {
  .lf-sort { margin-left: 0; }
  .lf-sort label { display: none; }   /* the select's own value says what it is */
}

/* --------------------------------------------------------------------------
   HEADER SEARCH, SUB-NAVIGATION, CATEGORY LINKS, EMPTY STATES  (Phase 14)

   Three of the four header icons went nowhere and there was no search anywhere
   in the theme. These are the surfaces that fixes that, plus the shared
   dead-end treatment used by the 404 page and an empty search.
   -------------------------------------------------------------------------- */

/* ---- search panel ---- */
/* The panel is a band the header opens into, not a form that appears below it:
   one hairline-ruled field running most of the width, the label as a small
   eyebrow above it, and the button reduced to a word. A boxed input with a
   filled button read as an admin search inside an editorial header. */
.lf-search__panel {
  border-top: 1px solid var(--lf-line);
  background: var(--lf-white);
  padding: clamp(1.4rem, 2.6vw, 2rem) 0 clamp(1.2rem, 2.2vw, 1.6rem);
}
.lf-search__panel--inline { border: 0; padding: 1.4rem 0 0; background: none; }
.lf-search__form {
  display: flex; flex-wrap: wrap; gap: .6rem 1.5rem; align-items: baseline;
}
.lf-search__label {
  flex: 0 0 100%; font-family: var(--lf-sans); font-size: .68rem;
  letter-spacing: .18em; text-transform: uppercase; color: var(--lf-taupe);
  margin-bottom: .35rem;
}
.lf-search__input {
  flex: 1 1 20rem; min-width: 0; min-height: 48px; padding: 0 0 .55rem;
  font-family: var(--lf-serif); font-size: clamp(1.35rem, 2.4vw, 1.9rem);
  font-weight: 400; letter-spacing: -.01em; color: var(--lf-navy);
  background: none; border: 0; border-bottom: 1px solid var(--lf-line-strong);
  border-radius: 0; -webkit-appearance: none; appearance: none;
}
.lf-search__input::placeholder { color: var(--lf-taupe-mid); opacity: 1; }
.lf-search__input:focus { outline: none; border-bottom-color: var(--lf-navy); }
.lf-search__input:focus-visible { outline: none; border-bottom-color: var(--lf-navy); }
/* The submit is a word on a rule, matching `.lf-new__all` and
   `.lf-timeless__link` — the page's existing way of writing an action. */
.lf-search__submit.lf-search__submit {
  flex: 0 0 auto; min-height: 44px; align-self: flex-end;
  background: none; border: 0; border-bottom: 1px solid var(--lf-line-strong);
  border-radius: 0; padding: 0 0 .45rem; color: var(--lf-navy);
  font-size: .74rem; letter-spacing: .18em; text-transform: uppercase;
  transition: border-color .25s var(--lf-ease);
}
.lf-search__submit.lf-search__submit:hover { background: none; color: var(--lf-navy); border-bottom-color: var(--lf-navy); }
.lf-search__pages { margin: 3rem 0 0; }
.lf-search__pages h2 {
  font-family: var(--lf-sans); font-size: .74rem; letter-spacing: .18em;
  text-transform: uppercase; font-weight: 400; color: var(--lf-taupe); margin: 0 0 .9rem;
}
.lf-search__pages ul { list-style: none; margin: 0; padding: 0; }
.lf-search__pages li { border-bottom: 1px solid var(--lf-taupe-pale); }
.lf-search__pages a {
  display: block; padding: .85rem 0; font-family: var(--lf-sans);
  color: var(--lf-navy); text-decoration: none;
}

/* ---- desktop sub-navigation ----
   Absolutely positioned so opening it never moves the page, and hidden by
   visibility rather than display so the links stay focusable in source order
   for the moment focus enters the item. */
.lf-nav__item { position: relative; }
.lf-subnav {
  position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  min-width: 14rem; padding: .55rem 0;
  background: var(--lf-white); border: 1px solid var(--lf-taupe-pale);
  box-shadow: 0 14px 34px rgba(0, 20, 46, .10);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .14s ease, visibility .14s ease;
  z-index: 60;
}
.lf-nav__item.is-open > .lf-subnav { opacity: 1; visibility: visible; pointer-events: auto; }
.lf-subnav ul { list-style: none; margin: 0; padding: 0; }
.lf-subnav a {
  display: flex; align-items: center; justify-content: space-between; gap: 1.4rem;
  min-height: 40px; padding: .1rem 1.15rem;
  font-family: var(--lf-sans); font-size: .9rem; letter-spacing: 0;
  text-transform: none; color: var(--lf-navy-60); text-decoration: none; white-space: nowrap;
}
.lf-subnav a:hover, .lf-subnav a:focus-visible { color: var(--lf-navy); background: var(--lf-ivory); }
.lf-subnav a span { color: var(--lf-taupe-mid); font-size: .78rem; }
.lf-subnav__all { border-bottom: 1px solid var(--lf-taupe-pale); margin-bottom: .35rem; padding-bottom: .35rem; }
.lf-subnav__all a { color: var(--lf-navy); }

/* ---- mobile accordion ---- */
.lf-mobilenav__item { border-bottom: 1px solid var(--lf-taupe-pale); }
.lf-mobilenav__row { display: flex; align-items: stretch; }
.lf-mobilenav__row > a { flex: 1 1 auto; }
.lf-mobilenav__toggle {
  flex: 0 0 auto; width: 52px; min-height: 52px;
  display: grid; place-items: center;
  background: none; border: 0; border-left: 1px solid var(--lf-taupe-pale); cursor: pointer;
}
.lf-mobilenav__toggle .chev {
  width: 9px; height: 9px; border-right: 1.5px solid var(--lf-navy-60);
  border-bottom: 1.5px solid var(--lf-navy-60); transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .16s ease;
}
.lf-mobilenav__toggle[aria-expanded="true"] .chev { transform: rotate(-135deg) translate(-2px, -2px); }
/*
 * `[hidden]` HAS TO WIN, AND IN THIS FILE IT DOES NOT BY DEFAULT.
 *
 * The user agent's `[hidden] { display: none }` is a single class-less rule,
 * so ANY author rule setting `display` on the same element beats it. That has
 * now caused two visible defects: the empty basket/wishlist badge rendered as a
 * permanent navy dot, and this sub-list opened already expanded. A global guard
 * is blunt, but the alternative is remembering the rule at every new component
 * — and it has already been forgotten twice.
 */
[hidden] { display: none !important; }
.lf-mobilenav__sub { list-style: none; margin: 0; padding: 0 0 .5rem; background: var(--lf-ivory); }
.lf-mobilenav__sub a {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 46px; padding: 0 1.1rem 0 2rem;
  font-family: var(--lf-sans); font-size: .93rem; color: var(--lf-navy-60); text-decoration: none;
}
.lf-mobilenav__sub a span { color: var(--lf-taupe-mid); font-size: .8rem; }

/* ---- rooms list: the shared dead-end recovery ---- */
.lf-empty-state { max-width: 46rem; padding: clamp(1rem, 3vw, 2rem) 0 0; }
.lf-empty-state h2 {
  font-family: var(--lf-serif); font-weight: 400; color: var(--lf-navy);
  font-size: clamp(1.4rem, 2.4vw, 1.9rem); line-height: 1.2; margin: 0 0 .7rem;
}
.lf-empty-state p {
  font-family: var(--lf-sans); font-size: 1rem; line-height: 1.65;
  color: var(--lf-navy-60); margin: 0 0 1.6rem;
}
.lf-empty-state em { font-style: normal; color: var(--lf-navy); }
.lf-catlinks {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: .5rem; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
.lf-catlinks a {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  min-height: 56px; padding: 0 1.15rem;
  border: 1px solid var(--lf-taupe-pale); background: var(--lf-white);
  font-family: var(--lf-sans); font-size: .96rem; color: var(--lf-navy); text-decoration: none;
  transition: border-color .14s ease, background .14s ease;
}
.lf-catlinks a:hover, .lf-catlinks a:focus-visible {
  border-color: var(--lf-navy); background: var(--lf-ivory);
}
.lf-catlinks__n { color: var(--lf-taupe-mid); font-size: .82rem; }

/* The newsletter block keeps its place; the form that silently discarded
   addresses does not. */
.lf-signup__pending {
  font-family: var(--lf-sans); font-size: .95rem; line-height: 1.65;
  color: var(--lf-navy-60); margin: .9rem 0 0;
}
.lf-signup__pending a { color: var(--lf-navy); }

/* ===================================================== CATEGORY BUYING GUIDE
   The lower guide, on the WHITE page canvas. Warm surfaces are used only
   inside the cards; nothing here paints a full-width band.                  */

.lf-guide { background: #FFFFFF; }
.lf-guide__head { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
.lf-guide__head .lf-eyebrow { color: var(--lf-gold); margin-bottom: .6rem; }
.lf-guide__head h2 {
  font-family: var(--lf-serif); font-weight: 500; color: var(--lf-navy);
  font-size: clamp(1.5rem, 2.4vw, 2rem); line-height: 1.14; margin: 0; letter-spacing: -.015em;
}

/* Prose blocks sit side by side rather than stacking into an article. Three
   short columns read as guidance; the same words in one column read as a
   page of text the shopper has to get past. */
/* The guide overrides the single-column reading measure. `.lf-ed--single`
   caps the main column at 74ch for prose, which is right for a guide page and
   wrong here — it left three cards huddled in the middle 44% of the archive
   with empty margins either side. */
.lf-guide .lf-ed,
.lf-guide .lf-ed--single { max-width: none; margin-inline: 0; }
.lf-guide .lf-ed__main {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 2vw, 1.75rem); align-items: start;
  max-width: none; margin-inline: 0;
}
.lf-guide .lf-ed__block {
  background: var(--lf-cream); border: 1px solid var(--lf-line); border-radius: 4px;
  padding: clamp(1.1rem, 1.8vw, 1.5rem); margin: 0;
}
.lf-guide .lf-ed__block h2 {
  font-family: var(--lf-serif); font-weight: 500; color: var(--lf-navy);
  font-size: 1.12rem; line-height: 1.25; margin: 0 0 .7rem; letter-spacing: -.005em;
}
.lf-guide .lf-ed__block h2::before {
  content: ""; display: block; width: 26px; height: 1px;
  background: var(--lf-gold); margin-bottom: .8rem;
}
.lf-guide .lf-ed__block p { margin: 0 0 .7rem; font-size: .88rem; line-height: 1.65; color: var(--lf-taupe-deep); }
.lf-guide .lf-ed__block p:last-child { margin-bottom: 0; }

/* `.lf-ed__block`'s 70ch reading measure is right for a one-column guide page
   and wrong here: it capped the two full-span blocks at 630px inside a 1354px
   row, so `grid-column: 1 / -1` was being granted and then thrown away. */
.lf-guide .lf-ed__block { max-width: none; }

/* The size table and the FAQ span the row: a table squeezed into a third of
   the row stops being readable, and the questions close the guide rather than
   competing as one of three options. */
.lf-guide .lf-ed__block--sizes,
.lf-guide .lf-ed__block--wide,
.lf-guide .lf-ed__main > #ed-faq { grid-column: 1 / -1; }

/* Spanning the row is only worth it if the width is used. Both full-span
   blocks split into explanation and content side by side; below the desktop
   breakpoint the halves stack in source order with no extra rules. */
@media (min-width: 901px) {
  .lf-guide .lf-ed__block--sizes,
  .lf-guide .lf-ed__main > #ed-faq {
    display: grid; align-items: start;
    column-gap: clamp(1.75rem, 3.5vw, 3.5rem);
  }
  .lf-guide .lf-ed__block--sizes { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .lf-guide .lf-ed__main > #ed-faq { grid-template-columns: minmax(0, .8fr) minmax(0, 2.2fr); }
  .lf-guide .lf-ed__block--sizes .lf-ed__tablewrap { margin-top: 0; }
}
.lf-guide .lf-ed__tablewrap { overflow-x: auto; margin-top: .9rem; }
.lf-guide .lf-ed__table { width: 100%; border-collapse: collapse; font-size: .86rem; }
.lf-guide .lf-ed__table th,
.lf-guide .lf-ed__table td { text-align: left; padding: .6rem .8rem .6rem 0; border-bottom: 1px solid var(--lf-gold-line); white-space: nowrap; }
.lf-guide .lf-ed__table th {
  font-size: .6rem; letter-spacing: .17em; text-transform: uppercase;
  color: var(--lf-taupe); font-weight: 400;
}
.lf-guide .lf-ed__table td { color: var(--lf-navy); }
.lf-guide .lf-ed__table tr:last-child td { border-bottom: 0; }

/* Archive card refinement — scoped to `.lf-grid--archive` so the signed-off
   homepage strips keep their exact type. Three small moves: the name carries
   more of the card, the price reads as a figure rather than a line of body
   text, and the metadata stops being the lightest thing on the page. */
.lf-grid--archive .lf-card__title { font-size: 1.21rem; }
.lf-grid--archive .lf-card__meta {
  font-size: .8rem; font-weight: 400; color: var(--lf-taupe-deep);
}
.lf-grid--archive .lf-card__price { font-size: 1.08rem; font-weight: 500; }
/* Prices land on one line across a row instead of stepping up and down with
   the length of each name. The card becomes a column and the price takes the
   slack; nothing above it is stretched, so the image stages are untouched. */
.lf-grid--archive .lf-card { display: flex; flex-direction: column; height: 100%; }
.lf-grid--archive .lf-card__media { flex: 0 0 auto; }
.lf-grid--archive .lf-card__price { margin-top: auto; padding-top: .35rem; }
@media (max-width: 560px) {
  .lf-grid--archive .lf-card__title { font-size: 1.06rem; }
  .lf-grid--archive .lf-card__meta { font-size: .76rem; }
}

/* FAQ reuses the approved product-page accordion rather than a second design.
   The accordion carries its own white card, so the block around it drops its
   cream frame — otherwise the questions sit in a card inside a card. */
.lf-guide .lf-ed__faq { grid-column: 1 / -1; margin-top: clamp(1.25rem, 2.5vw, 2rem); }
.lf-guide .lf-ed__main > #ed-faq {
  background: transparent; border: 0; padding: clamp(.5rem, 1vw, 1rem) 0 0;
}

@media (max-width: 980px) {
  .lf-guide .lf-ed__main { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .lf-guide .lf-ed__main { grid-template-columns: minmax(0, 1fr); }
  /* The base editorial table carries `min-width: 30rem` for wide data tables,
     which is 480px — wider than a 390px phone, so the mattress column was cut
     off inside the scroller. This table has three short columns and does not
     need the floor; fixed layout wraps them into equal thirds instead. */
  .lf-guide .lf-ed__table { min-width: 0; table-layout: fixed; }
  .lf-guide .lf-ed__table th,
  .lf-guide .lf-ed__table td { white-space: normal; padding-right: .5rem; }
}

/* ---- sticky filter toolbar, desktop only ----
   It follows the shopper through the GRID and stops there. A toolbar that
   travels into the buying guide and the footer is chrome, not a control.
   `.lf-archive__results` is the containing block that gives it that range —
   without it the toolbar was declared sticky and still scrolled away, because
   its own wrapper closed before the first product. */
@media (min-width: 901px) {
  .lf-archive__barwrap {
    /* The offset is the header's real measured height, published by the
       header script, so it cannot drift out of step with the header. */
    position: sticky; top: var(--lf-headh, 89px); z-index: 30;
  }
  .lf-archive__bar { border-bottom-color: transparent; }
  /* The bar lives inside the 1280px wrap, so its own background stops at the
     wrap edge and products scrolled past it either side. The backing layer is
     full-bleed; the bar's content stays in the wrap. */
  .lf-archive__barwrap::before {
    content: ""; position: absolute; z-index: -1;
    left: 50%; width: 100vw; transform: translateX(-50%);
    top: 0; bottom: 0; background: #FFFFFF;
    border-bottom: 1px solid var(--lf-line);
  }
}

/* ---- skip link ----
   Off-screen until focused rather than `display:none`, which would take it out
   of the tab order and defeat the point. */
.lf-skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  padding: .7rem 1.1rem; border-radius: 2px;
  background: var(--lf-navy); color: #FFFFFF;
  font-size: .8rem; letter-spacing: .06em; text-transform: uppercase;
}
.lf-skip:focus {
  left: 1rem; top: 1rem;
  outline: 2px solid var(--lf-gold); outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   NARROW-PHONE HEADER FIT — 2026-09-06, after the public launch.

   Measured on the live site: the header row is a three-column grid whose tracks
   do not compress —

       grid-template-columns: 48px 89.6px 188px    burger · logo · four controls
       gap 8px × 2 + padding 20px × 2

   which needs 381.6px. At 360px the browser sacrificed the right padding and
   still ran 2px past the viewport; at 320px it ran 42px past. Every page
   inherited it, so the whole site scrolled sideways on a small phone.

   This buys back 28px below 375px — 8px from each side of the padding, and the
   12px of gap between four controls that already sit 44px apart and do not
   need it. Nothing moves visually beyond those margins: the logo keeps its full
   width, all four controls stay, and the breakpoint is below the narrowest
   width the design is drawn for.

   VERIFIED AFTER: 360, 375, 390 and 430 all report zero horizontal overflow
   with the logo still at its full 48px.

   320px IS STILL 22px SHORT and is deliberately not addressed here. The header
   at that width genuinely cannot hold a 48px burger, an 89.6px logo and four
   44px controls, so closing it means removing or shrinking one of them — a
   decision about the header, not about its margins, and the header is being
   rebuilt in another session as this is written.
   -------------------------------------------------------------------------- */
@media (max-width: 374px) {
  .lf-header__inner { padding-left: 12px; padding-right: 12px; }
  .lf-actions--utility { gap: 0; }
}


/* ===========================================================================
   PDP ASSURANCE STRIP
   The band that closes the buying area, between the product grid and the
   specifications. See `inc/pdp-assurance.php` — every line in it is a
   `lomond_claim()`, so this file styles the band and never states anything.
   =========================================================================== */
.lf-assure {
  background: var(--lf-cream);
  border-top: 1px solid var(--lf-line);
  border-bottom: 1px solid var(--lf-line);
  padding: clamp(1.75rem, 3.4vw, 2.6rem) 0;
  margin: clamp(2.5rem, 4.5vw, 3.75rem) 0 0;
}
.lf-assure__grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: clamp(1.25rem, 2.6vw, 2.25rem);
  /* Four across on desktop, two on tablet, one on a phone — driven by the
     available width rather than by a breakpoint, so it also survives inside a
     narrower template without a second media query. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}
.lf-assure__item { display: flex; align-items: flex-start; gap: .85rem; }
.lf-assure__icon { flex: 0 0 auto; }
.lf-assure__icon svg {
  width: 28px; height: 28px; display: block;
  fill: none; stroke: var(--lf-gold); stroke-width: 1.35;
}
/* The star is drawn filled, so it must not also be stroked — a 1.35 stroke on
   a filled path thickens every point and turns it into a blob at 28px. */
.lf-assure__icon svg path[fill="currentColor"] { color: var(--lf-gold); }
.lf-assure__body { display: block; }
.lf-assure__title {
  display: block; font-family: var(--lf-sans); font-size: 1rem;
  font-weight: 500; line-height: 1.35; color: var(--lf-navy);
  letter-spacing: .01em;
}
.lf-assure__note {
  display: block; margin-top: .32rem;
  font-family: var(--lf-sans); font-size: .82rem; line-height: 1.5;
  color: var(--lf-taupe-deep); text-wrap: pretty;
}

/* ---------------------------------------------------------------------------
   TABLET: THE GALLERY MUST NOT EAT THE WHOLE FIRST SCREEN.
   Below 901px the grid collapses to one column, which is right — two columns in
   771px is two cramped columns. But a full-width stage then renders 771px tall
   on an 820px-wide tablet, and the title, the price and the buy button are all
   below the fold on arrival: the customer's first screen is a photograph and
   nothing else.
   Phones keep the full-bleed stage — at 390px the picture IS the first screen,
   and there is no width to give back. This band is the in-between case only.
   --------------------------------------------------------------------------- */
@media (min-width: 601px) and (max-width: 900px) {
  /*
   * CAPPED BY HEIGHT, EXPRESSED AS A WIDTH.
   *
   * A flat `max-width: 560px` fixed the square stages and did nothing for the
   * portrait ones: the stage's height is its width divided by `--lf-gal-ar`, so
   * a 0.78 ratio still rendered 680px tall on an 820px tablet and still put the
   * price below the fold. Working back from the height the first screen can
   * afford — `52vh` — and multiplying by the ratio gives the width that
   * produces it, whatever shape the product's stage happens to be.
   *
   * `min()` keeps the 560px ceiling for landscape stages, which would otherwise
   * grow wider than the column to reach 52vh.
   */
  .lf-gallery__main {
    max-width: min(560px, calc(52vh * var(--lf-gal-ar, 1)));
    margin-inline: auto;
  }
  .lf-gallery__thumbs { max-width: 560px; margin-inline: auto; }
}


/* ===========================================================================
   EDITORIAL DIVIDER  —  see `lomond_editorial_divider()`
   A section transition: centred uppercase copy between two fine gold rules.
   Restrained, spacious, editorial. Never a banner, a card or a button.
   =========================================================================== */
.lf-edivide {
  display: flex; align-items: center; justify-content: center;
  /* 18px at the top end, not 36. Measured off the approved design: the rules
     sit close to the phrase, so the three parts read as one motif rather than
     as a line, a caption and another line. */
  gap: clamp(.85rem, 1.5vw, 1.15rem);
  /* Same measure as the rest of the page, so the motif is centred on the
     content rather than on the viewport. */
  max-width: var(--lf-max); margin-inline: auto;
  padding-inline: var(--lf-gutter);
  padding-block: clamp(2.75rem, 5vw, 4.25rem);
}
/*
 * The rules SHRINK but do not grow without limit. `flex: 0 1 <basis>` lets them
 * give way to the phrase on a narrow screen while capping them at ~150px on a
 * wide one — two 500px lines either side of six words is a rule with a caption,
 * which is the opposite of the reading the design asks for.
 *
 * `border: 0` first: a bare `<hr>` carries the user agent's inset border and a
 * default margin, and both would show.
 */
.lf-edivide__rule {
  /* Capped at 100px. The design's rules are about a third of the phrase's
     width; letting them reach 150 turned the motif into a rule with a caption
     in the middle of it. */
  flex: 0 1 clamp(2.5rem, 7vw, 6.25rem);
  height: 1px; margin: 0; border: 0;
  background: var(--lf-gold-line);
}
.lf-edivide__text {
  flex: 0 0 auto;
  font-family: var(--lf-sans);
  font-size: clamp(.72rem, 1.05vw, .85rem);
  font-weight: 400; line-height: 1;
  /* .34em is what makes it read as a catalogue motif rather than as a caption
     in small caps. It is the single most important value in this component. */
  letter-spacing: .34em; text-transform: uppercase;
  /* Indent by one tracking step: letter-spacing is applied AFTER the last
     glyph too, so without this the phrase sits visually left of centre by half
     a space — the kind of drift that is invisible until it is pointed out. */
  text-indent: .34em;
  color: var(--lf-gold);
  white-space: nowrap;
}

@media (max-width: 700px) {
  .lf-edivide { gap: clamp(.7rem, 3vw, 1.1rem); padding-block: clamp(2.25rem, 8vw, 3rem); }
  /* The phrase is 26 characters; at .34em tracking it stops fitting a 350px
     column, and the choice is between shrinking it into illegibility and
     letting the rules go first. The rules go first, then the tracking eases —
     the words are the component and are never allowed below 11px. */
  .lf-edivide__rule { flex: 1 1 1.5rem; min-width: 1rem; }
  .lf-edivide__text { font-size: .69rem; letter-spacing: .2em; text-indent: .2em; }
}
@media (max-width: 380px) {
  /* Below this the phrase cannot hold one line at a readable size, so it wraps
     to two centred lines rather than overflowing or shrinking further. */
  .lf-edivide__text { white-space: normal; text-align: center; line-height: 1.6; }
}
