/* ============================================================
   MINTHOUSE — site stylesheet
   Light commerce chrome, editorial hero, auction gravitas.
   ============================================================ */

/* ---------- tokens ----------
   "Fresh pull" system: warm cream paper, warm-charcoal ink,
   flat dark surfaces, pastel foil used as thin accents — never
   as background soup. The aurora the dark bands once wore is
   gone from all three of them; see the HERO banner below. */
:root {
  /* Lifted a step in both directions: the ground goes lighter and the
     ink goes darker, so the day rooms carry the same deliberate
     separation the night ones do rather than sitting in the middle. */
  --paper: #ece8e1;
  --panel: #ffffff;
  --wash: #e0dbd1;
  --wash2: #d5cfc2;
  --ink: #120f0b;
  --ink2: #35322a;
  --mut: #5c584e;
  --faint: #8e897f;
  --line: #d2ccbf;
  --line2: #bcb5a6;
  --dark: #1c1915;
  --dark2: #29231b;
  --dark-line: #3b342a;
  --live: #9e3732;
  --up: #2e5f44;
  --down: #9e3732;
  --brass: #8f6f33;
  --brass-soft: #d3b573;
  --brass-lit: #f4e7c3;          /* the highlight the foil sweep passes through */
  /* the mint mark as a mask, so any element can carry the foil sweep */
  --mh-mark-mask: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%2064%2056'%3E%3Cpath%20fill-rule%3D'evenodd'%20d%3D'M6%2050%20V6%20H21%20L32%2020%20L43%206%20H51%20L58%2013%20V50%20H45%20V26%20L32%2042%20L19%2026%20V50%20Z%20M32%2024%20L41%2034%20L32%2046%20L23%2034%20Z'%20fill%3D'%23fff'%2F%3E%3Cpath%20d%3D'M32%2029%20L37%2034%20L32%2041%20L27%2034%20Z'%20fill%3D'%23fff'%2F%3E%3C%2Fsvg%3E");
  --holo-mint: #b9dfc9;
  --holo-sky: #b3cfe8;
  --holo-lilac: #e3cfae; /* champagne — the lilac read as AI-purple */
  --holo-butter: #ecd9a4;
  --holo-blush: #e9c3c4;
  /* Category tints — the top stop of each browse-tile gradient; the
     bottom stop is the theme's own --wash2. Stated per theme, so the
     colour-coding survives the night themes instead of being discarded
     by a kill rule the way the old hard-coded pairs were. */
  --cat-pokemon: #f6efdb;
  --cat-baseball: #edf1e7;
  --cat-basketball: #f4ece1;
  --cat-football: #efeae0;
  --cat-soccer: #eaf0ea;
  --cat-hockey: #e9eef3;
  --cat-tcg: #efeaf2;
  --cream: #f4efe3;
  --cream-dim: #e7dfcd;
  --dark-fg: #c8c2b4;
  --dark-fg-mut: #a29c8e;
  --dark-fg-dim: #8b8578;
  --up-tint: #eaf3ec;
  --brass-ink: #6b5224;           /* brass dark enough to set text on a light tint */
  --warn: #8a5613;                /* caution: reversible operator actions */
  --warn-tint: #f6efe4;
  --live-tint: #f9edea;
  --foil: linear-gradient(90deg, var(--holo-mint), var(--holo-sky) 28%, var(--holo-lilac) 55%, var(--holo-butter) 80%, var(--holo-blush));
  --font-d: "Archivo", "Inter", -apple-system, sans-serif;
  --font-b: "Inter", -apple-system, "Segoe UI", sans-serif;
  --font-m: "IBM Plex Mono", ui-monospace, SFMono-Regular, monospace;
  /* Radius scale — three values, no literals. Every component declares its
     radius once; the engraved-controls block near the end of this file is
     the single source for --r-0 and must not be duplicated upstream. */
  --r-0: 0;                       /* controls: buttons, inputs, chips, tags, modals, toasts, photography */
  --r-s: 4px;                     /* nested inside a surface: thumbnails, skeletons, small tiles */
  --r-m: 8px;                     /* page-level surfaces: cards, bands, panels, tables */
  --shadow-1: 0 1px 2px rgba(24, 22, 18, 0.06), 0 10px 26px rgba(24, 22, 18, 0.09);
  --shadow-2: 0 2px 6px rgba(24, 22, 18, 0.08), 0 22px 52px rgba(24, 22, 18, 0.15);
  /* Motion — two speeds and a fade, one easing. Six durations written
     eight ways had accreted (0.06s to .28s, the leading zero present or
     absent depending on which pass wrote the line); every transition now
     states one of these. */
  --dur-fast: 0.12s;              /* pressed states: borders, checks, small controls */
  --dur-base: 0.16s;              /* hovers, lifts, colour */
  --dur-slow: 0.28s;              /* crossfades: the checkout handover */
  --ease: ease;
  /* Spacing scale — the 4px grid. 43 distinct values had grown at the
     call sites, two thirds of them off any grid; the frequent on-grid
     values were migrated to these, and the off-grid survivors migrate as
     their components are reworked, not by a blind rewrite. */
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 40px; --s-8: 48px;
  /* Type scale — eight steps against the 31 hand-nudged sizes the file
     had reached. --fs-400 is the body; the label tier sits at --fs-100
     to --fs-300 and takes a 12px floor on phones at the foot of this
     file. Sizes already on the scale were migrated; the half-pixel
     strays keep their measured fits until each is retuned by eye. */
  --fs-100: 11px; --fs-200: 12px; --fs-300: 13px; --fs-400: 15px;
  --fs-500: 18px; --fs-600: 21px; --fs-700: 26px; --fs-800: 34px;
  --maxw: 1264px;
  --on-ink: #fff;
}

/* ---------- reset-ish ---------- */
* { box-sizing: border-box; margin: 0; padding: 0; }
/* scroll-padding clears the sticky category bar: every in-document
   anchor used to land its heading behind it, and the smooth scroll made
   the overshoot look deliberate. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scrollbar-gutter: stable; scroll-padding-top: 80px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
/* Open dialogs own the scroll: the page behind locks (the stable gutter
   above keeps the layout from shifting when the scrollbar goes). */
body.mh-lock { overflow: hidden; }
body {
  font-family: var(--font-b);
  font-size: var(--fs-400);
  line-height: 1.55;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, select, textarea { font: inherit; color: inherit; }
::selection { background: var(--ink); color: var(--paper); }

/* keyboard focus */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: var(--r-0);
}
.hero :focus-visible, .consign :focus-visible, .sellhero :focus-visible, footer.site :focus-visible {
  outline-color: var(--cream);
}

/* THE FIRST THING A KEYBOARD REACHES.

   The utility bar, the wordmark, the watchlist, the four theme rooms,
   the portfolio and wallet buttons, the search field and the whole
   category nav stand between the top of a page and its first lot — more
   than a dozen stops, twenty-odd on the browse pages — and a bidder
   moving between a grid and a lot walks all of them on every move. This
   is the one control that lets them past.

   It is the first element in every <body>, ahead of the div js/shell.js
   fills, so nothing the shell draws can get in front of it. Hidden by
   clip and not by display:none or visibility:hidden, because both of
   those take an element out of the focus order and this one has to stay
   in it. Revealed on :focus rather than :focus-visible: it appears only
   when it already holds focus, and a control the reader cannot see is
   one they cannot decide to leave.

   z-index 90 puts it over the sticky category nav (50) and the search
   suggestions (60), and under the modal overlay (100) — a modal keeps
   its own focus and must not be stepped out of sideways.

   --ink on --on-ink is the pair every button on the site is drawn with,
   so the plate reads in all four rooms without a per-theme rule. What it
   is drawn ON has to be one ground and not two: the utility bar is a
   dark band in every theme and the masthead below it is a light one in
   two of them, so a plate at the top corner straddled the seam and the
   ring the block above gives it — --ink, offset outward — disappeared
   into the dark bar in paper and porcelain. It is dropped clear of the
   bar instead and lands whole on the masthead panel, where --ink against
   --panel is the theme's own strongest pair and the ring reads exactly
   as it reads on every other control. 47 is the lowest the masthead ever
   starts: the utility bar is 40 at full width and 45 where its ticker
   takes two lines, over the 2px foil rule. The shortest masthead under
   that is 77, and the plate and its ring are 48. Aligned to the 24px
   page gutter, so on a phone it stands over the wordmark it skips. */
.skiplink {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.skiplink:focus {
  position: fixed;
  top: calc(47px + var(--s-2));
  left: var(--s-5);
  z-index: 90;
  display: inline-flex;
  align-items: center;
  width: auto;
  height: auto;
  min-height: 44px;
  overflow: visible;
  clip-path: none;
  padding: 12px 20px;
  background: var(--ink);
  color: var(--on-ink);
  border: 1px solid var(--ink);
  border-radius: var(--r-0);
  font-family: var(--font-d);
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}
/* The landmark is given tabindex="-1" in the markup so that following the
   link moves the keyboard and not only the viewport — without it the next
   Tab goes back to the masthead the reader just skipped. It takes no ring
   of its own: a 2px outline drawn around a whole page of content is not a
   focus indicator, and the control that sent focus here already showed
   one. */
main[tabindex="-1"]:focus { outline: none; }

/* thin pastel foil rule — the one decorative motif */
/* THE FOIL RULE, MADE LIVE.

   It was a static 2px gradient, and it is the only holo gesture the site
   made — one bar under the masthead, one above the footer, on every
   page. A holo does not sit still: it moves because the light does. The
   band is twice the width of the rule and drifts across it slowly
   enough to read as a sheen rather than as a loading bar. */
.foil-rule {
  height: 2px;
  background: var(--foil);
  background-size: 200% 100%;
  opacity: 0.85;
  animation: mh-foil-drift 18s linear infinite;
}
@keyframes mh-foil-drift {
  from { background-position: 0% 50%; }
  to   { background-position: 200% 50%; }
}

.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 24px; }

/* ---------- type utilities ---------- */
.eyebrow {
  font-family: var(--font-d);
  font-weight: 700;
  font-size: var(--fs-100);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mut);
}
/* Brass as TEXT is --brass-ink on a light ground and --brass-soft on a dark
   one. Plain --brass measured 3.41–4.36:1 against both and is a rule colour,
   not a type colour. In the night themes --brass-ink resolves to --brass,
   which is already the light gold those themes want. */
.eyebrow.brass { color: var(--brass-ink); }
.sellhero .eyebrow.brass, .consign .eyebrow.brass,
footer.site .eyebrow.brass { color: var(--brass-soft); }
.num, .price { font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }
.mono { font-family: var(--font-m); font-size: 12.5px; }
.up { color: var(--up); }
.down { color: var(--down); }

h1, h2, h3 { font-family: var(--font-d); line-height: 1.08; letter-spacing: -0.01em; }

/* ---------- buttons ---------- */
/* One declaration per control. This block used to be half of a pair —
   these values here, and an engraved-register override at the far end of
   the file that superseded most of them — so every tweak had to be made
   twice and the dead half still shipped its hex. The engraved values ARE
   the values; the register itself is explained at the "House control
   language" banner further down. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  font-family: var(--font-d);
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  padding: 14px 24px;
  background: var(--ink);
  color: var(--on-ink);
  border: 1px solid var(--ink);
  border-radius: var(--r-0);
  transition: background var(--dur-base) var(--ease), color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
  white-space: nowrap;
  /* The touch floor, stated once for every button on the site. The padded
     height landed at 41 and .btn.sm at 33, and three separate places in
     this file had already patched their own copy up to 44 — the archive
     pager, the archive search button, the quick bids. It belongs here. */
  min-height: 44px;
}
.btn:hover { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn.ghost { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn.ghost:hover { background: var(--ink); color: var(--on-ink); border-color: var(--ink); }
.btn.ondark { background: var(--cream); color: var(--dark); border-color: var(--cream); }
.btn.ondark:hover { background: transparent; color: var(--cream); border-color: var(--cream); }
.btn.ondark.ghost { background: transparent; color: var(--cream); border-color: rgba(250, 247, 240, 0.5); }
.btn.ondark.ghost:hover { background: var(--cream); color: var(--dark); border-color: var(--cream); }
.btn.sm { padding: 10px 16px; font-size: 10.5px; }
.btn.xl { padding: 17px 30px; font-size: var(--fs-200); letter-spacing: 0.14em; }
.btn.full { width: 100%; }
.btn[disabled] { opacity: 0.45; cursor: default; }

.linkline {
  font-weight: 600;
  font-size: 13.5px;
  transition: opacity var(--dur-base) var(--ease);
}
.linkline:hover { opacity: 0.6; }
/* A "see all" link at the end of a band head, and the cost-breakdown door
   under the bid box, are section controls rather than words in a
   sentence, and they measured 21px tall. They take the utility bar's
   transparent patch: the band head keeps 26px of air under it and the
   settle row 9px above, so nothing the patch reaches over is a target.
   The linklines INSIDE prose — the fee door in the bid note, the
   Conditions of Sale link in the guide, every one in the legal body — are
   deliberately left alone: a 44px patch over a line of running text
   reaches into the lines above and below it and takes their taps. */
.band-head .linkline, .bb-settle .linkline { position: relative; }
.band-head .linkline::after, .bb-settle .linkline::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 100%; height: 44px;
  transform: translate(-50%, -50%);
}

/* ============================================================
   HEADER
   ============================================================ */
.utilbar {
  background: var(--dark);
  color: var(--dark-fg);
  font-size: var(--fs-200);
}
.utilbar .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  /* min-height, so nothing a longer sale name does can be cut off by the
     bar. A fixed height here clipped wrapped text rather than growing. */
  /* 40, not 34. The bar was carrying a status chip, a sale name and
     three facts in a strip barely taller than its own type, which is
     what made it read as packed rather than as trim. */
  min-height: 40px;
}
/* 16, not 9. Same words, more air between them: the crowding was
   spacing before it was ever wording. */
.utilbar .ticker { display: flex; align-items: center; gap: 16px; min-width: 0; }
/* And the diamond separators get their own breathing room, so the three
   facts read as three things rather than one run-on. */
.utilbar .ticker .sep:empty { margin: 0 4px; }
/* The front page omits the ticker (the hero already says all of it), and
   space-between with one child aligns it left — which slid the whole
   utility nav across to where the wordmark sits. Pinning it right holds
   both layouts, with and without the strip. */
.utilbar nav { margin-left: auto; }
/* nowrap lives HERE, not only in the phone block. Between 721px and 768px
   the auction name wrapped to three lines inside a bar with a hard 34px
   height and was clipped top and bottom. */
.utilbar .ticker b { color: var(--cream); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* :not(.livetag) — the truncation is for the sale name, which can be
   long. The LIVE chip is a fixed mark of two words and a gem; it has
   nothing to ellipsise, and being a truncation target is what clipped
   its diamond. */
.utilbar .ticker span:not(.livetag) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.livetag {
  font-family: var(--font-d);
  font-weight: 800;
  font-size: 9px;
  letter-spacing: 0.14em;
  color: var(--on-ink);
  background: var(--live);
  padding: 2.5px 6px 2px;
  flex: none;
  line-height: 1;
}
.utilbar nav { display: flex; gap: 18px; flex: none; }
/* Sign in and Sign out are <button class="utilink"> now, not anchors to
   nowhere; they dress exactly like the links beside them. The resets at
   the top of the file strip the UA chrome from every button; the rest
   of an anchor's shape is stated here, so the markup does not have to
   carry it as an inline style. */
.utilink {
  padding: 0;
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  text-align: left;
  cursor: pointer;
}
.utilbar nav a:hover, .utilbar nav .utilink:hover { color: var(--cream); }
/* THE TAP IS BIGGER THAN THE WORD.
   Sign in, Sign out and the account link are 12px type in a 40px bar —
   measured 38x19 at 375px, and on a phone they are the only way into the
   account at all, since the marketing links go at 720. Growing the type
   or the bar to reach the touch floor would make the utility strip the
   loudest thing on the page, which is the opposite of what it is for. A
   transparent patch takes the touches instead: same device as .dash-info
   on the account page, same 44px, and nothing on screen changes. The bar
   is 40 tall, so the patch overhangs it by two pixels top and bottom —
   into the page's own top edge above and the foil rule below, neither of
   which is a target it can steal from. */
.utilbar nav a, .utilbar nav .utilink { position: relative; }
.utilbar nav a::after, .utilbar nav .utilink::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  min-width: 44px; width: 100%; height: 44px;
  transform: translate(-50%, -50%);
}

.masthead { border-bottom: 1px solid var(--line); background: var(--panel); }
.masthead .wrap {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 28px;
  height: 76px;
}
/* The wordmark keeps its natural lockup height; the grid coordinates are
   explicit at desktop and become flex coordinates in the compact header. */
.wordmark { display: block; line-height: 1; grid-column: 1; grid-row: 1; }
.wordmark .wm-row { display: flex; align-items: center; gap: var(--s-2); }
.wordmark .wm-mark { width: 21px; height: 21px; color: var(--ink); flex: none; }
.wordmark .wm-mark svg { width: 100%; height: 100%; }
footer.site .wm-mark { color: var(--cream); }
.wordmark .wm-main {
  font-family: var(--font-d);
  font-weight: 900;
  font-stretch: 122%;
  font-size: 23px;
  letter-spacing: 0.045em;
  color: var(--ink);
}
.wordmark .wm-sub {
  display: block;
  font-family: var(--font-d);
  font-weight: 600;
  font-size: 8.5px;
  letter-spacing: 0.34em;
  color: var(--mut);
  margin-top: 3px;
  text-transform: uppercase;
}
.searchbox { position: relative; max-width: 560px; width: 100%; justify-self: center; grid-column: 2; grid-row: 1; }
.searchbox input {
  width: 100%;
  height: 44px;
  border: 1px solid var(--line2);
  border-radius: var(--r-m);
  background: var(--wash);
  padding: 0 16px 0 42px;
  font-size: 14px;
  outline: none;
  transition: border-color var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
}
.searchbox input:focus { border-color: var(--ink); background: var(--panel); }
.searchbox .sicon {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--mut); pointer-events: none;
}
.search-pop {
  position: absolute;
  top: calc(100% + 6px);
  left: 0; right: 0;
  background: var(--panel);
  border: 1px solid var(--line2);
  border-radius: var(--r-m);
  box-shadow: var(--shadow-2);
  z-index: 60;
  overflow: hidden;
  display: none;
}
.search-pop.open { display: block; }
.search-pop a.hit {
  display: grid;
  grid-template-columns: 34px 1fr auto;
  gap: var(--s-3);
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
}
.search-pop a.hit:last-child { border-bottom: 0; }
.search-pop a.hit:hover { background: var(--wash); }
.search-pop .hit-thumb svg { width: 34px; height: auto; }
.search-pop .hit-t { display: block; font-size: var(--fs-300); font-weight: 600; line-height: 1.3; }
.search-pop .hit-m { display: block; font-size: 11.5px; color: var(--mut); margin-top: 2px; }
.search-pop .hit-p { font-weight: 700; font-size: var(--fs-300); }
.search-pop .allhits {
  display: block; text-align: center; padding: 11px;
  font-size: 12.5px; font-weight: 600; color: var(--ink2); background: var(--wash);
}
.search-pop .allhits:hover { background: var(--wash2); }
/* The keyboard cursor. The arrow keys move aria-activedescendant rather
   than focus — focus has to stay in the field for the next keystroke —
   so there is no :focus to paint and the selected row has to be drawn
   from its ARIA state. --wash2 reads as moved-to against both row
   backgrounds: a lot row sits on the panel, an "all hits" row is
   already on --wash. Written tighter than :hover so a pointer resting
   elsewhere in the list cannot outrank the cursor. */
.search-pop [role="option"][aria-selected="true"] { background: var(--wash2); }

.mast-actions { display: flex; align-items: center; gap: 10px; grid-column: 3; grid-row: 1; }
/* The masthead's own controls clear the touch floor in the dimension the
   row constrains. Height is free here — the bar is padded, not packed —
   so it is simply 44 rather than the 42 and 36 these measured at 375px.
   Width is not free: a phone's top line is 173px of lockup against
   whatever the controls take, and pushing four icons to 44 wide apiece
   would cost a whole extra row of masthead on a 430px phone to gain nine
   pixels on a target that is already 44 tall and 35 wide. */
.iconbtn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 44px;
  padding: 0 13px;
  border: 1px solid transparent;
  border-radius: var(--r-s);
  font-weight: 600;
  font-size: var(--fs-300);
  color: var(--ink2);
}
.iconbtn:hover { background: var(--wash); }
/* `img, svg { max-width: 100% }` globally resolves against a shrunken
   button, which collapsed the Watchlist star to a couple of pixels at 390px
   and to nothing at 375px, and left the wallet glyph 0x0 above 540px. A
   glyph has no intrinsic size to fall back on, so it is pinned here rather
   than only inside a narrow media block. */
.iconbtn svg, .btn svg { width: 17px; height: 17px; flex: none; max-width: none; }
#walletbtn svg { width: 17px; height: 17px; flex: none; max-width: none; }

/* The connected wallet, in the masthead. It shows ONE fact — the balance
   when it is known, the address when it is not — because the pair together
   made a button wide enough to crowd the search field. Tabular figures so
   the number does not jitter as it changes mid-auction, and a fixed gap so
   the dot never collides with a long figure. */
/* .btn.sm sets 10px of padding, which put these two at 36 tall beside
   44-tall neighbours; the floor is stated rather than arrived at. */
#walletbtn, #portfoliobtn { min-height: 44px; }
#walletbtn { gap: var(--s-2); }
/* Connected: the button carries two facts, stacked. Side by side they ran
   to roughly 22 characters and crowded the search field; stacked, the
   balance stays the headline and the address sits under it as a caption.
   The button is allowed to grow for it — it is showing more than
   "Connect wallet" did. */
#walletbtn.wb-on { padding-top: 7px; padding-bottom: 7px; align-items: center; }
#walletbtn .wb-stack {
  display: flex; flex-direction: column; align-items: flex-start;
  line-height: 1.15; min-width: 0;
}
#walletbtn .wb-bal {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: var(--fs-300);
  letter-spacing: 0.01em;
  white-space: nowrap;
}
/* The caption. Deliberately quiet: it identifies the account, it is not
   the number anybody is reading. `solo` is the no-balance case, where the
   address is the only thing there and should not look like a footnote. */
#walletbtn .wb-addr {
  font-size: 9.5px; letter-spacing: .02em; opacity: .72; white-space: nowrap;
}
#walletbtn .wb-addr.solo { font-size: 11.5px; opacity: 1; }
/* "in wallet" — the qualifier that stops the figure reading as bid capacity
   under escrow. Quiet, and never wrapping away from the number it governs. */
#walletbtn .wb-qual { font-weight: 400; font-size: 9.5px; opacity: .7; margin-left: 3px; letter-spacing: .02em; }
/* Connected-and-on-the-right-chain. */
#walletbtn .wb-dot { font-size: 0.62em; line-height: 1; opacity: .85; flex: none; }
.iconbtn .cnt {
  position: absolute; top: 2px; right: 4px;
  min-width: 15px; height: 15px;
  background: var(--ink);
  color: var(--on-ink);
  font-size: 9.5px; font-weight: 700;
  display: none; align-items: center; justify-content: center;
  padding: 0 4px;
}
.iconbtn .cnt.on { display: inline-flex; }

.catnav {
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 50;
}
.catnav .wrap { display: flex; align-items: stretch; gap: var(--s-1); overflow-x: auto; scrollbar-width: none; }
.catnav .wrap::-webkit-scrollbar { display: none; }
.catnav a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-d);
  font-weight: 700;
  font-size: var(--fs-300);
  letter-spacing: 0.02em;
  padding: 13px 13px 11px;
  border-bottom: 2px solid transparent;
  color: var(--ink2);
  white-space: nowrap;
}
.catnav a .ni { width: 15px; height: 15px; color: var(--mut); flex: none; }
.catnav a .ni svg { width: 100%; height: 100%; }
.catnav a:hover .ni, .catnav a.active .ni { color: var(--ink); }
.catnav a:hover { color: var(--ink); border-bottom-color: var(--line2); }
.catnav a.active, .catnav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--ink); }
/* Both nav strips scroll on a phone with their scrollbars hidden, and
   nothing said so — at 375px "Consign" sat entirely off-screen with no
   cue it existed. The edge fade is the cue. At rest each fade covers
   only the wrap's own padding, so nothing legible sits under it unless
   there is more strip to scroll to. */
.catnav .wrap, .catbar .wrap {
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(90deg, transparent 0, #000 24px, #000 calc(100% - 28px), transparent);
}

/* ============================================================
   THE CHROME RESERVES ITS OWN SPACE
   ============================================================
   #site-header and #site-footer ship as empty divs and are filled by
   js/shell.js at boot, so every page painted its content against the top
   of the viewport and then had it shoved down by a masthead arriving
   late. Measured with the layout-shift API, observer installed before the
   document ran: 1.00 on the front page and on a lot at 1280, 0.93 at 768,
   0.71 on the browse grid, 0.23 on each of the three documents — "poor"
   by the 0.25 line on four of twelve pages and over the 0.1 "good" line
   on nine of them, with <main> named as the shifting node every time.
   Nothing about it was a rendering cost. The height of the furniture is
   known before a byte of JSON arrives, because it is furniture.

   The floors below are the rendered header measured to the pixel under:

     40      utility bar (its own min-height)
      2      foil rule
     77 · 123 · 154   masthead, at one, two and three wrapped rows
     47.14   category nav
     ----
     166 · 212 · 243

   Deliberately a pixel or two SHORT of the real height rather than over.
   A floor that overshoots leaves a band of bare paper hanging under the
   nav on every page, which is a visible defect; a fraction of a pixel of
   residual shift is not one. Re-measured with remote fonts blocked, in
   case a failed webfont changed the nav's line box: identical to the
   pixel, so this does not depend on Google answering.

   416px is not a round number, it is where the masthead's top line stops
   fitting: 173.3 of lockup plus 8 of gap plus 187.3 of controls plus 48
   of gutter is 416.7, so 417 is the first width that holds them on one
   row and 416 is the last that spends a third row on them.

   /auctions is the one page left with a shift, and it is 45px rather than
   248: its category bar is unhidden by js/browse.js, on that page only,
   so no rule here can know to reserve it. */
#site-header { min-height: 166px; }
@media (max-width: 1160px) { #site-header { min-height: 212px; } }
@media (max-width: 416px)  { #site-header { min-height: 243px; } }

/* The footer is the last thing in the document, so filling it cannot
   displace anything above it — this floor is not about layout shift. It
   is about the short pages (status, confirm, unsubscribe) ending at their
   own last sentence with nothing under them and then growing a whole
   footer, which moves the scrollbar out from under the reader's hand.
   300px is the shortest the real footer ever measures, at the widest
   layout where its six columns are one row; every narrower viewport
   stacks it taller, so this floor cannot overshoot at any width. */
#site-footer { min-height: 300px; }

/* ============================================================
   HERO
   ============================================================ */
/* Flat. The stage wore three radial aurora layers and a feTurbulence
   noise overlay here, was given three quieter layers in a later pass,
   and was finally flattened by a third — with the first two layers and
   the noise data-URI still shipping dead. The flattening is now simply
   what the rule says; the editorial treatment is at the HERO banner
   near the end of this file. */
.hero {
  background: var(--paper);
  color: var(--ink);
  overflow: hidden;
  position: relative;
}
.hero .wrap {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: var(--s-8);
  align-items: center;
  padding-top: 58px;
  padding-bottom: 62px;
}
.hero-eyebrow { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.hero h1 {
  min-height: 2.1em;
  font-size: clamp(30px, 4vw, 46px);
  font-weight: 800;
  font-stretch: 112%;
  letter-spacing: -0.015em;
  line-height: 1.04;
  margin-bottom: 20px;
  max-width: 13em;
}
.hero .lotmeta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  color: var(--dark-fg); font-size: var(--fs-300); margin-bottom: 26px;
}
.gradechip {
  display: inline-flex; align-items: center;
  font-family: var(--font-d);
  font-weight: 800; font-size: 11.5px; letter-spacing: 0.06em;
}
.hero .bidblock { display: flex; align-items: flex-end; gap: var(--s-7); margin-bottom: 30px; }
.hero .bidblock .lbl { font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--dark-fg-mut); font-weight: 600; margin-bottom: 6px; }
/* min-height, for the same reason .hero h1 above carries one: js/home.js
   writes the figure and the clock into empty divs, and an empty div has no
   line box at all, so the whole block below them jumped a line's worth
   when the bootstrap landed. One line is exactly what each of them ever
   holds, so the reserve is the rendered height. */
.hero .bidblock .val { font-size: clamp(30px, 3.4vw, 42px); font-weight: 700; letter-spacing: -0.02em; line-height: 1; min-height: 1em; }
.hero .bidblock .sub { font-size: 12.5px; color: var(--dark-fg-mut); margin-top: 7px; }
.hero-ctas { display: flex; gap: var(--s-3); flex-wrap: wrap; }
.hero-media { position: relative; display: flex; justify-content: center; }
/* The stage holds its shape before the slab arrives. js/slabs.js draws
   every holder on one viewBox, "0 0 340 554", so the box the drawing will
   occupy is known exactly — and below 940px the media column takes
   order:-1 and sits ABOVE the copy, so an empty anchor growing to 489px
   pushed the headline, the price and both buttons down the screen after
   paint. That single box was most of the front page's 0.93 layout shift
   at 768. Stated as the drawing's own ratio rather than a pixel height,
   so it stays exact at every width the wrap resolves to. */
.hero-media .slabwrap {
  width: min(360px, 80%);
  aspect-ratio: 340 / 554;
  filter: drop-shadow(0 30px 60px rgba(0, 0, 0, 0.55));
}
.hero-media::before {
  content: "";
  position: absolute;
  inset: auto 8% -34px 8%;
  height: 60px;
  background: radial-gradient(50% 100% at 50% 0%, rgba(0, 0, 0, 0.5), transparent 70%);
}

/* ============================================================
   SECTIONS
   ============================================================ */
section.band { padding: 54px 0 60px; }
section.band.washed { background: var(--wash); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.band-head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 20px;
  margin-bottom: 26px;
}
.band-head h1, .band-head h2 {
  font-size: 25px;
  font-weight: 800;
  font-stretch: 112%;
  letter-spacing: -0.01em;
  margin-top: 7px;
}
.band-head .linkline { flex: none; margin-bottom: 4px; }

/* ---------- lot cards ---------- */
.lotgrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(236px, 1fr);
  gap: 18px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 6px;
  scrollbar-width: thin;
}
.rail > * { scroll-snap-align: start; }

.lotcard {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: box-shadow var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
  position: relative;
}
.lotcard-link {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
  color: inherit;
}
.lotcard:hover { box-shadow: var(--shadow-2); transform: translateY(-2px); border-color: var(--line2); }
.lotcard .thumb {
  background: linear-gradient(180deg, var(--wash) 0%, var(--wash2) 100%);
  padding: 18px 34px 14px;
  position: relative;
}
.lotcard .thumb[data-cat="pokemon"]    { background: linear-gradient(180deg, var(--cat-pokemon), var(--wash2)); }
.lotcard .thumb[data-cat="baseball"]   { background: linear-gradient(180deg, var(--cat-baseball), var(--wash2)); }
.lotcard .thumb[data-cat="basketball"] { background: linear-gradient(180deg, var(--cat-basketball), var(--wash2)); }
.lotcard .thumb[data-cat="football"]   { background: linear-gradient(180deg, var(--cat-football), var(--wash2)); }
.lotcard .thumb[data-cat="soccer"]     { background: linear-gradient(180deg, var(--cat-soccer), var(--wash2)); }
.lotcard .thumb[data-cat="hockey"]     { background: linear-gradient(180deg, var(--cat-hockey), var(--wash2)); }
.lotcard .thumb[data-cat="tcg"]        { background: linear-gradient(180deg, var(--cat-tcg), var(--wash2)); }
.lotcard .thumb svg { width: 100%; height: auto; }
.lotcard .watch {
  position: absolute; top: 8px; right: 8px;
  width: 38px; height: 38px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-s);
  color: var(--mut);
  background: rgba(255, 255, 255, 0.65);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease);
}
/* The star keeps its 38px pill and takes 44px of touches. It sits 8px
   inside a corner the card clips, so the patch stays within the tile and
   the only thing under it is the thumb it is drawn on — the card's own
   link is the body below, not the photograph. */
