/* ==================================================================
   Smalls Auctions
   Committed green. White page. Two families on a contrast axis.
   Decoration budget: nothing gets a border or a fill unless it
   cannot do its job without one.
   ================================================================== */

/* ---------- fonts ----------
   Self-hosted, not fonts.googleapis.com. The Google stylesheet is a
   render-blocking request to a third-party origin, so on throttled mobile it
   cost a DNS lookup, a TLS handshake and a round trip before anything painted,
   then a second origin for the files themselves. First and largest contentful
   paint were the same number (3.8s) with zero blocking time: nothing was slow
   once it started, the start was late. Served from our own origin they are on
   a connection the browser has already made.

   Variable faces covering 400-600, which is every weight the site uses.
   Roman only: there is not one <em>, <i> or font-style:italic in the whole
   site, and the old Google request was fetching four italic files anyway.
   Both families are Omnibus-Type, under the SIL Open Font License, which
   permits self-hosting. Licence in static/fonts/OFL.txt.

   unicode-range is kept as Google served it, so latin-ext is only fetched by a
   page that actually needs a character from it. */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/archivo-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/archivo-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Petrona';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/petrona-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Petrona';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/fonts/petrona-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* ---- green ramp, hue 145, anchored on the logo (#344E35) ---- */
  --green-900: oklch(0.255 0.050 145);
  --green-800: oklch(0.330 0.062 145);   /* primary surface */
  --green-700: oklch(0.400 0.068 145);
  --green-600: oklch(0.478 0.070 145);
  --green-200: oklch(0.884 0.042 145);
  --green-100: oklch(0.950 0.020 145);
  /* ---- neutrals, barely tinted toward the brand hue ---- */
  --ink:       oklch(0.285 0.050 145);   /* headings — green, not black */
  --body:      oklch(0.360 0.034 145);
  --muted:     oklch(0.480 0.026 145);
  --hairline:  oklch(0.885 0.012 145);
  --white:     #fff;
  /* The hint of green. Lot photography is shot on white; this is what it
     mounts on, so the object reads as an object and not as a hole in the
     page. Tinted toward the brand hue, never toward warm. */
  --mat:       oklch(0.962 0.012 145);
  /* ---- on green ---- */
  --on-green:       oklch(0.975 0.012 145);
  --on-green-muted: oklch(0.815 0.030 145);
  --on-green-rule:  oklch(0.450 0.055 145);

  /* ---- one accent, for sold lots only ---- */
  --rust: oklch(0.545 0.125 42);

  --serif-display: "Petrona", "Hoefler Text", Georgia, serif;
  --serif: "Petrona", "Hoefler Text", Georgia, serif;
  --sans:  "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;

  --gutter: clamp(20px, 4vw, 56px);
  --maxw: 1360px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);   /* ease-out-quart */
  /* Symmetric curve for the lot crossfade: eases in and out equally, so the
     outgoing lot leaves as gently as the incoming one arrives. */
  --fade-ease: cubic-bezier(0.45, 0, 0.55, 1);
  --fade: 1150ms;

  --z-sticky: 100;
  --z-menu: 200;
}

/* ---------- reset ---------- */

*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%; scroll-behavior: smooth;
  scroll-padding-top: 104px;   /* the header is sticky; anchors must clear it */
}

body {
  margin: 0;
  background: var(--white);
  color: var(--body);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
}

/* Form controls do not inherit type. Without this, a button with no font of
   its own renders its label in the UA default face at 13.33px, under the
   site's 14px floor. */
button, input, select, textarea { font-family: inherit; }

img { max-width: 100%; display: block; }
a { color: inherit; }

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 400;
  color: var(--ink);
  margin: 0;
  text-wrap: balance;
}

p { margin: 0 0 1.15em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

:focus-visible { outline: 2px solid var(--green-700); outline-offset: 3px; }
.on-green :focus-visible { outline-color: var(--on-green); }

/* ---------- layout ---------- */

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: 760px; }
.wrap--mid { max-width: 1040px; }

section { padding-block: clamp(52px, 6vw, 104px); }
section.tight { padding-block: clamp(36px, 4.5vw, 64px); }

/* Surface rhythm. White is the page; the tinted surface is used sparingly and
   deliberately — the hero band, one section on the home page, the mailing
   block — and never as the default for a page header. Lot grids always sit on
   pure white, because the catalogue photography is shot on white and anything
   else frames it.

   Two white sections in a row get a hairline between them, unless the second
   is a continuation of the first, which .sec-join marks. */
.sec-surface { background: var(--white); box-shadow: inset 0 1px 0 var(--hairline); }
.sec-white + .sec-white:not(.sec-join),
section + section:not([class*="sec-"]):not(.on-green):not(.sec-join) {
  box-shadow: inset 0 1px 0 var(--hairline);
}

/* ---------- type scale (1.28 ratio) ---------- */

.display { font-family: var(--serif-display); font-weight: 500; font-size: clamp(2.75rem, 6.2vw, 3.625rem); line-height: 1.03; letter-spacing: -0.012em; }
.h2 { font-family: var(--serif-display); font-weight: 500; font-size: clamp(2rem, 3.7vw, 3rem); line-height: 1.1; letter-spacing: -0.01em; }
.h3 { font-size: 1.75rem; line-height: 1.2; letter-spacing: -0.01em; }

.lede { font-size: clamp(1.125rem, 1.4vw, 1.3125rem); line-height: 1.6; max-width: 60ch; }

/* The only small-caps label in the system: data labels and lot meta.
   Never used as a kicker above a section heading. */
.label {
  font-family: var(--sans);
  font-size: 0.875rem; font-weight: 500;
  color: var(--muted);
}
.on-green .label { color: var(--on-green-muted); }

.num { font-variant-numeric: tabular-nums; }

/* Meta lines. Separators are generated per item, so a wrap never strands
   one at the end of a row. Sized to Lawsons' 14px / 500 / 0.1em. */
.metaline {
  display: flex; flex-wrap: wrap; gap: 6px 0;
  font-size: 0.875rem; font-weight: 500;
}
.metaline > span { display: inline-flex; align-items: baseline; }
.metaline > span + span::before {
  content: "\00B7"; margin: 0 14px; color: var(--hairline);
}
/* Narrow enough to wrap, and a leading "·" at the head of a line reads as a
   typo. Space does the separating instead. */
@media (max-width: 600px) {
  .metaline { gap: 4px 20px; }
  .metaline > span + span::before { content: none; }
}
.on-green .metaline > span + span::before { color: var(--on-green-rule); }

.hero-head { min-width: 0; }
/* The readable middle register. Without it the hero jumps straight from a
   58px headline to a row of 14px caps, which reads as two sizes, not a scale. */
.hero-lede {
  font-size: clamp(1.125rem, 1.4vw, 1.3125rem);
  line-height: 1.6;
  color: var(--body);
  max-width: 46ch;
  margin: 0 0 26px;
}
.marquee-band { min-width: 0; }

/* ---------- links & buttons ---------- */

.btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 31px; min-height: 48px;
  font-family: var(--sans); font-size: 0.9375rem; font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase; text-decoration: none;
  color: var(--white); background: var(--green-800);
  border: 1px solid var(--green-800); border-radius: 4px; cursor: pointer;
  transition: background 220ms var(--ease), border-color 220ms var(--ease), color 220ms var(--ease);
}
.btn:hover { background: var(--green-900); border-color: var(--green-900); }

.btn--ghost { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--white); }

.on-green .btn { background: var(--on-green); color: var(--green-900); border-color: var(--on-green); }
.on-green .btn:hover { background: transparent; color: var(--on-green); }
.on-green .btn--ghost { background: transparent; color: var(--on-green); border-color: var(--on-green-rule); }
.on-green .btn--ghost:hover { background: var(--on-green); color: var(--green-900); }

/* Underlined text link — the default call to action, not a button */
.ulink {
  display: inline-block;
  font-size: 0.875rem; font-weight: 500;
  text-decoration: none; color: var(--ink); padding-bottom: 2px;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 100% 1px; background-repeat: no-repeat; background-position: 0 100%;
  transition: background-size 280ms var(--ease);
}
.ulink:hover { background-size: 0% 1px; }
.on-green .ulink { color: var(--on-green); }

/* ---------- header ---------- */

.header-aside {
  display: flex; align-items: center; gap: 18px; margin-left: clamp(16px, 1.8vw, 28px);
  font-size: 0.875rem; color: var(--on-green-muted);
}
.header-aside a { color: var(--on-green-muted); text-decoration: none; white-space: nowrap; }

/* Between the full desktop header and the drawer there is not room for
   everything. The bidder login goes first: it is in the footer, in the
   drawer, and on every lot page. The phone number and the social links stay. */
/* 1560, not 1280: the header row is wider than the 1360px content column, so
   between roughly 1281 and 1560 the aside ran past the right edge of the
   viewport and put a scrollbar on every page. Measured, not guessed. */
@media (max-width: 1560px) {
  .header-aside > a[rel="noopener"] { display: none; }
}
@media (max-width: 1300px) {
  .header-aside > a[href^="tel:"] { display: none; }
  /* The type comes down to 15px — still above the floor — before anything is
     dropped, because the five nav labels are the point of the header. */
  .nav a { font-size: 0.9375rem; }
  .nav .btn { padding: 12px 20px; font-size: 0.875rem; }
  .brand img { height: 58px; }
}
.header-aside a:hover { color: var(--on-green); text-decoration: underline; }

.nav-aside { display: none; }
.site-header { position: sticky; top: 0; z-index: var(--z-sticky); background: var(--green-800); }
.site-header .wrap {
  display: flex; align-items: center; min-height: 96px; position: relative;
  gap: clamp(20px, 2.5vw, 36px);
}
.brand { flex-shrink: 0; line-height: 0; }
.brand img { height: 68px; width: auto; }

.nav { display: flex; align-items: center; gap: clamp(18px, 2.2vw, 32px); margin-left: auto; }
.nav a {
  font-size: 1.03125rem; font-weight: 500; letter-spacing: 0.05em;
  text-transform: uppercase; text-decoration: none; color: var(--on-green-muted); padding-block: 4px;
  white-space: nowrap;   /* "Past Sales" on two lines reads as two links */
  transition: color 200ms var(--ease);
}
.nav a:hover { color: var(--on-green); }
.nav a[aria-current="page"] { color: var(--on-green); box-shadow: 0 1px 0 var(--on-green); }
.nav .btn { background: var(--on-green); color: var(--green-900); border-color: var(--on-green); }
.nav .btn:hover { background: transparent; color: var(--on-green); }

.burger {
  display: none; margin-left: auto;
  background: none; border: 0; padding: 12px 0 12px 12px;
  font: inherit; font-size: 0.875rem; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--on-green); cursor: pointer;
}

/* ---------- green surface ---------- */

.on-green { background: var(--green-800); color: var(--on-green-muted); }
.on-green h1, .on-green h2, .on-green h3 { color: var(--on-green); }
.on-green .lede { color: var(--on-green-muted); line-height: 1.7; }

/* ---------- hero ---------- */

.hero { padding-block: clamp(52px, 5.8vw, 94px); overflow: hidden; }
.hero-grid {
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: clamp(32px, 4.5vw, 68px);
  align-items: center;
}
.hero-grid > * { min-width: 0; }
.hero h1 {
  font-family: var(--serif-display);
  font-size: clamp(2.125rem, 4.1vw, 3.625rem);
  margin-bottom: 22px;
}
/* Grid children default to min-width:auto, which lets a max-content track
   blow past its column. This is what sent the marquee off the viewport. */
.split > *, .lot-detail > *, .band-grid > * { min-width: 0; }

.hero-meta { margin-bottom: 26px; color: var(--muted); }

.hero-actions { display: flex; gap: 14px 28px; flex-wrap: wrap; align-items: center; }

@keyframes rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }

/* ---------- section heading ---------- */

.status {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--green-800); color: var(--white);
  padding: 7px 15px; border-radius: 999px;
  font-size: 0.875rem; font-weight: 500;   /* 14px — the site's type floor */
  margin: 0 0 18px; white-space: nowrap; max-width: 100%;
}
.status .sep { color: rgba(255, 255, 255, 0.42); }
/* The two closing-date spans closing_spans() writes into every .status pill:
   the full Lawsons-style date on a normal viewport, an abbreviated one below
   520px. The full string does not fit a pill on one line under ~400px even
   at the pill's own 14px floor — "Closing Sunday 1 November 2026 | 12.00 PM"
   wrapped the pill to two lines and read as a slab rather than a chip. */
.status-short { display: none; }
@media (max-width: 520px) {
  /* white-space stays normal, not nowrap: the bare pill (no "Sale 387 ·" or
     "Bidding open ·" prefix) fits the short label on one line with room to
     spare, but the prefixed pills elsewhere do not always, and nowrap turned
     that into text spilling past the pill's edge instead of the plain,
     readable two-line wrap this now falls back to. */
  .status { white-space: normal; line-height: 1.5; padding: 7px 13px; letter-spacing: 0.08em; }
  .status-full { display: none; }
  .status-short { display: inline; }
}
.status svg { flex: none; width: 13px; height: 13px; }

/* ---------- hero carousel ---------- */

.hero-carousel {
  position: relative; background: var(--white); overflow: hidden;
  padding: 0;                 /* it is a <section>; the global block padding does not apply here */
}
.hc-track { display: grid; min-height: clamp(440px, 44vw, 600px); }

/* Fade through blank, never across.
   Both of these stack their slides in one grid cell and cross-fade. That is
   right for a photograph and wrong for type: for the whole of the 1150ms both
   lots' titles, lot numbers and estimates were painted over each other at
   partial opacity, which on a phone — where the card is full width and the
   title is 17px — is an unreadable smear, not a transition. It is also what
   Lighthouse was reporting as contrast failures on the rotator.
   Splitting the duration in two and delaying the incoming slide by half means
   the outgoing one is gone before the next appears. Same total duration, same
   3s cadence, no JS change. */