.lotcard .watch::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 44px; height: 44px;
  transform: translate(-50%, -50%);
}
.lotcard:hover .watch, .lotcard:focus-within .watch, .lotcard .watch:focus-visible, .lotcard .watch.on { opacity: 1; }
.lotcard .watch:hover { color: var(--ink); background: #fff; }
.lotcard .watch.on { color: var(--brass); }
.lotcard .watch svg { width: 16px; height: 16px; }
.lotcard .body { padding: 14px 16px 15px; display: flex; flex-direction: column; gap: var(--s-2); flex: 1; }
/* The lot number and the estimate are the two facts that make a tile a lot
   rather than a product. --faint is the decoration tier and measured
   3.01/3.10/3.49/3.88:1 here and 2.24/2.38/3.08/3.53:1 on .est. */
.lotcard .meta { display: flex; justify-content: space-between; font-size: var(--fs-100); letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut); font-weight: 600; }
.lotcard .title {
  font-size: 13.8px;
  font-weight: 600;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 2.7em;
}
.lotcard:hover .title { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
.lotcard .gradeline { display: flex; gap: 6px; align-items: center; }
.gradetag {
  font-family: var(--font-d);
  font-weight: 800;
  font-size: 10.5px;
  letter-spacing: 0.05em;
  background: var(--ink);
  color: var(--on-ink);
  padding: 3px 6px;
}
.gradetag.auto { background: var(--brass); }
.gradetag.ghost { background: transparent; color: var(--ink2); }
.lotcard .priceline { display: flex; align-items: baseline; justify-content: space-between; margin-top: auto; }
.lotcard .bid { font-size: var(--fs-500); font-weight: 700; letter-spacing: -0.01em; }
.lotcard .bids { font-size: var(--fs-200); color: var(--mut); }
.lotcard .clock {
  display: flex; align-items: center; justify-content: space-between;
  border-top: 1px solid var(--line);
  margin: 4px -16px -15px;
  padding: 9px 16px;
  background: var(--wash);
  font-family: var(--font-m);
  font-size: 11.5px;
  color: var(--ink2);
}
/* A countdown is never red. Under an hour the tile leans on weight; the
   words change in js/shell.js, which is where urgency belongs. */
.lotcard .clock .cd.soon { font-weight: 700; }
.lotcard .clock .est { color: var(--mut); font-family: var(--font-b); }
.lotcard.closed .clock { color: var(--mut); }
.soldtag {
  position: absolute; top: 10px; left: 10px;
  font-family: var(--font-d); font-weight: 800; font-size: 10px; letter-spacing: 0.1em;
  background: var(--live); color: var(--on-ink); padding: 3px 7px;
}

/* ---------- category tiles ---------- */
.cattiles { display: grid; grid-template-columns: repeat(6, 1fr); gap: 14px; }
.cattile {
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  background: var(--panel);
  padding: 18px 16px 16px;
  transition: box-shadow var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
  position: relative;
  overflow: hidden;
}
.cattile:hover { box-shadow: var(--shadow-1); transform: translateY(-2px); }
.cattile .mini { display: block; width: 64px; margin-bottom: 12px; }
.cattile b { display: block; font-family: var(--font-d); font-weight: 800; font-size: 14.5px; letter-spacing: 0.01em; }
.cattile span { font-size: var(--fs-200); color: var(--mut); }
.cattile .arr { position: absolute; right: 14px; bottom: 14px; width: 15px; height: 15px; color: var(--faint); transition: transform var(--dur-base) var(--ease), color var(--dur-base) var(--ease); }
.cattile:hover .arr { transform: translateX(3px); color: var(--ink); }

/* ---------- results ---------- */
.resulttable { width: 100%; border-collapse: collapse; }
.resulttable th {
  text-align: left;
  font-size: var(--fs-100); letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--mut); font-weight: 600;
  padding: 0 14px 10px;
  border-bottom: 1px solid var(--line2);
}
.resulttable td { padding: 13px 14px; border-bottom: 1px solid var(--line); font-size: 13.5px; }
.resulttable tr:hover td { background: var(--wash); }
.resulttable .rt-title { font-weight: 600; max-width: 560px; }
.resulttable .rt-price { font-weight: 700; text-align: right; white-space: nowrap; font-size: 14.5px; }
.resulttable .rt-date, .resulttable .rt-auction { color: var(--mut); white-space: nowrap; }
.resulttable th.rt-price { text-align: right; }

/* ---------- consign band ---------- */
/* the consign band keeps its dark stage, loses the orbs */
.consign { background: var(--dark); color: var(--cream); }
.consign .wrap {
  display: grid; grid-template-columns: 1.3fr 0.7fr; gap: var(--s-7); align-items: center;
  padding-top: 58px; padding-bottom: 58px;
}
.consign h2 { font-size: clamp(24px, 2.6vw, 32px); font-weight: 800; font-stretch: 112%; margin: 10px 0 12px; }
.consign p { color: var(--dark-fg); max-width: 46em; }
.consign .cta { justify-self: end; display: flex; gap: var(--s-3); flex-wrap: wrap; }
/* The consignment terms, set as terms and not as metrics.

   This was .stats: three figures at 22px with their names stacked
   underneath in 600-weight tracked uppercase. That stack — a large
   number over a small caption — is the house style of a product
   page, and it made three ordinary contract terms look like traction
   numbers. Here the figure and the thing it measures sit on ONE
   baseline, in the reading register, divided by the same hairline the
   rest of the site divides things with. The number still leads,
   because it is the part a consignor is looking for. */
.consign .terms {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  column-gap: 0;
  row-gap: 8px;
  margin: 20px 0 0;
  max-width: 46em;
  color: var(--dark-fg);
  font-size: var(--fs-300);
}
/* The divider TRAILS its term rather than leading the next one.

   Led, it survives a line break at the start of the new line, where a
   lone vertical rule in front of "7 days" reads as a list bullet — which
   is what the first build of this did at every width where the estimate
   button squeezed the column. Trailing, a wrap leaves the rule at the
   end of the line above, where it reads as the continuation it is. */
.consign .terms span { display: inline-flex; align-items: baseline; gap: 0.4em; }
.consign .terms span:not(:last-child) {
  margin-right: 20px;
  padding-right: 20px;
  border-right: 1px solid var(--dark-line, rgba(255, 255, 255, 0.16));
}
.consign .terms b {
  font-family: var(--font-d);
  font-weight: 800;
  font-size: 19px;
  letter-spacing: -0.01em;
  color: var(--cream);
}
@media (max-width: 640px) {
  /* One term per line on a phone, and no rules at all: a divider
     between two things that are already on separate lines is doing
     nothing but taking ink. */
  .consign .terms { display: block; }
  .consign .terms span { display: block; margin: 0 0 6px; }
  .consign .terms span:not(:last-child) { margin-right: 0; padding-right: 0; border-right: 0; }
}

/* ============================================================
   FOOTER
   ============================================================ */
footer.site {
  background: var(--dark);
  color: var(--dark-fg-mut);
  font-size: var(--fs-300);
  margin-top: 0;
}
footer.site .cols {
  display: grid;
  /* Six now: the brand, four link groups, and the Hobby Brief signup.
     The brief column is widest after the brand because it holds a field
     and a sentence rather than a list of short links, and at 1fr the
     input wrapped its button onto a second line at every desktop
     width. */
  grid-template-columns: 1.4fr 1fr 1fr 1fr 1fr 1.5fr;
  gap: 32px;
  padding: 46px 0 32px;
  border-bottom: 1px solid var(--dark-line);
}
/* ---------- the Hobby Brief signup, in the footer ---------- */
footer.site .brief-blurb {
  margin-top: 14px;
  line-height: 1.6;
  color: var(--dark-fg-mut);
}
footer.site .briefform {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}
footer.site .briefform input {
  flex: 1 1 auto;
  min-width: 0; /* a flex item's default min-width:auto is what pushes a
                   field out of its column instead of letting it shrink */
  /* There is no --dark-field token: the footer is the only dark surface
     on the site that takes typed input, so the fill is stated here
     rather than invented as a global nobody else would use. */
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--dark-line);
  border-radius: 6px;
  color: #fff;
  font: inherit;
  font-size: 13px;
  padding: 8px 10px;
  /* 41px measured at 375. A signup field and its button are the only
     controls in the footer and they take the same floor as everything
     else on a phone. */
  min-height: 44px;
}
/* --dark-fg-mut, not -dim: a placeholder is text and owes the same
   4.5:1 as body copy. -dim measured 4.0 against the footer in midnight,
   which tools/design-contrast.js reads as the failure it is. */
footer.site .briefform input::placeholder { color: var(--dark-fg-mut); }
footer.site .briefform input:focus-visible {
  outline: 2px solid var(--brass, #8f6f33);
  outline-offset: 1px;
}
footer.site .briefform button { flex: 0 0 auto; min-height: 44px; }
footer.site .brief-said {
  margin-top: 10px;
  line-height: 1.55;
  color: var(--dark-fg-mut);
}
/* The refusal is the one line here a reader must not skim past.
   --live is what .errmsg uses for the same job elsewhere. */
footer.site .brief-said.bad { color: var(--live); }
@media (max-width: 1100px) {
  /* Before the two-column fallback below, the brief needs its own row:
     squeezed to a fifth of a narrow grid the field is unusable. */
  footer.site .cols { grid-template-columns: 1.4fr 1fr 1fr 1fr 1fr; }
  footer.site .briefcol { grid-column: 1 / -1; }
}
footer.site .brandcol .wm-main { color: #fff; font-size: 19px; }
/* the token, not its paper-theme literal — the hard-coded grey was the
   one thing on a porcelain page still wearing the warm theme */
footer.site .brandcol .wm-sub { color: var(--dark-fg-dim); }
footer.site .brandcol p { margin-top: 14px; line-height: 1.6; max-width: 30em; color: var(--dark-fg-mut); }
/* h2, not h4. These are labels for link groups, not a fourth level of
   the document outline, and as h4 they skipped a level on every page
   that ended in an h2 -- which is most of them. Going UP a level is
   never a skip, so h2 is safe under any page. The rule moved with the
   tag; the type is unchanged. */
footer.site h2 {
  font-family: var(--font-d);
  color: var(--cream); font-size: 11.5px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase;
  margin-bottom: 14px;
}
footer.site ul { list-style: none; display: grid; gap: 9px; }
footer.site ul a:hover { color: var(--cream); }
/* THE FOOTER'S LINK COLUMNS TAKE SPACING, NOT 44px BOXES.
   Measured at 375px these are 20px tall on a 9px gap — a 29px pitch. The
   honest fix everywhere else on the site is to grow the control, and here
   it is the wrong one: four lists of five links at 44px apiece adds about
   300px to a footer that already runs 842 on a phone, and the reader
   would be scrolling past the house's site map to reach the fine print.
   The pitch goes to 40 instead, which is what separates the targets, and
   the type stays the size a footer's type is. */
@media (max-width: 720px) {
  footer.site ul { gap: 20px; }
  footer.site .legalrow { gap: 16px 18px; }
}
/* THE PITCH IS NOT THE TARGET, THOUGH.

   Everything above separates one footer link from the next; none of it
   ever made a single one of them big enough to hit. What a pointer has
   to land on is the link's own box, and measured at 375 that box is
   16px tall in these columns (13px type), 14 on the fine line and 20 in
   the legal row, against the 24 that WCAG 2.5.8 asks. Twenty-one
   targets, on every page of the site.

   The columns and the fine line take their padding on an INLINE box
   deliberately. Vertical padding on an inline non-replaced element is
   painted and hit-tested but never enters the line box, so each of these
   targets grows ten pixels and not one baseline in the footer moves —
   the 300px of extra footer the block above refused to spend is still
   not spent. The padding reaches about three pixels into the space above
   and below, which is empty: no other target lives there, so nothing is
   taken from a neighbour the way a 44px patch laid over a line of prose
   would take it. */
footer.site ul a { padding: 5px 0; }     /* 16 -> 26 */
footer.site .fine a { padding: 6px 0; }  /* 14 -> 26 */
/* The legal row is a flex container, so its links are blockified and the
   trick above is not open to them: padding there really would push the
   row taller and open the gaps between its wrapped lines. The negative
   margin hands back exactly what the padding took, so the outer box, the
   row's height and the space between its lines are the numbers they
   were, and the target inside them is 26px rather than 20. Symmetrical,
   so the baseline the whole row is aligned on does not move either. */
footer.site .legalrow a { padding: 3px 0; margin: -3px 0; }
footer.site .fine {
  padding: 18px 0 0;
  font-size: 11.5px;
  line-height: 1.7;
  color: var(--dark-fg-dim);
}
footer.site .fine p { margin: 0; }
footer.site .legalrow {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 18px;
  padding: 14px 0 30px;
  color: var(--dark-fg-mut);
}
footer.site .legalrow a:hover { color: var(--cream); }
footer.site .legalrow .demo { margin-left: auto; color: var(--dark-fg-dim); }

/* ============================================================
   BROWSE
   ============================================================ */
.browsehead { border-bottom: 1px solid var(--line); background: var(--wash); }
.browsehead .wrap { padding-top: 30px; padding-bottom: 24px; }
.browsehead h1 { font-size: 27px; font-weight: 800; font-stretch: 112%; margin-top: 8px; }
.browsehead .sub { color: var(--mut); font-size: 13.5px; margin-top: 8px; }
/* The heading and its closing line share one baseline: as stacked rows
   the band ran four lines tall and read as a list. Wraps on a phone,
   where the two facts stack again because they must. */
.browsehead .bh-row { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; }
.browsehead .bh-row h1 { margin-top: 8px; }
/* One line held open. js/browse.js writes the closing line into an empty
   div, and an empty div has no line box, so the whole grid stepped down
   20px when the bootstrap landed. */
.browsehead .bh-row .sub { margin-top: 0; min-height: 20px; }

.browse-layout {
  display: grid;
  grid-template-columns: 248px 1fr;
  gap: 36px;
  align-items: start;
  padding: 30px 0 70px;
}
.facets { position: sticky; top: 64px; display: grid; gap: var(--s-1); }
.facet { border-bottom: 1px solid var(--line); padding: 14px 0 16px; }
.facet:first-child { padding-top: 0; }
/* h2 for the same reason as the footer: these sat under the page h1 and
   skipped two levels to reach h4. */
.facet h2 {
  font-family: var(--font-d);
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 11px;
  display: flex; justify-content: space-between; align-items: center;
}
.facet .opt {
  display: flex; align-items: center; gap: 9px;
  padding: 4.5px 0;
  font-size: 13.5px;
  color: var(--ink2);
  cursor: pointer;
  user-select: none;
}
.facet .opt:hover { color: var(--ink); }
.facet .opt .box {
  width: 15px; height: 15px;
  border: 1.5px solid var(--line2);
  flex: none;
  display: flex; align-items: center; justify-content: center;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.facet .opt input {
  position: absolute;
  opacity: 0;
  width: 15px; height: 15px;
  margin: 0;
  pointer-events: none;
}
.facet .opt input:focus-visible + .box { outline: 2px solid var(--ink); outline-offset: 2px; }
.facet .opt input:checked + .box { background: var(--ink); border-color: var(--ink); }
.facet .opt input:checked + .box::after {
  /* the mint-mark gem, set into the plate */
  content: "";
  width: 5px; height: 5px;
  background: var(--on-ink);
  transform: rotate(45deg);
}
.facet .opt .n { margin-left: auto; color: var(--mut); font-size: var(--fs-200); }
button.clear, .facet .clear { font-size: var(--fs-200); color: var(--mut); font-weight: 600; cursor: pointer; letter-spacing: 0.02em; background: none; border: 0; padding: 2px 4px; font-family: inherit; }
.facet .clear:hover { color: var(--ink); }

.browse-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
  margin-bottom: 18px;
}
.browse-toolbar .count { font-size: 13.5px; color: var(--mut); }
.browse-toolbar .count b { color: var(--ink); font-weight: 700; }
.sortsel { display: flex; align-items: center; gap: 9px; font-size: var(--fs-300); color: var(--mut); }
/* `display: flex` above outranks the UA's own [hidden] rule, so a sort
   control that ships hidden has to be told so here. /results does exactly
   that: one sale is not a choice, and the filter used to be rendered and
   then taken away at boot, which shrank the band head under the table. */
.sortsel[hidden] { display: none; }
.sortsel select, select.sortsel {
  /* 44, not 38. The archive's copy of this control already carried an
     inline 44 to escape the same shortfall; the height is the height.

     `select.sortsel` alongside the descendant form: the portfolio page
     puts the class on the SELECT itself rather than on a wrapper, and a
     control matched by neither rule shipped in the browser's own grey —
     the one element on the Salon page wearing another product's theme. */
  height: 44px;
  border: 1px solid var(--line2); border-radius: var(--r-s);
  background: var(--panel); color: var(--ink); padding: 0 10px;
  font-size: var(--fs-300); font-weight: 600;
  outline: none; cursor: pointer;
}
.sortsel select:focus, select.sortsel:focus { border-color: var(--ink); }
/* UNAVAILABLE IS SAID WITH THE SURFACE, NOT BY DIMMING THE WORDS.

   The archive disables Sort while the featured grid stands, because
   there are no sections to reorder yet — correct, and the only thing
   missing was a house style for it, so the browser supplied its own:
   #918e86 on paper, which measured 3.18:1 against a 4.5 requirement and
   was the single node below AA in a 15,341-node sweep. A disabled
   control is exempt from 1.4.3, which is exactly why it is worth not
   leaning on: the state reads off the washed field and the cursor, and
   the label stays legible to somebody deciding whether to search.
   Never opacity here — it lowers the ratio it is trying to excuse.

   `-webkit-text-fill-color` because `color` alone loses: Chrome greys a
   disabled control through an internal fill that sits above the cascade,
   so setting `color` moved the measurement from 3.18:1 to 2.69:1 and no
   further — the ink landed at --mut composited 0.7 over the field, which
   is the fill doing it, not the cascade. The background measured clean at
   --wash through the same read, so this is text-only and not element
   opacity. The fill property is the one the browser actually reads, and
   `opacity: 1` stops the same trick being played a second way. */
.sortsel select:disabled, select.sortsel:disabled,
.sortsel select option:disabled {
  color: var(--mut); -webkit-text-fill-color: var(--mut); opacity: 1;
  background: var(--wash); cursor: not-allowed;
}
.browse-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.emptystate {
  border: 1px dashed var(--line2); border-radius: var(--r-m);
  padding: 60px 30px; text-align: center; color: var(--mut);
}
.emptystate b { display: block; color: var(--ink); font-size: 16px; margin-bottom: 6px; }

/* ============================================================
   WORKING INDICATOR — the mint mark, foil-sheened
   ------------------------------------------------------------
   The same mark and the same sweep as the page-transition loader,
   scaled down for in-page waits (archive queries, search, any
   pending fetch) so every wait on the site looks like the house.
   ============================================================ */
.mhload { display: inline-flex; align-items: center; gap: 9px; }
.mhload .mk {
  width: 23px; height: 20px; flex: none;
  -webkit-mask: var(--mh-mark-mask) center/contain no-repeat;
  mask: var(--mh-mark-mask) center/contain no-repeat;
  background: linear-gradient(112deg, var(--brass) 0%, var(--brass) 34%, var(--brass-lit) 50%, var(--brass) 66%, var(--brass) 100%) 0 0/260% 100%;
  animation: mhsheen 1.5s ease-in-out infinite, mhadmire 2.8s ease-in-out infinite alternate;
}
.mhload.sm .mk { width: 17px; height: 15px; }
.mhload.block {
  display: flex; flex-direction: column; gap: var(--s-3);
  align-items: center; justify-content: center;
  padding: 54px 20px; color: var(--mut); font-size: 13.5px;
}
.mhload.block .mk { width: 46px; height: 40px; }
@keyframes mhsheen { 0% { background-position: 130% 0; } 100% { background-position: -30% 0; } }
@keyframes mhadmire {
  0% { transform: perspective(700px) rotateY(-13deg) rotateX(4deg); }
  100% { transform: perspective(700px) rotateY(13deg) rotateX(-3deg); }
}
@media (prefers-reduced-motion: reduce) {
  .mhload .mk { animation: mhsheen 2.4s linear infinite; }
}

/* ============================================================
   LOT PAGE
   ============================================================ */
.crumbbar { border-bottom: 1px solid var(--line); background: var(--wash); font-size: 12.5px; color: var(--mut); }
/* The links fill the bar's own 44, so its padding goes: a 44px control
   inside 6px of padding is a 56px bar, and the bar was already the right
   height — it was the links inside it that measured 15 and 19. */
.crumbbar .wrap { display: flex; align-items: center; justify-content: space-between; gap: 8px 16px; flex-wrap: wrap; min-height: 44px; }
.crumbbar a { display: inline-flex; align-items: center; min-height: 44px; }
.crumbbar .lotnav { white-space: nowrap; }
.crumbbar a:hover { color: var(--ink); text-decoration: underline; }
/* The separator is arguably decoration and the audit classed it that way,
   but it is a rendered glyph in a text run and it measured 2.24:1. Cheaper
   to clear it than to argue the exemption. */
.crumbbar .sep { margin: 0 7px; color: var(--mut); }
/* Previous lot and Next lot are how a phone walks the sale, and they
   measured 19px tall. The bar already reserves 44 for itself, so the
   links simply fill it. */
.crumbbar .lotnav { display: flex; gap: var(--s-4); font-weight: 600; }

.lot-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 440px;
  gap: 44px;
  padding: 34px 0 60px;
  align-items: start;
}
.lot-media { position: sticky; top: 76px; }
.lot-stage {
  background: linear-gradient(180deg, var(--wash) 0%, var(--wash2) 100%);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  padding: 34px 56px;
  display: flex; justify-content: center;
}
.lot-stage .slabwrap {
  width: min(380px, 100%);
  /* The hero's reasoning, on the page where it cost most: below 940px the
     media column stacks above the lot panel, so 619px of holder arriving
     late pushed the title, the current bid, the countdown and the bid
     form down after paint — the 1.00 layout shift the lot page measured
     at 768. One viewBox, "0 0 340 554", for every slab js/slabs.js draws. */
  aspect-ratio: 340 / 554;
  filter: drop-shadow(0 24px 40px rgba(34, 29, 49, 0.28));
  transition: transform var(--dur-fast) ease-out;
  transform-style: preserve-3d;
  will-change: transform;
}
/* And the crop strip under it, which is always exactly three buttons
   (js/lot.js: the whole slab, the label, the card). 64px wide less 12 of
   padding and 2 of border leaves 50 of drawing, which on the same viewBox
   is 81.5 tall — 95.5 with the frame back on. 95 is that, rounded down so
   the reserve can never stand taller than what fills it. */
.lot-thumbs { display: flex; gap: 10px; margin-top: 14px; min-height: 95px; }
.lot-thumbs button {
  flex: none;
  width: 64px;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  background: var(--wash);
  padding: 6px;
  transition: border-color var(--dur-fast) var(--ease);
}
.lot-thumbs button.active, .lot-thumbs button:hover { border-color: var(--ink); }
.lot-thumbs svg { width: 100%; height: auto; }
.lot-note { margin-top: 16px; font-size: var(--fs-300); color: var(--mut); line-height: 1.6; }
.lot-note b { color: var(--ink2); }

/* ONE line of title held open, and one line only.
   js/lot.js writes the title into an empty h1 and the sub-line and the
   watch control into empty boxes, so the bid panel underneath them —
   price, countdown, the bid form — arrived, then dropped 100px. That was
   what the layout-shift API named on this page at 1024 and above once the
   holder above was reserved: DIV.bidbox moving, not growing.
   ONE line because the catalogue has both: "1952 Topps Mickey Mantle
   #311" measures 29.5 in the 440px rail and the One Piece secret rare
   measures 59. Reserving the longer of the two would hang 29.5px of empty
   paper under every short title, which is a defect you can see and half a
   shift is not. */
.lot-panel h1 { font-size: 23px; font-weight: 800; font-stretch: 108%; line-height: 1.18; letter-spacing: -0.01em; min-height: 1.18em; }
.lot-sub { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; color: var(--mut); font-size: var(--fs-300); margin-top: 10px; min-height: 20px; }
.lot-sub .gradetag { font-size: var(--fs-100); }
.lot-sub .cert { font-family: var(--font-m); font-size: 11.5px; }
/* The star and its word are written in by js/lot.js; 23 is the row they
   land at, rounded down so the reserve is never taller than they are. */
.watchrow { margin-top: 6px; min-height: 23px; }
/* 20px of type carrying a 44px tap, by the utility bar's patch rather
   than by a 44px-tall box: this line sits between the lot title and the
   bid panel and a padded control there reads as a button competing with
   Place bid, which is the one control on the page that should. */
.watchrow button { position: relative; display: inline-flex; gap: 7px; align-items: center; font-size: var(--fs-300); font-weight: 600; color: var(--mut); }
.watchrow button::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 100%; height: 44px;
  transform: translate(-50%, -50%);
}
.watchrow button:hover { color: var(--ink); }
/* The pressed label used to take --brass with the star. As text at 13px
   weight 600 that measured 3.76:1 against a 4.5 requirement in paper, at
   1440 and at 375, which the second pass of tools/design-contrast.js
   found on its first run. The star keeps the brass, where 1.4.11's 3:1
   applies and 3.76 clears it; the word takes --ink, which is the same
   colour the unpressed state already uses on hover, so the two states are
   still told apart by weight of colour rather than by hue alone. */
.watchrow button.on { color: var(--ink); }
.watchrow button.on svg { color: var(--brass); }
.watchrow svg { width: 15px; height: 15px; }
/* How many other people are watching this lot is a fact about the sale,
   not decoration. On --faint it measured 2.48:1 in paper, 2.59 in
   porcelain, 3.93 in midnight and 4.22 in vault against a 4.5
   requirement, at 1440 and at 375, and it was set by an inline style
   attribute so no CSS-level sweep could see it. --mut is the same
   substitution .arc-offline and .cw-steps li already took; the lighter
   weight keeps it secondary to the verb beside it. */

.bidbox {
  border: 1px solid var(--line2);
  border-radius: var(--r-m);
  margin-top: 18px;
  overflow: hidden;
}
.bidbox .bb-top {
  display: grid; grid-template-columns: 1fr 1fr;
  border-bottom: 1px solid var(--line);
}
.bidbox .bb-cell { padding: 16px 18px; }
.bidbox .bb-cell + .bb-cell { border-left: 1px solid var(--line); }
.bidbox .bb-lbl { font-size: var(--fs-100); letter-spacing: 0.12em; text-transform: uppercase; color: var(--mut); font-weight: 600; margin-bottom: 5px; }
/* One line reserved, as in the hero: the price and the countdown are
   written into empty divs by js/lot.js and an empty div is zero tall. */
.bidbox .bb-val { font-size: 25px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; min-height: 1.1em; }
.bidbox .bb-sub { font-size: var(--fs-200); color: var(--mut); margin-top: 4px; }
/* the countdown keeps the panel's ink at every duration — see .cd.soon on
   the tile: red is reserved for a refused or losing bid */
.bidbox .bb-mid { padding: 16px 18px; border-bottom: 1px solid var(--line); background: var(--wash); }
.bidrow { display: flex; gap: 10px; }
.bidrow .amt {
  flex: 1;
  position: relative;
}
.bidrow .amt input {
  width: 100%; height: 50px;
  border: 1px solid var(--line2); border-radius: var(--r-s);
  padding: 0 14px 0 30px;
  font-size: 16px; font-weight: 600;
  outline: none;
  background: var(--panel);
  font-variant-numeric: tabular-nums;
}
.bidrow .amt input:focus { border-color: var(--ink); }
.bidrow .amt .cur { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--mut); font-weight: 600; }
.bidrow .btn { height: 50px; padding: 0 26px; }
/* The chips are written in by js/lot.js, so the row reserves the height
   they land at — the same 44px touch floor the buttons themselves take
   below. Without it the bid form grew a row under the reader's thumb. */
.quickbids { display: flex; gap: var(--s-2); margin-top: 10px; min-height: 44px; }
/* 44px, at every pointer: these chips are the most tapped control on
   the page and sat at 34px with a 40px touch patch. */