.hc-slide {
  grid-area: 1 / 1;
  opacity: 0; visibility: hidden;
  transition: opacity calc(var(--fade) / 2) var(--fade-ease),
              visibility 0s linear calc(var(--fade) / 2);
}
.hc-slide.is-on,
.hero-carousel:not(.js-ready) .hc-slide:first-child {
  opacity: 1; visibility: visible;
  transition: opacity calc(var(--fade) / 2) var(--fade-ease) calc(var(--fade) / 2),
              visibility 0s;
}

/* Banner slides: the photograph fills the frame and the copy sits in the
   open half the photograph was composed to leave. */
.hc-slide--banner { display: grid; }
.hc-slide--banner > img { grid-area: 1/1; width: 100%; height: 100%; object-fit: cover; }
.hc-slide--banner > .wrap { grid-area: 1/1; display: flex; align-items: center; }
.hc-slide--banner .hc-body { margin-left: auto; width: min(48%, 540px); position: relative; }

/* A short vertical rule marking where the photograph ends and the copy begins.
   Deliberately shorter than the slide: it reads as a separator, not a column
   divider. Drawn as a pseudo-element so it does not spend one of the
   stylesheet's three border declarations. */
.hc-slide--banner .hc-body::before {
  content: ""; position: absolute;
  right: 100%; margin-right: clamp(28px, 3.6vw, 54px);
  top: 50%; transform: translateY(-50%);
  width: 1px; height: clamp(200px, 32vw, 400px);
  background: var(--green-800);        /* the navbar green */
}

/* Split slides: the photograph is absolutely placed on the right half and the
   copy rides the site's own .wrap, so it lands on exactly the same left edge
   as the logo and every section below. */
.hc-slide--split { position: relative; display: block; }
.hc-slide--split .hc-media { position: absolute; inset: 0 0 0 50%; }
.hc-slide--split .hc-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hc-slide--split > .wrap {
  position: relative; z-index: 1;
  min-height: inherit; height: 100%;
  display: flex; align-items: center;
  /* The hero is a full-bleed band, so the copy tracks the viewport edge
     instead of the centred content column it would otherwise inherit. The
     left inset clears the previous-slide arrow, which sits at 22–68px. */
  max-width: none;
  padding-left: clamp(88px, 6.5vw, 112px);
}
.hc-slide--split .hc-body {
  width: min(46%, 560px);
  padding-block: clamp(36px, 4.5vw, 64px);
}

/* Slide one carries the page's h1; the other slides are h2. Same type. */
.hc-body h1,
.hc-body h2 {
  font-family: var(--serif-display);
  font-size: clamp(2rem, 3.4vw, 3rem);
  line-height: 1.08; letter-spacing: -0.014em;
  margin: 0 0 18px;
}
.hc-body p { font-size: clamp(1.0625rem, 1.25vw, 1.1875rem); line-height: 1.6; margin: 0 0 26px; max-width: 42ch; }
.hc-body .label { display: block; margin-bottom: 16px; }
.hc-actions { display: flex; gap: 14px 26px; flex-wrap: wrap; align-items: center; }
/* max-width + nowrap made the label spill past its own pill.
   font-size restores the pill's intended 14px type-floor size: .hc-body p
   above (one class + one element, equal specificity order) was winning
   against .status's own font-size because it comes later in the file, which
   is what made this pill render at 17px and wrap to two lines on a phone. */
.hc-body .status { max-width: none; font-size: 0.875rem; }

/* ---------- carousel controls ---------- */

/* The controls sit over arbitrary photography, so they carry their own
   surface rather than hoping the image behind them is light. */
.hc-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  z-index: 2; width: 46px; height: 46px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--white); border: 0; cursor: pointer;
  color: var(--ink); opacity: 0.82;
  transition: opacity 200ms var(--ease);
}
.hc-arrow:hover { opacity: 1; }
.hc-arrow svg { width: 26px; height: 26px; }
.hc-arrow--prev { left: clamp(10px, 1.4vw, 22px); }
.hc-arrow--next { right: clamp(10px, 1.4vw, 22px); }

.hc-foot {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: clamp(16px, 2vw, 26px); z-index: 2;
  display: flex; align-items: center; gap: 20px;
  background: var(--white); padding: 9px 18px; border-radius: 999px;
}
.hc-dots { display: flex; gap: 14px; }
.hc-dots button {
  width: 30px; height: 3px; padding: 0; border: 0; cursor: pointer;
  background: var(--ink); opacity: 0.24;
  transition: opacity 220ms var(--ease);
}
.hc-dots button[aria-current="true"] { opacity: 0.85; }
.hc-pause {
  font: inherit; font-size: 0.875rem; font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase;
  background: none; border: 0; cursor: pointer; padding: 2px 0;
  color: var(--muted);
}
.hc-pause:hover { color: var(--ink); }

@media (max-width: 860px) {
  .hc-track { min-height: 0; }
  .hc-slide--split { display: flex; flex-direction: column; }
  .hc-slide--split .hc-media { position: static; inset: auto; order: -1; }
  .hc-slide--split .hc-media img { aspect-ratio: 3/2; height: auto; }
  .hc-slide--split > .wrap {
    min-height: 0; display: block;
    /* height: 100% is a desktop rule. Left on, it clamps this slide to the
       height of the shorter banner slides and the carousel clips the rest. */
    height: auto;
    padding-left: var(--gutter);   /* arrows are hidden at this width */
  }
  .hc-slide--split .hc-body { width: 100%; padding: 32px 0 60px; }
  .hc-body .status { white-space: normal; max-width: 100%; }
  /* A banner slide was an image with the copy overlaid on an 88%-opaque white
     card. Full-bleed and nearly as tall as the slide, the card covered almost
     the whole photograph on a phone — "only text visible, where is pic?" was
     the complaint, and it was a fair one: a sliver of colour down the left
     edge was all that was left of the picture.
     Stacked instead, the same pattern .hc-slide--split already uses below:
     the photograph is its own full-width row, in the open, and the copy
     follows in normal flow underneath on the page's own white, not on top of
     the photograph at all. */
  .hc-slide--banner { display: flex; flex-direction: column; }
  .hc-slide--banner > img {
    order: -1; position: static;
    width: 100%; height: auto; min-height: 0; aspect-ratio: 3/2;
    /* These photographs are composed with the subject on the left and open
       wall or background on the right (so the desktop copy has somewhere to
       sit). A default centred crop on a ratio this much narrower than the
       source (2.5:1) would cut across the subject itself. Left-anchored, the
       crop only ever trims the empty right-hand side. */
    object-position: left;
  }
  .hc-slide--banner > .wrap {
    min-height: 0; height: auto; display: block;
  }
  .hc-slide--banner .hc-body {
    width: 100%; margin: 0; background: none;
    padding: 28px 0 56px; border-radius: 0;
  }
  .hc-slide--banner .hc-body::before { display: none; }
  .hc-arrow { display: none; }

  /* At this width the copy fills the slide, so an overlaid pill lands on the
     last call to action. The controls drop below the photograph instead, on
     the gutter so they line up with the copy above and the sections below —
     margin:auto did not centre them, because a block-level flex container is
     already full width. */
  .hc-foot {
    position: static; transform: none;
    margin: 14px 0 0; background: none;
    padding: 0 var(--gutter);
    justify-content: space-between;
  }
}