.quickbids button {
  flex: 1;
  border: 1px solid var(--line2);
  border-radius: var(--r-s);
  background: var(--panel);
  min-height: 44px;
  font-size: 12.5px; font-weight: 600;
  font-variant-numeric: tabular-nums;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.quickbids button:hover { border-color: var(--ink); }
.bidbox .bb-note { font-size: var(--fs-200); color: var(--mut); margin-top: 10px; line-height: 1.55; }
/* The next-bid line, and only that one: it is written on every open lot,
   so holding a line for it stops the settle row and everything under it
   stepping down at boot. Its neighbours here are NOT reserved —
   #bidcalc ships hidden and #maxnote stays empty until there is a sealed
   maximum, so a floor on either would be permanent dead space. */
#bidnote { min-height: 18px; }
.bidbox .bb-note b { color: var(--ink2); }
.bidstate {
  display: none;
  padding: 11px 18px;
  font-size: var(--fs-300); font-weight: 600;
  border-bottom: 1px solid var(--line);
}
.bidstate.win { display: block; background: var(--up-tint); color: var(--up); }
.bidstate.out { display: block; background: var(--live-tint); color: var(--live); }
.bidstate.confirm { display: block; background: var(--wash); color: var(--ink2); }
.bidbox .bb-settle { padding: 15px 18px; }
/* One line reserved: js/lot.js always writes what happens at close into
   this row, and an empty span left the row flat until it did. */
.bidbox .bb-settle .srow { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 18px; }
.bidbox .bb-settle .stxt { font-size: 12.5px; color: var(--mut); line-height: 1.5; }
.bidbox .bb-settle .stxt b { color: var(--ink); }
.bidbox .bb-settle .linkline { font-size: 12.5px; }

/* tabs */
/* FOUR TABS, ONE LINE, NEVER A SIDEWAYS SCROLL.
   This strip sits in the lot column, which is about 400px on a 1024px
   laptop — so five tabs (js/lot.js adds "Catalogue note" to the four in
   the markup) ran to 466px and the last one was cut off mid-word behind a
   scrollbar nobody looks for. Population moved into Market, "Shipping &
   payment" became "Shipping", and the padding came in a little. Wrapping
   is the fallback rather than scrolling: a second row is visible and
   obvious, a horizontal scroll is neither. */
.lot-tabs { margin-top: 34px; border-bottom: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 2px; }
.lot-tabs button {
  font-family: var(--font-d);
  font-weight: 700; font-size: 13.5px;
  padding: 11px 12px;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  color: var(--mut);
  margin-bottom: -1px;
}
.lot-tabs button:hover { color: var(--ink); }
.lot-tabs button.active { color: var(--ink); border-bottom-color: var(--ink); }
.tabpane { display: none; padding-top: 22px; }
.tabpane.active { display: block; }

.chartbox { border: 1px solid var(--line); border-radius: var(--r-m); padding: 18px 18px 8px; }
.chartbox .chead { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 4px; }
.chartbox .chead b { font-size: 14px; }
.chartbox .chead span { font-size: var(--fs-200); color: var(--mut); }
.chartbox svg { width: 100%; height: auto; }

.compstable { width: 100%; border-collapse: collapse; margin-top: 16px; font-size: var(--fs-300); }
.compstable th { text-align: left; font-size: 10.5px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--mut); padding: 0 10px 8px; border-bottom: 1px solid var(--line2); }
.compstable td { padding: 10px; border-bottom: 1px solid var(--line); }
.compstable .cprice { font-weight: 700; text-align: right; }
.compstable th.cprice { text-align: right; }
.compstable .cvenue { color: var(--mut); }

.bidhist { list-style: none; }
.bidhist li {
  display: grid; grid-template-columns: 1fr auto auto;
  gap: var(--s-4);
  padding: 10px 4px;
  border-bottom: 1px solid var(--line);
  font-size: 13.5px;
  align-items: baseline;
}
.bidhist .who { font-weight: 600; }
.bidhist .who .you { color: var(--up); }
.bidhist .amt { font-weight: 700; font-variant-numeric: tabular-nums; }
.bidhist .when { color: var(--mut); font-size: var(--fs-200); }

/* FOUR FIGURES ON ONE BASELINE.

   Four fixed columns in a 400px lot rail is not enough width for "At
   grade or better", so that label wrapped to three lines, "Graded
   higher" to two, and "PSA 7" to one. Each figure then started wherever
   its own label happened to stop, and four numbers sitting at four
   different heights is what made the block read as unsettled: the eye
   has no line to travel along.

   Two rules fix it and they work together. The columns wrap to 2x2
   rather than crushing to four, so the labels have room in the narrow
   rail where the problem actually appeared; and every cell reserves two
   lines for its label and pins the figure to the bottom, so a one-line
   label and a two-line label still deliver their numbers to the same
   baseline. Three-line labels no longer occur at any width this grid
   now produces. */
.popgrid {
  display: grid;
  /* 150px, not 128px, and the difference is a whole row of layout. The
     lot rail is about 440px: at 128px three cells fit and the fourth
     drops alone onto a second row, which is the least settled shape
     four things can take. At 150px only two fit, so the block resolves
     to a balanced 2x2 at every width the rail actually has, and opens
     to a single row of four only where there is real room for it. */
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--s-3);
}
.popcell {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  padding: 14px;
  text-align: center;
}
.popcell.hl { border-color: var(--ink); background: var(--wash); }
/* The label absorbs the slack, so the figure is pinned to the bottom of
   the cell. Grid already stretches every cell in a row to the tallest
   one; letting the label grow into that height is what puts all the
   figures on a line, and unlike a reserved min-height it cannot be
   defeated by a label that runs to three lines in a narrow rail. */
.popcell .g {
  flex: 1 1 auto;
  font-size: var(--fs-100); letter-spacing: 0.08em; color: var(--mut);
  font-weight: 600; text-transform: uppercase;
  line-height: 1.3;
  display: flex; align-items: center; justify-content: center;
}
.popcell .n {
  font-family: var(--font-d); font-weight: 800; font-size: var(--fs-600);
  margin-top: 4px;
  line-height: 1.1;
}
.popnote { font-size: 12.5px; color: var(--mut); margin-top: 12px; line-height: 1.6; }

.shipblock { display: grid; gap: 14px; }
.shiprow { display: flex; gap: 14px; align-items: flex-start; border: 1px solid var(--line); border-radius: var(--r-s); padding: 15px 16px; }
/* Only the row's own title goes block. A nested <b> inside the paragraph
   is inline emphasis and must stay in the sentence. */
.shiprow > div > b { display: block; font-size: 13.5px; }
.shiprow p { font-size: 12.5px; color: var(--mut); margin-top: 3px; line-height: 1.55; }
.shiprow p b { font-weight: 700; color: var(--ink2); }

.similar { padding: 46px 0 66px; border-top: 1px solid var(--line); }

/* ============================================================
   MODALS / TOASTS
   ============================================================ */
.overlay {
  position: fixed; inset: 0;
  background: rgba(34, 29, 49, 0.58);
  z-index: 100;
  display: none;
  align-items: flex-start;
  justify-content: center;
  padding: 7vh 20px 40px;
  overflow-y: auto;
}
.overlay.open { display: flex; }
.modal {
  background: var(--panel);
  width: 100%;
  max-width: 460px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.35);
  overflow: hidden;
  animation: modalin 0.18s ease;
}
.modal.wide { max-width: 560px; }
@keyframes modalin { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.modal .m-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line);
}
.modal .m-head b { font-family: var(--font-d); font-weight: 800; font-size: 16px; font-stretch: 108%; }
.modal .m-close { width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border-radius: var(--r-s); color: var(--mut); }
.modal .m-close:hover { background: var(--wash); color: var(--ink); }
.modal .m-body { padding: 22px; }
.modal .m-note { font-size: var(--fs-200); color: var(--mut); line-height: 1.6; }

/* Payment-sheet variant: embedded content runs edge to edge, the header
   sheds its rule, and the whole thing reads as one surface. */
.modal.sheet { max-width: 520px; }
.modal.sheet .m-body { padding: 0; }
.modal.sheet .m-head { border-bottom: 0; padding: 15px 16px 13px 20px; }
.modal.sheet .m-head b { font-size: 14px; letter-spacing: 0.01em; }

.provider {
  display: flex; align-items: center; gap: 13px;
  width: 100%;
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  padding: 13px 15px;
  margin-bottom: 9px;
  text-align: left;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.provider:hover { border-color: var(--ink); }
.provider .ptile {
  width: 34px; height: 34px; border-radius: var(--r-s);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-d); font-weight: 800; font-size: var(--fs-300);
  color: #fff; background: var(--dark2);
  flex: none;
}
.provider b { display: block; font-size: 14px; }
.provider span { display: block; font-size: var(--fs-200); color: var(--mut); }
.provider .arr { margin-left: auto; width: 15px; height: 15px; color: var(--faint); }

.field { margin-bottom: 14px; }
/* Form labels are NOT transformed. The wallet dialog's label carries a
   literal address prefix — "Receiving wallet (0x… on Base)" — and uppercase
   rendered it 0X…, which is not a valid address prefix. A label that can
   contain a technical literal cannot be transformed at all, because the
   literal is inline in the string and there is nothing to exempt. */
.field label { display: block; font-size: 11.5px; font-weight: 700; letter-spacing: 0.06em; color: var(--ink2); margin-bottom: 6px; font-family: var(--font-d); }
.field input, .field select, .field textarea {
  width: 100%;
  height: 46px;
  border: 1px solid var(--line2);
  border-radius: var(--r-s);
  padding: 0 13px;
  outline: none;
  background: var(--panel);
  transition: border-color var(--dur-fast) var(--ease);
}
.field textarea { height: auto; padding: 12px 13px; resize: vertical; min-height: 96px; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--ink); }
.field .hint { font-size: 11.5px; color: var(--mut); margin-top: 5px; }
.field.err input { border-color: var(--live); }
.field .errmsg { display: none; font-size: 11.5px; color: var(--live); margin-top: 5px; font-weight: 600; }
.field.err .errmsg { display: block; }

/* settle modal */
.invoice { border: 1px solid var(--line); border-radius: var(--r-s); margin-bottom: 16px; }
.invoice .irow {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 10px 14px;
  font-size: var(--fs-300);
  border-bottom: 1px solid var(--line);
}
.invoice .irow:last-child { border-bottom: 0; }
.invoice .irow.total { font-weight: 700; font-size: 14.5px; background: var(--wash); }
.invoice .irow .sub { color: var(--mut); font-size: 11.5px; }
.invoice .save { color: var(--up); font-weight: 600; }
.paybox { border: 1px solid var(--line2); border-radius: var(--r-s); padding: 16px; background: var(--wash); }
.paybox .prow { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
.paybox .plbl { font-size: var(--fs-100); letter-spacing: 0.1em; text-transform: uppercase; color: var(--mut); font-weight: 600; }
.paybox .pamt { font-family: var(--font-m); font-size: 17px; font-weight: 500; }
.paybox .addr {
  display: flex; gap: var(--s-2); align-items: center;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-s);
  padding: 10px 12px;
}
.paybox .addr code {
  font-family: var(--font-m); font-size: var(--fs-100); color: var(--ink2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  flex: 1;
}
.paybox .copybtn { flex: none; font-size: 11.5px; font-weight: 700; color: var(--ink); letter-spacing: 0.04em; }
.paybox .copybtn:hover { text-decoration: underline; }
.paybox .pfoot { display: flex; justify-content: space-between; align-items: center; margin-top: 10px; font-size: 11.5px; color: var(--mut); }
.paybox .qr { margin: 14px auto 4px; width: 132px; height: 132px; background: #fff; border: 1px solid var(--line); border-radius: var(--r-s); padding: 8px; display: none; }
.paybox .qr img { width: 100%; height: 100%; image-rendering: pixelated; }
.paybox .qr.on { display: block; }
.ratefoot { font-size: 11.5px; color: var(--mut); margin-top: 12px; line-height: 1.6; }

.toasthost {
  position: fixed;
  bottom: 24px; left: 50%; transform: translateX(-50%);
  z-index: 200;
  display: grid; gap: var(--s-2);
  width: min(430px, calc(100vw - 40px));
}
.toast {
  background: var(--dark);
  color: var(--cream);
  border-radius: var(--r-m);
  padding: 13px 16px;
  font-size: 13.5px;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.35);
  display: flex; gap: 10px; align-items: flex-start;
  animation: toastin 0.22s ease;
}
@keyframes toastin { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.toast.out { border-left-color: var(--live); }
.toast.good { border-left-color: var(--up); }
.toast b { font-weight: 700; }
.toast .tmsg { flex: 1; line-height: 1.45; }
.toast .tact { flex: none; font-weight: 700; color: var(--cream); text-decoration: underline; text-underline-offset: 2px; }

/* ============================================================
   SELL PAGE
   ============================================================ */
/* flat dark stage — the two corner washes that sat here were the last
   decorative gradient on the site, and they went with the hero's */
.sellhero { background: var(--dark); color: var(--cream); }
.sellhero .wrap { padding-top: 62px; padding-bottom: 66px; max-width: 880px; }
.sellhero h1 { font-size: clamp(30px, 4vw, 44px); font-weight: 800; font-stretch: 112%; margin: 14px 0 16px; }
.sellhero p { color: var(--dark-fg); font-size: 16px; max-width: 40em; line-height: 1.6; }
/* wrap, like .hero-ctas — this row is a PAIR of .btn.xl, and .btn is
   nowrap by design, so on one line the two of them ran 466px wide in a
   375px viewport and scrolled the whole document sideways */
.sellhero .cta { margin-top: 28px; display: flex; gap: var(--s-3); flex-wrap: wrap; }

.feetable { width: 100%; border-collapse: collapse; }
.feetable th { font-size: var(--fs-100); letter-spacing: 0.1em; text-transform: uppercase; color: var(--mut); text-align: left; padding: 0 16px 10px; border-bottom: 1px solid var(--line2); }
.feetable td { padding: 14px 16px; border-bottom: 1px solid var(--line); font-size: 14px; }
.feetable .ft-rate { font-family: var(--font-d); font-weight: 800; font-size: 16px; white-space: nowrap; }
.feetable .ft-note { color: var(--mut); font-size: 12.5px; }

/* auto-fit, not a fixed four: the deposit step is present only when the
   escrow is on, so the row holds four boxes or three — either way they
   share the full width as one neat row instead of leaving a dead column. */
.steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0; border: 1px solid var(--line); border-radius: var(--r-m); overflow: hidden; }
.step { padding: 22px 20px 24px; border-left: 1px solid var(--line); background: var(--panel); }
/* The hidden deposit step is still the first CHILD, so the first visible
   box must also drop its left border or it doubles the frame's. */
.step:first-child, .step[hidden] + .step { border-left: 0; }
.step .n {
  font-family: var(--font-m);
  font-size: var(--fs-100); color: var(--mut);
  display: block; margin-bottom: 10px;
}
.step b { display: block; font-family: var(--font-d); font-weight: 800; font-size: var(--fs-400); margin-bottom: 6px; }
.step p { font-size: 12.5px; color: var(--mut); line-height: 1.55; }

/* The guide page's own furniture, out of its markup. */
.band-steps { padding-bottom: 40px; }
.guide-band { border-radius: var(--r-m); }
.guide-band-inner { padding: 0 8px; }
.guide-tablewrap { overflow-x: auto; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-m); padding: 6px 0; }
.guide-fine { margin-top: 22px; font-size: 13.5px; color: var(--mut); line-height: 1.6; max-width: 760px; }
.guide-fine + .guide-fine { margin-top: 10px; }
.guide-cta { margin-top: 26px; }

/* ============================================================
   LEGAL
   ============================================================ */
.legal-layout { display: grid; grid-template-columns: 230px 1fr; gap: 44px; padding: 40px 0 80px; align-items: start; }
.legal-toc { position: sticky; top: 70px; display: grid; gap: 2px; font-size: var(--fs-300); }
/* 34px rows in the contract navigation, on a phone where this list IS the
   document's navigation: the padding grows to the touch floor rather than
   the type. */
.legal-toc a { display: flex; align-items: center; min-height: 44px; padding: 7px 10px; border-left: 2px solid var(--line); color: var(--mut); }
.legal-toc a:hover { color: var(--ink); border-left-color: var(--ink2); }
/* 68ch, not the 760px card width: at 14px type that column ran to
   roughly 105 characters a line on the two longest documents on the
   site. Contract prose gets book measure and book size. */
.legal-body { max-width: 68ch; font-size: 16px; }
.legal-body h1 { font-size: 30px; font-weight: 800; font-stretch: 112%; margin-bottom: 6px; }
.legal-body .rev { color: var(--mut); font-size: var(--fs-300); margin-bottom: 34px; }
/* A heading binds to the text it introduces: 4px down, a blank line's
   worth up. It used to sit 10px off both, the same gap two paragraphs
   get from each other. */
.legal-body h2 { font-size: var(--fs-500); font-weight: 800; font-stretch: 108%; margin: var(--s-6) 0 var(--s-1); padding-top: 10px; }
.legal-body p, .legal-body li { color: var(--ink2); line-height: 1.7; }
.legal-body p { margin-bottom: var(--s-5); }
.legal-body ul { padding-left: 20px; margin: var(--s-3) 0 var(--s-5); }
.legal-body li { margin-bottom: var(--s-2); }
.legal-body .callout { border: 1px solid var(--line); border-radius: 0 var(--r-s) var(--r-s) 0; background: var(--wash); padding: 14px 16px; font-size: var(--fs-300); margin: 14px 0; }

/* ============================================================
   RESPONSIVE
   ============================================================ */
@media (max-width: 1100px) {
  .lotgrid { grid-template-columns: repeat(3, 1fr); }
  .cattiles { grid-template-columns: repeat(3, 1fr); }
  .lot-layout { grid-template-columns: minmax(0, 1fr) 400px; gap: 30px; }
}
@media (max-width: 940px) {
  .masthead .wrap { grid-template-columns: auto 1fr auto; gap: var(--s-4); height: 66px; }
  .wordmark .wm-sub { display: none; }
  /* THE FILTER PANEL RESERVES ITS OWN HEIGHT, BECAUSE HERE IT IS ON TOP.
     Below 940 the sidebar stops being a sidebar and stacks above the grid,
     so js/browse.js filling an empty aside pushed every lot down the page
     after paint — 348px of it, which was the whole of the browse page's
     0.37 layout shift at 768 once the slabs were reserved.
     The panel is not data-shaped the way it looks: the four groups are
     constants in js/browse.js (grading house, GRADE_BANDS, PRICE_BANDS,
     ENDING), and in two columns the two tall ones set the height, so it
     measures 348.2 at every width from 430 to 940 and in both rooms —
     the Buy Now room drops the Closing group and lands on the same
     number. Narrower than 430 it is taller (369 to 411), never shorter.
     340 is that measurement with a margin under it, so the reserve can
     never stand taller than the panel that fills it. Change a band list
     in js/browse.js and this wants re-measuring. */
  .facets { min-height: 340px; }
  .hero .wrap { grid-template-columns: minmax(0, 1fr); gap: var(--s-7); padding-top: 44px; padding-bottom: 50px; }
  .hero-media { order: -1; }
  .hero-media .slabwrap { width: min(300px, 70%); }
  .browse-layout { grid-template-columns: minmax(0, 1fr); }
  .facets { position: static; grid-template-columns: repeat(2, 1fr); gap: 0 24px; }
  .lot-layout { grid-template-columns: minmax(0, 1fr); }
  .lot-media { position: static; }
  .consign .wrap { grid-template-columns: minmax(0, 1fr); }
  .consign .cta { justify-self: start; }
  footer.site .cols { grid-template-columns: 1fr 1fr; }
  footer.site .legalrow .demo { margin-left: 0; }
}
/* THE SEARCH FIELD GETS ITS OWN ROW WELL BEFORE A PHONE.

   The three-column masthead survives down to 721px, and the rule that gives
   the search box a full-width second row only fired at 720px. Between those
   two the field was squeezed by the wordmark on one side and the wallet,
   Watchlist and Theme buttons on the other: at 768px — an iPad in portrait,
   or a laptop window dragged to two-thirds — it measured about 100px and its
   placeholder rendered as "Searc". The site's only search entry point could
   not show what had been typed into it.

   The second row starts at 1160px instead. Nothing else about the compact
   masthead changes; the field simply stops competing for width. */
/* AND THE STACKED MASTHEAD WRAPS RATHER THAN CUTTING THE HOUSE'S OWN NAME.

   Two tracks in a grid have to divide the width between them somehow, and
   whichever one is told to yield gets ruined at the width where the sum
   stops fitting. Both ways round were tried here and both failed, in
   opposite directions:

     Below 720px the wordmark was the yielding track (`minmax(0, 1fr)`
     with `overflow: hidden`), so at 375px it was handed 132px for a
     lockup that measures 173 and the brand read MINTHOU — 41px cut off,
     on all twelve pages, with the earlier 17px/0.03em tightening already
     applied and still nine pixels short. Between 541 and 699 the wallet
     and portfolio buttons still carried their words, 414px of actions
     against a 226px lockup, and the name degraded to a lone M.

     Between 721 and about 810 the ACTIONS were the yielding track, and
     an overflowing box with `justify-self: end` overflows leftward — so
     the buttons were painted over the word instead, which is the same
     incident the 720px block below was written to stop.

   There is no split of one row that holds, because at 375px the honest
   numbers are 173 of name plus 188 of controls plus 48 of gutter against
   375 of phone, and the controls are already at the touch floor. So the
   row is allowed to become two rows. The wordmark never shrinks, the
   actions sit at the right of whatever line they land on, and the search
   field keeps a full row of its own. Nothing is clipped at any width,
   including ones nobody has measured: a viewport too narrow for the pair
   simply gets one more line of masthead, which is what a phone should
   spend on the name of the house it is bidding at.

   Flex, not grid, because wrapping is the whole mechanism. `order` puts
   the search field last; it precedes the actions in the markup, where it
   belongs for the keyboard. */
@media (max-width: 1160px) {
  .masthead .wrap {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: var(--s-4);
    row-gap: 10px;
    height: auto;
    padding-top: 12px;
    padding-bottom: 12px;
  }
  .wordmark { flex: 0 0 auto; order: 1; }
  /* margin-left, not justify-self: on a line of its own the auto margin is
     what still holds the actions against the right rail. */
  .mast-actions { flex: 0 0 auto; order: 2; margin-left: auto; }
  .searchbox { flex: 1 0 100%; order: 3; max-width: none; min-width: 0; }
}

/* THE MASTHEAD CONTROLS GO TO ICONS AT 810, AND 810 IS A MEASUREMENT.

   Labelled, the four controls measure 519px; the lockup beside them is
   226px and the wrap's gutters and gap take another 64. That is 809px of
   top line, so 810 is the last viewport where they cannot share it. Above
   it the words stay — a laptop window at 900px has the room and "Connect
   wallet" is the one control on this bar worth spelling out. Below it they
   would take a whole extra row of masthead, on the tablets and phones that
   can least afford one.

   The Watchlist label used to go at 720 and the wallet and portfolio words
   at 540, which is three widths for one decision, and it is what left an
   iPad in portrait carrying 519px of buttons under a wrapped lockup. One
   width now, and it is the width they stop fitting at. */
@media (max-width: 810px) {
  .iconbtn .lbltxt { display: none; }
  /* Hide the WORD, never the content. `span:last-child` also matched the
     address span once a wallet was connected, so on a phone the button
     rendered as an empty black rectangle in both states — and the icon
     had no intrinsic size to fall back on. */
  #walletbtn .wb-label { display: none; }
  /* A compact masthead cannot hold the caption as well; the balance is the
     half worth keeping, and the address is one tap away in the panel. */
  #walletbtn .wb-addr { display: none; }
  #walletbtn .wb-addr.solo { display: inline; font-size: var(--fs-100); }
  #walletbtn .wb-bal { font-size: 12.5px; }
  #walletbtn.wb-on { padding-top: 9px; padding-bottom: 9px; }
  #walletbtn { padding: 9px 11px; }
  /* max-width:none is load-bearing: the global `img, svg { max-width: 100% }`
     resolves against the shrunken button and collapsed the icon to 4.9px. */
  #walletbtn svg { width: 16px; height: 16px; display: block; max-width: none; flex: none; }
  /* The portfolio control keeps its icon by the wallet button's rules. */
  #portfoliobtn .pb-label { display: none; }
  #portfoliobtn { padding: 9px 11px; }
  #portfoliobtn svg { width: 16px; height: 16px; display: block; max-width: none; flex: none; }
  /* The theme control is the one button with no icon, so its word IS the
     button — hiding the label the way the others do would leave an empty
     square. It gets the room instead, from the padding around it. */
  .iconbtn { padding: 0 8px; gap: 5px; }
  .tbtn { padding: 0 9px; font-size: var(--fs-200); }
}
@media (max-width: 720px) {
  /* The marketing links go, but NOT the account controls. Hiding the
     whole nav left a phone with no way to sign in, sign out, or reach
     My Account — the account page was reachable only by typing the URL. */
  .utilbar nav a { display: none; }
  .utilbar nav a.acctlink,
  .utilbar nav [data-signin],
  .utilbar nav [data-signout] { display: inline; }
  .utilbar nav { gap: 14px; }
  .utilbar .ticker span:not(.livetag) { display: none; }
  .utilbar .ticker b { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* The wrap is a wrapping flex row from 1000px down — see the banner
     above. Only the gaps change here: on a phone the two halves of the top
     line sit closer together, and the controls closer still to each other.
     Neither one shrinks, so neither one can be clipped by the other. */
  .masthead .wrap { column-gap: var(--s-3); }
  .mast-actions { gap: var(--s-1); }
  .lotgrid, .browse-grid { grid-template-columns: repeat(2, 1fr); }
  .cattiles { grid-template-columns: repeat(2, 1fr); }
  .band-head h1, .band-head h2 { font-size: var(--fs-600); }
  .steps { grid-template-columns: 1fr 1fr; }
  .step:nth-child(3) { border-left: 0; }
  .step:nth-child(n+3) { border-top: 1px solid var(--line); }
  .legal-layout { grid-template-columns: 1fr; }
  .legal-toc { position: static; }
  .popgrid { grid-template-columns: repeat(2, 1fr); }
  .bidbox .bb-top { grid-template-columns: 1fr; }
  .bidbox .bb-cell + .bb-cell { border-left: 0; border-top: 1px solid var(--line); }
  /* Hide the header cell with the column, or the table keeps a dangling
     empty "Auction" heading over nothing. */
  .resulttable .rt-auction,
  .resulttable thead th:nth-child(4) { display: none; }
  .lot-stage { padding: 22px 24px; }
}
@media (max-width: 540px) {
  /* The wallet and portfolio controls shed their words at 720 now, with
     the Watchlist label and the masthead's own layout — see the block
     above. What is left here is the lockup itself, one step down. */
  .wordmark .wm-main { font-size: 20px; }
}
@media (max-width: 460px) {
  .lotgrid, .browse-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .lotcard .thumb { padding: 12px 18px 10px; }
  .lotcard .bid { font-size: 15.5px; }
  .hero .bidblock { gap: 24px; }
  /* The two-up grid leaves a tile ~157px wide, and at the desktop size
     the clock's widest honest contents ("59m 59s" beside
     "Est. $300K–$400K") need ~194px, so about half the tiles broke into
     two lines and the grid rows disagreed by 18px. Sized so that worst
     pair fits one line with room to spare (measured: 131.4px of content
     against 137px inside the padding), with no nowrap, so a still
     narrower viewport degrades by wrapping rather than by clipping.

     The strip bleeds to the card's edges and then puts its text back on
     the body's own inset, so the two paddings are one measurement and
     narrowing the clock alone moved its row 6px left of the rail every
     other line in the tile sits on (measured at 375px: text at 11px,
     title at 17px, all 50 tiles, all four themes). The inset is cut on
     the body as well, which keeps the rail and leaves the 137px the
     one-line measurement above counted on. */
  .lotcard .body { padding: 14px 10px 15px; }
  .lotcard .clock { margin: 4px -10px -15px; padding: 9px 10px; font-size: 10px; }
  /* At 375px the wordmark's glyphs ran to x=225 in a box that ended at
     x=196 — the watchlist star painted over the final E and the brand
     read "MINTHOUS". The clipping is answered by the wrap now, so this
     size is no longer load-bearing against it; it is kept because it is
     what buys the top line back. At 17px the lockup measures 173 against
     201 at 20px, which is the difference between a 430px phone holding
     the name and the controls on one line and spending a whole row on
     them. Below about 417px it wraps regardless, and should. */
  .wordmark .wm-main { font-size: 17px; letter-spacing: 0.03em; }
  .masthead .wrap { column-gap: var(--s-2); }
}

/* ONE FOOTER COLUMN ON THE SMALLEST PHONE THERE IS.
   A `1fr` track will not go below its own min-content, and the brand
   column's min-content is the wordmark lockup: 190px of mark and
   MINTHOUSE that cannot be broken. Beside a 77px link column and a 32px
   gap that is 299px of footer inside 272px of page, and at 320 the whole
   document scrolled sideways by 3px to reach a footer heading. 350 is
   where the arithmetic turns — 299 plus the 48 of gutter — and 360 up
   were already clean, which is why nothing wider changes. It sits below
   the 940px two-column rule because that one would otherwise outrank it
   on the same specificity. */
@media (max-width: 350px) {
  footer.site .cols { grid-template-columns: minmax(0, 1fr); }
}

/* A BUTTON IN AN EMPTY STATE MAY WRAP ITS LABEL.
   .btn is `white-space: nowrap` on purpose everywhere else — a hammer
   price or PLACE BID broken across two lines is unreadable — but an empty
   state carries whole sentences on its button, and "Sign in to your
   bidder account" measures 307px inside the 220 an emptystate has at
   320px. The account and portfolio pages both scrolled sideways when
   signed out, which is the first screen a new bidder sees. The label
   wraps below 360 rather than the page moving; 375 up already fits it on
   one line. */
@media (max-width: 360px) {
  .emptystate .btn { white-space: normal; }
}

/* reduced motion — pseudo-elements included: the bare * missed them,
   which would have left the status band's ::before mark shimmering
   through a setting that says not to */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
}

/* ============================================================
   CARD ARCHIVE
   ============================================================ */
.arc-search { padding: 26px 0 4px; }
.arc-inputrow { display: flex; gap: 10px; align-items: stretch; }
.arc-inputrow .searchbox { flex: 1; }
.arc-inputrow .sortsel select { height: 44px; }
.arc-hint { font-size: 12.5px; color: var(--mut); margin-top: 10px; }