/* ---------- lot rotator: one lot at a time, crossfading ---------- */

.lot-rotator { display: grid; }
/* Fades through blank, not across — see the note on .hc-slide above. */
.lot-rotator > .lot {
  grid-area: 1 / 1;
  opacity: 0; visibility: hidden;
  transition: opacity calc(var(--fade) / 2) var(--fade-ease),
              visibility 0s linear calc(var(--fade) / 2);
}
.lot-rotator > .lot.is-on,
.lot-rotator:not(.js-ready) > .lot:first-child {
  opacity: 1; visibility: visible;
  transition: opacity calc(var(--fade) / 2) var(--fade-ease) calc(var(--fade) / 2),
              visibility 0s;
}

/* A fixed image box so swapping lots never nudges the layout. */
.lot-rotator .lot-img {
  aspect-ratio: auto;
  height: clamp(230px, 24vw, 320px);
  background: var(--white);
  margin-bottom: 14px;
}
.lot-rotator .lot-img img { transition: none; }
.lot-rotator .lot:hover .lot-img img { transform: none; }
.lot-rotator .lot h3 { -webkit-line-clamp: 2; }

.marquee-foot {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; padding-top: 16px;
}
.marquee-pause {
  font: inherit; font-size: 0.875rem; font-weight: 500;
  letter-spacing: 0.1em; text-transform: uppercase;
  background: none; border: 0; padding: 8px 0; cursor: pointer;
  color: var(--muted); box-shadow: 0 1px 0 var(--hairline);
}
.marquee-pause:hover { color: var(--ink); }

.shead { display: flex; align-items: baseline; justify-content: space-between; gap: 24px; flex-wrap: wrap; margin-bottom: clamp(28px, 3.5vw, 52px); }
.shead p { margin: 12px 0 0; font-size: 1.0625rem; color: var(--muted); max-width: 52ch; }

/* ---------- lot grid ---------- */

.lot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: clamp(34px, 3.4vw, 48px) clamp(20px, 2.2vw, 30px); }

.lot-grid--4 { grid-template-columns: repeat(3, 1fr); }
/* The catalogue is dense by nature; it keeps the rhythm but not the button. */
.lot-grid--dense .lot h3 { margin-bottom: 10px; }
@media (max-width: 900px) { .lot-grid--4 { grid-template-columns: repeat(2, 1fr); } }
.lot-grid--dense { grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }

.lot { display: flex; flex-direction: column; text-decoration: none; color: inherit; }

/* White whatever the section: the photography is shot on white, so the
   object sits on the page instead of in a box. */
.lot-img { aspect-ratio: 1/1; overflow: hidden; margin-bottom: 16px; background: var(--white); }
.lot-img img { width: 100%; height: 100%; object-fit: contain; transition: transform 600ms var(--ease); }
.lot:hover .lot-img img { transform: scale(1.04); }

.lot .no { font-size: 0.875rem; font-weight: 500; color: var(--muted); margin-bottom: 8px; }

.lot h3 {
  font-size: 1.1875rem; line-height: 1.34; letter-spacing: 0; margin-bottom: 10px;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.lot:hover h3 { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }

.lot .est { font-variant-numeric: tabular-nums;
  margin-top: auto; font-size: 0.9375rem; font-weight: 500;
  color: var(--muted);
}

.lot .est b { color: var(--ink); font-weight: 500; }
.lot .sold { color: var(--rust); font-weight: 600; }

/* ---------- catalogue index (replaces the category card grid) ---------- */

.index-list { columns: 2; column-gap: clamp(32px, 5vw, 80px); list-style: none; margin: 0; padding: 0; }
.index-list li { break-inside: avoid; }
.index-list a {
  display: flex; align-items: baseline; gap: 14px; padding: 18px 0;
  text-decoration: none; color: var(--ink);
  box-shadow: 0 1px 0 var(--hairline);
  transition: color 200ms var(--ease);
}
.index-list a:hover { color: var(--green-700); }
.index-list .name { font-family: var(--serif); font-size: 1.5rem; }
.index-list .dots { flex: 1; border-bottom: 1px dotted var(--hairline); transform: translateY(-4px); }
.index-list .n { font-size: 0.875rem; color: var(--muted); }

/* ---------- figure / split ---------- */

.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 5vw, 80px); align-items: center; }
.split--wide-img { grid-template-columns: 0.85fr 1.15fr; }
.split img { width: 100%; height: auto; aspect-ratio: 4/3; object-fit: cover; }
.split figure { margin: 0; }
.split figcaption { margin-top: 12px; font-size: 0.875rem; color: var(--muted); }

/* The /auctions/ "current sale" card: a lot photograph standing in for the
   sale, same title and description the hero on / already carried. On a
   phone, where .split stacks to one column, the photo ran full column width
   at a 1:1 ratio (350px) and the margins below it were sized for a desktop
   two-column layout, for roughly 800px before "Sale 388 opens Friday" even
   started. Capped and tightened here; nothing is removed, only sized to what
   the scroll is worth. .split .sale-preview-img needs the two-class
   specificity to beat .split img above. */
.split .sale-preview-img { aspect-ratio: 1/1; object-fit: contain; }
.sale-preview-h2 { margin-bottom: 18px; }
.sale-preview-lede { margin-bottom: 26px; }
.sale-preview-meta { margin-bottom: 30px; }
@media (max-width: 860px) {
  .sale-preview-figure { width: 180px; margin-right: auto; }
  .sale-preview-h2 { margin-bottom: 10px; }
  .sale-preview-lede { margin-bottom: 14px; }
  .sale-preview-meta { margin-bottom: 16px; }
}

.bleed-figure { margin: 0; }
.bleed-figure img { width: 100%; height: auto; aspect-ratio: 21/9; object-fit: cover; }

/* ---------- steps (numbered because the sequence IS the content) ---------- */

.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: clamp(28px, 3vw, 48px); }
.step .n { font-family: var(--serif); font-size: 2.25rem; color: var(--green-600); line-height: 1; display: block; margin-bottom: 14px; }
.step h3 { font-size: 1.25rem; margin-bottom: 8px; }
.step p { font-size: 0.9375rem; color: var(--muted); margin: 0; }

/* ---------- past sales list ---------- */