.arc-statusband {
  margin: 18px 0 6px;
  font-size: 13.5px;
  color: var(--ink2);
  padding: 6px 0 6px 12px;
}
/* A running query used to be signalled by the hairline alone — one brown
   moving to a neighbouring brown, with no text change and no motion. The
   house mark carries the wait now; the border change stays as
   reinforcement.

   THE MARK IS DRAWN ONCE, AND IT IS DRAWN BY MH.working.

   It used to be drawn twice. This rule painted a 17x15 mint mark with a
   ::before, and every caller of bandWorking() also assigns
   `statusEl.innerHTML = MH.working(...)`, which brings its own 23x20 one
   — so a search showed two gold M's side by side at two different sizes.
   The one that survives is MH.working's, because it is the same mark and
   sweep every other pending fetch on the site uses, it carries the label
   the reader is waiting on, and it announces itself (role="status",
   aria-live="polite"). A decorative ::before could do none of that. */
.arc-statusband.working { border-left-color: var(--brass); }

.arc-section { padding: 26px 0 8px; }
.arc-sechead { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s-4); margin-bottom: 16px; }
.arc-sechead h2 { font-size: var(--fs-600); font-weight: 800; font-stretch: 112%; margin-top: 6px; }
.arc-count { font-size: 12.5px; color: var(--mut); white-space: nowrap; margin-bottom: 3px; }
.arc-none { color: var(--mut); font-size: 13.5px; padding: 6px 0 14px; }
/* A source that didn't answer: one line, not an error page. Quiet, but it
   still has to be readable — the reader is being told why a section is
   short, and --faint measured 2.24:1 here. */
.arc-offline {
  display: flex; align-items: baseline; gap: 10px;
  padding: 11px 14px; margin: 10px 0;
  border: 1px solid var(--line); border-radius: var(--r-s);
  background: var(--wash);
  font-size: 12.5px; color: var(--mut);
}
.arc-offline b { font-family: var(--font-d); font-weight: 700; color: var(--mut); }
.arc-offline .linkline { margin-left: auto; font-size: var(--fs-200); color: var(--mut); }
.arc-relaxed { color: var(--mut); font-size: 12.5px; margin: -6px 0 12px; padding: 6px 10px; background: var(--wash); border-radius: 0 var(--r-s) var(--r-s) 0; }

.arc-pager { display: flex; align-items: center; justify-content: center; gap: var(--s-4); padding: 18px 0 6px; }
/* Sized once. This button carried three competing heights — 34px here,
   auto from the engraved layer, 40px under (hover: none) — and the
   archive Search button needed an inline 44px to escape them. 44px is
   the touch floor, so it is simply the height. */
.arc-pager .btn { min-height: 44px; padding: 10px 18px; font-size: 10.5px; }
.arc-pager .btn[disabled] { opacity: 0.35; pointer-events: none; }
.arc-pageinfo { font-size: 12.5px; color: var(--mut); font-variant-numeric: tabular-nums; min-width: 92px; text-align: center; }

/* column counts that all divide the 12-card page — every full page is a
   clean rectangle at every width; only a result set's true last page can
   run short, and its cells stay equal-width and left-aligned */
.arc-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 14px;
  padding-bottom: 18px;
}
@media (max-width: 1250px) { .arc-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 900px)  { .arc-grid { grid-template-columns: repeat(3, 1fr); } }
/* ≤720px drops to 2 columns in the responsive block below */
.arc-card {
  display: flex;
  flex-direction: column;
  text-align: left;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r-m);
  overflow: hidden;
  padding: 0;
  transition: box-shadow var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
}
.arc-card:hover { box-shadow: var(--shadow-1); transform: translateY(-2px); border-color: var(--line2); }
.arc-img {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 5 / 6.4;
  background: linear-gradient(180deg, var(--wash), var(--wash2));
  padding: 14px;
}
/* Card photography is never rounded — it matches every lot tile in the
   product, and these were the last two literal radii in the file. */
.arc-img img { max-width: 100%; max-height: 100%; object-fit: contain; border-radius: var(--r-0); box-shadow: 0 6px 18px rgba(34, 29, 49, 0.18); }
.arc-img svg { width: auto; height: 100%; max-width: 100%; }
.arc-img img.fit-left { height: 96%; width: auto; aspect-ratio: 876 / 1154; object-fit: cover; object-position: left center; }
.arc-noscan {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  width: 74%; aspect-ratio: 5 / 7;
  border: 1.5px dashed var(--line2); border-radius: var(--r-0);
  color: var(--mut); font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600;
  text-align: center; padding: 12px;
}
.arc-noscan span:first-child {
  font-family: var(--font-d); font-weight: 800; font-size: var(--fs-300);
  letter-spacing: 0; text-transform: none; color: var(--mut); line-height: 1.25;
}
.arc-body { display: flex; flex-direction: column; gap: var(--s-1); padding: 12px 14px 14px; }
.arc-name { font-size: 13.8px; font-weight: 700; line-height: 1.3; color: var(--ink); }
.arc-meta { font-size: 11.5px; color: var(--mut); line-height: 1.4; }
.arc-price { font-size: var(--fs-300); font-weight: 700; color: var(--ink); margin-top: 2px; }
.arc-price em { font-style: normal; font-weight: 500; font-size: 10.5px; color: var(--mut); }
/* WHERE A PRICE WOULD BE, WHEN THERE IS NONE. It takes the same slot at
   the same rhythm as the figure it stands in for, so a grid of mixed
   sources keeps one baseline and a card without a price does not look
   like a card that failed to load. */
.arc-noprice {
  display: block; margin-top: 2px;
  font-size: 11px; line-height: 1.35; color: var(--mut); text-wrap: pretty;
}
.arc-status {
  margin-top: 7px; padding-top: 8px;
  border-top: 1px solid var(--line);
  font-size: 11.5px; color: var(--mut); line-height: 1.4;
}
.arc-status b { font-family: var(--font-d); font-weight: 800; font-size: 10.5px; letter-spacing: 0.06em; text-transform: uppercase; }
.arc-status.st-live b { color: var(--up); }      /* biddable now */
.arc-status.st-soon b { color: var(--live); }    /* on the clock */
.arc-status.st-pending b { color: var(--brass-ink); } /* held by a buyer */
.arc-status.st-sold b { color: var(--live); }
.arc-status.st-off b { color: var(--mut); }      /* nothing to act on */

/* skeletons */
.arc-skel { pointer-events: none; }
.arc-skel .arc-img { background: var(--wash); }
.arc-skel .sk { display: block; height: 11px; border-radius: var(--r-s); background: var(--wash2); }
.arc-skel .sk1 { width: 80%; }
.arc-skel .sk2 { width: 60%; }
.arc-skel .sk3 { width: 70%; margin-top: 6px; }
@keyframes arcpulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
.arc-skel .arc-img, .arc-skel .sk { animation: arcpulse 1.4s ease infinite; }

/* detail modal */
.arc-detail { display: grid; grid-template-columns: 200px 1fr; gap: 20px; align-items: start; }
.arc-detailimg img { width: 100%; border-radius: var(--r-0); box-shadow: 0 10px 28px rgba(34, 29, 49, 0.22); }
.arc-detailimg img.fit-left { aspect-ratio: 876 / 1154; object-fit: cover; object-position: left center; }
.arc-detailimg svg { width: 100%; height: auto; display: block; }
.arc-detailimg .arc-noscan { width: 100%; }
.arc-detailbody .arc-status { border-top: 0; padding-top: 0; margin-top: 0; display: block; font-size: 12.5px; }

@media (max-width: 720px) {
  .arc-inputrow { flex-wrap: wrap; }
  .arc-inputrow .searchbox { flex-basis: 100%; }
  .arc-inputrow .sortsel { flex: 1; }
  .arc-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .arc-detail { grid-template-columns: 1fr; }
  .arc-detailimg { max-width: 240px; margin: 0 auto; }
}

/* ============================================================
   Luxury-house layer — serif titles, bid modes, reserve chips,
   extended bidding, specialist card, catalogue notes
   ============================================================ */
:root { --font-serif: "Iowan Old Style", Palatino, "Palatino Linotype", Georgia, serif; }

/* light serif reserved for lot + sale titles — never bold, never giant */
.lot-panel h1 { font-family: var(--font-serif); font-weight: 400; font-stretch: 100%; font-size: 25px; letter-spacing: 0; }
.salenum { display: block; font-size: var(--fs-200); letter-spacing: 0.08em; font-weight: 500; color: var(--mut); text-transform: uppercase; margin-top: 4px; }

/* bid modes */
.bidmode { display: flex; gap: 18px; margin-bottom: 10px; }
.bidmode label { display: flex; align-items: center; gap: 7px; font-size: var(--fs-300); font-weight: 600; color: var(--ink); cursor: pointer; }
.bidmode input { accent-color: var(--ink); width: 15px; height: 15px; }
.bidmode em { font-style: normal; font-weight: 400; color: var(--mut); }

/* reserve + extension chips */
.rchip { display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; padding: 2px 7px; vertical-align: 1px; }
.rchip.met { color: var(--up); background: var(--up-tint); }
/* Caution is --warn on --warn-tint. The hand-mixed pair this replaced
   measured 3.98:1 in paper and 4.13:1 in porcelain, which broke the
   documented chip floor of 4.54:1. */
.rchip.notmet { color: var(--warn); background: var(--warn-tint); }
.rchip.none { color: var(--mut); background: var(--wash); }
/* Extended bidding is a fairness mechanism, not an alarm: caution colours,
   no animation. It was a pulsing red badge while the two toasts that
   announce the same event are typed "good". */
.extchip { display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.05em; padding: 2px 7px; color: var(--warn); background: var(--warn-tint); margin-right: 6px; }

/* bid history auto marker */
.autobid { font-size: 10px; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--mut); background: var(--wash); padding: 1px 5px; }

/* specialist card */
.speccard { display: flex; align-items: center; gap: 14px; border: 1px solid var(--line); border-radius: var(--r-m); padding: 14px 16px; margin: 16px 0 4px; background: var(--panel); }
.speccard b { font-size: 13.5px; }
.speccard p { font-size: 12.5px; color: var(--mut); margin: 2px 0 0; }
.speccard .btn { margin-left: auto; padding: 10px 18px; font-size: 10.5px; }
.specmono { display: flex; align-items: center; justify-content: center; width: 42px; height: 42px; border: 1px solid var(--line); background: var(--wash); font-family: var(--font-serif); font-size: var(--fs-400); color: var(--ink); flex-shrink: 0; }
/* The same slot holds a portrait when a specialist has one. */
img.specmono { object-fit: cover; padding: 0; }

/* catalogue note + provenance — the Sotheby's register */
.catnote p { font-family: var(--font-serif); font-size: 14.5px; line-height: 1.65; color: var(--ink); margin: 0 0 12px; }
.provenance { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
.provenance h3 { font-size: 11.5px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; color: var(--mut); margin: 0 0 8px; }
.provenance ul { list-style: none; margin: 0; padding: 0; }
.provenance li { font-family: var(--font-serif); font-size: 13.5px; color: var(--ink); padding: 3px 0; }
.provenance li + li { border-top: 1px dotted var(--line); }

/* ============================================================
   Consignment wizard
   ============================================================ */
.cw { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-m); padding: 26px 28px; }
.cw-steps { display: flex; gap: var(--s-1); list-style: none; margin: 0 0 24px; padding: 0; flex-wrap: wrap; }
/* A step not yet reached is quieter, not unreadable: --faint measured
   3.01:1 here and the text names what the seller has left to do. */
.cw-steps li { display: flex; align-items: center; gap: var(--s-2); font-size: 12.5px; font-weight: 600; color: var(--mut); padding-right: 18px; }
.cw-steps li span { display: flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: 1.4px solid var(--line); font-size: var(--fs-100); }
.cw-steps li.now { color: var(--ink); }
.cw-steps li.now span { border-color: var(--ink); background: var(--ink); color: var(--panel); }
.cw-steps li.done { color: var(--up); }
.cw-steps li.done span { border-color: var(--up); background: var(--up-tint); }
.cw-steps li:not(:last-child)::after { content: ""; width: 18px; height: 1px; background: var(--line); margin-left: 4px; }

.cw-grid { display: grid; grid-template-columns: 1fr 300px; gap: 34px; align-items: start; }
.cw-form .field { margin-bottom: 16px; }
.cw-preview { position: sticky; top: 90px; }
.cw-slab { background: var(--wash); border: 1px solid var(--line); border-radius: var(--r-m); padding: 20px 34px; }
.cw-slab svg { width: 100%; height: auto; display: block; }
.cw-slab.sm { max-width: 150px; padding: 10px 14px; flex-shrink: 0; }
.cw-cap { font-size: var(--fs-200); color: var(--mut); margin-top: 10px; text-align: center; }
.cw-foot { font-size: var(--fs-200); color: var(--mut); margin-top: 12px; }
.cw-h { font-size: var(--fs-200); letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; color: var(--mut); margin: 0 0 8px; }
.hint.ok { color: var(--up); font-weight: 600; }

.cw-pending { display: flex; gap: 22px; align-items: flex-start; }
.cw-pending b { font-size: 16px; }
.cw-pending p { color: var(--mut); font-size: 13.5px; margin: 8px 0 0; max-width: 52ch; }
.cw-ref { font-family: "IBM Plex Mono", monospace; font-size: 12.5px; color: var(--ink); background: var(--wash); padding: 2px 8px; }

.cw-est { font-size: var(--fs-700); font-weight: 700; margin: 0 0 4px; }
.cw-estnote { font-size: 12.5px; color: var(--mut); margin: 0 0 16px; }
.cw-route { border: 1px solid var(--line); border-radius: var(--r-m); padding: 13px 16px; margin-bottom: 16px; background: var(--wash); }
.cw-route b { font-size: 13.5px; }
.cw-route p { font-size: 12.5px; color: var(--mut); margin: 4px 0 0; }
.cw-fees ul { list-style: none; margin: 0 0 16px; padding: 0; }
.cw-fees li { font-size: var(--fs-300); color: var(--ink); padding: 7px 0; border-bottom: 1px dotted var(--line); }
.cw-check { display: flex; gap: 9px; align-items: flex-start; font-size: var(--fs-300); font-weight: 500; cursor: pointer; }
.cw-check input { margin-top: 2px; accent-color: var(--ink); width: 15px; height: 15px; flex-shrink: 0; }
input[type="range"] { width: 100%; accent-color: var(--ink); }

.cw-confirm { margin-bottom: 22px; }
.cw-confirm b { font-size: 16px; }
.cw-confirm p { color: var(--mut); font-size: 13.5px; margin: 8px 0 14px; max-width: 64ch; }
.cw-slip { display: flex; align-items: center; gap: 18px; justify-content: space-between; border: 1px dashed var(--line); border-radius: var(--r-m); padding: 14px 18px; background: var(--wash); max-width: 460px; }
.cw-slip > div { font-size: 12.5px; color: var(--mut); }
.cw-slip b { display: block; color: var(--ink); font-size: 13.5px; margin: 2px 0; }
.cw-sliplbl { display: block; font-size: 10.5px; letter-spacing: 0.07em; text-transform: uppercase; font-weight: 700; }
.cw-track { list-style: none; margin: 0 0 14px; padding: 0; }
.cw-track li { display: flex; align-items: center; gap: var(--s-3); padding: 9px 0; font-size: 13.5px; color: var(--mut); border-bottom: 1px dotted var(--line); }
.cw-track li .pip { width: 11px; height: 11px; border: 1.6px solid var(--line); flex-shrink: 0; }
.cw-track li.done { color: var(--ink); }
.cw-track li.done .pip { background: var(--up); border-color: var(--up); }
.cw-track li.next { color: var(--ink); }
.cw-track li.next .pip { border-color: var(--ink); }
.cw-salename { color: var(--mut); font-size: var(--fs-200); }
.cw-actions { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; }

.cw-list { display: flex; flex-direction: column; gap: 10px; }
.cw-item { display: flex; align-items: center; gap: var(--s-4); text-align: left; background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-m); padding: 12px 16px; cursor: pointer; font: inherit; color: var(--ink); }
.cw-item:hover { border-color: var(--ink); }
.cw-itemslab { width: 44px; flex-shrink: 0; }
.cw-itemslab svg { width: 100%; height: auto; display: block; }
.cw-item b { font-size: 13.5px; display: block; }
.cw-itemsub { font-size: var(--fs-200); color: var(--mut); }
.cw-itemest { margin-left: auto; font-weight: 700; font-size: 13.5px; white-space: nowrap; }

@media (max-width: 900px) {
  .cw-grid { grid-template-columns: 1fr; }
  .cw-preview { position: static; max-width: 260px; margin: 0 auto; }
}
@media print {
  header, footer, .cw-steps, .cw-track, .cw-actions, .cw-foot, #site-header, #site-footer { display: none !important; }
  /* "Print packing slip" means the slip. js/consign.js marks
     body.printing-slip around window.print(), and the marketing page —
     hero, process band, fee table — stays out of that printout, which
     used to run to pages of chrome around one address card. A File-menu
     print of the whole page keeps them. */
  body.printing-slip .sellhero,
  body.printing-slip #process,
  body.printing-slip #fees,
  body.printing-slip #submit .band-head { display: none !important; }
  body.printing-slip #submit.band { padding: 0; }
  body.printing-slip .cw { border: 0; padding: 0; }
}

.soldtag.passed { background: var(--mut); color: var(--on-ink); }

/* ============================================================
   House control language — square, tracked, engraved.
   Controls read like plate engraving: uppercase, letterspaced,
   hard corners, invert on hover instead of a tint. Surfaces
   (cards, panels) keep their radius; CONTROLS go square.
   ============================================================ */
/* The .btn rules themselves live in the buttons block at the top of the
   file — this register used to override them from here, and the pair
   drifted. */

/* text links: a real underline, offset like an engraver's rule */
.linkline { text-decoration: underline; text-underline-offset: 4px; text-decoration-thickness: 1px; text-decoration-color: var(--line2); }
.linkline:hover { opacity: 1; text-decoration-color: var(--ink); }

/* Placeholder text is text, and nothing in this product had ever styled
   it. Every placeholder on every page was the browser's own grey —
   rgb(117,117,117) in Chrome — over four different themed surfaces, so
   the site-wide search box failed 4.5:1 in all four themes and every
   field on /sell failed in three, including the bid amount box and the
   fields where the placeholder is the only instruction the user gets.

   It was invisible to both passes of tools/design-contrast.js, because a
   placeholder is not a child text node and its colour is not
   getComputedStyle(el).color, so a text-node walker goes past every input
   in the product without seeing anything. That tool grew a placeholder
   pass of its own in the same round as this rule, which is what keeps
   this measured rather than asserted.

   --mut is this house's token for text quieter than ink that is still
   meant to be read, and it clears 4.5:1 against every surface an input
   takes (--wash, --panel, --paper) in all four themes; the entered value
   stays --ink, so the field still reads as empty. The explicit opacity is
   for Firefox, which multiplies the placeholder colour by 0.54 by
   default and would undo this on an engine no pass here measures. */
::placeholder { color: var(--mut); opacity: 1; }

/* inputs and selects: square, ruled */
.field input, .field select, .field textarea, .searchbox input, .sortsel select,
select.sortsel, .amt, #bidinput { border-radius: var(--r-0); }
.quickbids button { border-radius: var(--r-0); font-family: "IBM Plex Mono", monospace; font-size: var(--fs-200); letter-spacing: 0; }
.quickbids button:hover { background: var(--ink); color: var(--on-ink); border-color: var(--ink); }

/* countdown numerals: plate numerals, not app chrome */
.bb-val.cd { font-family: "IBM Plex Mono", monospace; font-weight: 500; font-variant-numeric: tabular-nums; }

/* chips square */
.gradetag, .rchip, .extchip, .soldtag, .autobid, .cw-ref { border-radius: var(--r-0); }
.lotcard .watch { border-radius: var(--r-0); }

/* Toasts: square, with a hairline rule rather than a 3px tab. The
   variants below only ever change its colour, so the width lives here
   once and the tell goes with it. */
.toast { border-radius: var(--r-0); border-left: 1px solid var(--ink); }

/* modal: square plate */
.modal { border-radius: var(--r-0); }

/* one visible focus language everywhere — no default blue ring */
.btn:focus-visible, .linkline:focus-visible, .lot-tabs button:focus-visible,
.quickbids button:focus-visible, .lotcard .watch:focus-visible,
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible,
.searchbox input:focus-visible, .sortsel select:focus-visible, select.sortsel:focus-visible,
.cw-item:focus-visible, .arc-card:focus-visible,
.pf-row:focus-visible, .pf-hit:focus-visible, .pf-chartmode button:focus-visible,
.pf-controls input:focus-visible, .pf-cardlink:focus-visible,
.mh-dateopen:focus-visible, .mh-cal-day:focus-visible, .mh-cal-btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
  border-radius: var(--r-0);
}

/* ---------- funding (Peer Pay onramp) ---------- */
.fundbox { border-top: 1px solid var(--line); margin-top: 16px; padding-top: 16px; }
.fundhead { margin-bottom: 10px; }
.fundhead b { display: block; font-size: 13.5px; }
.fundhead span { font-size: var(--fs-200); color: var(--mut); }
.fundpresets { margin-bottom: 10px; }
.fundrow { display: flex; gap: var(--s-2); }
.fundrow .amt { flex: 1; display: flex; align-items: center; border: 1px solid var(--line2); background: var(--panel); }
.fundrow .amt .cur { padding: 0 2px 0 12px; color: var(--mut); font-weight: 600; }
.fundrow .amt input { flex: 1; border: 0; background: none; padding: 11px 10px 11px 2px; font: inherit; font-variant-numeric: tabular-nums; min-width: 0; }
.fundrow .amt input:focus { outline: none; }
.fundrow .amt:focus-within { border-color: var(--ink); }
.fundrow .btn { white-space: nowrap; padding: 0 18px; font-size: 10.5px; }

/* engraved layer — second pass: controls the first pass missed */
.iconbtn, .lot-thumbs button, .modal .m-close, .provider, .provider .ptile,
.iconbtn .cnt, .livetag, .gradechip, .facet .opt .box { border-radius: var(--r-0); }
/* fixed-height row: let the engraved padding set the height, and never
   let it settle under the 44px inputs beside it */
.arc-inputrow .btn { height: auto; min-height: 44px; }
/* A technical literal is never transformed. Addresses, transaction hashes,
   cert numbers, reference codes and lot ids all render through these slots,
   and text-transform on any of them prints a value the user cannot use:
   0x… becomes 0X…, which is not a valid address prefix. This is a standing
   guard, not a patch — it holds wherever a caps rule is added later. */
.mono, code, kbd, samp, .cert, .cw-ref,
.paybox .addr code, .field label .mono, .field label code {
  text-transform: none;
  letter-spacing: 0;
}
/* focus must stay visible on dark bands — cream ring there, ink elsewhere */
.hero :focus-visible, .sellhero :focus-visible, .consign :focus-visible,
footer.site :focus-visible, .utilbar :focus-visible { outline-color: var(--cream); }

/* mint mark — the counter takes the color of the surface it's struck on */
.mm-counter { fill: var(--panel); }
footer.site .mm-counter { fill: var(--dark); }
.ad-side .mm-counter { fill: var(--dark); }

/* mark v2: freestanding — wider than tall, no container */
.wordmark .wm-mark { width: 24px; height: 21px; }
.ad-mark { width: 23px; height: 20px; }
/* WALLET BRAND TILES CARRY THEIR OWN ART, SO THE TILE ADDS NOTHING.

   This drew a 1px border around art that already has its own shape — a
   rounded square inside a rounded square, which is what made the list
   read as boxed-in. And the two kinds of art disagreed about size: an
   SVG mark filled the 34px tile while a vendor's PNG sat at 26px in the
   middle of it, so no two logos in the column were the same size.

   One treatment now: no border, no background, art fills the tile, and
   the tile clips to the house radius so a square logo is rounded like
   the rest. `object-fit: contain` keeps a non-square vendor icon from
   stretching, and `background: #fff` sits behind transparent art only
   (a dark glyph on the page's own paper is otherwise invisible in the
   midnight and vault themes). */
.provider .ptile.brand {
  padding: 0; border: 0; overflow: hidden;
  background: #fff; border-radius: var(--r-s);
}
.provider .ptile.brand svg,
.provider .ptile.brand img {
  width: 100%; height: 100%; display: block; object-fit: contain;
}

/* ============================================================
   House display register — serif headlines, engraved tags,
   gem-cut details. The chrome stays Archivo; the voice goes serif.
   ============================================================ */
/* The LIVE tag is a solid stamp. It was briefly restyled to an outline —
   --live type on the dark utility bar — which measured 2.54:1 in paper and
   2.92:1 in porcelain. Solid keeps the stamp and passes in all four:
   --on-ink is white on the day themes and near-black on the night ones,
   where --live is a light salmon. */
.livetag {
  font-weight: 700;
  letter-spacing: 0.18em;
}

/* display headlines in the serif register — light, never bold */
.hero h1, .sellhero h1, .band-head h1, .band-head h2, .browsehead h1, #bh-title {
  font-family: var(--font-serif);
  font-weight: 400;
  font-stretch: 100%;
  letter-spacing: 0;
}
.hero h1 { font-size: clamp(32px, 4.3vw, 52px); line-height: 1.07; }
.sellhero h1 { font-size: clamp(30px, 4vw, 46px); line-height: 1.1; }
.band-head h1, .band-head h2 { font-size: 24px; }

.hero-media { display: flex; flex-direction: column; align-items: center; gap: 14px; }

/* the last circles become house shapes */
.specmono { border-radius: var(--r-0); }
.cw-steps li span { border-radius: var(--r-0); }
.cw-track li .pip { border-radius: var(--r-0); width: 9px; height: 9px; transform: rotate(45deg); }

/* inline archive results in the header search */
.search-pop .arclead { color: var(--mut); }
.search-pop .archit .hit-t { font-weight: 600; }
.search-pop .hit-close { font-size: 10px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--mut); background: var(--wash); padding: 1px 5px; margin-left: 6px; }
.search-pop .archit { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
.search-pop .archit > span:first-child { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.search-pop .archit .hit-m { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* narrow-viewport fits */
.bidmode { flex-wrap: wrap; row-gap: 6px; }
@media (max-width: 560px) {
  .fundrow { flex-wrap: wrap; }
  .fundrow .amt { flex-basis: 100%; }
  .fundrow .btn { flex: 1; }
}

/* engraved second pass — stragglers from the verify round */
.bidrow .amt input { border-radius: var(--r-0); }
.facet .opt .box.radio { border-radius: var(--r-0); transform: rotate(45deg); width: 11px; height: 11px; }
.facet .opt input:checked + .box.radio::after { transform: none; width: 4.5px; height: 4.5px; }

/* ============================================================
   Narrow-viewport corrections — QA sweep round
   ============================================================ */
/* Lot tabs WRAP instead of scrolling. The old rule hid the scrollbar too
   (scrollbar-width:none plus a ::-webkit-scrollbar reset), so an
   overflowing strip gave no indication at all that a tab was off-screen —
   which is how "Shipping & payment" came to sit cut in half at the right
   edge of a 1024px laptop with nothing to suggest it was reachable.
   Keeping the page from widening is still the goal; a second row does that
   and stays visible. */
.lot-tabs { overflow-x: visible; }
.lot-tabs button { flex: none; }

/* the wrapped fund button keeps real height (base rule strips padding) */
@media (max-width: 560px) {
  .fundrow .btn { padding: 13px 18px; }
}

/* results/browse toolbar selects never force sideways scroll */
@media (max-width: 420px) {
  .sortsel select { max-width: 150px; }
}

/* touch: the watch star must be visible without hover, and the facet
   rows reach the 44px target the buttons now hold at every pointer */
@media (hover: none) {
  .lotcard .watch { opacity: 1; }
  .facet .opt { min-height: 44px; }
}

/* hero bid block wraps before it clips at very narrow widths */
.hero .bidblock { flex-wrap: wrap; }

/* ============================================================
   THEMES — four house presets. Paper is the default :root set;
   the others override tokens, and the components follow. Dark
   editorial surfaces (hero, footer, admin sidebar) stay dark in
   every preset, retuned per theme. Slabs and scans never change:
   the cards are physical objects.
   ============================================================ */
html[data-theme="porcelain"] {
  --paper: #eceef2; --panel: #ffffff; --wash: #dfe2e6; --wash2: #d3d7dd;
  --ink: #0f1114; --ink2: #31353d; --mut: #4f545b; --faint: #868c95;
  --line: #cdd2d9; --line2: #b4bbc4;
  --dark: #16181d; --dark2: #20242b; --dark-line: #31363f;
  --dark-fg: #c4c8ce; --dark-fg-mut: #9ba0a8; --dark-fg-dim: #848a93;
  --brass: #86682f; --brass-soft: #c9ad72; --brass-lit: #efe3bd;
  --up: #2f6b4c; --live: #ad3b37; --down: #ad3b37;
  --up-tint: #e6f1ea; --live-tint: #f8ebe9;
  --warn: #7f4f11; --warn-tint: #f4eee2; --brass-ink: #634b1f;
  --on-ink: #fff;
  --holo-mint: #b0d8c4; --holo-sky: #abcbe7; --holo-lilac: #dcc9ab;
  --holo-butter: #e5d29e; --holo-blush: #e3bdbf;
  --cat-pokemon: #f2ecd8; --cat-baseball: #e9efe5; --cat-basketball: #f0e8dd;
  --cat-football: #ebe7df; --cat-soccer: #e5eee6; --cat-hockey: #e4ebf3;
  --cat-tcg: #ece7f2;
  --shadow-1: 0 1px 2px rgba(14, 18, 26, 0.06), 0 8px 24px rgba(14, 18, 26, 0.08);
  --shadow-2: 0 2px 6px rgba(14, 18, 26, 0.08), 0 20px 48px rgba(14, 18, 26, 0.14);
}
/* THE TWO NIGHT ROOMS, RETUNED — and what was wrong with them.

   Both were built the way a dark theme gets built when nobody decides:
   a ground ramp in even steps of one desaturated slate
   (#10141d → #1a2029 → #232a35 → #2c3440 is four samples of the same
   colour at four brightnesses) under type at the very top of the range.
   Cream at #f3eee1 over a #10141d room measures about 16:1. Nothing is
   WRONG at 16:1 — it clears every guideline twice over — but it is the
   contrast of a terminal, not of a printed card, and it is what makes a
   dark theme read as a default rather than a room. Loud is not the same
   as intentional.

   A holo card is the reference and it is a precise one: the base is
   deep and quiet and low-contrast, the card's own art stays true, and
   the foil is a NARROW band that only catches at an angle. The flash is
   earned by being contained. So:

   - The grounds commit to a hue instead of hovering near gray. Midnight
     is actually navy and lifts violet as it rises; vault is actually
     bronze and lifts amber.
   - The ramp is deliberately UNEVEN. Room to card is the big step —
     that is a card lying on a table and it should read instantly — and
     the steps above it are fine, because they are separating panels
     inside one object, not objects from the room.
   - Type comes down off the ceiling. Body lands around 11–13:1: still
     far above the 4.5:1 floor, but soft enough to sit ON the ground
     rather than burn a hole through it.
   - Brass is the only high-chroma family left, and it is the foil. It
     is the one thing allowed to flash, which is exactly why it reads as
     a decision rather than as decoration.

   Measured with tools/design-contrast.js, not judged by eye. */
html[data-theme="midnight"] {
  /* the evening sale: a saleroom after dark. Indigo ground with real
     blue in it, candlelight cream, brass foil. */
  color-scheme: dark;
  --paper: #080c15; --panel: #121a28; --wash: #1c2536; --wash2: #273245;
  --ink: #f6f1e6; --ink2: #ddd6c6; --mut: #ada695; --faint: #79808f;
  --line: #2d374a; --line2: #404c60;
  --dark: #05080f; --dark2: #101724; --dark-line: #2a3444;
  --live: #dd8078; --down: #dd8078; --up: #7fbf9b;
  --brass: #d9bd80; --brass-soft: #ecd7a4; --brass-lit: #fbf1d4;
  --up-tint: rgba(127, 191, 155, 0.14); --live-tint: rgba(221, 128, 120, 0.13);
  --warn: #d9a95f; --warn-tint: rgba(217, 169, 95, 0.13); --brass-ink: var(--brass);
  --on-ink: #131926;
  /* the dark-band, foil and category families, stated for this room
     rather than inherited from paper */
  --cream: #f6f1e6; --cream-dim: #ddd6c6;
  --dark-fg: #cfc8b7; --dark-fg-mut: #ada695; --dark-fg-dim: #8b8574;
  --holo-mint: #8fb6a1; --holo-sky: #8cabc9; --holo-lilac: #bfa87e;
  --holo-butter: #c9b385; --holo-blush: #c49a9c;
  --cat-pokemon: #2e2b1f; --cat-baseball: #222b25; --cat-basketball: #2d281f;
  --cat-football: #292620; --cat-soccer: #202a26; --cat-hockey: #21293a;
  --cat-tcg: #292636;
  /* Deeper and softer than a light room's: an object on a dark ground
     is separated by falloff, not by a line. */
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.5), 0 12px 32px rgba(0, 0, 0, 0.55);
  --shadow-2: 0 2px 8px rgba(0, 0, 0, 0.55), 0 28px 64px rgba(0, 0, 0, 0.7);
}
html[data-theme="vault"] {
  /* the safe: blackened bronze under a single warm bulb. Warm metal all
     the way down — the ground carries amber, so gold belongs to it
     instead of sitting on top of a neutral gray. */
  color-scheme: dark;
  --paper: #0b0906; --panel: #18140e; --wash: #241e16; --wash2: #30291f;
  --ink: #faf4e4; --ink2: #e3dbc6; --mut: #b3a992; --faint: #837a68;
  --line: #352d22; --line2: #4a4132;
  --dark: #050403; --dark2: #100d09; --dark-line: #2b241b;
  --live: #de8074; --down: #de8074; --up: #85c19c;
  --brass: #e2c489; --brass-soft: #efd9a6; --brass-lit: #fbf0d2;
  --up-tint: rgba(133, 193, 156, 0.15); --live-tint: rgba(222, 128, 116, 0.14);
  --warn: #dcb06d; --warn-tint: rgba(220, 176, 109, 0.14); --brass-ink: var(--brass);
  --on-ink: #13100b;
  /* the dark-band, foil and category families, stated for this room
     rather than inherited from paper */
  --cream: #faf4e4; --cream-dim: #e3dbc6;
  --dark-fg: #d2c9b2; --dark-fg-mut: #b3a992; --dark-fg-dim: #8e8571;
  --holo-mint: #97b79f; --holo-sky: #93a9bf; --holo-lilac: #c7ac79;
  --holo-butter: #d1b884; --holo-blush: #c69b96;
  --cat-pokemon: #2d2716; --cat-baseball: #23281b; --cat-basketball: #2c2317;
  --cat-football: #282219; --cat-soccer: #20271e; --cat-hockey: #1f252e;
  --cat-tcg: #272132;
  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.6), 0 12px 32px rgba(0, 0, 0, 0.62);
  --shadow-2: 0 2px 8px rgba(0, 0, 0, 0.62), 0 30px 68px rgba(0, 0, 0, 0.78);
}

/* ============================================================
   THE HOLO PASS — where the shimmer actually lives.

   The brief is a Pokémon holo, and the useful thing about that
   reference is how DISCIPLINED a real one is. The foil is not
   sprayed over the card. It sits in defined regions, it is
   invisible head-on, and it only announces itself when the card
   moves. Everything below follows that: nothing shimmers at rest
   except the two hairline rules, and the big surfaces only catch
   the light when a pointer passes over them.

   THE SLABS ARE NEVER TOUCHED. Not once, nowhere in this block.
   The lots are real cards being sold, and a holo sweep laid over a
   photograph of a card is the house editorialising the goods — the
   buyer would be looking at our foil, not the seller's. An earlier
   pass here put the sweep on .lotcard and it had to come off. The
   ROOM shimmers; the merchandise stays exactly as photographed.

   Three places, and no others:

     1. the page ground itself — the iridescence lives in the
        background, which is what makes the colour feel like foil
        instead of paint
     2. the foil rules, which drift always — the card's edge
        catching the room
     3. the permanently dark furniture, the utilbar and the footer

   Everything here is decoration over content, so all of it is
   pointer-events: none and none of it is ever the only carrier of
   meaning. And all of it stops for prefers-reduced-motion, which
   is at the bottom of this block.
   ============================================================ */

/* The sweep itself, stated once. Transparent at both ends so the
   band has somewhere to come from and go to. */
:root {
  --holo-sweep: linear-gradient(
    115deg,
    transparent 28%,
    var(--holo-sky) 38%,
    var(--holo-lilac) 46%,
    var(--holo-butter) 54%,
    var(--holo-blush) 62%,
    transparent 72%
  );
}

/* ---------- 1. the page ground ---------- */
/* Fixed, so the sheen belongs to the room and does not slide up the
   screen as the reader scrolls — a holo tilts with the light, not
   with the page. z-index -1 puts it over body's flat --paper fill and
   under every piece of content. */
body::before {
  content: "";
  position: fixed;
  inset: -20vmax;
  pointer-events: none;
  z-index: -1;
  background: var(--holo-sweep);
  background-size: 220% 220%;
  opacity: 0.05;
  mix-blend-mode: soft-light;
  animation: mh-holo-drift 42s ease-in-out infinite alternate;
}
/* The night rooms carry it much further. This is the whole answer to
   "the dark colours look flat": a near-black ground reflects nothing,
   so the iridescence has to be IN it. screen adds light instead of
   tinting, which is what foil does. */
html[data-theme="midnight"] body::before,
html[data-theme="vault"] body::before {
  opacity: 0.16;
  mix-blend-mode: screen;
}

/* ---------- 3. the dark bands, at rest ---------- */
/* Only in the night rooms, only on the permanently dark furniture,
   and low enough that it reads as the surface not being flat rather
   than as an effect. 34s, because anything a reader can time is a
   distraction. */
html[data-theme="midnight"] .utilbar,
html[data-theme="midnight"] footer.site,
html[data-theme="vault"] .utilbar,
html[data-theme="vault"] footer.site {
  position: relative;
  isolation: isolate;
}
html[data-theme="midnight"] .utilbar::after,
html[data-theme="midnight"] footer.site::after,
html[data-theme="vault"] .utilbar::after,
html[data-theme="vault"] footer.site::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--holo-sweep);
  background-size: 300% 300%;
  opacity: 0.06;
  mix-blend-mode: screen;
  animation: mh-holo-drift 34s ease-in-out infinite alternate;
  z-index: -1;
}
@keyframes mh-holo-drift {
  from { background-position: 0% 50%; }
  to   { background-position: 100% 50%; }
}

/* Brass gets its foil back on the two marks that are pure ornament.
   Text keeps its flat, measured colour — a gradient behind letterforms
   is the one place this would cost readability. */
html[data-theme="midnight"] .foil-rule,
html[data-theme="vault"] .foil-rule { opacity: 1; }

/* The sheen stays; only its travel stops. An iridescent ground is a
   colour choice and survives the preference — what does not survive is
   anything that moves on its own. */
@media (prefers-reduced-motion: reduce) {
  .foil-rule,
  body::before,
  html[data-theme="midnight"] .utilbar::after,
  html[data-theme="midnight"] footer.site::after,
  html[data-theme="vault"] .utilbar::after,
  html[data-theme="vault"] footer.site::after { animation: none; }
}

/* night patches — pieces whose light-tuned constants would sink or glare */
html[data-theme="midnight"] .rchip.met, html[data-theme="vault"] .rchip.met { background: var(--up-tint); }
/* .rchip.notmet needs no night patch now that it is --warn on --warn-tint:
   both tokens are already retuned per theme. */
html[data-theme="midnight"] .cw-steps li.done span, html[data-theme="vault"] .cw-steps li.done span { background: var(--up-tint); }
/* the category thumbs need no night kill rule now that their tints are
   tokens the night themes state themselves */
/* .ad-chip.warn needs no night patch either: admin/admin.css already states
   it as --warn on --warn-tint, and this hand-mixed override was the last
   semantic hex outside the token blocks. */
/* .ad-chip.gold/.ok/.bad need no night patches: the flat status-mark
   rules below reset the chips to letterspaced labels with a diamond, and
   these three-class patches outranked that reset and re-filled the desk
   chips with tinted boxes in midnight and vault. The diamond colours are
   theme tokens already. */
html[data-theme="midnight"] .ad-loginerr, html[data-theme="vault"] .ad-loginerr { background: var(--live-tint); }
/* .arc-relaxed needs no night patch either: its rule is --brass-soft
   now, which every theme retunes — the butter it wore was invisible
   against the default theme's wash and patched everywhere else. */

/* ---------------- theme selector ---------------- */
.themebtn { position: relative; }
.themepop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  background: var(--panel); border: 1px solid var(--line2);
  box-shadow: var(--shadow-2); min-width: 196px; padding: 6px 0;
  display: none;
}
.themepop.open { display: block; }
.themepop .tp-h { display: block; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; font-weight: 700; color: var(--mut); padding: 7px 14px 3px; }
.themepop button {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 8px 14px; font-size: 12.5px; font-weight: 600; color: var(--ink);
}
.themepop button:hover { background: var(--wash); }
.themepop button[aria-checked="true"]::after { content: ""; width: 6px; height: 6px; background: var(--brass); margin-left: auto; flex: none; }
.tp-swatch { width: 16px; height: 16px; border: 1px solid var(--line2); flex: none; position: relative; overflow: hidden; }
.tp-swatch::after { content: ""; position: absolute; inset: 0 0 0 50%; }
.tp-swatch.paper { background: #eae6df; } .tp-swatch.paper::after { background: #191713; }
.tp-swatch.porcelain { background: #e9ebee; } .tp-swatch.porcelain::after { background: #15171b; }
.tp-swatch.midnight { background: #10141d; } .tp-swatch.midnight::after { background: #f3eee1; }
.tp-swatch.vault { background: #100e0b; } .tp-swatch.vault::after { background: #e6c98b; }

/* night: the watch star sits on a dark glass pill, not a white one */
html[data-theme="midnight"] .lotcard .watch, html[data-theme="vault"] .lotcard .watch { background: rgba(20, 17, 24, 0.65); }
html[data-theme="midnight"] .lotcard .watch:hover, html[data-theme="vault"] .lotcard .watch:hover { background: var(--panel); color: var(--ink); }

/* ============================================================
   ACCOUNT PAGE
   ============================================================ */
/* minmax(0, 1fr) is load-bearing. With no explicit track the implicit column
   is `auto`, and the <section> grid items keep the grid default
   min-width: auto — so the track floor became the sections' min-content,
   which .acct-main b (white-space: nowrap) drove to 664.9px inside a 335px
   container. The page scrolled sideways at every viewport and the ellipsis
   never engaged, because the box had grown to fit the title. The explicit
   minmax caps the track; min-width: 0 on the items stops a long catalogue
   title in any future section doing the same thing again. */
.acct-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 34px; max-width: 860px; }
.acct-grid > * { min-width: 0; }

/* ---------- the balance dashboard ----------
   One column on a phone — balances first, because the aside precedes the
   grid in the DOM — and a pinned right-hand column on a screen wide
   enough to have been wasting that space. */
.acct-layout { display: grid; grid-template-columns: minmax(0, 1fr); gap: 34px; align-items: start; }
@media (min-width: 1180px) {
  .acct-layout { grid-template-columns: minmax(0, 1fr) 340px; gap: var(--s-8); }
  .acct-grid { grid-column: 1; grid-row: 1; }
  /* Sticky, but never taller than the screen it is stuck to: the card
     carries actions and a wallet list now, and a pinned panel that
     cannot scroll hides its own bottom. */
  .acct-dash { grid-column: 2; grid-row: 1; position: sticky; top: 84px; max-height: calc(100vh - 100px); overflow-y: auto; }
}
.dash-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-m); padding: 20px 22px 8px; }
.dash-row { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; padding: 13px 0; border-top: 1px solid var(--line); }
.dash-hero { flex-direction: column; align-items: flex-start; gap: 2px; border-top: 0; padding-top: 2px; }
.dash-label { font-size: 12.5px; color: var(--mut); line-height: 1.4; }
.dash-num { font-variant-numeric: tabular-nums; font-size: 16px; font-weight: 600; white-space: nowrap; }
.dash-hero .dash-num { font-family: var(--font-d); font-size: var(--fs-800); font-weight: 800; letter-spacing: -0.01em; line-height: 1.1; }
.dash-total .dash-label { color: var(--ink); font-weight: 700; position: relative; }
.dash-total .dash-num { font-size: var(--fs-600); font-weight: 800; }
/* The eligibility tag is .acct-chip — the house's own square mark — not
   a rounded pill of its own. It only needs a seat beside the label. */
.dash-label .acct-chip { margin-left: 8px; vertical-align: 1px; }
.dash-paused { margin: 0 0 12px; color: var(--live); }
.dash-line { margin: var(--s-3) 0 0; }
/* The binding-offer sentence is fine print, and fine print is text:
   --faint measured 3.01:1 in paper at 11.5px against a 4.5 requirement.
   --mut is the tier .bidbox .bb-note already reads its notes in. */
.dash-fine { margin: 14px 0 12px; font-size: 11.5px; line-height: 1.5; color: var(--mut); }
/* Both classes named, because .acct-h is declared further down this file
   with `margin: 0 0 12px` at the same specificity and wins the cascade on
   order: this rule's top margin never applied, so the wallet heading sat
   flush against the escrow controls above it and the sentence, the
   deposit button and the list read as one undifferentiated block. */
.acct-h.dash-subh { font-size: var(--fs-100); margin: var(--s-5) 0 var(--s-3); }
.dash-actions { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-top: var(--s-4); }
/* .btn is nowrap over overflow: hidden, so a label too long for its box is
   SHORN rather than spilled — nothing on the page looks broken and the
   word is simply missing letters. "Link or re-verify the connected wallet"
   lost 13px of itself in this 340px column and 25px at the phone type
   floor. The labels this card carries are sentences: they wrap. */
.dash-actions .btn { white-space: normal; }
/* The escrow controls are their own zone in this card — money a contract
   holds, not the figures above — and they mounted with ten pixels of air
   and no edge, which is what made three unlike elements read as one. */
#escrow-panel:not(:empty) {
  margin-top: var(--s-4);
  padding-top: var(--s-4);
  border-top: 1px solid var(--line);
}
#escrow-panel > :first-child { margin-top: 0; }
.dash-wallets { border-top: 1px solid var(--line); }
/* TWO LINES BY CONSTRUCTION, because four things never fitted one.
   In the 340px sidebar this list lives in, flex handed the address
   whatever the balance, the standing chip and the Unlink button left
   over, and that measured zero: a truncated token wrapped down three
   lines inside a box clipped to nothing, so an address rendered as a
   vertical column of characters. The chip's long form then drove the
   button 197px past the card's own edge. Grid settles both by shape —
   the wallet and its balance, then what it counts for and the control
   that undoes it — and neither column can starve the other. */
.dash-wal {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  /* Baseline, not centre: everything in this row is type, and the long
     form of the chip is two lines, which centring left the Unlink beside
     it floating between them rather than sitting on the line it belongs
     to. Each grid row aligns on its own first baseline. */
  align-items: baseline;
  column-gap: var(--s-3); row-gap: var(--s-2);
  padding: var(--s-3) 0; border-bottom: 1px solid var(--line);
  font-size: 12.5px;
}
/* nowrap is the guard that was missing: text-overflow does nothing
   without it, so the ellipsis this rule asked for never appeared and the
   address broke between characters instead. */
.dash-wal .mono { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dash-wal-amt { justify-self: end; font-variant-numeric: tabular-nums; color: var(--mut); white-space: nowrap; }
/* The long form of this chip is a sentence, so it is allowed the line
   breaks the tracked-caps tier normally refuses. */
.dash-wal .acct-chip { min-width: 0; align-items: baseline; line-height: 1.5; }
/* UNLINKING IS RARE, AND IT WAS THE LOUDEST MARK IN THE ROW.
   As .btn.ghost it drew a 46px outlined plate beside a balance it is not
   more important than. Demoted to the house's text-control language —
   the underline .linkline wears — while keeping the 44px touch target the
   way .dash-info and the utility bar keep theirs: a transparent patch,
   not a bigger box. Size and tracking are left to .btn.sm so the phone
   type floor further down still reaches it. */
.dash-wal .btn.bk-unlink {
  position: relative; overflow: visible;
  justify-self: end;
  min-height: 0; padding: 0;
  border: 0; background: none; box-shadow: none;
  color: var(--mut);
  text-decoration: underline; text-underline-offset: 4px;
  text-decoration-thickness: 1px; text-decoration-color: var(--line2);
}
.dash-wal .btn.bk-unlink::before { display: none; }
.dash-wal .btn.bk-unlink::after {
  content: "";
  position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; min-width: 100%;
  transform: translate(-50%, -50%);
}
.dash-wal .btn.bk-unlink:hover:not([disabled]) {
  transform: none; background: none; box-shadow: none;
  color: var(--ink); text-decoration-color: var(--ink);
}
/* The ⓘ beside Bidding power. A button, so a keyboard and a phone reach
   the explanation hover cannot give them. */
.dash-info {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-left: 6px; padding: 0;
  border: 1px solid var(--line2); border-radius: 50%; background: none;
  font-family: var(--font-m); font-size: 10px; font-style: italic; color: var(--mut);
  cursor: help; vertical-align: 1px;
}
/* The ring stays 16px; the tap does not. A transparent 44px square
   centred on it takes the touches the glyph itself is too small to. */
.dash-info::before {
  content: "";
  position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px;
  transform: translate(-50%, -50%);
}
.dash-info:hover, .dash-info:focus-visible { border-color: var(--ink2); color: var(--ink); }
.dash-tip {
  position: absolute; bottom: calc(100% + 10px); left: 0; z-index: 40;
  width: 250px; padding: 10px 12px;
  background: var(--panel); border: 1px solid var(--line2); border-radius: var(--r-m);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.14);
  font-size: 12.5px; font-weight: 400; color: var(--ink2); line-height: 1.5;
  display: none;
}
.dash-info:hover + .dash-tip, .dash-info:focus-visible + .dash-tip { display: block; }
.acct-h { font-size: var(--fs-300); letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut); margin: 0 0 12px; }
.acct-row {
  display: flex; align-items: center; gap: 14px; padding: 10px 12px;
  border: 1px solid var(--line); background: var(--panel); margin-bottom: 8px;
  color: var(--ink); text-decoration: none;
}
.acct-row:hover { border-color: var(--line2); }
.acct-slab { width: 40px; flex: none; }
.acct-slab svg { width: 100%; height: auto; display: block; }
.acct-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.acct-main b { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acct-sub { font-size: var(--fs-200); color: var(--mut); }
.acct-chip {
  flex: none; font-size: 10.5px; font-weight: 700; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--mut);
}
.acct-tablewrap { overflow-x: auto; border: 1px solid var(--line); }
.acct-table { width: 100%; border-collapse: collapse; font-size: var(--fs-300); background: var(--panel); }
.acct-table th, .acct-table td { padding: 9px 12px; text-align: left; border-bottom: 1px solid var(--line); white-space: nowrap; }
.acct-table th { font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut); }
.acct-table .num { text-align: right; }
.acct-table tr:last-child td { border-bottom: none; }
.acctlink { font-weight: 700; }

/* ============================================================
   HERO — editorial, no aurora. Day themes read as paper and ink;
   night themes keep a flat dark stage. The only decoration is the
   slab itself and the foil hairline the site already owns. The flat
   stage itself is stated once, in the HERO block near the top of
   the file.
   ============================================================ */
.hero-eyebrow .eyebrow { color: var(--brass-ink); }
.hero .lotmeta { color: var(--mut); }
.hero .bidblock .lbl { color: var(--mut); }
.hero .bidblock .sub { color: var(--mut); }
/* The hero countdown inherits the hero's own ink — 42px of red at eighteen
   hours out said "error" for a lot that is simply open, and the identical
   value on the lot page was black. One fact, one colour. */
.hero .btn.ondark { background: var(--ink); color: var(--on-ink); border-color: var(--ink); }
.hero .btn.ondark:hover { background: var(--ink2); border-color: var(--ink2); }
.hero .btn.ondark.ghost { background: transparent; color: var(--ink); border-color: var(--line2); }
.hero .btn.ondark.ghost:hover { border-color: var(--ink); }
.hero :focus-visible { outline-color: var(--ink); }
.hero-media .slabwrap { filter: drop-shadow(0 22px 40px rgba(31, 27, 20, 0.28)); }
.hero-media::before { background: radial-gradient(50% 100% at 50% 0%, rgba(31, 27, 20, 0.18), transparent 70%); }

html[data-theme="midnight"] .hero, html[data-theme="vault"] .hero {
  background: var(--dark); color: var(--cream);
}
html[data-theme="midnight"] .hero .lotmeta, html[data-theme="vault"] .hero .lotmeta,
html[data-theme="midnight"] .hero .bidblock .lbl, html[data-theme="vault"] .hero .bidblock .lbl,
html[data-theme="midnight"] .hero .bidblock .sub, html[data-theme="vault"] .hero .bidblock .sub { color: var(--dark-fg-mut); }
html[data-theme="midnight"] .hero .btn.ondark, html[data-theme="vault"] .hero .btn.ondark {
  background: var(--cream); color: var(--dark); border-color: var(--cream);
}
html[data-theme="midnight"] .hero .btn.ondark:hover, html[data-theme="vault"] .hero .btn.ondark:hover {
  background: var(--cream-dim); border-color: var(--cream-dim);
}
html[data-theme="midnight"] .hero .btn.ondark.ghost, html[data-theme="vault"] .hero .btn.ondark.ghost {
  background: transparent; color: var(--cream); border-color: var(--dark-line);
}
html[data-theme="midnight"] .hero .btn.ondark.ghost:hover, html[data-theme="vault"] .hero .btn.ondark.ghost:hover { border-color: var(--cream); }
html[data-theme="midnight"] .hero :focus-visible, html[data-theme="vault"] .hero :focus-visible { outline-color: var(--cream); }

/* ============================================================
   CATEGORY SUBSECTION BAR + BUY NOW CARDS
   ============================================================ */
/* The second nav tier. Lighter than the section row above it — same rhythm,
   no rule under the active item, so it reads as "inside" rather than "beside". */
.catbar { background: var(--wash); border-bottom: 1px solid var(--line); }
.catbar .wrap { display: flex; align-items: center; gap: 2px; overflow-x: auto; scrollbar-width: none; }
.catbar .wrap::-webkit-scrollbar { display: none; }
.catbar button {
  display: inline-flex; align-items: baseline; gap: 7px;
  /* 38px measured at 375, in the strip a phone uses to change category.
     The row above it (.catnav) already stands at 46; this one matches the
     floor rather than sitting eight pixels under it. */
  min-height: 44px;
  padding: 9px 12px; background: transparent; border: 0;
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.01em;
  color: var(--mut); white-space: nowrap; border-radius: var(--r-s);
}
.catbar button .n {
  font-family: var(--font-m); font-size: 10.5px; color: var(--mut);
  font-weight: 500; letter-spacing: 0;
}
/* Not the active chip. Hover is (0,3,1) and `.active` below is (0,2,1),
   so without this exclusion hovering the selected category set ink on the
   ink background it already has: the label measured 1.00 against a 4.5
   threshold and was invisible, in all four themes, with no transition to
   move it back. The selected chip keeps its own colours under the
   pointer, which is also what it should look like. */
.catbar button:hover:not(:disabled):not(.active) { color: var(--ink); }
.catbar button.active { background: var(--ink); color: var(--on-ink); }
.catbar button.active .n { color: var(--on-ink); opacity: 0.72; }
.catbar button:disabled { opacity: 0.34; cursor: default; }

.browse-toolbar { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.browse-toolbar .count { margin-right: auto; }
.lotcard .bnstate {
  font-family: var(--font-d); font-weight: 700; font-size: 11.5px;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--up);
}
.lotcard.buynow.closed .bnstate { color: var(--mut); }
.soldtag.pending { background: var(--brass); color: var(--on-ink); }

/* Buy It Now offer under the bid controls — a quiet second path */
.binoffer {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  margin-top: 14px; padding: 12px 14px;
  border: 1px solid var(--line);
  font-size: 12.5px; color: var(--mut); background: var(--panel);
}
.binoffer b { color: var(--ink); }
.binoffer .btn { flex: none; }

/* ---------- sidenote — the "noted" device ----------
   One recipe for the 3px tinted left rule. It had been re-typed four
   separate ways — legal callout, archive status band, relaxed-search
   note, the Buy It Now offer — two of them byte-identical with no
   shared class, and one in a butter that vanished against the default
   theme's wash. The rule is brass-soft, which every theme retunes;
   state colours (the status band's working brass) sit on top of it.
   New markup takes the classes; the four existing blocks are grouped
   here so the recipe exists exactly once. */
/* A HAIRLINE, NOT A TAB. These carried a 3px brass bar, which is the
   single most recognisable tell of a generated interface and reads as a
   coloured tab stuck to the side of a note. The marginal rule is the
   right idea and it only ever wanted to be a rule: at 1px it is the same
   hairline this stylesheet divides everything else with, and the brass
   still says which notes are the house speaking. */
.sidenote,
.legal-body .callout,
.arc-statusband,
.arc-relaxed,
.binoffer { border-left: 1px solid var(--brass-soft); }
.sidenote--framed { border: 1px solid var(--line); border-left: 1px solid var(--brass-soft); background: var(--panel); }
.sidenote--alert { border-left-color: var(--live); }

/* profile & settings on the account page */
.acct-profile { display: grid; gap: var(--s-4); }
.acct-card { border: 1px solid var(--line); background: var(--panel); padding: 18px 18px 16px; }
.acct-sub-h { font-size: 13.5px; font-weight: 700; margin: 0 0 12px; color: var(--ink); }
.acct-check { display: flex; align-items: center; gap: 10px; min-height: 44px; font-size: 13.5px; padding: 8px 0; cursor: pointer; }
.acct-check input { width: 16px; height: 16px; flex: none; accent-color: var(--ink); }
.acct-actions { margin-top: 14px; }
.acct-row2 { display: flex; gap: var(--s-3); }
.acct-half { flex: 1; min-width: 0; }
@media (max-width: 520px) { .acct-row2 { flex-direction: column; gap: 0; } }

/* wallet quick-action chips + cash-out preset active state */
.quickbids [data-pane].active, .fundpresets [data-co].active { background: var(--ink); color: var(--on-ink); }
.wide .qr img { width: 200px; height: 200px; }

/* ---------- embedded Peer checkout ----------
   Full-bleed inside the dialog: the checkout surface runs edge to edge
   between two hairlines, framed by a quiet host bar above and a single
   note below. No box-in-box borders. */
/* The sheet's frame box owns its height explicitly, and both layers fill
   it absolutely. Sizing the iframe alone and letting the flex parent
   follow left the frame measuring zero once the loading mark stopped
   holding the box open. */
.peerframe { position: relative; height: min(76vh, 760px); }

/* The pop-out lives in the title bar next to the close button: one glyph,
   no words. The sheet used to carry a whole footer row under the frame
   spelling out the host and "New tab", which competed with the checkout
   for attention on the one screen where nothing should. */
.peerframe-out {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; margin-right: 2px;
  color: var(--mut); font-size: 14px; line-height: 1;
  text-decoration: none; border-radius: var(--r-0);
  transition: color var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
}
.peerframe-out:hover { color: var(--ink); background: var(--wash); }
.peerframe-out.paid { color: var(--up); }
.peerframe-out.paid svg { width: 15px; height: 15px; display: block; }

/* The house mark holds the frame's place while the remote checkout loads,
   then hands over in a single crossfade. Both layers occupy the same box
   so nothing reflows at the swap — the old sheet flashed a white
   rectangle between opening and the checkout arriving. */
/* The frame is NEVER hidden. The house mark simply sits on top of it
   until the checkout has painted, then fades away.

   The earlier version faded the frame IN, which meant any failure to
   detect "loaded" left the checkout invisible — a blank sheet where the
   payment should be. Covering rather than hiding makes the worst case a
   mark that lingers a moment over a working checkout, instead of a
   working checkout nobody can see. */
.peerframe-wait {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  background: #fff;
  transition: opacity var(--dur-slow) var(--ease);
}
.peerframe-frame {
  position: absolute; inset: 0;
  width: 100%; height: 100%; border: 0; display: block;
  background: #fff; z-index: 1;
}
@media (prefers-reduced-motion: reduce) {
  .peerframe-wait { transition: none; }
}