.sale-row {
  display: grid; grid-template-columns: 200px 1fr auto;
  gap: clamp(20px, 3vw, 44px); align-items: center;
  padding: clamp(20px, 2.4vw, 32px) 0;
  box-shadow: 0 1px 0 var(--hairline);
  text-decoration: none; color: inherit;
}
.sale-row img { width: 200px; height: auto; aspect-ratio: 3/2; object-fit: cover; }
.sale-row h3 { font-size: 1.5rem; margin: 6px 0 8px; }
.sale-row .totals {
  font-size: 0.875rem; font-weight: 500; letter-spacing: 0.1em;
  color: var(--muted);
}
.sale-row .totals b { color: var(--ink); font-weight: 500; }
.sale-row:hover h3 { text-decoration: underline; text-underline-offset: 3px; }
.sale-row--pending { opacity: 0.5; }
.sale-row--pending .ph {
  width: 200px; aspect-ratio: 3/2; background: var(--green-100);
  display: grid; place-items: center; color: var(--muted);
  font-size: 0.875rem;
}

/* ---------- catalogue ---------- */

/* An element's own display rule otherwise beats the hidden attribute, which
   is how every filtered-out lot stayed on screen. */
[hidden] { display: none !important; }

.cat-head { padding-block: clamp(28px, 3.4vw, 48px); }
.cat-head-grid { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: clamp(28px, 4vw, 64px); align-items: end; }
.cat-head h1 { font-family: var(--serif-display); font-weight: 500; font-size: clamp(2rem, 3.4vw, 2.875rem); line-height: 1.1; letter-spacing: -0.01em; margin: 16px 0 12px; }
.cat-head .metaline { color: var(--muted); }
.sale-details { margin-top: 18px; max-width: 72ch; }
.sale-details summary {
  cursor: pointer; list-style: none; display: inline-flex; align-items: center; gap: 10px; min-height: 44px;
  font-size: 0.875rem; font-weight: 500; color: var(--ink);
}
.sale-details summary::-webkit-details-marker { display: none; }
.sale-details summary::after { content: "+"; font-size: 1.125rem; letter-spacing: 0; }
.sale-details[open] summary::after { content: "–"; }
.sale-details p { margin: 10px 0 0; }

.cat-side { display: grid; gap: 14px; justify-items: start; padding: 26px 28px; box-shadow: inset 0 0 0 1px var(--hairline); }
.cat-side .label { margin: 0; }
.cat-clock { font-family: var(--serif); font-size: 1.75rem; line-height: 1.15; color: var(--ink); margin: 0; }
.cat-side .btn { width: 100%; justify-content: center; }

/* The label and the countdown were two of this box's four stacked rows; on a
   phone, where .cat-head-grid has already dropped to one column and this box
   sits below a title, a breadcrumb and a status pill, every row here was
   scroll that still had not reached a single lot. Putting the label beside
   the countdown and tightening the box's own padding cuts it from four rows
   to three without dropping anything — the register button stays full width
   because it is the one thing on this page worth a thumb's whole reach. */
@media (max-width: 860px) {
  .cat-side { padding: 18px 20px; gap: 10px; }
  .cat-countdown { display: flex; align-items: baseline; gap: 8px; }
  .cat-clock { font-size: 1.25rem; }
}

.cat-body { padding-top: 0; }
.catalogue { display: grid; grid-template-columns: 256px minmax(0, 1fr); gap: clamp(28px, 3.6vw, 56px); align-items: start; }

.filters { position: sticky; top: 120px; max-height: calc(100vh - 140px); overflow: auto; padding: 4px 8px 24px 0; }
.filters-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 18px; }
.filters-head h2 { font-family: var(--serif); font-size: 1.5rem; font-weight: 400; margin: 0; }
.filters fieldset { border: 0; padding: 0; margin: 0 0 28px; min-width: 0; }
.filters legend { padding: 0; margin-bottom: 8px; font-size: 0.875rem; font-weight: 500; color: var(--muted); }
.ftree, .ftree ul { list-style: none; margin: 0; padding: 0; }
.ftree ul { padding-left: 26px; }
.ftree label { display: flex; align-items: center; gap: 10px; min-height: 36px; font-size: 0.9375rem; color: var(--body); cursor: pointer; }
.ftree label:hover { color: var(--ink); }
.ftree input { flex: none; width: 16px; height: 16px; margin: 0; accent-color: var(--green-800); cursor: pointer; }
.ftree .n { margin-left: auto; padding-left: 8px; font-size: 0.875rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.fgroup > label { font-weight: 500; color: var(--ink); }

.toolbar { display: flex; align-items: center; gap: 12px 26px; flex-wrap: wrap; margin-bottom: clamp(24px, 2.6vw, 36px); }
.toolbar input[type="search"], .toolbar input[type="number"], .toolbar select {
  font: inherit; font-size: 1rem; padding: 10px 0; min-height: 44px;
  border: 0; border-bottom: 1px solid var(--hairline);
  background: transparent; color: var(--ink); border-radius: 0;
}
.toolbar input[type="search"] { flex: 1 1 200px; min-width: 0; }
.toolbar input::placeholder { color: var(--muted); }
.toolbar select { cursor: pointer; }
.toolbar .count { font-weight: 500; color: var(--ink); }
.toolbar label.inline, .goto { display: inline-flex; align-items: center; gap: 10px; font-size: 0.875rem; color: var(--muted); margin: 0; }
.goto input { width: 72px; }
.filters-toggle { display: none; }

.lot-grid--cat { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); }

.pager { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; margin-top: clamp(40px, 4vw, 64px); }
.pager button {
  font: inherit; font-size: 0.9375rem; min-width: 44px; min-height: 44px; padding: 0 10px;
  background: none; border: 0; color: var(--muted); cursor: pointer;
}
.pager button:hover { color: var(--ink); }
.pager button[aria-current="page"] { color: var(--ink); font-weight: 600; box-shadow: inset 0 -1px 0 var(--ink); }
.pager button:disabled { opacity: 0.35; cursor: default; }
.pager .gap { min-width: 24px; display: inline-flex; align-items: center; justify-content: center; color: var(--muted); }

@media (max-width: 860px) {
  .cat-head-grid, .catalogue { grid-template-columns: minmax(0, 1fr); }
  .filters { position: static; max-height: none; overflow: visible; display: none; padding: 0; }
  .filters.open { display: block; }
  .filters-toggle { display: inline-flex; }
  .toolbar input[type="search"] { flex-basis: 100%; order: 3; }
}

/* ---------- lot detail ---------- */

.lot-detail { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: clamp(32px, 5vw, 76px); align-items: start; }
.lot-detail .gallery-main { width: 100%; height: auto; aspect-ratio: 1/1; object-fit: contain; }
/* Unselected thumbnails recede; no frame, per the border budget. 72px clears
   the 44px tap target without an overlay. */
/* Zoom. The dialog escapes every stacking context, so the viewer is never
   clipped by the gallery's own overflow. */