/* ---------- WalletConnect pairing (local QR) ---------- */
.wcpair .fundhead { margin-bottom: 12px; }
.wcqr {
  width: 232px; height: 232px; margin: 4px auto 12px; padding: 10px;
  background: #fff; border: 1px solid var(--line); border-radius: var(--r-s);
  display: flex; align-items: center; justify-content: center;
}
.wcqr svg { width: 100%; height: 100%; display: block; }
.wcwait { font-size: var(--fs-200); color: var(--mut); }
.wcactions { display: flex; gap: var(--s-2); justify-content: center; margin-bottom: 10px; }
.wcpair #wc-back { margin-top: 12px; }

/* ---------- cash-out order history ---------- */
.co-ordershead {
  margin: 18px 0 8px; font-size: var(--fs-100); font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--mut);
}
.co-order { border-top: 1px solid var(--line); padding: 10px 2px; }
.co-orderrow { display: flex; align-items: center; gap: 10px; }
.co-orderrow .price { font-size: 14px; }
.co-orderrow .btn { margin-left: auto; }
.co-orderline { margin: 6px 0 0; font-size: var(--fs-200); color: var(--mut); line-height: 1.5; }

/* Preset chips keep their label on one line; the chip itself wraps. */
.quickbids button, .fundpresets button { white-space: nowrap; }

/* ---------- assurance line (replaces the old four-card trust strip) ----------
   One quiet row of facts under the auction head. No icons, no cards, no
   paragraphs — the grid below is what the visitor came for. */
.assure {
  display: flex; flex-wrap: wrap; gap: 6px 18px;
  margin: 12px 0 0; padding: 0; list-style: none;
  font-size: var(--fs-200); color: var(--mut);
  /* The row is written in by js/browse.js. One line of it is reserved —
     the least it is ever, so the reserve cannot exceed what arrives —
     which keeps the grid below from stepping down on a wide screen. */
  min-height: 18px;
}
.assure li { display: flex; align-items: center; }
/* The separator is the house diamond, not a round dot.

   A 3px circle between list items is the separator every interface
   reaches for, and four of them across one line was the most generic
   thing on the page. The same gem the mint mark sets into the M is
   already doing this work as the status mark above, so the site has one
   small shape and it means "Minthouse" wherever it appears. Brass, and
   a shade smaller than the status diamond, because this one is
   punctuation rather than information. */
.assure li + li::before {
  content: ""; width: 4px; height: 4px;
  transform: rotate(45deg);
  background: var(--brass); margin-right: 18px;
}
/* The same diamond as a free-standing separator, for metadata lines that
   used to reach for the round middle dot. Punctuation, not information:
   aria-hidden in the markup, so the line must read sensibly without it.
   :empty, because the breadcrumb bar has long spelled its "/" inside a
   span of this same class name — a span with content keeps its text and
   its own .crumbbar rule; only the empty span draws the diamond. */
.sep:empty {
  display: inline-block; width: 4px; height: 4px;
  transform: rotate(45deg);
  background: var(--brass); margin: 0 7px; vertical-align: middle;
}
/* An empty value in a table cell or KPI. A drawn hairline, not the em
   dash the house voice does not use: same read, no glyph. */
.nil::before {
  content: ""; display: inline-block; width: 12px; height: 1px;
  background: var(--line2); vertical-align: middle;
}

/* ---------- price history chart ----------
   Editorial, not terminal: hairline grid, one weighted line, a soft
   directional wash. Green/red carry the delta only — the frame stays
   in house neutrals so the chart reads as a document, not a ticker. */
.pchart { border: 1px solid var(--line); border-radius: var(--r-m); background: var(--panel); overflow: hidden; }
.pchart-head {
  display: flex; align-items: flex-start; flex-wrap: wrap; gap: 10px 16px;
  padding: 14px 16px 10px;
}
.pchart-id { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pchart-label {
  font-size: 10.5px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--mut);
}
.pchart-val {
  font-family: var(--font-d); font-weight: 800; font-size: var(--fs-700); line-height: 1.1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
.pchart-delta {
  display: flex; align-items: baseline; gap: var(--s-2);
  font-size: 12.5px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.pchart-delta.up { color: var(--up); }
.pchart-delta.down { color: var(--down); }
.pchart-delta.flat { color: var(--mut); }
.pchart-pct { font-weight: 700; }
.pchart-range { color: var(--mut); font-weight: 400; font-size: 11.5px; }

/* the mini window box, top right */
.pchart-windows {
  display: flex; flex: none; margin-left: auto;   /* hugs the top-right corner */
  border: 1px solid var(--line); border-radius: var(--r-s); overflow: hidden;
}
.pchart-windows button {
  min-height: 44px;               /* the touch floor, same as the quick bids */
  padding: 5px 9px; font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
  color: var(--mut); background: transparent; transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.pchart-windows button + button { border-left: 1px solid var(--line); }
.pchart-windows button:hover { background: var(--wash); color: var(--ink); }
.pchart-windows button.on { background: var(--ink); color: var(--on-ink); }

.pchart-plot { position: relative; padding: 0 4px 4px; }
.pchart-svg { display: block; width: 100%; height: 260px; }
.pchart-tick { font: 10.5px var(--font-b), sans-serif; }
.pchart-empty { padding: 40px 16px; margin: 0; font-size: var(--fs-300); color: var(--mut); text-align: center; }
.pchart-tip {
  position: absolute; pointer-events: none; z-index: 2;
  background: var(--ink); color: var(--on-ink);
  padding: 5px 9px; border-radius: var(--r-s);
  font-size: 11.5px; line-height: 1.35; white-space: nowrap;
  display: flex; flex-direction: column;
}
.pchart-tip b { font-variant-numeric: tabular-nums; font-size: 12.5px; }
.pchart-tip span { color: var(--on-ink); opacity: .62; font-size: 10.5px; }
.pchart-note { margin: 0; padding: 0 16px 13px; font-size: 11.5px; color: var(--mut); line-height: 1.5; }

@media (max-width: 560px) {
  .pchart-val { font-size: 22px; }
  .pchart-svg { height: 200px; }
}

/* .rt-demo (the bordered fixture chip) is gone: nothing renders it.
   .susptag's old bordered form is gone too — the STATUS MARKS section
   below owns its whole appearance now. */

/* The Population heading is an h2 for document structure — it follows the
   lot title's h1 and a skipped level fails the a11y gate — but it reads
   as a small section label in the market pane, so it keeps the size it
   had as an h3 rather than growing to h2's 22.5px. 1.17em is the value
   that made it 17.55px before: nothing here ever set an h3 size, so that
   was the browser default (1.17em of a 15px parent), and h2's default is
   1.5em. Stated as the same em the default used, so it tracks the parent
   the way it always did instead of freezing a pixel measurement. */
/* And it needs air above it. The comparables note ends a paragraph and
   this heading opened the next subject with 0 margin between them, so
   the two ran together as one block of text with a bold line in it.
   More space above a heading than below it, which is the rule the rest
   of the page already follows. */
.popsection-h { font-size: 1.17em; margin-top: 28px; margin-bottom: 12px; }

/* The sign-in dialog's fallbacks. One way in is the email code; these are
   the doors almost nobody needs, so they sit under a rule at note size
   rather than competing with the button above them. The three-way
   segmented control they replaced asked a first-time visitor to classify
   themselves before they had done anything. */
.authfoot {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: .82rem;
  color: var(--mut);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
}
.authalt { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; margin-top: 10px; }
/* a rendered glyph in a text run, not a rule — --line measured 1.56:1,
   the same defect the crumb separator was already cleared of */
/* The glyph is gone: the separator draws itself, as .sep does. */
.authsep {
  display: inline-block; width: 4px; height: 4px;
  transform: rotate(45deg); background: var(--line2);
  margin: 0 2px; vertical-align: middle; flex: none;
}
#authlede { margin-bottom: 14px; }
#authmsg[role="alert"] { margin-top: 10px; color: var(--live); }

/* ============================================================
   STATUS MARKS
   ============================================================
   A sale catalogue does not fill a rectangle to say a thing is
   live, or that a reserve was met. It sets the words small and
   wide and strikes one accent beside them, and the accent is the
   only part carrying colour. Filled and outlined badges are the
   house style of software, not of a saleroom, and every chip on
   this site was one of the two.

   Two marks, meaning two different kinds of thing:

     a DIAMOND, the gem the mint mark sets into the M, marks a
     STATE — live, met, not met, eligible, extended.

     a RULE, a hairline stood on end, marks a CLASSIFICATION —
     who graded the card and what they said about it.

   The label is always ink, or cream on the dark bands, and the
   mark is always the colour. That split is what makes this hold
   across four themes: the outline LIVE tag tried here before
   measured 2.54:1 in paper because it made --live the TEXT. A 5px
   diamond is not text and is not read, so it may take any weight
   of colour a theme hands it, while the word beside it keeps the
   contrast of ordinary type.

   Sizes stay in the tracked-caps tier the phone floor below
   already clamps, so this section changes how the marks look and
   not how small they are allowed to get. */
.livetag, .rchip, .extchip, .acct-chip, .autobid, .ad-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 0;
  padding: 0;
  font-family: var(--font-d);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  line-height: 1;
  /* INHERIT, and this is the load-bearing line.

     The first build set --ink here and then tried to name the dark
     surfaces to override: `.utilbar .livetag, .hero .livetag { cream }`.
     That is wrong on its face, because .hero is NOT dark — the home
     page's hero ground measures rgb(234,230,223) in paper — so the tag
     went cream on greige at 1.08:1 and disappeared. Enumerating which
     surfaces are dark is a list that has to be right on every page, in
     four themes, forever, and it was wrong on the first page tested.

     Inheriting is right everywhere by construction: the label takes the
     colour the text around it already uses, which each surface has
     already had to get right for its own body copy. The diamond is the
     only thing that sets its own colour. */
  color: inherit;
  vertical-align: baseline;
}
/* THE DIAMOND IS CUT, NOT ROTATED — and that is a bug fix, not a taste.

   It was a 5px square under transform: rotate(45deg). A transform does
   not change layout, so the rotated corners stick out about 1px past
   the 5px box on every side, and any ancestor with overflow: hidden
   shears them off. `.utilbar .ticker span` sets exactly that, for
   ellipsis on the sale name — and .livetag IS a span in that ticker, so
   the LIVE mark in the top bar had its left and right points sliced
   flat on every page of the site.

   clip-path cuts the diamond out of a box that already contains it:
   7px is the diagonal of the 5px square it replaces, so the mark is the
   same size on screen and now nothing of it lies outside its own box.
   That fixes it here and everywhere else these chips are set down,
   including containers nobody has written yet. */
.livetag::before, .rchip::before, .extchip::before,
.acct-chip::before, .ad-chip::before {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
  background: var(--mut);
}
/* The tinted grounds are declared with two classes each, which outranks
   the single-class reset above, so they have to be cleared by name or
   they survive it: .rchip.none kept a --wash fill through the first
   build of this section and was the one chip still wearing a box. */
.rchip.met, .rchip.notmet, .rchip.none,
.acct-chip.ok, .acct-chip.warn, .acct-chip.bad,
.ad-chip.ok, .ad-chip.warn, .ad-chip.bad, .ad-chip.gold {
  background: none;
  border: 0;
  padding: 0;
  color: inherit;
}

/* The state, and nothing else, is what the diamond says. */
.rchip.met::before, .acct-chip.ok::before, .ad-chip.ok::before { background: var(--up); }
.rchip.notmet::before, .extchip::before,
.acct-chip.warn::before, .ad-chip.warn::before { background: var(--brass); }
.rchip.none::before { background: var(--line2); }
.ad-chip.gold::before { background: var(--brass); }
.livetag::before, .acct-chip.bad::before, .ad-chip.bad::before { background: var(--live); }
/* A marker in bid history is not a state and takes no diamond. */
.autobid { color: var(--mut); }

/* No per-surface colour overrides live here any more. `color: inherit`
   above makes every one of them unnecessary, and the .hero rule that
   used to be in this block was actively wrong: that hero is light. */

/* Grade: grader and grade, stood against a hairline. Brass for a
   third party's opinion, ink for the house's own auto grade, and
   the faint rule for a card nobody has graded at all. */
.gradetag {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: none;
  border: 0;
  padding: 0;
  font-family: var(--font-d);
  font-weight: 700;
  font-size: 10.5px;
  letter-spacing: 0.1em;
  line-height: 1;
  color: inherit;
}
.gradetag::before {
  content: "";
  flex: none;
  width: 1px;
  height: 11px;
  background: var(--brass);
}
.gradetag.auto { background: none; color: inherit; }
.gradetag.auto::before { background: var(--ink2); }
.gradetag.ghost { color: var(--mut); border: 0; padding: 0; }
.gradetag.ghost::before { background: var(--line2); }

/* The hero's grade is the same statement one size up, and it was the
   last outlined box on the site: `border: 1px solid currentColor` drawn
   in --mut, which is the shape this whole section exists to retire. It
   sits on the dark hero, so the label takes the cream every other
   on-dark label takes, and the rule stays brass. */
.gradechip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: 0;
  padding: 0;
  font-family: var(--font-d);
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: 0.1em;
  line-height: 1;
  color: inherit;
}
.gradechip::before {
  content: "";
  flex: none;
  width: 1px;
  height: 13px;
  background: var(--brass);
}
/* no surface override needed: the label inherits its context. */

/* A paused account is a STATE, so it takes the diamond and not the rule.
   It was --live type inside a --live box, which is both the badge shape
   and the one colour pairing this file has repeatedly measured too low;
   the word now carries ordinary label contrast and the diamond carries
   the alarm. */
.susptag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 8px;
  border: 0;
  padding: 0;
  background: none;
  font-family: var(--font-d);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  line-height: 1;
  color: inherit;
  vertical-align: baseline;
}
.susptag::before {
  content: "";
  flex: none;
  width: 5px;
  height: 5px;
  transform: rotate(45deg);
  background: var(--live);
}
/* no surface override needed: the label inherits its context. */

/* SOLD is the one mark that keeps a filled ground, because it sits
   on a photograph of a card and has to stay legible over whatever
   is under it. It stops being an alarm, though: a sale is a record,
   not a warning, so it is struck in ink rather than in red. */
.soldtag {
  background: var(--ink);
  color: var(--panel);
  font-family: var(--font-d);
  font-weight: 700;
  font-size: 10px;
  letter-spacing: 0.16em;
  padding: 4px 8px;
}
.soldtag.passed { background: var(--mut); color: var(--panel); }

/* ============================================================
   PHONE TYPE FLOOR — no label under 12px at arm's length.
   The tracked-caps tier reads fine at 9–11.5px on a desk and does
   not on a phone: measured at 375px, "LIVE" was 9px, the watchlist
   count 9.5px, "Current bid" 11.5px — 364 elements under 12px on
   one screen. Labels and buttons clamp to the 12px step here. The
   tile clock keeps its measured fit from the 460px block, and the
   half-pixel body sizes are already over the floor.
   ============================================================ */
@media (max-width: 540px) {
  .eyebrow, .livetag, .iconbtn .cnt, .lotcard .meta,
  .gradetag, .lot-sub .gradetag,
  .bidbox .bb-lbl, .hero .bidblock .lbl,
  .rchip, .extchip, .autobid, .soldtag, .acct-chip, .arc-status b,
  .arc-noscan, .pchart-label, .pchart-windows button,
  .susptag, .catbar button .n, .search-pop .hit-close,
  .themepop .tp-h, .co-ordershead, .cw-sliplbl,
  .resulttable th, .compstable th, .acct-table th, .feetable th,
  .pf-conf, .pf-stale, .pf-figlab, .pf-chartmode button,
  .btn, .btn.sm, .fundrow .btn, .arc-pager .btn, .speccard .btn { font-size: var(--fs-200); }
  /* The floor is paid for out of the padding, not out of the type. The
     display button carries 30px a side and 0.14em of tracking, so
     raising its label from 10.5px to 12px widened it by roughly a fifth
     — enough that the sell hero's pair measured 466px against a 375px
     viewport. The label keeps the size it needs to be read; the box
     around it gives up the room. */
  .btn.xl { padding: 15px 18px; letter-spacing: 0.1em; }
}

/* ============================================================
   PORTFOLIO — the collection register.
   Reuses the account page's chassis (.acct-layout, .dash-card,
   .acct-table) so the register reads as part of the account, not a
   second product. Everything below is the delta: confidence marks in
   the status-marks language, the holdings rows, the detail head, and
   the add-card combobox. Tokens only; the four themes inherit.
   ============================================================ */
.pf-day { font-size: var(--fs-300); font-weight: 600; margin-top: 4px; font-variant-numeric: tabular-nums; }
.pf-day.mutline { color: var(--mut); font-weight: 400; }
.pf-fresh { margin: 10px 0 0; }
.pf-dash-actions {
  display: flex; flex-direction: column; gap: var(--s-3);
  margin-top: var(--s-4); padding-bottom: var(--s-2); align-items: flex-start;
}
.pf-dash-actions .btn.full { width: 100%; }
.pf-dash-actions .linkline { line-height: 1.5; }

/* The rail is sticky and capped at the viewport, and with the overflow
   on the rail itself whatever sits LAST inside it is what the cap cuts —
   which is Download CSV. Compacting the rows and padding the foot only
   moved the cut: a short viewport, or one more custody line, put the
   link back under the edge, sliced in half with no scrollbar visible to
   say so. So the cap now belongs to a rail that never scrolls, the
   figures take whatever height is left over and scroll inside
   .dash-scroll, and the actions sit outside that scroller. The last
   control cannot be clipped because it is no longer inside the box
   doing the clipping. */
@media (min-width: 1180px) {
  #pf-dash { display: flex; flex-direction: column; overflow: hidden; }
  /* min-height: 0 twice over: a flex item's floor is its own content, so
     without it neither the card nor the scroller would shrink under the
     cap and the figures would push the foot straight back out again. */
  #pf-dash > .dash-card { display: flex; flex-direction: column; min-height: 0; }
  /* The border draws the scroller's edge. A half line of a freshness note
     ending in mid-air is the same thing the operator complained about; the
     card already rules off every figure with this hairline, so the foot
     gets one too and the boundary reads as a seam rather than a crop. */
  #pf-dash .dash-scroll { min-height: 0; overflow-y: auto; border-bottom: 1px solid var(--line); }
  #pf-dash .pf-dash-actions { flex: none; }
}

/* confidence: a diamond mark, label in inherited ink — never a tinted pill */
.pf-conf, .pf-stale {
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut);
  white-space: nowrap;
}
.pf-conf::before {
  content: ""; display: inline-block; width: 5px; height: 5px;
  transform: rotate(45deg); margin-right: 6px; vertical-align: 1px;
  background: var(--mut);
}
.pf-conf.hi::before { background: var(--ink); }
.pf-conf.med::before { background: var(--brass); }
.pf-conf.low::before { background: transparent; box-shadow: inset 0 0 0 1px var(--ink2); }
.pf-conf.none::before { background: transparent; box-shadow: inset 0 0 0 1px var(--line2); }
.pf-stale { color: var(--warn); }

/* evidence class: what KIND of number this is. Same micro-label language
   as the confidence marks — a word, not a tinted pill. */
.pf-evd {
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; white-space: nowrap;
  border: 1px solid var(--line2); border-radius: var(--r-s); padding: 1px 5px;
  color: var(--mut);
}
.pf-evd.idx { border-style: dashed; }
.pf-evd.ovr { color: var(--warn); border-color: var(--warn); }
.pf-evd.sale { color: var(--ink); border-color: var(--ink2); }
.pf-estkind { margin: 4px 0 0; }
.pf-noreason { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }

/* WHEN THE EVIDENCE WAS TRUE. Set beside the figure, not instead of it:
   the same micro-label language as the confidence mark, one weight
   quieter, because it qualifies the number rather than competing with
   it. */
.pf-asof {
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 500;
  letter-spacing: 0.06em; color: var(--mut); white-space: nowrap;
}
/* The owner's provenance line wears the same voice and is allowed to
   break: "as of 8/4 ET" alone never needs to wrap, but the owner's line
   leads with a source in their own words ("Card Ladder · as of 8/5"),
   and free text on a nowrap span sheared the estimate column at every
   width the register renders — the exact fault tools/table-fit.js
   exists to catch, and did. */
.pf-asof.wrap { white-space: normal; overflow-wrap: anywhere; line-height: 1.35; }

/* WHY THERE IS NO FIGURE. The cell this replaces was empty, so the one
   thing this must not do is look like decoration: it is the answer to
   the question the blank raised. Stacked under the "No estimate" mark so
   the reason wraps without pushing the money column sideways, and the
   full sentence rides in .offscreen for a screen reader. */
.pf-noval { display: flex; flex-direction: column; gap: 2px; }
.pf-why {
  font-size: var(--fs-200); line-height: 1.35; color: var(--mut);
  max-width: 20ch; white-space: normal; text-wrap: pretty;
}
/* the coverage breakdown on the dashboard's "Worth a look" */
.pf-whylist { margin: 6px 0 0; padding: 0 0 0 1.1em; }
.pf-whylist li {
  font-size: var(--fs-200); line-height: 1.45; color: var(--mut);
  margin: 0 0 4px;
}
.pf-whylist li b { color: var(--ink2); font-weight: 600; }

/* A market cell waiting on a re-query. It occupies the height of the
   figure it is standing in for, so the rows under it do not move when
   the answer lands. The sheen is the masthead's, slowed; with reduced
   motion it is a plain resting bar, which still reads as "not yet". */
.pf-wait {
  display: inline-block; width: 84px; height: 12px; border-radius: 2px;
  vertical-align: middle;
  background: linear-gradient(90deg, var(--line) 0%, var(--wash) 50%, var(--line) 100%)
    0 0 / 220% 100%;
  animation: pf-waitsheen 1.4s ease-in-out infinite;
}
@keyframes pf-waitsheen {
  0% { background-position: 130% 0; }
  100% { background-position: -30% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .pf-wait { animation: none; background: var(--line); }
}

/* where the headline comes from, and the source line */
.pf-coverage { margin: 10px 0 0; }

/* privacy: one small control on the hero, states carried in the glyph */
.pf-privtoggle {
  appearance: none; background: none; border: 1px solid var(--line2);
  border-radius: var(--r-s); color: var(--mut); cursor: pointer;
  font: inherit; font-size: var(--fs-100); line-height: 1;
  padding: 2px 7px; margin-left: 6px; vertical-align: 2px;
}
.pf-privtoggle:hover { color: var(--ink); border-color: var(--ink2); }

/* quick filters: the chip row under the search */
.pf-chips { display: flex; gap: var(--s-2); flex-wrap: wrap; margin-bottom: var(--s-3); }
.pf-chips button {
  appearance: none; background: var(--panel); border: 1px solid var(--line2);
  border-radius: 999px; padding: 4px 12px; cursor: pointer;
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--mut);
  transition: color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
}
.pf-chips button:hover { color: var(--ink); }
.pf-chips button.on { color: var(--ink); border-color: var(--ink); }

/* density: compact halves the row air, nothing else changes */
.pf-densbtn {
  appearance: none; background: none; border: 1px solid var(--line2);
  border-radius: var(--r-s); padding: 6px 10px; cursor: pointer;
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--mut);
}
.pf-densbtn:hover { color: var(--ink); }
.pf-compact td, .pf-compact th { padding-top: 5px; padding-bottom: 5px; }
.pf-compact .pf-thumb { width: 24px; }
.pf-compact .pf-thumb svg { width: 24px; }

/* insights: three quiet cards, all derived from the table's own figures */
.pf-insights { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--s-4); }
.pf-insight h3 {
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--mut);
  margin: 0 0 var(--s-3);
}
.pf-insight h3 + .pf-allocrow { margin-top: 2px; }
.pf-allocrow {
  display: flex; align-items: center; gap: var(--s-3);
  font-size: var(--fs-300); padding: 4px 0;
}
.pf-allocrow > span:first-child { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pf-moverttl { max-width: 60%; }
.pf-allocbar { flex: 1 1 40px; height: 4px; background: var(--line); border-radius: 2px; overflow: hidden; }
.pf-allocbar i { display: block; height: 100%; background: var(--ink2); }
.pf-allocrow .num { margin-left: auto; font-variant-numeric: tabular-nums; }

/* the market check line on the detail page */
.pf-refreshline { display: flex; gap: var(--s-3); align-items: center; margin-top: var(--s-3); flex-wrap: wrap; }
.pf-refreshline .bb-note { margin: 0; }

/* holdings table */
.pf-controls { display: flex; gap: var(--s-3); align-items: center; margin-bottom: var(--s-3); flex-wrap: wrap; }
.pf-controls input[type="search"] {
  flex: 1 1 220px; min-width: 160px; padding: 9px 12px;
  border: 1px solid var(--line2); border-radius: var(--r-0);
  background: var(--panel); color: var(--ink); font: inherit; font-size: var(--fs-300);
}
.pf-controls input[type="search"]::placeholder { color: var(--mut); opacity: 1; }
.pf-sortlab { font-size: var(--fs-200); color: var(--mut); }
.pf-table td { vertical-align: middle; }
.pf-row { cursor: pointer; }
.pf-cell-card { display: flex; gap: var(--s-3); align-items: center; min-width: 220px; }
.pf-thumb { flex: none; width: 34px; display: block; }
.pf-thumb svg { width: 34px; height: auto; display: block; border-radius: var(--r-s); }
.pf-cardtxt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pf-cardtitle { font-weight: 600; font-size: var(--fs-300); line-height: 1.3; }
.pf-cardmeta { font-size: var(--fs-200); color: var(--mut); }
.pf-rowact { text-align: right; white-space: nowrap; }
.pf-rowact .linkline { font-size: var(--fs-300); }

/* chart mode: the tab language, two words, no chrome */
/* Right-aligned in normal flow above the card. An earlier revision
   "docked" this over the card's own header with a negative margin; on
   the live layout that landed the active tab's underline across the
   range pills — a stray black bar through 7D/30D. The toggle keeps its
   own line: unglamorous, and it can never collide with a card whose
   header the chart component owns. On the portfolio the chart headline
   IS the page hero — brokerage scale, number first — while the rail's
   copy of the same figure steps back so one number leads. */
.pf-chartmode { display: flex; gap: var(--s-4); justify-content: flex-end; margin-bottom: var(--s-3); }
.pf-chartsec .pchart-val { font-size: 34px; letter-spacing: -0.03em; }
.pf-chartsec .pchart-head { align-items: flex-start; }
.pf-chartsec .pchart-windows { margin-top: 6px; }
.acct-dash .dash-num { font-size: 24px; }
.pf-chartmode button {
  appearance: none; background: none; border: 0; min-height: 44px; padding: 10px 0;
  font-family: var(--font-d); font-size: var(--fs-200); font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--mut);
  border-bottom: 2px solid transparent; cursor: pointer;
  transition: color var(--dur-base) var(--ease);
}
.pf-chartmode button[aria-pressed="true"] { color: var(--ink); border-bottom-color: var(--ink); }

/* activity */
.pf-actlist { list-style: none; margin: 0; padding: 0; }
.pf-actlist li {
  display: flex; justify-content: space-between; gap: var(--s-4);
  padding: 10px 0; border-bottom: 1px solid var(--line); font-size: var(--fs-300);
}
.pf-actlist li:last-child { border-bottom: 0; }
.pf-act-what { min-width: 0; }
.pf-act-when { color: var(--mut); white-space: nowrap; display: flex; gap: var(--s-3); align-items: baseline; }

/* holding detail */
.pf-detailhead { display: flex; gap: var(--s-6); margin: var(--s-5) 0; align-items: flex-start; }
.pf-detailslab { flex: none; width: 190px; }
.pf-detailslab svg { width: 100%; height: auto; display: block; }
.pf-detailmain { min-width: 0; flex: 1; }
.pf-detailtitle {
  font-family: var(--font-serif); font-weight: 400; font-size: var(--fs-700);
  line-height: 1.15; margin: 0 0 6px;
}
.pf-figures {
  display: flex; flex-wrap: wrap; gap: var(--s-5) var(--s-6);
  margin: var(--s-4) 0; padding: var(--s-4) 0;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.pf-fig { display: flex; flex-direction: column; gap: 2px; }
.pf-figlab {
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut);
}
.pf-figval { font-family: var(--font-m); font-size: var(--fs-500); font-variant-numeric: tabular-nums; }
.pf-actions { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-4); }
.pf-excluded td { color: var(--mut); text-decoration: line-through; }
.pf-excluded td a { color: inherit; }

/* add-card combobox */
.pf-combo { margin: var(--s-2) 0; }
.pf-hit {
  display: flex; gap: var(--s-3); align-items: center; width: 100%;
  padding: 8px 10px; border: 0; border-bottom: 1px solid var(--line);
  background: none; text-align: left; cursor: pointer; font: inherit; color: var(--ink);
}
.pf-hit:hover, .pf-hit[aria-selected="true"] { background: var(--wash); }
.pf-formgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--s-4); }
.pf-importrow { margin-top: var(--s-3); }
.pf-importrow input[type="file"] { min-height: 44px; font-size: var(--fs-300); color: var(--ink2); }

/* The owner's own marks, listed in the estimate dialog: date, figure,
   source, and the way back from each. Ruled rows in the table language
   the dialogs already speak — the date and the money hold their lanes
   (tabular figures), the source takes what is left and wraps, and the
   take-back control sits at the end of the line it removes. */
.pfoe-hist { margin-top: var(--s-4); border-top: 1px solid var(--line); padding-top: var(--s-2); }
.pfoe-row {
  display: flex; align-items: baseline; gap: var(--s-3);
  padding: 7px 0; border-bottom: 1px solid var(--line);
}
.pfoe-row:last-child { border-bottom: 0; }
.pfoe-when {
  flex: none; width: 7ch; color: var(--mut);
  font-size: var(--fs-200); font-variant-numeric: tabular-nums;
}
.pfoe-amt { flex: none; font-weight: 600; font-variant-numeric: tabular-nums; }
.pfoe-src {
  min-width: 0; color: var(--mut); font-size: var(--fs-200);
  overflow-wrap: anywhere; line-height: 1.35;
}
.pfoe-x {
  flex: none; margin-left: auto; align-self: center;
  width: 28px; height: 28px; display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--line); border-radius: var(--r-s);
  color: var(--mut); cursor: pointer;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.pfoe-x:hover { color: var(--ink); border-color: var(--ink2); }
.pfoe-x:disabled { opacity: 0.5; cursor: default; }
.pfoe-x svg { width: 12px; height: 12px; }