.gallery { position: relative; }
.gallery-main { cursor: zoom-in; }
.zoom-btn {
  position: absolute; top: 12px; right: 12px;
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 16px;
  font-size: 0.875rem; font-weight: 500;
  background: var(--white); color: var(--ink); border: 0; border-radius: 999px;
  box-shadow: 0 0 0 1px var(--hairline); cursor: pointer;
  opacity: 0.9; transition: opacity 200ms var(--ease);
}
.zoom-btn:hover { opacity: 1; }
.zoom-btn svg { width: 18px; height: 18px; }
.zoom-dlg { border: 0; padding: 0; max-width: 100vw; max-height: 100vh; width: 100vw; height: 100vh; background: var(--white); }
.zoom-dlg::backdrop { background: rgba(0, 0, 0, 0.62); }
.zoom-stage { width: 100vw; height: 100vh; overflow: auto; display: grid; place-items: center; padding: 24px; }
.zoom-stage img { max-width: none; width: auto; height: auto; max-height: none; cursor: zoom-out; }
.zoom-close {
  position: fixed; top: 16px; right: 16px; z-index: 1;
  width: 44px; height: 44px; font-size: 1.75rem; line-height: 1;
  background: var(--white); color: var(--ink); border: 0; border-radius: 50%;
  box-shadow: 0 0 0 1px var(--hairline); cursor: pointer;
}

.gal-thumbs { display: grid; grid-template-columns: repeat(auto-fill, 72px); gap: 8px; margin-top: 16px; }
.gal-thumbs a { display: block; opacity: 0.5; transition: opacity 280ms var(--ease); }
.gal-thumbs a:hover, .gal-thumbs a[aria-current="true"] { opacity: 1; }
.gal-thumbs img { display: block; width: 72px; height: 72px; object-fit: contain; }
.lot-detail h1 { font-family: var(--serif-display); font-weight: 500; font-size: clamp(1.875rem, 3.4vw, 2.75rem); line-height: 1.1; letter-spacing: -0.01em; margin-bottom: 20px; }

.price-line { margin: 32px 0; }
.price-line dl { display: flex; gap: 48px; margin: 0 0 24px; flex-wrap: wrap; }
.price-line dt { font-size: 0.875rem; color: var(--muted); margin-bottom: 6px; }
.price-line dd { font-variant-numeric: tabular-nums; margin: 0; font-family: var(--serif); font-size: 1.875rem; color: var(--ink); line-height: 1; }
.price-line dd.sold { color: var(--rust); }

.spec { width: 100%; border-collapse: collapse; margin: 36px 0; font-size: 0.9375rem; }
.spec th, .spec td { text-align: left; padding: 14px 0; box-shadow: 0 1px 0 var(--hairline); vertical-align: top; }
.spec th { width: 38%; font-weight: 500; font-size: 0.875rem; color: var(--muted); padding-top: 17px; }
.spec td { color: var(--ink); }

.lot-nav { display: flex; justify-content: space-between; gap: 20px; padding-top: 24px; }

.note { font-size: 0.875rem; color: var(--muted); line-height: 1.55; }

.crumbs { font-size: 0.875rem; color: var(--muted); padding-block: 20px; }
.crumbs a { text-decoration: none; color: var(--muted); }
.crumbs a:hover { color: var(--ink); text-decoration: underline; }
.crumbs > span:not(.crumbs-here) { margin-inline: 9px; opacity: 0.5; }

/* ---------- prose ---------- */

.prose { max-width: 68ch; }
.prose h2 { font-size: 1.875rem; margin: 2em 0 .55em; }
.prose p { font-size: 1.125rem; line-height: 1.72; }
.prose ul { padding-left: 1.1em; margin-bottom: 1.3em; }
.prose li { margin-bottom: .55em; line-height: 1.7; }
/* Links inside running copy. .ulink is a standalone call to action with its
   own fixed 14px size, so using it mid-sentence visibly shrinks the words it
   sits between — which is what it did to "452 Oxford St, Paddington" in the
   homepage lede.
   :not(.btn) because this rule sits below .btn and matches at the same
   specificity, so a button inside prose was taking green-700 text on a
   green-800 fill: 1.32:1, an unreadable call to action on /buying/. */
.prose a:not(.btn):not(.ulink),
.lede a:not(.btn):not(.ulink) { color: var(--green-700); text-underline-offset: 3px; }

.pull { font-family: var(--serif); font-size: clamp(1.5rem, 2.4vw, 2rem); line-height: 1.3; color: var(--ink); margin: 1.8em 0; max-width: 24ch; }

/* ---------- forms ---------- */

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px 20px; }
.field { display: flex; flex-direction: column; gap: 8px; }
.field--full { grid-column: 1 / -1; }
.field label { font-size: 0.875rem; font-weight: 500; color: var(--muted); }
.field input, .field textarea, .field select {
  font: inherit; font-size: 1rem; padding: 12px 0; min-height: 46px;
  border: 0; border-bottom: 1px solid var(--hairline);
  background: transparent; color: var(--ink); width: 100%; border-radius: 0;
}
.field textarea { min-height: 120px; resize: vertical; padding-top: 10px; }
.field input::placeholder, .field textarea::placeholder { color: var(--muted); opacity: 1; }
.on-green .field input::placeholder, .on-green .field textarea::placeholder { color: var(--on-green-muted); opacity: 1; }
.field input:hover, .field textarea:hover, .field select:hover { border-bottom-color: var(--muted); }
.on-green .field label { color: var(--on-green-muted); }
.on-green .field input, .on-green .field textarea, .on-green .field select { color: var(--on-green); border-bottom-color: var(--on-green-rule); }
.on-green .field select option { color: var(--ink); }
.field-label { font-size: 0.875rem; font-weight: 500; color: var(--muted); }
.on-green .field-label { color: var(--on-green-muted); }

/* Photo upload. The whole box is the file input's label, so it works by tap,
   click or keyboard; site.js adds drag and drop, thumbnails and the meter. */
.dropzone {
  display: grid; justify-items: center; gap: 6px; text-align: center;
  padding: 30px 20px; cursor: pointer;
  border: 1px dashed var(--on-green-rule); border-radius: 4px;
  color: var(--on-green-muted);
  transition: background 200ms var(--ease), border-color 200ms var(--ease);
}
.dropzone:hover, .dropzone.is-over, .dropzone:focus-within {
  border-color: var(--on-green); background: color-mix(in oklch, var(--on-green) 6%, transparent);
}
.field .dropzone { font-size: 1rem; font-weight: 400; letter-spacing: 0; text-transform: none; }
.dropzone svg { width: 34px; height: 34px; color: var(--on-green); margin-bottom: 4px; }
.dropzone-head { color: var(--on-green); font-weight: 500; font-size: 1.0625rem; }
.dropzone-sub { font-size: 0.9375rem; max-width: 36ch; }
/* Visually hidden but still focusable through its label. */
.dropzone input { position: absolute; width: 1px; height: 1px; opacity: 0; }