@media (max-width: 720px) {
  .utilbar nav .utilink,
  .utilbar nav a.acctlink { display: inline-flex; align-items: center; min-height: 44px; }
  .bidmode label { min-height: 44px; }
  button.linkline { display: inline-flex; align-items: center; min-height: 44px; }
  .pf-detailhead { flex-direction: column; gap: var(--s-4); }
  .pf-detailslab { width: 150px; }
  .pf-formgrid { grid-template-columns: 1fr; }
  .pf-figures { gap: var(--s-4) var(--s-5); }
  .pf-figval { font-size: var(--fs-400); }
}
.pf-hitrow { display: flex; align-items: center; gap: var(--s-3); }
.pf-hitrow .pf-hit { flex: 1; min-width: 0; }
.pf-hitrow .pf-hitwatch { flex: none; font-size: var(--fs-200); }

/* ============================================================
   PORTFOLIO REGISTER — the market columns, the archive door,
   and the house calendar
   ============================================================
   The register borrows a brokerage's grammar — sparkline, change
   mark, headline that follows the pointer — without borrowing its
   costume: hairlines, tabular numerals, and colour that only ever
   rides on a market fact. */

/* The card cell is a LINK to the archive; the rest of the row opens
   the holding. Inherit ink, and let the hover say which door this is. */
.pf-cardlink {
  display: flex; gap: var(--s-3); align-items: center; min-width: 0;
  color: inherit; text-decoration: none;
}
.pf-cardlink:hover .pf-cardtitle { text-decoration: underline; text-underline-offset: 3px; }
/* A 1999 first-edition title runs sixty characters; unclamped it drove
   the card column past 400px and pushed Gain — the column a holder
   scans first — behind the table's sideways scroll. The full name is
   one click away on the card itself and in the title attribute. */
.pf-table .pf-cardtitle {
  display: block; max-width: 29ch;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pf-table th, .pf-table td { padding: 9px 10px; }
/* The card column takes the slack; the numbers beside it are what they
   are. Without this the title's own max-width became the column's
   minimum and the table pushed past its box on a wide screen. */
.pf-holdings .pf-cell-card { width: 100%; min-width: 0; }

/* ninety days of the card's own estimate, at reading size. The cell
   owns a FIXED lane: squeezed by the table it spilled its chip clean
   into the Gain column, printing "-4.3%$2,841.20" as one run-on
   figure. A stated width cannot be argued with. */
/* Both market columns hold a STATED lane, so the table's geometry does
   not depend on what the market happened to answer: a row waiting on a
   re-query, a row with a figure, and a row with a reason all occupy the
   same width, and nothing under them moves as the answers land. The
   ceiling matters as much as the floor — an unbounded Estimate column
   took 240px of a 963px table and pushed Gain out of the box. */
.pf-estcell { min-width: 128px; max-width: 190px; }
/* the figure reads first; its provenance sits under it, one step quieter */
.pf-estval { display: flex; flex-direction: column; gap: 2px; }
/* The reading line may BREAK BETWEEN its two atoms, never inside one.
   nowrap on the whole line held "$15,850 ◇ LOW" together, which the
   short market marks always afford — and then "$4,525 ◇ YOUR ESTIMATE"
   arrived, 214px against a 190px lane, shearing the column at every
   width (tools/table-fit.js). The money has no spaces and cannot break;
   the mark carries its own nowrap; so normal white-space keeps short
   pairs on one line and stacks the long one instead of spilling it. */
.pf-estnum { white-space: normal; }
.pf-estmeta { display: block; line-height: 1.3; white-space: normal; }
.pf-estmeta:empty { display: none; }
/* The lane is stated and the CONTENT wraps inside it. .acct-table td
   sets white-space: nowrap, which is right for a money column and wrong
   the moment a cell carries a sentence — "Tracking since 4 Aug" went
   straight through the table's right edge. An INHERITED value loses to
   any declared one, so the two spans that must wrap declare it on
   themselves (.pf-why, .pf-chgwin) rather than fighting the td rule's
   specificity from a class selector that cannot win. The two things
   that must never break — the spark and the percentage — keep nowrap.

   The CELL, though, must be allowed to break BETWEEN those pieces:
   with one genuine reading the Change column says "Tracking since
   <date>" beside the spark, and under the td's inherited nowrap that
   label could only continue past the cell's right edge (a 53px shear
   at every desktop width). white-space: normal on the cell lets the
   label drop under the spark instead; the spark stays whole and the
   percentage stack is an inline-flex column that cannot break inside
   itself, so the only new break point is the one the layout wants.
   (td.pf-sparkcell, not .pf-sparkcell: the td rule's element+class
   specificity beats a lone class, so a lone class changes nothing.) */
.pf-sparkcell { width: 126px; min-width: 126px; }
.acct-table td.pf-sparkcell { white-space: normal; }
.pf-spark {
  width: 56px; height: 24px; display: inline-block; vertical-align: middle;
  margin-right: 7px; opacity: 0.9;
}
.pf-spark.up { color: var(--up); }
.pf-spark.down { color: var(--down); }
.pf-chg {
  display: inline-block; vertical-align: middle; white-space: nowrap;
  font-size: var(--fs-200); font-weight: 700; font-variant-numeric: tabular-nums;
}
.pf-chg.up { color: var(--up); }
.pf-chg.down { color: var(--down); }
.pf-chg.none { color: var(--mut); font-weight: 400; }
/* the span the percentage was measured over, under it. A figure whose
   window is not stated is a claim without a unit — see changeMark. */
.pf-chgstack {
  display: inline-flex; flex-direction: column; align-items: flex-start;
  vertical-align: middle; line-height: 1.15; max-width: 100%;
}
.pf-chgwin {
  display: inline-block; max-width: 100%; white-space: normal;
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut);
  line-height: 1.3;
}

/* Real text a screen reader reads and the eye does not. The house had
   no such utility — only .skiplink, which is this plus a focus state —
   so every "the colour is not the only carrier" fix had to spell its
   qualifier out on screen or drop it. Same technique as .skiplink. */
.offscreen {
  position: absolute; width: 1px; height: 1px;
  /* The negative margin is not decoration: without it the 1px box sits
     at its static position, which in a right-aligned table cell is the
     cell's right EDGE — and tools/table-fit.js reads that one pixel as
     a cell shearing its contents. Pulled back inside, it measures as
     what it is: nothing anybody can see. */
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* the register's rows answer the pointer the way every other table
   on the desk already does */
.pf-table tbody tr:hover td { background: var(--wash); }

/* the provider list's name, once an account wallet sits above it */
.plist-h {
  font-size: var(--fs-300); letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--mut); margin: 18px 0 10px; font-weight: 600;
}

/* ---------- the house calendar ---------- */
.mh-datewrap { position: relative; }
.mh-datewrap input { padding-right: 42px; }
.mh-dateopen {
  position: absolute; right: 1px; top: 1px; bottom: 1px; width: 38px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-left: 1px solid var(--line);
  color: var(--mut); cursor: pointer;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.mh-dateopen:hover { color: var(--ink); background: var(--wash); }
.mh-dateopen svg { width: 16px; height: 16px; }
.mh-cal {
  position: fixed; z-index: 300; width: 268px;
  background: var(--panel); border: 1px solid var(--line2);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.18);
  padding: 14px 14px 10px;
}
.mh-cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.mh-cal-title { font-family: var(--font-d); font-weight: 700; font-size: 14px; letter-spacing: 0.01em; }
.mh-cal-nav { display: flex; gap: 2px; }
.mh-cal-btn {
  width: 30px; height: 30px; display: flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--line); color: var(--mut);
  font-size: 15px; line-height: 1; cursor: pointer;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.mh-cal-btn:hover { color: var(--ink); border-color: var(--ink); }
.mh-cal-week {
  display: grid; grid-template-columns: repeat(7, 1fr); margin-bottom: 2px;
}
.mh-cal-week span {
  text-align: center; font-size: 9.5px; font-weight: 700; letter-spacing: 0.12em;
  color: var(--faint); text-transform: uppercase; padding: 4px 0;
}
.mh-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.mh-cal-day {
  height: 32px; background: none; border: 0; font: inherit;
  font-size: 12.5px; font-variant-numeric: tabular-nums; color: var(--ink);
  cursor: pointer; transition: background var(--dur-fast) var(--ease);
}
.mh-cal-day:hover { background: var(--wash); }
.mh-cal-day.out { color: var(--faint); }
.mh-cal-day.today { box-shadow: inset 0 0 0 1px var(--line2); }
.mh-cal-day.sel { background: var(--ink); color: var(--on-ink); }
.mh-cal-day.sel:hover { background: var(--ink2); }
.mh-cal-foot {
  display: flex; justify-content: space-between; align-items: center;
  border-top: 1px solid var(--line); margin-top: 10px; padding-top: 8px;
}
.mh-cal-foot .linkline { font-size: var(--fs-200); }

/* ---------- native controls, dressed by the house ----------
   The dropdown's LIST is the platform's to paint (color-scheme
   already tells it which side of dark to stand on); the CONTROL is
   ours: no vendor chrome, the house chevron, room for it. */
.field select, .sortsel select {
  appearance: none; -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23776f82' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 10px 6px;
  padding-right: 34px;
}
html[data-theme="midnight"] .field select, html[data-theme="midnight"] .sortsel select,
html[data-theme="vault"] .field select, html[data-theme="vault"] .sortsel select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23a49dae' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* the CSV door, dressed as the button it is */
.pf-importrow input[type="file"]::file-selector-button {
  font-family: var(--font-d); font-weight: 700; font-size: 10.5px;
  letter-spacing: 0.12em; text-transform: uppercase;
  padding: 10px 16px; margin-right: 12px;
  background: transparent; color: var(--ink);
  border: 1px solid var(--ink); cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.pf-importrow input[type="file"]::file-selector-button:hover {
  background: var(--ink); color: var(--on-ink);
}

/* the settle-from-deposit row under a Buy Now reservation */
.bn-settlerow {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3);
  margin-top: 12px;
}
.bn-settlemsg { font-size: var(--fs-200); color: var(--mut); }
.bn-settlemsg.bad { color: var(--live); }

/* ============================================================
   TABLES THAT FIT
   ============================================================
   A ledger inside a 340px rail cannot be a six-column grid, and a
   sideways scrollbar in a panel is the interface admitting it laid
   the thing out wrong. Two rules do most of the work: the rail's
   tables lose their nowrap and stack their cells, and the register
   drops to a two-column card below the width where six columns can
   sit honestly. */

/* The sticky rail is 340px. Anything tabular in it wraps rather than
   scrolls: these rows are label-and-value pairs, not a grid. */
.acct-dash .acct-tablewrap { overflow-x: visible; }
.acct-dash .acct-table th,
.acct-dash .acct-table td { white-space: normal; padding: 8px 10px; }

/* THE COLUMN THE LEDGERS LIVE IN WAS TOO NARROW FOR THEM.

   860px was set for prose measure, and then account and portfolio
   filled the same column with six-column tables — so the register
   scrolled sideways at 1280px and 1680px alike, on screens with
   hundreds of spare pixels beside them. The reading measure still
   governs prose (.bb-note below); the grid itself takes the room the
   viewport actually has. */
.acct-grid { max-width: 1120px; }
.acct-grid .bb-note, .acct-grid .m-note { max-width: 76ch; }
@media (min-width: 1180px) {
  /* Beside the 340px rail, the ledgers get whatever is left rather
     than stopping at a number chosen for paragraphs. */
  .acct-grid { max-width: none; }
}

/* A LEDGER WRAPS BEFORE IT SLIDES.

   .acct-table sets white-space: nowrap, which is right for a money
   column and wrong for a shipping address or a card title: on a phone
   those rows drove tables 400px past their own box. Below the width
   where a multi-column table can sit honestly, every cell may wrap and
   the type comes in a step. Money columns keep their nowrap, because a
   figure broken across two lines is unreadable in a way a title is
   not. */
@media (max-width: 860px) {
  .acct-grid .acct-table th, .acct-grid .acct-table td,
  .acct-grid .compstable th, .acct-grid .compstable td {
    white-space: normal; padding: 9px 8px;
  }
  .acct-grid .acct-table .num, .acct-grid .compstable .num,
  .acct-grid .acct-table .price, .acct-grid .acct-table .mono { white-space: nowrap; }
  .acct-grid .acct-table, .acct-grid .compstable { font-size: 12.5px; }
  .pf-cell-card { min-width: 0; }
}

/* A PHONE CANNOT HOLD A FIVE-COLUMN LEDGER, AND SHOULD NOT PRETEND TO.

   .acct-stack marks the tables that become cards below phone width —
   invoices and shipping — the same shape the holdings register takes.
   Each cell names itself from its own data-label, so nothing is hidden
   and no figure is orphaned from what it measures. The action cell
   spans the card and its buttons sit at the foot, where an action
   belongs. */
@media (max-width: 620px) {
  .acct-stack thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .acct-stack, .acct-stack tbody, .acct-stack tr, .acct-stack td { display: block; width: auto; }
  .acct-stack tr {
    display: grid; grid-template-columns: auto 1fr; gap: 4px 14px; align-items: baseline;
    padding: 12px 12px 10px; border-bottom: 1px solid var(--line);
  }
  .acct-stack tr:last-child { border-bottom: 0; }
  .acct-stack td { border: 0; padding: 0; text-align: right; white-space: normal; }
  .acct-stack td::before {
    content: attr(data-label); justify-self: start; text-align: left;
    font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--mut);
  }
  /* Grid places ::before and the content as two cells of the row, so a
     labelled cell is a label-and-value pair and the action cell, which
     carries no label, spans both. */
  .acct-stack td { display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; }
  .acct-stack td.acct-actcell { display: block; margin-top: 8px; text-align: left; }
  .acct-stack td.acct-actcell:empty { display: none; }
}

/* A PHONE, where a ledger that has NOT been stacked still has to give
   something up. What it gives up is the decorative, never an
   obligation: buttons stack, a tracking number may break mid-string,
   and the chips lose their tracking. */
@media (max-width: 560px) {
  .acct-grid .acct-table, .acct-grid .compstable { font-size: 11.5px; }
  .acct-grid .acct-table th, .acct-grid .acct-table td { padding: 8px 6px; }
  /* An invoice id and a tracking number are strings, not figures: they
     may wrap mid-token rather than push the table sideways. */
  .acct-grid .acct-table .mono { white-space: normal; word-break: break-all; }
  /* An action cell holding two buttons is the widest thing in a
     shipping row; stacked, it is the narrowest it can be. */
  .acct-grid .acct-table td .btn.sm { display: block; width: 100%; margin: 0 0 4px; padding: 8px 8px; }
  .acct-grid .acct-table td .btn.sm:last-child { margin-bottom: 0; }
  .acct-grid .acct-table .acct-chip { letter-spacing: .06em; }
}

/* The holdings register, below the width six columns need. Each row
   becomes a small card: the card and its numbers, labelled. */
@media (max-width: 860px) {
  .pf-holdings thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .pf-holdings, .pf-holdings tbody, .pf-holdings tr, .pf-holdings td { display: block; width: auto; }
  .pf-holdings tr {
    border-bottom: 1px solid var(--line); padding: 12px 12px 10px;
    display: grid; grid-template-columns: 1fr auto; gap: 2px 12px; align-items: center;
  }
  .pf-holdings tr:last-child { border-bottom: 0; }
  .pf-holdings td { border: 0; padding: 0; }
  .pf-holdings .pf-cell-card { grid-column: 1 / -1; margin-bottom: 8px; }
  .pf-table .pf-cardtitle { max-width: none; white-space: normal; }
  /* Each remaining cell names itself, so a bare number is never
     orphaned from what it measures. */
  .pf-holdings td:not(.pf-cell-card)::before {
    content: attr(data-label); float: left;
    font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
    color: var(--mut);
  }
  .pf-holdings td:not(.pf-cell-card) { text-align: right; padding: 3px 0; }
  .pf-holdings .pf-sparkcell { width: auto; min-width: 0; }
  .pf-holdings .pf-estcell { min-width: 0; }
  .pf-spark { width: 56px; height: 20px; }
  /* Stacked, every value sits against the right rule, so the reason and
     the window label go with it. The reason keeps a measure — a sentence
     running the full width of a phone under a two-word label reads as a
     paragraph that lost its heading. */
  /* Both market cells take the WHOLE row when stacked. Sharing the
     two-column grid with Qty and Cost left the Estimate about a hundred
     pixels once its label had floated left, and "$445 Low as of 8/4 ET"
     sheared straight out of it — the spill tools/table-fit.js reports.
     These two carry a figure, a provenance line and sometimes a
     sentence; they get the width that needs. */
  .pf-holdings .pf-estcell, .pf-holdings .pf-sparkcell { grid-column: 1 / -1; }
  .pf-holdings .pf-noval, .pf-holdings .pf-chgstack { align-items: flex-end; }
  .pf-holdings .pf-why { max-width: 26ch; text-align: right; }
  /* A row with no figure has no change to report, and the reason is
     already in the Estimate cell above. Stacked, that left a "CHANGE"
     label standing over nothing — a heading for an answer that is
     somewhere else. The label goes with the value. */
  .pf-holdings td.pf-sparkcell:empty { display: none; }
}

/* The fee schedule and the results ledger: a note column that can wrap
   is the difference between a fitting table and a scrolling one. */
@media (max-width: 620px) {
  /* Every cell here may wrap, not only the notes column: on a 375px
     phone the RATE column's own "Delivery + 7 days" was the last nine
     pixels of overflow, and a term that wraps reads better than a
     table that slides. */
  .guide-tablewrap table th, .guide-tablewrap table td,
  .feetable .ft-rate,
  .resulttable th, .resulttable td {
    white-space: normal; padding-left: 8px; padding-right: 8px;
  }
  /* The prices-realized ledger, on the home page and its own: the sale
     title is the only cell with any give, so it takes the wrap and the
     figures beside it stay on one line. */
  .resulttable th, .resulttable td { font-size: 12.5px; padding-top: 10px; padding-bottom: 10px; }
  .resulttable .num, .resulttable .price { white-space: nowrap; }
}

/* The last pixel. At 375 the results ledger measured 326 in a 325 box —
   one pixel, which is still a scrollbar and still the interface
   admitting the layout does not fit. The horizontal padding comes in a
   notch on the narrowest phones and the column headers lose a little
   tracking; nothing else changes. */
@media (max-width: 420px) {
  .resulttable th, .resulttable td { padding-left: 6px; padding-right: 6px; }
  .resulttable th { letter-spacing: .06em; }
}

@media (max-width: 700px) {
  /* the sparkline is a reading aid, not a fact — the change mark
     carries the fact, so the line is what narrow screens give up */
  .pf-spark { display: none; }
}

/* ============================================================
   V6 FRONTEND — THE COLLECTOR'S SALON
   ------------------------------------------------------------
   A rare-object room, not generic commerce chrome. The card scans
   remain neutral; spectral colour belongs to the architecture,
   engraved edges and light in the room around the object.
   ============================================================ */

/* richer tonal ladders: every theme has a room, furniture and paper */
:root {
  --paper: #e7dfd2;
  --panel: #fbf7ef;
  --wash: #d9d0c1;
  --wash2: #c9bead;
  --ink: #130f0b;
  --ink2: #332b23;
  --mut: #5f5549;
  --faint: #82786b;
  --line: #c7baa7;
  --line2: #9f907d;
  --dark: #100d0a;
  --dark2: #1c1711;
  --dark-line: #4a3b2a;
  --brass: #9b7131;
  --brass-ink: #664512;
  --brass-soft: #d5b978;
  --brass-lit: #fff0bd;
  --holo-mint: #76d9b0;
  --holo-sky: #69bde6;
  --holo-lilac: #b89ce8;
  --holo-butter: #f1cc6e;
  --holo-blush: #e9859e;
  --shadow-1: 0 1px 0 rgba(255,255,255,.45) inset, 0 12px 30px rgba(39,28,17,.11);
  --shadow-2: 0 1px 0 rgba(255,255,255,.55) inset, 0 28px 70px rgba(28,19,11,.2);
  --salon-edge: linear-gradient(90deg, transparent, var(--brass-soft) 22%, var(--holo-sky) 50%, var(--holo-blush) 78%, transparent);
  --salon-glint: linear-gradient(112deg, transparent 24%, color-mix(in srgb, var(--holo-sky) 42%, transparent) 43%, color-mix(in srgb, var(--brass-lit) 58%, transparent) 50%, color-mix(in srgb, var(--holo-blush) 38%, transparent) 57%, transparent 76%);
  /* The day rooms' band: the holo family at full chroma and no pale
     core, because it is multiplied into a near-white plate rather than
     screened onto a dark one. Same 112deg rake as the salon glint, so
     the light in the room keeps one direction. */
  --lot-glint: linear-gradient(112deg, transparent 26%, var(--holo-mint) 36%, var(--holo-sky) 44%, var(--holo-lilac) 50%, var(--holo-butter) 57%, var(--holo-blush) 64%, transparent 74%);
}

html[data-theme="porcelain"] {
  --paper: #e4e6e8;
  --panel: #fbfbfa;
  --wash: #d4d8dc;
  --wash2: #c2c8cf;
  --ink: #0d1116;
  --ink2: #29323b;
  --mut: #515c67;
  --faint: #747f89;
  --line: #bec5cc;
  --line2: #929da8;
  --brass: #927038;
  --brass-ink: #604512;
  --up: #2d6749;
}

html[data-theme="midnight"] {
  --paper: #050914;
  --panel: #101a2a;
  --wash: #18263a;
  --wash2: #24364d;
  --ink: #fff9ea;
  --ink2: #e7dfca;
  --mut: #bbb29e;
  --faint: #929baa;
  --line: #354964;
  --line2: #536b88;
  --dark: #03060c;
  --dark2: #0a1220;
  --dark-line: #334864;
  --brass: #e7c77d;
  --brass-soft: #f1dba6;
  --brass-lit: #fff4ce;
  --holo-mint: #69e4b2;
  --holo-sky: #69c7ff;
  --holo-lilac: #ac91ff;
  --holo-butter: #f4cc67;
  --holo-blush: #ff809f;
  --on-ink: #101722;
  --shadow-1: 0 1px 0 rgba(255,255,255,.07) inset, 0 16px 38px rgba(0,0,0,.48);
  --shadow-2: 0 1px 0 rgba(255,255,255,.1) inset, 0 32px 80px rgba(0,0,0,.68);
}

html[data-theme="vault"] {
  --paper: #080603;
  --panel: #19130c;
  --wash: #261d13;
  --wash2: #36291b;
  --ink: #fff8e7;
  --ink2: #eadfc5;
  --mut: #c1b293;
  --faint: #968a76;
  --line: #463727;
  --line2: #6a543a;
  --dark: #030201;
  --dark2: #100c07;
  --dark-line: #493824;
  --brass: #eccb84;
  --brass-soft: #f4dca8;
  --brass-lit: #fff2c9;
  --holo-mint: #79d6a5;
  --holo-sky: #72bce1;
  --holo-lilac: #b494dc;
  --holo-butter: #f1ca68;
  --holo-blush: #e77f91;
  --on-ink: #151007;
  --shadow-1: 0 1px 0 rgba(255,255,255,.07) inset, 0 16px 40px rgba(0,0,0,.55);
  --shadow-2: 0 1px 0 rgba(255,255,255,.09) inset, 0 34px 84px rgba(0,0,0,.74);
}

/* The room carries spectral light. Large gradients move as one
   composited plane; merchandise never receives a colour overlay. */
body {
  position: relative;
  isolation: isolate;
  min-height: 100vh;
  background:
    radial-gradient(80% 65% at 7% 2%, color-mix(in srgb, var(--holo-mint) 12%, transparent), transparent 58%),
    radial-gradient(70% 54% at 94% 15%, color-mix(in srgb, var(--holo-blush) 10%, transparent), transparent 62%),
    linear-gradient(145deg, color-mix(in srgb, var(--brass-soft) 7%, transparent), transparent 42%),
    var(--paper);
}
body::before {
  inset: -32vmax;
  z-index: -2;
  opacity: .13;
  background:
    conic-gradient(from 205deg at 48% 46%, transparent 0 13%, var(--holo-mint) 20%, var(--holo-sky) 29%, transparent 39% 57%, var(--holo-lilac) 66%, var(--holo-butter) 74%, var(--holo-blush) 82%, transparent 91% 100%);
  background-size: 100% 100%;
  mix-blend-mode: soft-light;
  transform: rotate(-2deg) scale(1.04);
}
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .08;
  background-image:
    repeating-linear-gradient(90deg, transparent 0 79px, color-mix(in srgb, var(--ink) 12%, transparent) 80px),
    repeating-linear-gradient(0deg, transparent 0 79px, color-mix(in srgb, var(--ink) 8%, transparent) 80px);
  -webkit-mask-image: radial-gradient(ellipse at 50% 0%, #000, transparent 76%);
  mask-image: radial-gradient(ellipse at 50% 0%, #000, transparent 76%);
}
html[data-theme="midnight"] body::before,
html[data-theme="vault"] body::before {
  opacity: .42;
  mix-blend-mode: screen;
}
html[data-theme="midnight"] body::after,
html[data-theme="vault"] body::after { opacity: .16; }
/* precision type and lines */
h1, h2, h3 { text-wrap: balance; font-kerning: normal; }
p { text-wrap: pretty; }
.foil-rule {
  height: 3px;
  opacity: 1;
  background-image: var(--salon-edge);
  box-shadow: 0 1px 14px color-mix(in srgb, var(--holo-sky) 28%, transparent);
}
.eyebrow { letter-spacing: .2em; }
.sep { opacity: .9; }

/* engraved controls: firm silhouettes, a single controlled light pass */
.btn {
  position: relative;
  overflow: hidden;
  min-height: 46px;
  border-color: color-mix(in srgb, var(--ink) 84%, var(--brass));
  box-shadow: 0 1px 0 color-mix(in srgb, var(--panel) 28%, transparent) inset, 0 7px 20px color-mix(in srgb, var(--ink) 13%, transparent);
  transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease), background var(--dur-base) var(--ease), color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--salon-glint);
  transform: translateX(-115%);
  transition: transform .55s cubic-bezier(.2,.65,.3,1);
}
.btn:hover:not([disabled]) {
  transform: translateY(-1px);
  border-color: var(--brass);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--panel) 35%, transparent) inset, 0 12px 28px color-mix(in srgb, var(--ink) 18%, transparent);
}
.btn:hover::before { transform: translateX(115%); }
.btn:active:not([disabled]) { transform: translateY(0); box-shadow: none; }
.btn.ghost { background: color-mix(in srgb, var(--panel) 36%, transparent); border-color: var(--line2); }
.btn.ghost:hover { background: var(--ink); color: var(--on-ink); }
.btn[disabled]::before { display: none; }

/* header: a cabinet-quality rail rather than floating app chrome */
.masthead {
  background: color-mix(in srgb, var(--panel) 98%, var(--paper));
  border-bottom-color: var(--line2);
  box-shadow: 0 8px 30px color-mix(in srgb, var(--dark) 8%, transparent);
}
.wordmark .wm-mark { color: var(--brass-ink); }
html[data-theme="midnight"] .wordmark .wm-mark,
html[data-theme="vault"] .wordmark .wm-mark { color: var(--brass); }
.wordmark .wm-main { letter-spacing: .075em; }
.wordmark .wm-sub { letter-spacing: .38em; }
.searchbox input {
  border-color: var(--line);
  background: color-mix(in srgb, var(--wash) 78%, transparent);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--panel) 70%, transparent) inset;
}
.searchbox input:hover { border-color: var(--line2); }
.searchbox input:focus {
  border-color: var(--brass);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brass) 18%, transparent), 0 1px 0 color-mix(in srgb, var(--panel) 70%, transparent) inset;
}
.iconbtn {
  min-width: 44px;
  min-height: 44px;
  border-color: transparent;
  transition: color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease), background var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
}
.iconbtn:hover { border-color: var(--line2); background: color-mix(in srgb, var(--wash) 72%, transparent); transform: translateY(-1px); }
.catnav {
  background: color-mix(in srgb, var(--panel) 98%, var(--paper));
  border-bottom-color: var(--line2);
  box-shadow: 0 6px 22px color-mix(in srgb, var(--dark) 7%, transparent);
}
.catnav a { min-height: 46px; padding-left: 16px; padding-right: 16px; letter-spacing: .055em; }
.catnav a.active, .catnav a[aria-current="page"] { border-bottom-color: var(--brass); }
.catbar { background: color-mix(in srgb, var(--wash) 94%, transparent); border-bottom-color: var(--line2); }
.catbar button { min-height: 44px; }

/* marquee: asymmetrical editorial stage with its light behind the slab */
.hero {
  isolation: isolate;
  background:
    linear-gradient(102deg, color-mix(in srgb, var(--panel) 38%, transparent) 0 49%, transparent 49%),
    radial-gradient(50% 90% at 80% 48%, color-mix(in srgb, var(--holo-sky) 18%, transparent), transparent 62%),
    radial-gradient(42% 76% at 91% 18%, color-mix(in srgb, var(--holo-blush) 13%, transparent), transparent 68%),
    var(--paper);
  border-bottom: 1px solid var(--line2);
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0 0 0 50%;
  z-index: -1;
  pointer-events: none;
  background: var(--salon-glint);
  background-size: 190% 100%;
  opacity: .72;
  animation: mh-hero-light 14s ease-in-out infinite alternate;
}
.hero::after {
  content: "";
  position: absolute;
  top: 10%; bottom: 10%; left: 50%;
  width: 1px;
  background: linear-gradient(transparent, var(--line2) 22%, var(--brass) 50%, var(--line2) 78%, transparent);
  opacity: .7;
}
@keyframes mh-hero-light { from { background-position: 0 50%; } to { background-position: 100% 50%; } }
.hero .wrap { min-height: 620px; padding-top: 78px; padding-bottom: 82px; gap: 72px; }
.hero h1 { font-size: clamp(42px, 4.6vw, 66px); max-width: 11.5em; line-height: 1.01; margin-bottom: 26px; }
.hero h1 { min-height: 0; }
.hero .lotmeta { margin-bottom: 28px; }
.hero .hero-edition { color: var(--dark-fg-mut); }
html:not([data-theme="midnight"]):not([data-theme="vault"]) .hero .hero-edition { color: var(--mut); }
.hero .bidblock {
  width: min(100%, 560px);
  padding: 20px 0;
  margin-bottom: 28px;
  border-top: 1px solid var(--line2);
  border-bottom: 1px solid var(--line2);
}
.hero .bidblock .val { font-family: var(--font-m); font-weight: 500; letter-spacing: -.04em; }
.hero-media { z-index: 1; }
.hero-media::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 5% -3% 9%;
  border: 1px solid color-mix(in srgb, var(--brass) 42%, transparent);
  background:
    radial-gradient(circle at 50% 42%, color-mix(in srgb, var(--holo-sky) 20%, transparent), transparent 45%),
    radial-gradient(circle at 72% 64%, color-mix(in srgb, var(--holo-blush) 13%, transparent), transparent 38%);
  box-shadow: 0 0 80px color-mix(in srgb, var(--holo-sky) 12%, transparent) inset;
  transform: rotate(1.5deg);
}
.hero-media .slabwrap { position: relative; z-index: 1; width: min(400px, 86%); }
html[data-theme="midnight"] .hero,
html[data-theme="vault"] .hero {
  background:
    linear-gradient(102deg, color-mix(in srgb, var(--dark2) 74%, transparent) 0 49%, transparent 49%),
    radial-gradient(56% 100% at 82% 45%, color-mix(in srgb, var(--holo-sky) 34%, transparent), transparent 62%),
    radial-gradient(46% 86% at 96% 14%, color-mix(in srgb, var(--holo-blush) 27%, transparent), transparent 66%),
    radial-gradient(42% 68% at 58% 92%, color-mix(in srgb, var(--holo-mint) 18%, transparent), transparent 68%),
    var(--dark);
}
html[data-theme="midnight"] .hero::before,
html[data-theme="vault"] .hero::before { opacity: 1; mix-blend-mode: screen; }

/* section rhythm and catalogue furniture */
section.band { padding-top: 70px; padding-bottom: 76px; }
section.band.washed {
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--panel) 24%, transparent), transparent 42%),
    color-mix(in srgb, var(--wash) 92%, transparent);
  border-color: var(--line2);
}
.band-head { position: relative; padding-bottom: 18px; margin-bottom: 30px; border-bottom: 1px solid var(--line); }
.band-head::after {
  content: "";
  position: absolute;
  left: 0; bottom: -1px;
  width: 86px; height: 1px;
  background: var(--salon-edge);
}
.band-head h1, .band-head h2 { font-size: clamp(28px, 3vw, 38px); }
.lotcard {
  border-color: var(--line2);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--panel) 50%, transparent) inset, var(--shadow-1);
}
.lotcard::before {
  content: "";
  position: absolute;
  z-index: 3;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: var(--salon-edge);
  opacity: .42;
  transition: opacity var(--dur-base) var(--ease);
  pointer-events: none;
}
.lotcard:hover { transform: translateY(-5px); border-color: var(--brass); }
.lotcard:hover::before { opacity: 1; }
.lotcard .thumb { padding-top: 22px; padding-bottom: 18px; border-bottom: 1px solid var(--line); }
.lotcard .body { padding: 18px 18px 17px; gap: 10px; }
.lotcard .title { font-family: var(--font-serif); font-size: 16px; line-height: 1.32; font-weight: 500; }
.lotcard .bid { font-family: var(--font-m); font-weight: 500; }
.lotcard .clock { margin-left: -18px; margin-right: -18px; margin-bottom: -17px; padding: 11px 18px; border-color: var(--line2); }
.lotcard .watch { width: 44px; height: 44px; border: 1px solid var(--line); box-shadow: var(--shadow-1); }
.cattile { border-color: var(--line2); padding: 22px 18px 18px; box-shadow: var(--shadow-1); }
.cattile::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px; background: var(--salon-edge); opacity: .55; }
.cattile:hover { transform: translateY(-4px); box-shadow: var(--shadow-2); }
.cattile b { font-family: var(--font-serif); font-weight: 500; font-size: 17px; }

/* browse room */
.browsehead {
  background:
    radial-gradient(54% 160% at 90% 0%, color-mix(in srgb, var(--holo-sky) 14%, transparent), transparent 62%),
    linear-gradient(110deg, color-mix(in srgb, var(--panel) 50%, transparent), transparent 54%),
    var(--wash);
  border-bottom-color: var(--line2);
}
.browsehead .wrap { padding-top: 44px; padding-bottom: 36px; }
.browsehead h1 { font-size: clamp(34px, 4vw, 50px); }
.facet { border-bottom-color: var(--line2); padding-top: 17px; padding-bottom: 19px; }
.facet .opt { min-height: 38px; }
.browse-toolbar { padding-bottom: 14px; border-bottom: 1px solid var(--line); }
.sortsel select, .field input, .field select, .field textarea,
.pf-controls input[type="search"], .bidrow .amt input {
  border-color: var(--line2);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--panel) 80%, transparent) inset;
}
.sortsel select:focus, .field input:focus, .field select:focus,
.field textarea:focus, .pf-controls input[type="search"]:focus,
.bidrow .amt input:focus {
  border-color: var(--brass);
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brass) 17%, transparent);
}
.emptystate { border-style: solid; border-color: var(--line2); background: color-mix(in srgb, var(--panel) 70%, transparent); box-shadow: var(--shadow-1); }
.emptystate h1 { font-family: var(--font-serif); font-size: 30px; font-weight: 500; color: var(--ink); margin-bottom: 8px; }

/* lot room — desktop keeps the object left; mobile brings the decision
   and binding controls before the long product image. */
.crumbbar { border-bottom-color: var(--line2); background: color-mix(in srgb, var(--wash) 86%, transparent); }
.crumbbar .sep { opacity: 1; }
.lot-layout { column-gap: 54px; row-gap: 0; padding-top: 44px; }
.lot-panel { display: contents; }
.lot-panel > * { grid-column: 2; min-width: 0; }
.lot-media { grid-column: 1; grid-row: 1 / span 20; }
.lot-panel h1 { font-size: clamp(31px, 3vw, 43px); line-height: 1.08; }
.lot-stage {
  border-color: var(--line2);
  background:
    radial-gradient(70% 46% at 50% 10%, color-mix(in srgb, var(--holo-sky) 13%, transparent), transparent 68%),
    linear-gradient(160deg, var(--wash), var(--wash2));
  box-shadow: var(--shadow-2);
}
.bidbox { border-color: var(--line2); box-shadow: var(--shadow-1); background: color-mix(in srgb, var(--panel) 92%, transparent); }
.bidbox .bb-top { border-bottom-color: var(--line2); }
.bidbox .bb-cell + .bb-cell { border-left-color: var(--line2); }
.bidbox .bb-val { font-family: var(--font-m); font-weight: 500; letter-spacing: -.04em; }
.bidbox .bb-mid { background: color-mix(in srgb, var(--wash) 84%, transparent); }
.quickbids button, .shiprow, .chartbox, .pchart, .dash-card,
.acct-row, .acct-tablewrap { border-color: var(--line2); }
.quickbids button:hover { border-color: var(--brass); background: var(--wash); color: var(--ink); }
.lot-tabs { border-bottom-color: var(--line2); }
.lot-tabs button { min-height: 44px; letter-spacing: .045em; }
.lot-tabs button.active { border-bottom-color: var(--brass); }

/* account, portfolio and document surfaces */
.dash-card, .acct-row, .acct-tablewrap, .pchart, .chartbox, .legal-nav,
.guide-tablewrap, .feetable, .arc-searchbox {
  box-shadow: var(--shadow-1);
}
.acct-row { transition: transform var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease), background var(--dur-base) var(--ease); }
.acct-row:hover { transform: translateX(3px); border-color: var(--brass); background: var(--wash); }
.acct-table th, .compstable th, .resulttable th { background: color-mix(in srgb, var(--wash) 78%, transparent); }
.acct-table tr:hover td, .compstable tr:hover td { background: color-mix(in srgb, var(--wash) 70%, transparent); }

/* dialog and feedback furniture */
.overlay {
  background: color-mix(in srgb, var(--dark) 76%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(.9);
  backdrop-filter: blur(14px) saturate(.9);
}
.modal { border: 1px solid var(--line2); box-shadow: 0 42px 120px rgba(0,0,0,.52); }
.modal::before { content: ""; display: block; height: 2px; background: var(--salon-edge); }
.modal .m-head { border-bottom-color: var(--line2); }
.modal .m-head b { font-family: var(--font-serif); font-size: 22px; font-weight: 500; }
.modal .m-close { width: 44px; height: 44px; }
.provider { min-height: 62px; border-color: var(--line2); }
.provider:hover { border-color: var(--brass); background: var(--wash); }
.auth-intro {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: -2px 0 18px;
  padding: 0 0 15px;
  border-bottom: 1px solid var(--line);
  color: var(--mut);
  font: 700 9px/1 var(--font-d);
  letter-spacing: .18em;
  text-transform: uppercase;
}
.auth-mintmark {
  display: grid;
  width: 26px;
  height: 26px;
  place-items: center;
  border: 1px solid var(--brass);
  color: var(--brass-ink);
  font: 800 13px/1 var(--font-d);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brass) 8%, transparent);
}
html[data-theme="midnight"] .auth-mintmark,
html[data-theme="vault"] .auth-mintmark { color: var(--brass-soft); }
.field input[aria-invalid="true"], .bidrow input[aria-invalid="true"] {
  border-color: var(--live);
  box-shadow: 0 0 0 3px var(--live-tint);
}
.toast { border: 1px solid var(--dark-line); box-shadow: 0 20px 55px rgba(0,0,0,.42); }

/* dark furniture gets the brightest architectural holo */
.consign, .sellhero, footer.site { position: relative; isolation: isolate; overflow: hidden; }
.consign::before, .sellhero::before, footer.site::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(60% 150% at 4% 0%, color-mix(in srgb, var(--holo-mint) 18%, transparent), transparent 64%),
    radial-gradient(54% 140% at 96% 100%, color-mix(in srgb, var(--holo-blush) 16%, transparent), transparent 68%),
    var(--salon-glint);
  background-size: auto, auto, 180% 100%;
  opacity: .42;
}
footer.site { border-top: 1px solid var(--dark-line); }
footer.site h2 { color: var(--brass-soft); }
footer.site .cols { padding-top: 64px; }

/* phone: deliberate compact identity, decision-first lot layout, real targets */
@media (max-width: 940px) {
  .lot-layout { grid-template-columns: minmax(0, 1fr); padding-top: 28px; }
  .lot-panel > * { grid-column: 1; }
  .lot-panel h1 { grid-row: 1; }
  .lot-sub { grid-row: 2; }
  .watchrow { grid-row: 3; }
  .bidbox { grid-row: 4; }
  .lot-media { grid-column: 1; grid-row: 5; position: static; margin-top: 30px; }
  #specialist { grid-row: 6; }
  .lot-tabs { grid-row: 7; }
  .tabpane { grid-row: 8; }
  .lot-stage { padding: 28px clamp(28px, 12vw, 72px); }
}

@media (max-width: 720px) {
  .hero::after { display: none; }
  .hero { background:
    radial-gradient(92% 48% at 80% 88%, color-mix(in srgb, var(--holo-sky) 20%, transparent), transparent 72%),
    var(--paper); }
  html[data-theme="midnight"] .hero,
  html[data-theme="vault"] .hero { background:
    radial-gradient(92% 48% at 80% 88%, color-mix(in srgb, var(--holo-sky) 32%, transparent), transparent 72%),
    radial-gradient(72% 42% at 12% 6%, color-mix(in srgb, var(--holo-blush) 18%, transparent), transparent 75%),
    var(--dark); }
  .hero::before { inset: 44% -20% -12%; opacity: .82; }
  .hero .wrap { min-height: 0; padding-top: 50px; padding-bottom: 56px; gap: 44px; }
  .hero h1 { font-size: clamp(38px, 11vw, 54px); }
  section.band { padding-top: 54px; padding-bottom: 58px; }
  .band-head h1, .band-head h2 { font-size: 30px; }
  .browsehead .wrap { padding-top: 34px; padding-bottom: 28px; }
  .browsehead h1 { font-size: 38px; }
  .facet .opt, .catbar button { min-height: 44px; }
  .watchrow button { min-height: 44px; }
}

@media (max-width: 540px) {
  .masthead .wrap {
    height: auto;
    min-height: 106px;
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
    padding-top: 11px;
    padding-bottom: 11px;
  }
  .wordmark { width: auto; max-width: none; overflow: visible; grid-column: 1; grid-row: 1; }
  .wordmark .wm-mark { width: 18px; height: 18px; }
  .wordmark .wm-main { font-size: 17px; letter-spacing: .035em; white-space: nowrap; }
  .wordmark .wm-sub { display: none; }
  .mast-actions {
    grid-column: 1;
    grid-row: 2;
    width: 100%;
    gap: 8px;
    justify-self: stretch;
    justify-content: space-between;
  }
  .iconbtn { width: 44px; min-width: 44px; padding: 0; justify-content: center; }
  .themebtn .iconbtn { width: auto; min-width: 48px; padding: 0 6px; }
  #portfoliobtn, #walletbtn { min-width: 44px; min-height: 44px; }
  .searchbox { grid-column: 1; grid-row: 3; max-width: none; }
  .searchbox input { height: 44px; }
  .hero .bidblock { gap: 24px; }
  .hero .bidblock .val { font-size: 32px; }
  .lot-layout { padding-top: 22px; }
  .lot-panel h1 { font-size: 31px; }
  .lot-stage { padding: 20px 24px; }
  .bidbox .bb-cell { padding: 15px 14px; }
  .bidrow { flex-wrap: wrap; }
  .bidrow .amt { flex: 1 1 100%; }
  .bidrow .btn { width: 100%; }
  .quickbids { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); }
  .quickbids button { padding: 6px; }
  .modal .m-head { padding: 13px 14px 13px 18px; }
  .modal .m-body { padding: 18px; }
}

@media (prefers-reduced-motion: reduce) {
  body::before, .hero::before, .consign::before, .sellhero::before, footer.site::before { animation: none; }
  .btn:hover:not([disabled]), .iconbtn:hover, .lotcard:hover, .cattile:hover, .acct-row:hover { transform: none; }
  .btn::before { display: none; }
}

/* Private-client introductions are part of the page rather than inline
   spacing instructions, so they hold the same typographic hierarchy at
   every viewport. */
.private-page { padding: 48px 20px 72px; }
.private-page-head { margin-bottom: 30px; }
.private-page-head > div { max-width: 760px; }
.page-kicker {
  display: block;
  margin-bottom: 9px;
  color: var(--brass-ink);
  font: 700 10px/1 var(--font-d);
  letter-spacing: .22em;
  text-transform: uppercase;
}
html[data-theme="midnight"] .page-kicker,
html[data-theme="vault"] .page-kicker { color: var(--brass-soft); }
.private-page-head h1 { margin: 0 0 10px; }
.private-page-head p { margin: 0; max-width: 62ch; color: var(--mut); font-size: 14px; line-height: 1.65; }

/* The mobile catalogue opens on inventory. Facets remain a normal
   labelled form, revealed in place by the control directly above it. */
.filter-toggle, .filter-sheet-head { display: none; }
.filter-toggle {
  width: 100%;
  min-height: 48px;
  align-items: center;
  justify-content: space-between;
  margin: 18px 0 0;
  padding: 0 14px;
  border: 1px solid var(--line2);
  background: color-mix(in srgb, var(--panel) 82%, transparent);
  color: var(--ink);
  font: 700 12px/1 var(--font-d);
  letter-spacing: .08em;
  text-transform: uppercase;
  box-shadow: var(--shadow-1);
}
.filter-toggle::after { content: "+"; margin-left: 12px; color: var(--brass); font: 400 22px/1 var(--font-m); }
.filter-toggle[aria-expanded="true"]::after { content: "−"; }
.filter-toggle .filter-count { margin-left: auto; color: var(--mut); font-size: 10px; letter-spacing: .05em; }
.filter-toggle.has-filters .filter-count { color: var(--brass-ink); }
.filter-sheet-head {
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line2);
  font: 700 10px/1 var(--font-d);
  letter-spacing: .16em;
  text-transform: uppercase;
}

@media (max-width: 720px) {
  /* Override the legacy media-first phone composition. The catalogue
     proposition and live facts earn the first viewport; the object is
     still prominent immediately after them. */
  .hero-copy { order: 1; }
  .hero-media { order: 2; }
  .filter-toggle { display: flex; gap: 10px; }
  .browse-layout { display: block; padding-top: 14px; }
  .browse-layout > .facets { display: none; }
  .browse-layout > .facets.open {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 18px;
    margin: 0 0 20px;
    padding: 16px 16px 4px;
    border: 1px solid var(--line2);
    background: color-mix(in srgb, var(--panel) 90%, transparent);
    box-shadow: var(--shadow-1);
  }
  .filter-sheet-head { display: flex; grid-column: 1 / -1; }
  .browse-toolbar { margin-top: 4px; }
  .private-page { padding-top: 38px; padding-bottom: 58px; }
}

@media (max-width: 460px) {
  .browse-layout > .facets.open { grid-template-columns: 1fr; }
  .filter-sheet-head { grid-column: 1; }
  .private-page { padding-left: 16px; padding-right: 16px; }
}

/* ============================================================
   EDITORIAL CATALOGUE REFINEMENT
   Repeated rounded tiles become ruled auction records. Hierarchy comes
   from typography, cadence and material edges rather than card soup.
   ============================================================ */

/* Home categories read as a catalogue index. */
.cattiles { gap: 0 30px; }
.cattile {
  min-height: 96px;
  padding: 20px 4px 18px 18px;
  border-width: 1px 0 0;
  border-color: var(--line2);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
.cattile::before {
  top: 20px;
  bottom: 20px;
  width: 1px;
  background: linear-gradient(var(--brass), var(--holo-sky), var(--holo-blush));
  opacity: .45;
  transition: opacity var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
}
.cattile:hover {
  transform: translateX(4px);
  background: color-mix(in srgb, var(--panel) 34%, transparent);
  box-shadow: none;
}
.cattile:hover::before { opacity: 1; transform: scaleY(1.16); }
.cattile b { font-size: 19px; }

/* Auction lots are object plates: square, precise, and quiet until the
   cursor reaches them. */
.lotgrid, .browse-grid { gap: 20px 18px; }
.lotcard {
  border-radius: 0;
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  box-shadow: none;
  transform: none;
}
.lotcard::before {
  height: 2px;
  background: var(--salon-edge);
  opacity: .2;
}
.lotcard:hover {
  transform: translateY(-2px);
  border-color: var(--line2);
  box-shadow: 0 18px 42px color-mix(in srgb, var(--dark) 14%, transparent);
}
.lotcard:hover::before { opacity: .9; }
.lotcard .meta { letter-spacing: .075em; }

/* The plates catch the same single light pass as the engraved controls.
   The holo pass barred foil AT REST on the merchandise and that bar
   stands: nothing here shimmers until the pointer arrives, and what
   answers is the room's light crossing the case glass once — in front
   of the whole plate, never a treatment painted on the seller's card.
   Slower than the buttons because the surface is wider. On leaving,
   the light dissolves where it is rather than sweeping back; the
   transform goes home only after the fade, so the retreat is never
   seen. Closed lots sit out — a sold plate no longer catches the
   room. */
/* Each room shows the same pass by a different mechanism, because each
   room has different headroom. A night plate is dark and has room for
   LIGHT, so there the pale core is screened in and the band reads as a
   lamp crossing the glass. A day plate is already near-white and has no
   room to brighten — a cream band on a cream panel is a measured 0.7 of
   a lightness step, which is why the first pass here read as nothing at
   all. So the day rooms show the pass as COLOUR instead: the saturated
   holo ramp multiplied into the surface, which is also the truer
   reading — a real holo in daylight returns a rainbow, not a highlight.
   Amplitude is one knob per room below, tuned so each lands near the
   same perceived strength on its own ground rather than at the same
   number. Measured, not guessed: paper dE 26 / porcelain 22 at title
   contrast above 11:1, the night rooms dE ~40 above 5:1. */
.lotcard:not(.closed) { isolation: isolate; }
.lotcard:not(.closed)::after {
  --glint: .52;
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  background: var(--lot-glint);
  mix-blend-mode: multiply;
  opacity: 0;
  transform: translateX(-118%);
  transition: opacity .26s var(--ease), transform 0s var(--ease) .26s;
}
/* Porcelain's holo family is deliberately the palest of the four, so it
   needs the most amplitude to say the same thing. */
html[data-theme="porcelain"] .lotcard:not(.closed)::after { --glint: .72; }
html[data-theme="midnight"] .lotcard:not(.closed)::after,
html[data-theme="vault"] .lotcard:not(.closed)::after {
  --glint: .66;
  background: var(--salon-glint);
  mix-blend-mode: screen;
}
.lotcard:not(.closed):hover::after,
.lotcard:not(.closed):focus-within::after {
  opacity: var(--glint);
  transform: translateX(118%);
  transition: transform .8s cubic-bezier(.2, .65, .3, 1), opacity .22s ease-out;
}
/* A tap is not a light source. Touch leaves :hover asserted after the
   finger lifts, which would park the band mid-plate on the tapped tile
   — reachable in practice, because the watch star is the one target
   inside a card that does not navigate away. Keyboard focus is left
   alone, so a tablet with a keyboard still gets the pass. */
@media (hover: none) {
  .lotcard:not(.closed):hover:not(:focus-within)::after {
    opacity: 0;
    transform: translateX(-118%);
  }
}
/* Same rule the buttons' pass follows: a light that only exists as
   travel has nothing to keep when travel stops. */
@media (prefers-reduced-motion: reduce) {
  .lotcard:not(.closed)::after { display: none; }
}

/* Open numbered sequences, with the numerals acting as folio marks. */
.steps {
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 0 30px;
  border: 0;
  border-radius: 0;
  overflow: visible;
}
.step, .step:first-child, .step[hidden] + .step {
  position: relative;
  min-height: 190px;
  padding: 20px 8px 24px 0;
  border: 0;
  border-top: 1px solid var(--line2);
  background: transparent;
}
.step::after {
  content: "";
  position: absolute;
  left: 0; top: -1px;
  width: 54px; height: 1px;
  background: var(--salon-edge);
}
.step .n {
  margin: 0 0 24px;
  color: var(--brass-ink);
  font: 400 32px/.9 var(--font-serif);
  letter-spacing: -.03em;
}
html[data-theme="midnight"] .step .n,
html[data-theme="vault"] .step .n { color: var(--brass-soft); }
.step b { font-family: var(--font-serif); font-size: 20px; font-weight: 500; }
.step p { max-width: 30ch; font-size: 13px; line-height: 1.65; }

/* Consignor stage: an asymmetrical private-desk invitation. */
.sellhero .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(260px, .8fr);
  align-items: center;
  gap: 70px;
  max-width: var(--wrap);
  min-height: 560px;
  padding-top: 76px;
  padding-bottom: 82px;
}
.sellhero h1 {
  max-width: 9em;
  font-family: var(--font-serif);
  font-size: clamp(48px, 6vw, 76px);
  font-weight: 400;
  font-stretch: 100%;
  line-height: .98;
  letter-spacing: -.035em;
}
.sell-seal {
  position: relative;
  display: grid;
  min-height: 330px;
  place-items: center;
  align-content: center;
  gap: 15px;
  border: 1px solid color-mix(in srgb, var(--brass-soft) 42%, transparent);
  color: var(--brass-soft);
  background:
    radial-gradient(circle, color-mix(in srgb, var(--holo-sky) 18%, transparent), transparent 54%),
    color-mix(in srgb, var(--dark2) 84%, transparent);
  box-shadow: 0 0 0 9px color-mix(in srgb, var(--dark) 85%, transparent), 0 0 0 10px color-mix(in srgb, var(--brass) 22%, transparent), 0 28px 80px rgba(0,0,0,.34);
  transform: rotate(1.2deg);
}
.sell-seal::before, .sell-seal::after {
  content: "";
  position: absolute;
  inset: 15px;
  border: 1px solid color-mix(in srgb, var(--holo-sky) 18%, transparent);
  pointer-events: none;
}
.sell-seal::after { inset: 24px; border-color: color-mix(in srgb, var(--brass-soft) 16%, transparent); }
.sell-seal svg { width: 88px; height: 78px; filter: drop-shadow(0 10px 26px rgba(0,0,0,.32)); }
.sell-seal span { font: 700 10px/1 var(--font-d); letter-spacing: .22em; text-transform: uppercase; }
.sell-seal b { color: var(--cream); font: 500 12px/1 var(--font-m); letter-spacing: .03em; }

/* Prices realized: formal ledger furniture and an editorial consignment
   coda, not a generic table card followed by another card. */
.results-ledger { padding-top: 42px; }
.results-tools { margin-bottom: 20px; }
.results-panel {
  overflow-x: auto;
  padding: 8px 0 2px;
  border: 1px solid var(--line2);
  border-top: 3px double var(--line2);
  border-radius: 0;
  background: color-mix(in srgb, var(--panel) 90%, transparent);
  box-shadow: var(--shadow-1);
}
.resulttable th { padding-top: 14px; padding-bottom: 13px; border-bottom-color: var(--line2); }
.resulttable td { padding-top: 17px; padding-bottom: 17px; }
.resulttable .rt-title { font-family: var(--font-serif); font-size: 15px; font-weight: 500; }
.resulttable .rt-price { font-family: var(--font-m); font-weight: 500; letter-spacing: -.025em; }
.results-note { margin-top: 14px; color: var(--mut); font-size: 12.5px; line-height: 1.6; }
.results-consign { position: relative; margin-bottom: 62px; border-radius: 0; overflow: hidden; }
.results-consign::after {
  content: "SELLER / ZERO";
  position: absolute;
  right: 24px; top: 50%;
  color: color-mix(in srgb, var(--ink) 5%, transparent);
  font: 800 clamp(44px, 8vw, 100px)/1 var(--font-d);
  letter-spacing: -.06em;
  transform: translateY(-50%);
  pointer-events: none;
}
.results-consign-inner { position: relative; z-index: 1; padding: 0 8px; }
.results-consign h2 { margin: 0 0 14px; font-family: var(--font-serif); font-size: 30px; font-weight: 500; }

/* Archive entries carry museum-label captions and square image wells. */
.arc-search {
  margin-top: 30px;
  padding: 18px;
  border: 1px solid var(--line2);
  border-top: 2px solid var(--brass);
  background: color-mix(in srgb, var(--panel) 84%, transparent);
  box-shadow: var(--shadow-1);
}
.arc-card { border-radius: 0; border-color: var(--line2); box-shadow: none; }
.arc-card:hover { transform: translateY(-2px); border-color: var(--brass); box-shadow: 0 18px 40px color-mix(in srgb, var(--dark) 13%, transparent); }
.arc-img { border-bottom: 1px solid var(--line); background: linear-gradient(165deg, var(--wash), color-mix(in srgb, var(--panel) 55%, var(--wash2))); }
.arc-body { padding: 15px 15px 17px; }
.arc-name { font-family: var(--font-serif); font-size: 15px; font-weight: 500; line-height: 1.28; }
.arc-meta { font-family: var(--font-m); font-size: 10.5px; }

/* Contract pages read as bound documents. */
.legal-layout { grid-template-columns: 250px minmax(0, 68ch); gap: 58px; padding-top: 56px; }
.legal-toc {
  top: 86px;
  gap: 0;
  padding: 18px 0 16px;
  border-top: 2px solid var(--line2);
  border-bottom: 1px solid var(--line2);
}
.legal-toc::before {
  content: "On this page";
  padding: 0 12px 13px;
  color: var(--brass-ink);
  font: 700 9px/1 var(--font-d);
  letter-spacing: .2em;
  text-transform: uppercase;
}
.legal-toc a { padding: 9px 12px; border-left-width: 1px; line-height: 1.35; }
.legal-toc a[aria-current="location"] { color: var(--ink); border-left-color: var(--brass); background: color-mix(in srgb, var(--wash) 72%, transparent); }
.legal-body h1 { font-family: var(--font-serif); font-size: clamp(38px, 4vw, 54px); font-weight: 400; font-stretch: 100%; letter-spacing: -.025em; }
.legal-body .rev { padding-bottom: 22px; border-bottom: 1px solid var(--line2); }
.legal-body h2 {
  position: relative;
  margin-top: 48px;
  padding: 18px 0 0;
  border-top: 1px solid var(--line2);
  font-family: var(--font-serif);
  font-size: 24px;
  font-weight: 500;
  font-stretch: 100%;
}
.legal-body h2::before { content: ""; position: absolute; left: 0; top: -1px; width: 72px; height: 1px; background: var(--salon-edge); }
.legal-body .callout { border-radius: 0; border-left: 3px solid var(--brass); box-shadow: var(--shadow-1); }

/* Status is an operations ledger with deliberate breathing room. */
.status-page { max-width: 720px; padding: 58px 20px 90px; }
.status-page h1 { margin: 10px 0 8px; font-family: var(--font-serif); font-size: clamp(40px, 6vw, 58px); font-weight: 400; letter-spacing: -.025em; }
.status-lede { max-width: 58ch; margin: 0 0 30px; }
#status-app { padding: 16px; border: 1px solid var(--line2); border-top: 2px solid var(--brass); background: color-mix(in srgb, var(--panel) 78%, transparent); box-shadow: var(--shadow-1); }
#status-rows .acct-row { margin: 0; padding: 17px 4px; border-width: 0 0 1px; background: transparent; box-shadow: none; }
#status-rows .acct-row:last-child { border-bottom: 0; }
.status-facts { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line2); }

@media (max-width: 800px) {
  .sellhero .wrap { grid-template-columns: 1fr; gap: 46px; min-height: 0; }
  .sell-seal { width: min(100%, 420px); min-height: 260px; }
  .legal-layout { grid-template-columns: 1fr; gap: 34px; }
  .legal-toc { position: static; grid-template-columns: 1fr 1fr; }
  .legal-toc::before { grid-column: 1 / -1; }
}

@media (max-width: 540px) {
  .cattiles { grid-template-columns: 1fr 1fr; column-gap: 16px; }
  .cattile { padding-left: 12px; }
  .steps { grid-template-columns: 1fr; }
  .step { min-height: 0; padding: 18px 0 28px 72px; }
  .step .n { position: absolute; left: 0; top: 20px; font-size: 28px; }
  .step p { max-width: none; }
  .sellhero .wrap { padding-top: 58px; padding-bottom: 66px; }
  .sellhero h1 { font-size: 48px; }
  .sell-seal { min-height: 220px; }
  .sell-seal svg { width: 68px; }
  .arc-search { padding: 14px; }
  .legal-toc { grid-template-columns: 1fr; }
  .legal-toc::before { grid-column: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .cattile:hover, .lotcard:hover, .arc-card:hover { transform: none; }
}

/* ---------- portfolio: server pages + custody chips ---------- */
.pf-pagefoot {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-top: var(--s-4);
  justify-content: center;
}