.thumbs { list-style: none; margin: 4px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 10px; }
.thumbs:empty { display: none; }
.thumbs li { position: relative; aspect-ratio: 1; background: var(--white); border-radius: 3px; overflow: hidden; }
.thumbs img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumbs .doc { display: grid; place-items: center; height: 100%; font-size: 0.75rem; font-weight: 600; letter-spacing: 0.1em; color: var(--ink); }
.thumbs button {
  position: absolute; top: 4px; right: 4px; width: 24px; height: 24px; border-radius: 50%;
  border: 0; background: var(--green-900); color: var(--on-green); cursor: pointer;
  font-size: 15px; line-height: 24px; padding: 0;
}
.meter { margin-top: 4px; }
.meter-bar { height: 3px; background: var(--on-green-rule); }
/* scaleX rather than width: the bar is composited, not re-laid-out. */
.meter-bar span { display: block; height: 100%; width: 100%; transform: scaleX(0); transform-origin: 0 50%; background: var(--on-green); transition: transform 300ms var(--ease); }
.meter-text { font-size: 0.875rem; margin: 8px 0 0; color: var(--on-green-muted); }
.upload-error { font-size: 0.875rem; margin: 6px 0 0; color: var(--on-green); }

.check { display: flex; gap: 12px; align-items: flex-start; cursor: pointer; font-size: 0.9375rem; }
.check input { width: 18px; height: 18px; margin: 2px 0 0; flex: none; accent-color: var(--green-600); }
.field .check { text-transform: none; letter-spacing: 0; font-weight: 400; }
.on-green .field .check { color: var(--on-green-muted); }

/* Valuation band: copy and checklist on the left, the form on the right,
   both top-aligned because the form is the taller of the two. */
.split--form { align-items: start; }
.h3-sm { font-family: var(--sans); font-size: 1rem; font-weight: 600; margin: 0 0 12px; }
.on-green .h3-sm { color: var(--on-green); }
.ticks { list-style: none; margin: 0; padding: 0; }
.ticks li { position: relative; padding-left: 26px; margin-bottom: 9px; line-height: 1.5; }
.ticks li::before {
  content: ""; position: absolute; left: 2px; top: 0.42em;
  width: 11px; height: 6px; border-left: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg); color: var(--green-600);
}
.on-green .ticks li::before { color: var(--on-green); }

.jumplinks { display: flex; flex-wrap: wrap; gap: 12px 28px; margin: 28px 0 0; }
@media (max-width: 420px) {
  /* Four links, 28px apart, ran to 409px against a 350px column — "Request a
     valuation" alone was 124px of that. Shortened to "Free valuation" (see
     build.py) and the gap tightened; both links and font stay at the 14px
     floor, nothing shrinks below it. */
  .jumplinks { gap: 10px 16px; }
}

/* Services: three columns of copy, ruled at the top, no boxes. */
.service-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(28px, 3.4vw, 56px); }
.service { box-shadow: inset 0 1px 0 var(--hairline); padding-top: 24px; display: flex; flex-direction: column; align-items: flex-start; }
.service h3 { font-size: 1.5rem; margin: 0 0 6px; }
.service p { margin: 0 0 18px; color: var(--body); }
.service .service-price { font-size: 0.9375rem; color: var(--green-700); font-weight: 500; margin-bottom: 14px; }
.service .ulink { margin-top: auto; }
@media (max-width: 860px) { .service-grid { grid-template-columns: 1fr; } }

/* ---------- footer ---------- */

.site-footer { background: var(--green-900); color: var(--on-green-muted); font-size: 0.9375rem; }
.site-footer .wrap { padding-top: clamp(56px, 6vw, 88px); }
.site-footer h2 { font-family: var(--sans); font-size: 0.875rem; font-weight: 500; color: var(--on-green); margin: 0 0 18px; }
.footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1.2fr; gap: clamp(28px, 4vw, 64px); padding-bottom: 56px; }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer li { margin-bottom: 11px; }
.site-footer a { color: var(--on-green-muted); text-decoration: none; }
.site-footer a:hover { color: var(--on-green); text-decoration: underline; }
.site-footer .mark { font-family: var(--serif); font-size: 1.5rem; color: var(--on-green); display: block; margin-bottom: 16px; }
.footer-bottom {
  display: flex; justify-content: space-between; gap: 18px; flex-wrap: wrap;
  padding-block: 24px; font-size: 0.875rem; color: var(--on-green-muted);
  box-shadow: 0 -1px 0 var(--on-green-rule);
}

/* ---------- misc ---------- */

/* Screen-reader-only text. font: inherit so it is not read at the browser's
   own button default in the site's fallback face. */
.skip { position: absolute; left: -9999px; font: inherit; font-size: 0.875rem; }
.skip:focus { left: 16px; top: 16px; z-index: var(--z-menu); background: var(--white); padding: 14px 20px; border: 2px solid var(--green-800); }

/* The honeypot field on every form — see submit.php. Unlike .skip this never
   reveals itself: a real visitor must never be able to focus or fill it, or
   their submission gets silently dropped as spam. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.preview-bar { background: var(--rust); color: #fff; font-size: 0.875rem; text-align: center; padding: 8px 20px; }

/* ---------- responsive ---------- */

@media (max-width: 1080px) {
  .hero-grid, .split, .split--wide-img, .lot-detail { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .index-list { columns: 1; }
}

/* The header runs out of room before the rest of the layout does: the mark,
   five labels, the button, the phone number and three icons stop fitting at
   about 1060px. The drawer takes over there and nothing else moves. */
@media (max-width: 1060px) {
  .nav {
    display: none;
    position: absolute; top: 100%; left: 0; right: 0; z-index: var(--z-menu);
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--green-800); padding: 0 var(--gutter) 28px;
  }
  .nav.open { display: flex; }
  .nav a {
    padding: 16px 0; box-shadow: 0 1px 0 var(--on-green-rule);
    font-size: 1.03125rem;   /* the drawer has the room the bar did not */
  }
  .nav .btn { margin-top: 18px; justify-content: center; padding: 14px 31px; font-size: 0.9375rem; }
  /* .header-aside is hidden at this width, so the drawer carries the phone
     number, the bidder login and the social links instead of dropping them. */
  .nav-aside { display: flex; flex-direction: column; margin-top: 22px; }
  .nav-aside a {
    color: var(--on-green-muted); text-decoration: none;
    font-size: 0.9375rem; padding: 12px 0; min-height: 44px;
    display: flex; align-items: center;
  }
  .nav-aside .social--drawer {
    display: inline-flex; gap: 26px; margin-top: 16px; padding-block: 10px;
  }
  .nav-aside .social svg { width: 22px; height: 22px; }
  .nav-aside .social a { padding: 0; min-height: 0; }
  .burger { display: block; }
  .header-aside { display: none; }
}

@media (max-width: 860px) {
  .sale-row { grid-template-columns: 120px 1fr; }
  .sale-row img, .sale-row--pending .ph { width: 120px; }
  .sale-row > :last-child { grid-column: 1 / -1; }
  .form-grid { grid-template-columns: 1fr; }
  .topline .hide-sm { display: none; }
}

@media (max-width: 540px) {
  .footer-grid { grid-template-columns: 1fr; }
  .brand img { height: 54px; }
  .price-line dl { gap: 28px; }
}

/* ---------- a few things that only go wrong on a phone ---------- */

@media (max-width: 560px) {
  /* "Home / Auctions / Fine Jewellery / Sale 387 / Lot 1" does not fit on one
     line, and the break fell inside the last crumb, orphaning the "1".
     Only the current crumb is held together: nowrap on every link stopped the
     trail wrapping at all and pushed a separator past the right edge at 320px. */
  .crumbs-here { white-space: nowrap; }
  .crumbs > span:not(.crumbs-here) { margin-inline: 7px; }

  /* 72px tracks fit four across a 350px row, so a five-image lot left one
     thumbnail alone on a second row. 62px fits five and still clears the 44px
     tap target. */
  .gal-thumbs { grid-template-columns: repeat(auto-fill, 62px); }
  .gal-thumbs img { width: 62px; height: 62px; }

  /* Two columns of a 350px row leaves 133px for the label and 217px for the
     value, so "Getting here" sat on one line against four lines of address.
     Stacked, both get the full width. */
  .spec th, .spec td { display: block; width: auto; }
  .spec th { padding: 16px 0 2px; box-shadow: none; }
  .spec td { padding: 0 0 16px; box-shadow: 0 1px 0 var(--hairline); }
}

/* ---------- lots on a phone: a list, not a two-column grid ----------
   Two 167px columns is what 148px minimum tracks come to at 390px, and a lot
   title is long: "Bespoke Diamond & Sapphire 'Thumbs Up' Ring in 18ct Yellow
   Gold" ran to three clamped lines and still truncated mid-word, while the
   estimate wrapped under its own "Est." label. Because titles differ in
   length, the estimates in a row never landed on the same line either.

   One row per lot fixes all of it: the photograph keeps a fixed 104px square
   so every row starts at the same place, the title gets the full column width,
   and the estimate sits on one line. A row is ~136px against a ~348px card, so
   48 lots a page is also a shorter scroll than the grid it replaces.

   Scoped to .lot-grid > .lot: the homepage rotator uses .lot too and is a
   single large card by design. */
@media (max-width: 560px) {
  .lot-grid { grid-template-columns: minmax(0, 1fr); gap: 0; }

  .lot-grid > .lot {
    display: grid;
    grid-template-columns: 104px minmax(0, 1fr);
    grid-template-areas: "img no" "img title" "img est";
    grid-template-rows: auto auto 1fr;
    column-gap: 16px;
    align-content: start;
    padding: 18px 0;
    box-shadow: inset 0 -1px 0 var(--hairline);
  }
  .lot-grid > .lot:first-child { box-shadow: inset 0 1px 0 var(--hairline), inset 0 -1px 0 var(--hairline); }

  /* 92px, not 104: the text column is what should set the row height. When the
     photograph is the taller of the two, the row gains dead space under the
     estimate and the rules stop reading as an even rhythm. */
  .lot-grid > .lot > .lot-img {
    grid-area: img; width: 92px; height: 92px; margin-bottom: 0; align-self: start;
  }
  .lot-grid > .lot > .no    { grid-area: no; margin-bottom: 4px; }
  .lot-grid > .lot > h3     { grid-area: title; font-size: 1.0625rem; line-height: 1.38;
                              -webkit-line-clamp: 3; margin-bottom: 6px; }
  .lot-grid > .lot > .est   { grid-area: est; margin-top: 0; align-self: start; }

  /* The photograph no longer grows with the column, so the zoom on hover has
     nothing to do and would only jitter the row on a tap. */
  .lot-grid > .lot:hover .lot-img img { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .lot-rotator > .lot, .hc-slide { transition: none; }
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
  .hero-figure img { animation: none; opacity: 1; transform: none; }
}

/* ---------- social icons ---------- */

/* In the header they sit on green; in the footer, on the darker green. Both
   inherit currentColor, so the icons need no separate colour of their own. */
.social { display: inline-flex; align-items: center; gap: 15px; }
.social a { display: inline-flex; color: var(--on-green-muted); transition: color 200ms var(--ease); }
.social a:hover { color: var(--on-green); }
.social svg { width: 18px; height: 18px; display: block; }
.social--footer { margin-top: 2px; gap: 20px; }
.social--footer svg { width: 21px; height: 21px; }
.social--drawer { display: none; }

/* ---------- the group: Strand Coins and the Benchmark Catalogue ---------- */

.group-grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(30px, 4vw, 72px); }
.group-card figure { margin: 0 0 22px; }
.group-card img { width: 100%; height: auto; aspect-ratio: 16/10; object-fit: cover; }
.group-card h3 { font-size: 1.625rem; margin: 8px 0 12px; }
.group-card p { margin: 0 0 22px; max-width: 46ch; }

/* One line on a lot page or a category page, where the sister site answers a
   question the reader is already asking. Marked with a rule, not a box. */
.aside-note {
  position: relative; margin: 30px 0 0; padding-left: 20px;
  font-size: 0.9375rem; color: var(--muted);
}
.aside-note::before {
  content: ""; position: absolute; left: 0; top: 6px; bottom: 6px;
  width: 2px; background: var(--green-200);
}
.aside-note .ulink { margin-left: 6px; }

/* ---------- a row of text links ---------- */

.linkrow { display: flex; flex-wrap: wrap; gap: 18px 36px; }

/* ---------- question-and-answer prose ---------- */

.faq h2 { font-size: 1.5rem; margin: 2.1em 0 .5em; }
.faq h2:first-child { margin-top: 0; }
.faq h3 { font-size: 1.25rem; margin: 2em 0 .45em; color: var(--ink); }
.faq h3:first-child { margin-top: 0; }
.faq .spec { margin-top: 1.2em; }

@media (max-width: 760px) {
  .group-grid { grid-template-columns: 1fr; }
}

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

/* Every control reaches 44x44 on a touch device. The area is added with an
   overlay or min-height, never by changing padding, so nothing moves and the
   underline on .ulink stays on the baseline where it was drawn. */
/* Touch devices, plus any narrow viewport — the second half of the query is
   also what makes this testable in a resized window. */
@media (pointer: coarse), (max-width: 860px) {
  .ulink, .hc-dots button { position: relative; }
  .ulink::after,
  .hc-dots button::after {
    content: ""; position: absolute;
    top: 50%; transform: translateY(-50%); height: 44px;
  }
  .ulink::after { left: 0; right: 0; }
  .hc-dots button::after { left: -7px; right: -7px; }   /* 30px bar -> 44px */

  .hc-pause, .marquee-pause, .burger {
    min-height: 44px; display: inline-flex; align-items: center;
  }
  .social a { position: relative; }
  .social a::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 44px; height: 44px; transform: translate(-50%, -50%);
  }
  .crumbs a, .footer-grid a, .nav a { padding-block: 4px; }
}
.empty-note { margin: 40px 0 0; color: var(--muted); max-width: 52ch; }
