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

/* ---------- tokens ----------
   ONE SEMANTIC CONTRACT, STATED ONCE PER ROOM.

   Every colour on this site resolves through the roles below. The four
   rooms — paper, porcelain, midnight, vault — each define the SAME set,
   and nothing downstream reads a room's name, only a role:

     --canvas            the page ground
     --surface-1         panels, cards, the masthead
     --surface-2         washed bands, table heads, wells
     --surface-raised    menus, dialogs, the lifted step
     --surface-inset     thumbnails, stages, the deeper well
     --text-primary      --text-secondary   --text-muted   --text-faint
     --border-subtle     --border-strong    (strong holds 3:1 on every
                         surface: it is what a control's boundary is drawn in)
     --accent            the room's metal: warm brass, cool pewter,
                         moon silver, muted bronze — used small, at rest, as a rule,
                         a numeral, a selected edge
     --accent-hover      --accent-foreground   (type ON the accent)
     --accent-ink        the accent dark or light enough to set TEXT on
                         the room's own surfaces
     --accent-on-band    the accent as set on the permanently dark furniture
     --urgent / --urgent-tint / --urgent-foreground   live, losing, refused
     --positive / --positive-tint                      gain, met, success
     --caution / --caution-tint                        reversible warnings
     --band-bg / --band-surface / --band-border        the permanently dark
     --band-fg / --band-fg-2 / --band-fg-muted / --band-fg-faint
                         furniture: utility bar, consign band, consignor
                         stage, footer — dark in every room, retuned per room
     --text-inverse      type on a --text-primary plate (the primary CTA)
     --focus-ring        solid, 2px, and never spectral
     --selection         ::selection ground
     --shadow-color      the room's falloff, an rgb triplet for rgb(… / a)
     --foil-a / --foil-b / --foil-c    the room's three-colour MATERIAL —
                         uneven, two families and a third, never a rainbow
     --foil-highlight    the narrow near-white specular line
     --foil-ambient-opacity   the ceiling for foil laid over an AREA
                         (under .06 in the day rooms, under .10 at night);
                         a 1–2px edge may run brighter because its area
                         is nothing
     --grain-opacity / --engrave-opacity / --vignette-opacity
                         the three textures a room may own: paper's fibre,
                         the vault's engine-turned guilloché, midnight's one
                         local vignette behind the featured card. Zero in
                         the rooms that do not own them, so no rule below
                         ever names a room to decide whether to draw one.

   THE SHORT NAMES ARE ALIASES. --paper, --panel, --ink, --mut, --line,
   --brass and the rest of the older vocabulary are consumed some two
   thousand times across this file, admin/admin.css, docs-site and the
   inline styles the scripts write. They stay, as references to the roles
   above — each is `var(--role)` and never a second value — so a colour is
   decided in one place and can be read under two spellings. New rules
   take the roles; the alias table is the compatibility layer. One thing
   to know about it: an alias resolves on the root, so inside a re-scoped
   palette (the picker's swatches, which carry their own room's roles)
   only the ROLE names answer for that room.

   The spectral vocabulary — --holo-*, --salon-*, --foil, --ground-* — is
   gone, not aliased. Where foil appears is the subject of this file's
   material direction, and every consumer was rewritten onto the foil
   roles so that no old placement survived by reference. */
:root {
  /* ---- structure: the same in every room ---- */
  /* the mint mark as a mask, so any element can carry the foil */
  --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");
  /* Paper's fibre: one 160px tile of monochrome turbulence. It rasters
     once and tiles forever; --grain-opacity decides whether a room shows
     it at all. */
  --grain: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20width='160'%20height='160'%3E%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.9'%20numOctaves='2'%20stitchTiles='stitch'/%3E%3CfeColorMatrix%20type='saturate'%20values='0'/%3E%3C/filter%3E%3Crect%20width='160'%20height='160'%20filter='url(%23n)'/%3E%3C/svg%3E");
  /* The vault's guilloché: interlocking engine-turned rings, a 72px tile
     of hairline strokes. It is drawn white and shown at a few percent, so
     on the safe's ground it reads as an engraved plate and nowhere else
     is it shown at all. Confined by rule to the hero, the seal and the
     footer. */
  --engrave: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='72'%20height='72'%20viewBox='0%200%2072%2072'%3E%3Cg%20fill='none'%20stroke='%23fff'%20stroke-width='.7'%3E%3Ccircle%20cx='36'%20cy='36'%20r='30'/%3E%3Ccircle%20cx='0'%20cy='0'%20r='30'/%3E%3Ccircle%20cx='72'%20cy='0'%20r='30'/%3E%3Ccircle%20cx='0'%20cy='72'%20r='30'/%3E%3Ccircle%20cx='72'%20cy='72'%20r='30'/%3E%3Ccircle%20cx='36'%20cy='36'%20r='19'/%3E%3Ccircle%20cx='36'%20cy='36'%20r='8'/%3E%3C/g%3E%3C/svg%3E");
  /* the dialog scrim */
  --overlay: color-mix(in srgb, var(--band-bg) 76%, transparent);
  --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;
  --font-serif: "Iowan Old Style", Palatino, "Palatino Linotype", Georgia, serif;
  /* 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 */
  /* 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. Foil that answers the hand uses --dur-foil: long
     enough to read as a surface turning, short enough never to lag it. */
  --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 */
  --dur-foil: 0.22s;              /* a foil edge catching, or letting go of, the light */
  --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;
  /* One step wider, for the displays that have the room. --maxw is the
     measure everything on this site is composed against and it does not
     move; this is a second stop the page takes at 1620 and above, where
     1264 stops reading as a considered column and starts reading as a
     narrow strip in a large empty field. A step and not a rubber band:
     1560 was chosen because it puts a fourth lot plate in the browse grid
     at 293.5px — within 5px of the 298.66 the three-up design already
     chose — so the catalogue gains a card per row and no object on the
     page changes size. The prose pages do not take it; see the wide block
     near the foot of this file. */
  --maxw-wide: 1560px;
  /* ---- the alias table: older spelling → role ---- */
  --paper: var(--canvas);
  --panel: var(--surface-1);
  --wash: var(--surface-2);
  --wash2: var(--surface-inset);
  --ink: var(--text-primary);
  --ink2: var(--text-secondary);
  --mut: var(--text-muted);
  --faint: var(--text-faint);
  --line: var(--border-subtle);
  --line2: var(--border-strong);
  --brass: var(--accent);
  --brass-soft: var(--accent-on-band);
  --brass-lit: var(--foil-highlight);
  --brass-ink: var(--accent-ink);
  /* THE MARK'S OWN METAL — --mark-holo / --mark-holo-lit, declared once
     per room like every role. The glistening M (the page-transition
     loader and every .mhload wait) used the room's brass pair raw, and
     two rooms paid for it: the light rooms' sweep peaked at white over
     a light ground — a mark that vanishes mid-shine — and midnight's
     highlight was ice-blue over a blue night. Each room now states a
     body dark enough to hold its ground and a highlight that stays
     METAL: gold in the light rooms, moon-platinum in midnight, the
     vault's own gold stated as itself. */
  --dark: var(--band-bg);
  --dark2: var(--band-surface);
  --dark-line: var(--band-border);
  --cream: var(--band-fg);
  --dark-fg: var(--band-fg-2);
  --dark-fg-mut: var(--band-fg-muted);
  --dark-fg-dim: var(--band-fg-faint);
  --live: var(--urgent);
  --down: var(--urgent);
  --live-tint: var(--urgent-tint);
  --up: var(--positive);
  --up-tint: var(--positive-tint);
  --warn: var(--caution);
  --warn-tint: var(--caution-tint);
  --on-ink: var(--text-inverse);
}

:root, .tp-swatch {
  /* ---- the foil, composed once on the roles ----
     Three composites make the whole system, and every room re-skins them
     through --foil-a/b/c and --foil-highlight without another line.
     They are declared on :root AND on the picker's swatches: a custom
     property is substituted where it is declared, so a composite written
     only on the root would carry the page's room into every swatch. On
     the swatch it is re-composed from the swatch's own roles:
       --foil-spectrum  the packed material — a holds the first fifth, b
                        the middle, the highlight a hair's breadth at the
                        centre, c the last fifth. Uneven on purpose: real
                        foil shoulders between two or three families, it
                        does not step through seven.
       --foil-edge      the same run with transparent ends, for hairlines
                        that begin and end inside their element
       --foil-ring      the run closed into a ring, for the loupe's rim */
  --foil-spectrum: linear-gradient(90deg, var(--foil-a) 0%, var(--foil-a) 20%, var(--foil-b) 44%, var(--foil-highlight) 50%, var(--foil-b) 56%, var(--foil-c) 78%, var(--foil-c) 100%);
  --foil-edge: linear-gradient(90deg, transparent, var(--foil-a) 14%, var(--foil-b) 42%, var(--foil-highlight) 49%, var(--foil-c) 72%, transparent);
  --foil-ring: conic-gradient(from 210deg, var(--foil-a), var(--foil-b), var(--foil-highlight), var(--foil-c), var(--foil-a));
  --material-edge: linear-gradient(100deg, var(--foil-a), var(--foil-b) 37%, var(--foil-highlight) 51%, var(--foil-c) 76%, var(--foil-a));
  --material-tint: linear-gradient(118deg, color-mix(in srgb, var(--foil-a) var(--foil-wash), transparent), transparent 38%, color-mix(in srgb, var(--foil-c) var(--foil-wash), transparent));
  --surface-hover: color-mix(in srgb, var(--surface-raised) 65%, var(--surface-1));
  --surface-selected: var(--surface-2);
}

/* ============================================================
   THE FOUR ROOMS. Paper is the :root set; the other three restate
   every role. Each block ALSO scopes to its swatch in the theme picker
   (.tp-swatch.<room>), which is how the picker previews a room the
   reader is not in from the same declarations that paint it — the
   swatch's pseudo-elements read --canvas, --surface-1, --accent and
   the foil through inheritance, so the preview can never drift from
   the room. Slabs and scans never change: the cards are physical
   objects, and they stay the most colourful thing in every room.
   ============================================================ */
:root, .tp-swatch.paper {
  /* PAPER — the archival catalogue. Warm uncoated ivory; the panels a
     shade lighter, the way a tipped-in plate sits on the leaf. Near-black
     brown ink, oxblood for the live and the urgent, aged brass kept to
     rules and numerals. A faint monochrome fibre on the ground, never
     dirt. Foil: soft celadon through mineral blue to old gold. Matte. */
  color-scheme: light;
  --canvas: #f0ebe1;
  --surface-1: #faf6ee;
  --surface-2: #e7dfd1;
  --surface-raised: #fffcf6;
  --surface-inset: #ded4c2;
  --text-primary: #1b130c;
  --text-secondary: #3d3127;
  --text-muted: #5a4f43;
  --text-faint: #62584c;
  --border-subtle: #d1c5b2;
  --border-strong: #786b5b;
  --accent: #8a6a2e;
  --mark-holo: #7a591d;
  --mark-holo-lit: #ecca6d;
  --accent-hover: #6e5323;
  --accent-foreground: #fff8e8;
  --accent-ink: #5c4314;
  --accent-on-band: #d4c49c;
  --urgent: #7f2b27;
  --urgent-tint: #f1e3e0;
  --urgent-foreground: #fff5f3;
  --positive: #2d5d43;
  --positive-tint: #e4efe6;
  --caution: #7e4d0e;
  --caution-tint: #f3ebdc;
  --band-bg: #20231d;
  --band-surface: #2c3027;
  --band-border: #4a4f40;
  --band-fg: #f1eadb;
  --band-fg-2: #cfc6b6;
  --band-fg-muted: #c0bbaa;
  --band-fg-faint: #ada896;
  --text-inverse: #fbf6ea;
  --focus-ring: #1b130c;
  --selection: #e4d6b2;
  --shadow-color: 38 28 14;
  /* one shadow family: a hairline of top light struck into the surface,
     then a soft warm falloff — the paper is matte, so the falloff is wide
     and weak */
  --shadow-1: 0 1px 0 color-mix(in srgb, var(--surface-raised) 35%, transparent) inset, 0 12px 26px rgb(var(--shadow-color) / 0.065);
  --shadow-2: 0 1px 0 color-mix(in srgb, var(--surface-raised) 80%, transparent) inset, 0 24px 60px rgb(var(--shadow-color) / 0.18);
  --foil-a: #aec8b7;
  --foil-b: #a3b8c6;
  --foil-c: #cdb989;
  --foil-highlight: #fbf7ea;
  --foil-ambient-opacity: 0.035;
  --grain-opacity: 0.025;
  --engrave-opacity: 0;
  --vignette-opacity: 0;
  /* Category tints — the plate behind a browse thumbnail, mixed into
     --surface-inset at the component. Stated per room so the colour
     coding survives the night rooms. */
  --cat-pokemon: #f6efdb;
  --cat-baseball: #edf1e7;
  --cat-basketball: #f4ece1;
  --cat-football: #efeae0;
  --cat-soccer: #eaf0ea;
  --cat-hockey: #e9eef3;
  --cat-tcg: #efeaf2;
  /* the select chevron, stated per room (a data-URI cannot read var();
     the stroke matches the room's own --text-muted) */
  --chev: 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='%235a4f43' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --brand-mark: #5c4314;
  --brand-type: #1b130c;
  --foil-wash: 3%;
  --band-urgent: #f1b2a6;
  --brand-mark-on-band: #d9bf7e;
  --brand-type-on-band: #f1eadb;
  --frame-foil-opacity: .62;
}
html[data-theme="porcelain"], .tp-swatch.porcelain {
  /* PORCELAIN — the museum vitrine. A cool high-key gray-white ground,
     clean near-white surfaces a full step above it, graphite type, crisp
     blue-gray rules, cool pewter used sparingly. No grain, and shadows
     reduced to a hairline: the light in a vitrine is even. Foil: silver
     into ice blue with a pure white specular line. Precise, bright, quiet. */
  color-scheme: light;
  --canvas: #edf0f2;
  --surface-1: #fcfdfd;
  --surface-2: #e3e8ec;
  --surface-raised: #ffffff;
  --surface-inset: #d6dfe4;
  --text-primary: #1c2126;
  --text-secondary: #3a4149;
  --text-muted: #525a63;
  --text-faint: #58636c;
  --border-subtle: #cbd4da;
  --border-strong: #6c7883;
  --accent: #60757d;
  --mark-holo: #745a1f;
  --mark-holo-lit: #ecca6d;
  --accent-hover: #4d6670;
  --accent-foreground: #fffaf0;
  --accent-ink: #425c66;
  --accent-on-band: #b7cfd2;
  --urgent: #9c3430;
  --urgent-tint: #f4e6e5;
  --urgent-foreground: #fff5f3;
  --positive: #2c6447;
  --positive-tint: #e2efe7;
  --caution: #7a4e10;
  --caution-tint: #f2ece0;
  --band-bg: #17242a;
  --band-surface: #223239;
  --band-border: #3d535c;
  --band-fg: #eef0f2;
  --band-fg-2: #c9ced5;
  --band-fg-muted: #bbc9ce;
  --band-fg-faint: #a5b8c0;
  --text-inverse: #ffffff;
  --focus-ring: #1c2126;
  --selection: #cfdceb;
  --shadow-color: 16 22 30;
  /* almost no shadow — a vitrine separates by edge and by tone */
  --shadow-1: 0 1px 0 color-mix(in srgb, var(--surface-raised) 35%, transparent) inset, 0 5px 14px rgb(var(--shadow-color) / 0.045);
  --shadow-2: 0 1px 0 rgba(255, 255, 255, 0.9) inset, 0 14px 36px rgb(var(--shadow-color) / 0.12);
  --foil-a: #b4c7ca;
  --foil-b: #bccbdc;
  --foil-c: #d9d5c9;
  --foil-highlight: #ffffff;
  --foil-ambient-opacity: 0.025;
  --grain-opacity: 0;
  --engrave-opacity: 0;
  --vignette-opacity: 0;
  --cat-pokemon: #f2ecd8; --cat-baseball: #e9efe5; --cat-basketball: #f0e8dd;
  --cat-football: #ebe7df; --cat-soccer: #e5eee6; --cat-hockey: #e4ebf3;
  --cat-tcg: #ece7f2;
  --chev: 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='%23525a63' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --brand-mark: #5d4816;
  --brand-type: #1c2126;
  --foil-wash: 3%;
  --band-urgent: #f1b2a6;
  --brand-mark-on-band: #d2bb7e;
  --brand-type-on-band: #eef0f2;
  --frame-foil-opacity: .62;
}
html[data-theme="midnight"], .tp-swatch.midnight {
  /* MIDNIGHT — the private viewing room. A blue-black ground, never pure
     black, with ink-navy surfaces layered up from it in real steps. Warm
     ivory for the reading type, muted slate for the metadata, silver in
     small amounts. Shadows deep, because a dark room separates by
     falloff. One local vignette, behind the featured card, and that is
     the whole of its atmosphere. Foil: mineral blue into oxidised teal with a
     narrow cool highlight. Atmospheric but crisp — no neon. */
  color-scheme: dark;
  --canvas: #0a111e;
  --surface-1: #131f31;
  --surface-2: #1a2840;
  --surface-raised: #202f48;
  --surface-inset: #0d182a;
  --text-primary: #edf0f5;
  --text-secondary: #ccd5e2;
  --text-muted: #aebbd0;
  --text-faint: #9baabc;
  --border-subtle: #344766;
  --border-strong: #7b90b1;
  --accent: #bccce5;
  --mark-holo: #b6b0c8;
  --mark-holo-lit: #f0ebf8;
  --accent-hover: #d8e3f5;
  --accent-foreground: #131d25;
  --accent-ink: #c1d0e8;
  --accent-on-band: #bccce5;
  --urgent: #ec9e94;
  --urgent-tint: rgba(236, 158, 148, 0.13);
  --urgent-foreground: #1c0e0c;
  --positive: #93c08d;
  --positive-tint: rgba(147, 192, 141, 0.14);
  --caution: #d9a95f;
  --caution-tint: rgba(217, 169, 95, 0.13);
  --band-bg: #070d18;
  --band-surface: #112038;
  --band-border: #304461;
  --band-fg: #edf0ed;
  --band-fg-2: #ccd6dd;
  --band-fg-muted: #becadf;
  --band-fg-faint: #a5b5cf;
  --text-inverse: #101722;
  --focus-ring: #edf0ed;
  --selection: #34496d;
  --shadow-color: 0 0 0;
  --shadow-1: 0 1px 0 color-mix(in srgb, var(--surface-raised) 35%, transparent) inset, 0 12px 28px rgb(var(--shadow-color) / 0.22);
  --shadow-2: 0 1px 0 rgba(255, 255, 255, 0.08) inset, 0 30px 76px rgb(var(--shadow-color) / 0.65);
  --foil-a: #6f94cf;
  --foil-b: #adc0e2;
  --foil-c: #9eaccd;
  --foil-highlight: #edf3ff;
  --foil-ambient-opacity: 0.09;
  --grain-opacity: 0;
  --engrave-opacity: 0;
  --vignette-opacity: var(--foil-ambient-opacity);
  --cat-pokemon: #2e2b1f; --cat-baseball: #222b25; --cat-basketball: #2d281f;
  --cat-football: #292620; --cat-soccer: #202a26; --cat-hockey: #21293a;
  --cat-tcg: #292636;
  --chev: 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='%23a4adbf' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --brand-mark: #d9bb74;
  --brand-type: #f1e9d6;
  --foil-wash: 6%;
  --band-urgent: #f1b2a6;
  --brand-mark-on-band: #d9bb74;
  --brand-type-on-band: #f1e9d6;
  --frame-foil-opacity: .82;
}
html[data-theme="vault"], .tp-swatch.vault {
  /* VAULT — the secure archive. Warm black, espresso rather than navy,
     with tobacco surfaces raised from the ground and fine bronze rules.
     Compact shadows keep the archive legible without heavy gold framing. Parchment type, muted bronze,
     oxidised green held to the gain colour and the foil's third family.
     The guilloché shows at less than two percent on the hero, the seal and the
     footer and nowhere else. Foil: brushed bronze through champagne to patinated green. */
  color-scheme: dark;
  --canvas: #0c0c0a;
  --surface-1: #171611;
  --surface-2: #201d16;
  --surface-raised: #2a241a;
  --surface-inset: #10100c;
  --text-primary: #f1e9da;
  --text-secondary: #d9ceba;
  --text-muted: #bdae96;
  --text-faint: #b0a18a;
  --border-subtle: #403828;
  --border-strong: #9b8567;
  --accent: #d7b866;
  --mark-holo: #e0bd6a;
  --mark-holo-lit: #fff1cc;
  --accent-hover: #ead29a;
  --accent-foreground: #1a1208;
  --accent-ink: #dbc27f;
  --accent-on-band: #d6b96e;
  --urgent: #efa18f;
  --urgent-tint: rgba(239, 161, 143, 0.14);
  --urgent-foreground: #1c0d09;
  --positive: #a0c49a;
  --positive-tint: rgba(160, 196, 154, 0.15);
  --caution: #dcb06d;
  --caution-tint: rgba(220, 176, 109, 0.14);
  --band-bg: #090a08;
  --band-surface: #171710;
  --band-border: #45402a;
  --band-fg: #f0e6d2;
  --band-fg-2: #d2c6ae;
  --band-fg-muted: #c5c3aa;
  --band-fg-faint: #afb198;
  --text-inverse: #0c0c0a;
  --focus-ring: #f1e9da;
  --selection: #5a4420;
  --shadow-color: 0 0 0;
  /* A warm top light separates the surface from its compact falloff. */
  --shadow-1: 0 1px 0 color-mix(in srgb, var(--surface-raised) 35%, transparent) inset, 0 12px 28px rgb(var(--shadow-color) / 0.24);
  --shadow-2: inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent), 0 1px 0 rgba(255, 255, 255, 0.07) inset, 0 34px 84px rgb(var(--shadow-color) / 0.74);
  --foil-a: #cbaa60;
  --foil-b: #e4d2a0;
  --foil-c: #a6ac86;
  --foil-highlight: #fff2cc;
  --foil-ambient-opacity: 0.075;
  --grain-opacity: 0;
  --engrave-opacity: 0.018;
  --vignette-opacity: 0;
  --cat-pokemon: #2d2716; --cat-baseball: #23281b; --cat-basketball: #2c2317;
  --cat-football: #282219; --cat-soccer: #20271e; --cat-hockey: #1f252e;
  --cat-tcg: #272132;
  --chev: 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='%23ad9f86' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --brand-mark: #e0bd6a;
  --brand-type: #f0e6d2;
  --foil-wash: 6%;
  --band-urgent: #f1b2a6;
  --brand-mark-on-band: #e0bd6a;
  --brand-type-on-band: #f0e6d2;
  --frame-foil-opacity: .82;
}

/* ---------- 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(--selection); color: var(--text-primary); }

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

/* 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 3px 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;
}
/* Visually hidden, announced: the standard 1px clip, for live regions
   whose words are for assistive tech alone. The skiplink above is the
   same pattern with a :focus escape hatch. */
.vh {
  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; }

/* THE FOIL RULE — the thin line under the masthead and over the footer,
   the site's one spectral constant. Two pixels of the room's packed
   material, still. It used to drift on an eighteen-second loop under a
   coloured glow; a rule that moves on its own is a loading bar, and a
   glow is a halo. On a fine pointer the hand still turns it: the packed
   spectrum is three element-widths wide, and the shell's pointer contract
   (html[data-mh-pointer], --mh-px) pans the window across it as the
   reader crosses the page — the edge of a card catching the light as it
   tilts. Without the contract it rests at its centre, highlight and all. */
.foil-rule {
  height: 2px;
  background-image: var(--foil-spectrum);
  background-size: 300% 100%;
  background-position: 50% 50%;
}
html[data-mh-pointer] .foil-rule {
  background-position: calc(var(--mh-px, 0.5) * 100%) 50%;
  transition: background-position var(--dur-foil) var(--ease);
}


.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(--band-fg); color: var(--band-bg); border-color: var(--band-fg); }
.btn.ondark:hover { background: transparent; color: var(--band-fg); border-color: var(--band-fg); }
.btn.ondark.ghost { background: transparent; color: var(--band-fg); border-color: color-mix(in srgb, var(--band-fg) 50%, transparent); }
.btn.ondark.ghost:hover { background: var(--band-fg); color: var(--band-bg); border-color: var(--band-fg); }
.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%; }
/* disabled keeps only the cursor here — the explicit treatment (wash
   ground, muted word, no shadow) lives in the STATES block at the foot
   of the file, and a second opacity here would be the two-generations
   pattern this file just finished burying */
.btn[disabled] { cursor: default; }

.linkline {
  font-weight: 600;
  font-size: 13.5px;
  transition: opacity var(--dur-base) var(--ease);
}
.linkline:hover { text-decoration-thickness: 2px; text-underline-offset: 4px; }
/* A "see all" link at the end of a band head is a section control rather
   than words in a sentence. It takes the utility bar's transparent patch;
   the band head keeps 26px of air under it, 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 { position: relative; }
.band-head .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 separators get their own breathing room, so the three
   facts read as three things rather than one run-on. On the dark
   band the mini M carries the room's foil, compressed the way the
   kit's gem compresses the whole scheme into one small stone —
   brass would read but the bar is the one place the mark is pure
   ornament on permanent dark, and it has earned its slice. */
.utilbar .ticker .sep:empty {
  margin: 0 4px;
  background: var(--foil-spectrum);
  background-size: 340% 100%;
  background-position: 50% 50%;
}
/* 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; }
/* Appearance lives in the STATUS MARKS group, which rebuilt every chip
   (weight, size, tracking, inherit colour, diamond). Only the flex fact
   about THIS position survives here: the ticker must not shrink it. */
.livetag { flex: none; }
.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.

   383px is not a round number, it is where the masthead's top line stops
   fitting. This breakpoint said 416 and had gone stale: the masthead's
   controls now shed their words at 720 rather than at three separate
   widths, so the row they need is narrower than it was when 416 was
   derived. Measured on the rendered page, the masthead is 121px — two
   rows — at every width from 384 up, and 149px — three rows — at 383 and
   below. With the floor still applied to 416 the band from 384 to 416
   reserved 243 against a real 215.14, and left 27.9px of bare paper
   hanging under the navigation on 390, 393, 402 and 412: the widths most
   phones in use actually report. Measured, that strip is 0 at 375, at
   417, at 430 and at 1440, and 27.9 across that band alone.

   So the floor moves to where the third row does. 384 to 416 now takes
   the 212 floor against 215.14, which is 3.14 short — the same shortfall
   417 to 1160 already carries, and on the correct side of the rule this
   block states.

   /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: 383px)  { #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
   ============================================================ */
/* ============================================================
   HERO — the editorial stage, stated ONCE.

   Four generations of this block had stacked: a flat stage here, a
   day/night ink retune in the account section, a "marquee" at the far
   end of the file that restated the ground as four spectral layers under
   an animated glint and a rotated plate with an 80px inner glow, and a
   940px media query that restated the lot of it again. Only the last
   rendered. These are the values that render, at the component's own
   site, on the roles — and the stage is the CANVAS in every room. The
   night rooms no longer switch it to the footer's black, so the hero
   belongs to the page it opens rather than to the furniture that closes
   it; one tonal wedge of the surface tone sits behind the copy, and no
   spectral layer touches the stage. The foil lives on the reflective
   plane behind the slab, below, and nowhere else in the hero.
   ============================================================ */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  color: var(--text-primary);
  background:
    linear-gradient(102deg, color-mix(in srgb, var(--surface-1) 60%, transparent) 0 49%, transparent 49%),
    var(--canvas);
  border-bottom: 1px solid var(--border-strong);
}
/* the vault's engraving, under the plate's half of the stage; every other
   room sets --engrave-opacity to 0 and this paints nothing */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--engrave) center / 72px 72px;
  opacity: var(--engrave-opacity);
  -webkit-mask-image: linear-gradient(90deg, transparent 42%, #000 78%);
  mask-image: linear-gradient(90deg, transparent 42%, #000 78%);
}
/* the centre rule: framing, in the room's metal at its midpoint */
.hero::after {
  content: "";
  position: absolute;
  top: 10%; bottom: 10%; left: 50%;
  width: 1px;
  pointer-events: none;
  background: linear-gradient(transparent, var(--border-strong) 22%, var(--accent) 50%, var(--border-strong) 78%, transparent);
  opacity: .7;
}
.hero .wrap {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 72px;
  align-items: center;
  min-height: 600px;
  padding-top: 52px;
  padding-bottom: 56px;
}
.hero-eyebrow { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.hero-eyebrow .eyebrow { color: var(--accent-ink); }
.hero h1 {
  /* The editorial serif is shared with the display-headlines group.
     Reserve one line during bootstrap; longer titles grow naturally. */
  min-height: 1.06em;
  font-size: clamp(42px, 4.3vw, 62px);
  line-height: 1.06;
  margin-bottom: 22px;
  max-width: 11.5em;
}
.hero .lotmeta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  color: var(--text-muted); font-size: var(--fs-300); margin-bottom: 28px;
}
.hero .hero-edition { color: var(--text-muted); }
.gradechip {
  display: inline-flex; align-items: center;
  font-family: var(--font-d);
  font-weight: 800; font-size: 11.5px; letter-spacing: 0.06em;
}
/* THE DECISION BLOCK. The current bid is the strongest numeral on the
   page — the register mono, one step under the headline — ruled above
   and below in the strong line, with the clock beside it. */
.hero .bidblock {
  display: flex; align-items: flex-end; flex-wrap: wrap; gap: var(--s-7);
  width: min(100%, 560px);
  padding: 20px 0;
  margin-bottom: 28px;
  border-top: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
}
.hero .bidblock .lbl { font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-muted); 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-family: var(--font-m); font-size: clamp(30px, 3.4vw, 42px); font-weight: 500; letter-spacing: -.04em; line-height: 1; min-height: 1em; }
.hero .bidblock .sub { font-size: 12.5px; color: var(--text-muted); margin-top: 7px; }
.hero .estline .est-lbl { color: var(--text-muted); }
.hero .estline .est-fig { color: var(--text-secondary); }
.hero-ctas { display: flex; gap: var(--s-3); flex-wrap: wrap; }
/* the stage's buttons: solid ink on the canvas, the room's strongest
   plate, from one declaration in all four rooms (the night rooms' ink is
   ivory, so there the button is the ivory plate it always was) */
.hero .btn.ondark { background: var(--text-primary); color: var(--text-inverse); border-color: var(--text-primary); }
.hero .btn.ondark:hover { background: var(--text-secondary); border-color: var(--text-secondary); }
.hero .btn.ondark.ghost { background: transparent; color: var(--text-primary); border-color: var(--border-strong); }
.hero .btn.ondark.ghost:hover { border-color: var(--text-primary); }

/* THE REFLECTIVE PLANE — the site's one area of foil.

   A quiet, square plate sits behind the slab, like a catalogue mount. Its top edge is two
   pixels of the room's foil, and across its face one narrow diagonal
   pass — two families of the material shouldering into a single near-
   white line — lies where the light would strike a sheet of glass. On a
   fine pointer the pass moves with the hand (the shell's --mh-px; the
   same contract the foil rule reads) within --dur-foil; everywhere else
   it rests at the centre. Two image layers and a fill: the cap. Nothing
   here touches the slab, which sits above the plate on its own layer and
   casts the room's shadow onto it. */
.hero-media { position: relative; z-index: 1; 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 {
  position: relative;
  z-index: 1;
  width: min(320px, 78%);
  aspect-ratio: 340 / 554;
  filter: drop-shadow(0 16px 24px rgb(var(--shadow-color) / 0.2));
}
/* midnight's one vignette: a local pool of the room's second foil family
   behind the featured card and nowhere else; the other rooms set
   --vignette-opacity to 0 */
.hero-media::before {
  content: "";
  position: absolute;
  z-index: -2;
  inset: -12% -24%;
  pointer-events: none;
  background: radial-gradient(50% 50% at 50% 50%, var(--foil-b), transparent 70%);
  opacity: var(--vignette-opacity);
}
.hero-media::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 7% 1% 8%;
  pointer-events: none;
  border: 1px solid var(--border-subtle);
  background:
    var(--foil-edge) 0 0 / 100% 2px no-repeat,
    linear-gradient(118deg, transparent 43.5%, color-mix(in srgb, var(--foil-a) 12%, transparent) 46.5%, color-mix(in srgb, var(--foil-b) 18%, transparent) 49.2%, color-mix(in srgb, var(--foil-highlight) 32%, transparent) 50.2%, color-mix(in srgb, var(--foil-c) 14%, transparent) 51.6%, transparent 56%) calc(var(--mh-px, 0.5) * 100%) 50% / 240% 100% no-repeat,
    color-mix(in srgb, var(--surface-1) 45%, transparent);
  transform: none;
  transition: background-position var(--dur-foil) var(--ease);
}


/* ============================================================
   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; }
/* The browse pager's row: one centred control under the grid. */
.gridmore { display: flex; justify-content: center; margin: 22px 0 4px; }
/* The label carries two live numbers ("Show 24 more (26 remaining)") and at
   320px they are wider than the wrap; a nowrap .btn sheared the parenthesis
   off. Wrapping to a second centred line keeps both numbers readable. */
.gridmore .btn { white-space: normal; }
.gridmore:empty { display: none; }
.rail {
  display: grid;
  grid-auto-flow: column;
  /* The 236px floor is what gives the rail its deliberate sliver of the
     next card. At 320 the viewport has 272 of content box, so one card
     plus its 18px gap left 18px of the next — a sliver too thin to read
     as "there is more this way" rather than as a clipping accident. The
     percentage resolves against the rail's own box, so the floor stands
     down only where the box cannot hold it: measured, 320 gives a 190px
     card and 64px of preview, 360 gives 230 and 64, and 375 up are
     untouched at the authored 236. */
  grid-auto-columns: minmax(min(236px, 100% - 82px), 1fr);
  gap: 18px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 6px;
  scrollbar-width: thin;
}
.rail > * { scroll-snap-align: start; }

.lotcard {
  /* ONE generation. Three grew over the campaigns — panel/r-m/shadow,
     the salon lift, the editorial object plate — and only the last
     rendered. These are the final computed values, stated once, on the
     roles: the first surface, the subtle rule, the room's own shadow
     family (a hairline in porcelain, a frame in the vault). */
  background: var(--surface-1);
  border: 1px solid var(--border-subtle);
  border-radius: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
  position: relative;
}
/* THE CARD'S TOP EDGE. At rest, a hairline of the room's metal. Under
   the pointer, or with focus inside, it is the one place on a card that
   shows foil: two pixels, on the edge, answering within --dur-foil. The
   sweep that used to cross the whole plate — a colour band multiplied
   into the seller's scan — is gone; nothing is ever laid over the art. */
.lotcard::before {
  content: "";
  position: absolute;
  z-index: 3;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: var(--accent);
  opacity: .28;
  transition: opacity var(--dur-foil) var(--ease);
  pointer-events: none;
}
.lotcard-link {
  display: flex;
  flex: 1;
  min-width: 0;
  flex-direction: column;
  color: inherit;
}
.lotcard:hover {
  transform: translateY(-2px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-2);
}
.lotcard:hover::before { background: var(--foil-edge); opacity: 1; }
/* the thumbnail plate: the inset surface, tinted flat by category — the
   gradient is gone, so the card's own colours are the only gradient in
   the tile */
.lotcard .thumb {
  background: var(--surface-inset);
  padding: 18px 34px 14px;
  position: relative;
}
.lotcard .thumb[data-cat="pokemon"]    { background: color-mix(in srgb, var(--cat-pokemon) 55%, var(--surface-inset)); }
.lotcard .thumb[data-cat="baseball"]   { background: color-mix(in srgb, var(--cat-baseball) 55%, var(--surface-inset)); }
.lotcard .thumb[data-cat="basketball"] { background: color-mix(in srgb, var(--cat-basketball) 55%, var(--surface-inset)); }
.lotcard .thumb[data-cat="football"]   { background: color-mix(in srgb, var(--cat-football) 55%, var(--surface-inset)); }
.lotcard .thumb[data-cat="soccer"]     { background: color-mix(in srgb, var(--cat-soccer) 55%, var(--surface-inset)); }
.lotcard .thumb[data-cat="hockey"]     { background: color-mix(in srgb, var(--cat-hockey) 55%, var(--surface-inset)); }
.lotcard .thumb[data-cat="tcg"]        { background: color-mix(in srgb, var(--cat-tcg) 55%, var(--surface-inset)); }
.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(--text-muted);
  /* the room's own raised surface, at glass — a pale pill on a day plate,
     a dark one at night, from one declaration */
  background: color-mix(in srgb, var(--surface-raised) 72%, transparent);
  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(--text-primary); background: var(--surface-raised); }
.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; }
/* Full titles keep the identifying name and edition visible at every width. */
.lotcard .title {
  font-size: 13.8px;
  font-weight: 600;
  line-height: 1.35;
  display: block;
  overflow-wrap: anywhere;
  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); }
/* The price and the count are the two numbers a bidder reads first and
   they were fusing into one string: measured on the seeded catalogue at
   320px, the gap between "$284,000" and "25 bids" is 0.0px on every card
   in the grid, and the count breaks mid-phrase onto two lines. A minimum
   column gap and a wrap fix both without a per-width patch — where the
   pair fits, space-between still pushes them to the rails; where it does
   not, the count moves down whole. --s-2 and not --s-3: measured, 8px
   clears the collision at 320 without pushing 375 into a wrap it does
   not need. This is the treatment .lotcard .clock already carries. */
.lotcard .priceline { display: flex; align-items: baseline; justify-content: space-between; margin-top: auto; flex-wrap: wrap; column-gap: var(--s-2); row-gap: 2px; }
.lotcard .bid { font-size: var(--fs-500); font-weight: 700; letter-spacing: -0.01em; }
.lotcard .bids { min-width: 0; max-width: 100%; font-size: var(--fs-200); color: var(--mut); overflow-wrap: anywhere; }
.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);
}
/* THE TILE'S MARKET LINE (js/shell.js fmvLineFor). The register's own
   estimate, one quiet line between the price and the clock. Muted by
   design: it is context for the price above it, not a second price —
   and the above/below badge borrows the up/down colours ONLY at the
   medium/high confidence the renderer demands, so a low-confidence
   figure can never wear a verdict's colour. "Near" is neutral: within
   the band is not good news or bad. */
.lotcard .fmvline {
  display: flex; align-items: baseline; justify-content: space-between; gap: 6px;
  font-family: var(--font-m); font-size: var(--fs-200); color: var(--mut);
  flex-wrap: wrap;
  margin-top: 2px;
}
.fmvbadge {
  font-family: var(--font-d); font-weight: 700; font-size: 9.5px;
  letter-spacing: 0.07em; text-transform: uppercase; white-space: nowrap;
  border-radius: var(--r-s); padding: 1px 5px;
}
.fmvbadge.below { color: var(--up); background: var(--up-tint); }
/* Tinted like the reserve chip, never ringed: an outlined uppercase
   micro-label is the one shape the house does not draw (see the evidence
   marks, which are words). Above sits on the caution-red tint the
   outbid state already uses; near on the wash, like a reserve unset. */
.fmvbadge.above { color: var(--down); background: var(--live-tint); }
.fmvbadge.near { color: var(--ink2); background: var(--wash); }

/* The lot page's estimate panel (js/lot.js comps): four explicit facts
   above the comparables, set as one compact label/value register. */
.fmvpanel { margin: 14px 0 10px; padding: 12px 14px; background: var(--wash); border: 1px solid var(--line); border-radius: var(--r-s); }
.fmvpanel .fmvmain { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: 7px 16px; align-items: baseline; }
.fmvpanel .fmvlabel { font-family: var(--font-d); font-size: var(--fs-100); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut); }
.fmvpanel .fmvanswer { display: block; min-width: 0; color: var(--ink2); font-size: var(--fs-300); font-weight: 600; line-height: 1.35; overflow-wrap: anywhere; }
.fmvpanel .fmvvalue { font-size: var(--fs-500); font-weight: 700; letter-spacing: -0.01em; }
.fmvpanel .fmvsource.ask, .fmvpanel .fmvsource.ovr,
.fmvpanel .fmvconf.low, .fmvpanel .fmvconf.stale { color: var(--brass-ink); }


/* 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(--urgent); color: var(--urgent-foreground); padding: 3px 7px;
}

/* ---------- category tiles ----------
   SEVEN CATEGORIES, AND THE GRID HAS TO KNOW IT.

   js/catalog.js declares exactly seven (MH.CATS): the six sports and card
   games, and "Other". A six-column grid therefore left the seventh alone
   on a second row beside five empty tracks — about a thousand pixels of
   ruled nothing under the index, in every theme and at every width, since
   the three column counts were 6, 3 and 2 and all three divide seven with
   one left over.

   And the count is not fixed at seven either: js/home.js draws a tile only
   for a category that has lots, so a box with two empty categories draws
   five — staging draws six today. A hard seven-track grid would then
   leave dead tracks on the right, which is the same defect pointed the
   other way. So the widest band states no track count at all: column flow
   with equal auto-columns puts however many tiles there are on one line,
   which is what an index line is. The middle band takes four and the
   phone two, both flowing by row again, and on the phone an odd tile at
   the end takes the full measure rather than sitting beside a hole —
   written on :nth-child(odd) so it stops applying by itself when the
   count is even. */
.cattiles { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 14px; }
.cattile {
  /* One generation, same story as .lotcard above: the editorial ledger
     row is what renders, so it is what is written. */
  min-height: 96px;
  border: solid var(--line2);
  border-width: 1px 0 0;
  border-radius: 0;
  background: transparent;
  padding: 20px 4px 18px 18px;
  transition: box-shadow var(--dur-base) var(--ease), transform var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
  position: relative;
  overflow: hidden;
}
.cattile::before {
  content: "";
  position: absolute;
  left: 0; top: 20px; bottom: 20px;
  width: 1px;
  /* Brass family only: a category list is navigation, and its accent
     is the house's metal, not an interference spectrum. */
  background: linear-gradient(var(--brass-soft), var(--brass) 60%, transparent);
  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 .mini { display: block; width: 64px; margin-bottom: 12px; }
.cattile b { display: block; font-family: var(--font-serif); font-weight: 500; font-size: 19px; 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; }
/* The heading over the figures is a heading. Both the header cell and the
   data cells carry .rt-price, so the figure treatment reached the <th>
   too: "PRICE REALIZED" came out 700 at 14.5px in the register mono while
   LOT, SOLD and AUCTION beside it were 11px Inter 600 small-caps — one of
   four headings in a different hand and a third larger. Alignment and
   nowrap stay shared; only the figure treatment narrows to the cells. */
.resulttable .rt-price { text-align: right; white-space: nowrap; }
.resulttable td.rt-price { font-weight: 700; 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-family: var(--font-serif); font-size: clamp(32px, 3.6vw, 48px); font-weight: 400; line-height: 1.12; letter-spacing: -.025em; margin: 0 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: color-mix(in srgb, var(--band-fg) 6%, transparent);
  border: 1px solid var(--band-border);
  border-radius: 6px;
  color: var(--band-fg);
  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(--band-fg);
  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: var(--band-fg); 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;
}
/* THE RAIL ARRIVES NARROW AND GROWS INTO ITS WIDTH.
   248 of rail plus 36 of gap is 284px, and the grid pays all of it the
   moment the rail appears: measured, the lot plate drops from 285.3px at
   940 to 191.0 at 941 — the smallest plate on the site, smaller than the
   228 a 768 tablet gets three-up, and it gets SMALLER as the window gets
   WIDER, which is the part a reader notices without being able to name.
   The rail does not need 248 to hold its own labels: the widest option
   row ("$10,000 - $100,000" and its count) measures 179px, and at 200 the
   panel still stands 747.6px tall with nothing wrapped. So it starts at
   200 and reaches its authored 248/36 by 1181, where it stays. Measured
   after: plate 211.0 at 941, 231.8 at 1024, 270.8 at 1180, 271.0 at 1181
   — monotonic, and nothing at or above 1181 moves. */
@media (min-width: 941px) {
  .browse-layout {
    grid-template-columns: clamp(200px, calc(200px + (100vw - 941px) * 0.2), 248px) 1fr;
    gap: clamp(24px, calc(24px + (100vw - 941px) * 0.05), 36px);
  }
}
.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(--focus-ring); 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 — the house's own letter */
  content: "";
  width: 7px; height: 6px;
  background: var(--on-ink);
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}
.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(--mark-holo) 0%, var(--mark-holo) 34%, var(--mark-holo-lit) 50%, var(--mark-holo) 66%, var(--mark-holo) 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: none; }
}

/* ============================================================
   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 color-mix(in srgb, var(--dark) 30%, transparent));
  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: 14px 16px 12px; background: var(--wash); }
.bidlabel {
  display: block;
  margin-bottom: 7px;
  font-size: var(--fs-100);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--mut);
}
/* The consignment wizard used to borrow the auction bid-mode class for
   its graded/raw question. Keep the house radio treatment without leaving
   a dormant bid-mode hook behind. */
.cw-radios {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  margin-bottom: 10px;
}
.cw-radios label {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-300);
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}
.cw-radios input {
  appearance: none;
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  margin: 0;
  border: 1px solid var(--line2);
  background: var(--panel);
  display: inline-grid;
  place-content: center;
  transition: border-color var(--dur-fast) var(--ease);
}
.cw-radios input::before {
  content: "";
  width: 9px;
  height: 8px;
  background: var(--ink);
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
  transform: scale(0);
  transition: transform var(--dur-fast) var(--ease);
}
.cw-radios input:hover { border-color: var(--ink2); }
.cw-radios input:checked { border-color: var(--ink); }
.cw-radios input:checked::before { transform: scale(1); }
.cw-radios input:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.cw-radios em { font-style: normal; font-weight: 400; color: var(--mut); }
@media (max-width: 720px) {
  .cw-radios label { min-height: 44px; }
}
.bidrow { display: flex; gap: 10px; }
.bidrow .amt {
  flex: 1;
  position: relative;
}
.bidrow .amt input {
  width: 100%; height: 48px;
  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: 48px; padding: 0 24px; }
/* 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: 8px; 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: 8px; line-height: 1.4; }
#bidcalc { color: var(--ink2); }
/* Reserve the compact minimum line so live updates do not move the panel. */
#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); position: relative; overflow: hidden; }
/* The ownership moment — one of the material direction's sanctioned
   signature surfaces: a single foil hairline over the chip that says the
   lot is yours. On the edge, never behind the words; the state itself is
   carried by the copy and the green, not by this. */
.bidstate.win::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background-image: var(--foil-spectrum);
  opacity: .55;
  pointer-events: none;
}
/* And the watched card's edge: the existing top rule reads a step
   stronger on a lot this collector has starred. Decoration echoing the
   star — the star itself carries the state. */
.lotcard:has(.watch.on)::before { opacity: .55; }
.bidstate.out { display: block; background: var(--live-tint); color: var(--live); }
.bidstate.confirm { display: block; background: var(--wash); color: var(--ink2); }
/* tabs */
/* FOUR TABS, NEVER A SIDEWAYS SCROLL.
   This strip sits in the lot column, which is about 400px on a 1024px
   laptop. The three base tabs leave room for the optional Catalogue note;
   a fifth control used to run past the rail and cut off mid-word behind a
   scrollbar nobody looks for. Population belongs in Market, and the
   labels and spacing stay terse. Wrapping is the fallback rather than
   scrolling: a second row is visible and obvious, a horizontal scroll is
   neither. */
.lot-tabs { margin-top: 28px; border-bottom: 1px solid var(--line); display: flex; flex-wrap: wrap; gap: 1px; }
.lot-tabs button {
  font-family: var(--font-d);
  font-weight: 700; font-size: 13px;
  padding: 8px 10px;
  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: 14px; }
.tabpane.active { display: block; }

.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; }
/* .cvenue: tombstone — no markup renders a comps venue cell any more. */

/* With the bid graph retired, Market opens directly on its evidence.
   Keep that first panel on the tab rail and let the table follow without
   the two stacked margins that used to make room for the chart. */
#pane-market > .fmvpanel:first-child { margin-top: 0; }
#pane-market > .compstable { margin-top: 0; }
#pane-market > .fmvpanel + .compstable { margin-top: 0; }
#pane-market > .compstable td { padding-block: 8px; }

.bidhist { list-style: none; }
.bidhist li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  column-gap: var(--s-3); row-gap: 2px;
  padding: 8px 2px;
  border-bottom: 1px solid var(--line);
  font-size: var(--fs-300);
  align-items: baseline;
}
.bidhist .who { min-width: 0; overflow-wrap: anywhere; font-weight: 600; }
.bidhist .who .you { color: var(--up); }
.bidhist .amt { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.bidhist .when { color: var(--mut); font-size: var(--fs-200); white-space: nowrap; }

/* 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; }
/* The smallest copy on the site was running the longest line: measured
   at 1440 and again at 2560, these rules set 12.5px type across 1182px,
   about 190 characters, and the eye loses the start of the next line on
   the way back. The measure is stated per tier in this file rather than
   globally (68ch for the 16px contract prose, 760px for the 13.5px
   note); 880px is this tier's, measured so the two longest rules —
   extended bidding at 754px and reserves at 843px — still set on one
   line and only the genuinely long ones fold. */
.shiprow p { font-size: 12.5px; color: var(--mut); margin-top: 3px; line-height: 1.55; max-width: 880px; }
.shiprow p b { font-weight: 700; color: var(--ink2); }
#pane-ship .shipblock { gap: 10px; }
#pane-ship .shiprow { padding: 12px 14px; }

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

/* ============================================================
   MODALS / TOASTS
   ============================================================ */
.overlay {
  position: fixed; inset: 0;
  background: var(--overlay);
  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: var(--shadow-2);
  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;
  gap: 12px;
  min-width: 0;
  padding: 18px 22px;
  border-bottom: 1px solid var(--line);
}
.modal .m-head b { min-width: 0; overflow-wrap: anywhere; font-family: var(--font-d); font-weight: 800; font-size: 16px; font-stretch: 108%; }
/* 40px, not 32: this is the control a phone must hit to leave a dialog. */
.modal .m-close { width: 40px; height: 40px; 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; }
/* The withdraw dialog now carries two notes — the caution, then the fine
   print — and butted together they read as one paragraph, which is the
   thing lifting the caution out was meant to stop. */
.modal .m-note + .m-note { margin-top: 10px; }
.modal-actions {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-2); margin-top: var(--s-4);
}
.modal-actions .btn { width: 100%; white-space: normal; }
.unlink-address { overflow-wrap: anywhere; word-break: break-all; }

/* Payment-sheet variant: embedded content runs edge to edge, the header
   sheds its rule, and the whole thing reads as one surface. The overlay
   spends almost all of the viewport on the provider instead of putting
   a second page's worth of scrolling inside a short dialog. */
.overlay.sheet-overlay {
  align-items: center;
  padding: max(12px, env(safe-area-inset-top)) 12px max(12px, env(safe-area-inset-bottom));
  overflow: hidden;
}
.modal.sheet {
  display: flex; flex-direction: column;
  max-width: 640px;
  height: min(924px, calc(100vh - 24px));
  height: min(924px, calc(100dvh - 24px));
}
.modal.sheet .m-body { padding: 0; flex: 1 1 auto; min-height: 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: var(--band-fg); background: var(--band-surface);
  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; }
/* The review dialogs' action pair: commit carries the amount, Cancel is
   a visible way out — never only the header X. */
.m-btnrow { display: flex; gap: 10px; margin-top: 2px; }
.m-btnrow .btn { flex: 1; }
.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;
}
/* The control that vouches for a crypto address gets a real hit area:
   the text alone measured 35×18px. Negative margin keeps the row's
   visual rhythm while the touch target meets the floor. */
.paybox .copybtn, .copybtn {
  flex: none; font-size: 11.5px; font-weight: 700; color: var(--ink);
  letter-spacing: 0.04em; min-height: 44px; min-width: 44px;
  display: inline-flex; align-items: center; justify-content: center;
  margin: -12px -8px; padding: 12px 8px;
}
.paybox .copybtn:hover, .copybtn:hover { text-decoration: underline; }
/* .paybox .pfoot: tombstone — the paybox footer row left the markup. */
.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; }
@media (max-width: 540px) {
  /* A receive address is verified by its TAIL, and the ellipsis was
     eating exactly that on phones: wrap the full value instead. And a
     wallet-panel header row wraps as a row, never mid-figure. */
  .paybox .addr code { white-space: normal; word-break: break-all; }
  .paybox .prow { flex-wrap: wrap; row-gap: 4px; }
  .paybox .pamt { white-space: nowrap; }
}
/* .ratefoot: tombstone — the onramp rate footnote left the markup. */

.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: 1px solid var(--dark-line);
  border-radius: var(--r-0);
  padding: 13px 16px;
  font-size: 13.5px;
  box-shadow: var(--shadow-2);
  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; }
/* The fee schedule is a long reference table inside a compact dialog. Keep
   its rows readable but dense, and let the worked example carry the section
   gap instead of a stack of one-off inline margins. */
.fee-dialog .eyebrow { margin: 0 0 8px; }
.fee-dialog .feetable td { padding-top: 12px; padding-bottom: 12px; }
.fee-dialog-note { margin: 8px 0 16px; color: var(--mut); font-size: 12px; line-height: 1.45; }
/* The commercial term the whole page turns on — 0% seller commission —
   was set at 16px, a single point above body copy. It is the schedule's
   headline and reads as one. */
.feetable .ft-rate { font-family: var(--font-d); font-weight: 800; font-size: var(--fs-600); letter-spacing: -0.01em; 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; }
/* A RATE CARD IS A PAIR. The bracket and the figure it buys are one row,
   and left in auto layout the two-column ladders on /guide let the raise
   column start 811px into a 1214px band — 533px right of the longest
   bracket's ink, 708px on the fee table under it. The eye has to cross an
   empty half-band to join a number to what it applies to. Give the
   bracket column its measure and the figure comes to meet it; the panel
   keeps the band, so it still lines up with the rule above it. The :has()
   guard leaves sell.html's three-column schedule alone — its notes column
   earns the full band — and below 900px the ladder needs every pixel and
   the wrap rule owns it. */
@media (min-width: 900px) {
  .guide-tablewrap .feetable:not(:has(thead th:nth-child(3))) th:first-child,
  .guide-tablewrap .feetable:not(:has(thead th:nth-child(3))) td:first-child { width: 34%; }
}
.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; }
/* min-width: 0, or a grid item's implicit floor is its content's
   max-content — the v1.4 TOC's longest section title drove the stacked
   phone layout to 440px inside a 390px viewport, and the whole document
   scrolled sideways to reach it. The labels wrap instead. */
.legal-layout > * { min-width: 0; }
.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); }
  /* four then three: seven in three columns is 3 + 3 + 1, the orphan
     again one band down. See the note at .cattiles. */
  .cattiles { grid-auto-flow: row; grid-template-columns: repeat(4, 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; }
  /* THE LOT NAMES ITSELF FIRST, AT EVERY WIDTH THE HERO STACKS AT.

     `.hero-media { order: -1 }` used to stand here and put the card above
     the copy for the whole stacked band, while a second pair of order
     rules at 720 put the copy back on top for phones. That left exactly
     one band — 721 to 940, which is every iPad in portrait — opening on
     stage light and slab art with the lot's name, its price, its
     countdown and both buttons below the fold: measured, .hero-copy's top
     was 1015px against a 900px viewport at 721, 768 and 820, against
     267px at 720 and below. The marquee lot was anonymous on the one
     screen it exists to introduce itself on.

     index.html puts .hero-copy before .hero-media, which is the order the
     page should read in, so the fix is to stop overriding it: markup
     order is the only order now, at every width, and the object still
     follows immediately underneath. The 720 pair below is a no-op kept
     for the record.

     Deleted with it: `.hero-media .slabwrap { width: min(300px, 70%) }`,
     which never once applied. The salon layer's own
     `.hero-media .slabwrap { width: min(400px, 86%) }` is the same
     specificity and later in the file, so it won at every width — the
     holder measured 400px at 600, 768, 820 and 940. With the copy leading
     again there is no reason to shrink the merchandise here, so the dead
     line goes rather than being made live. */
  .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; }
  /* A phone's footer is an index, not a monument: the link groups pack
     two-up, the brand and the Hobby Brief span the row, and the vertical
     rhythm halves — it measured 827px tall at 375 with a full page above
     it. Priority order is the markup's own: brand, then the groups, then
     the signup. */
  footer.site .cols { grid-template-columns: 1fr 1fr; gap: 18px 24px; padding: 32px 0 24px; }
  footer.site .brandcol, footer.site .briefcol { grid-column: 1 / -1; }
  footer.site .cols h2 { margin-bottom: 6px; }
  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; }
  /* Scoped to the masthead: bare .searchbox also matches the archive's
     search form, where `order: 3` moved the query field BEHIND its own
     Search button at every width under 1160. */
  .masthead .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-auto-flow: row; grid-template-columns: repeat(2, 1fr); }
  /* the odd tile at the end closes the index across the measure rather
     than sitting beside an empty track */
  .cattile:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .band-head h1, .band-head h2 { font-size: var(--fs-600); }
  .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); }
  /* THE AUCTION COLUMN STAYS ON A PHONE, AND THIS IS WHY.

     It used to be display:none here, header and all. The column carries
     the sale's name — and, on the home band, the word "demonstration",
     which js/home.js prints into this cell for every fixture row with the
     comment "printed, not implied by styling, so a screen reader and a
     sceptic read the same caveat". display:none takes an element out of
     the accessibility tree as well as off the page, so below 720px a
     demonstration sale was published with the caveat removed from both:
     on a phone the fixture rows and the real ones were indistinguishable,
     and .rt-fixture carries no styling of its own to tell them apart.

     A disclosure is not a column that may be dropped for width. What the
     ledger does below 620px instead is in the stacked-record block at the
     foot of this file: the row becomes a small record, the title takes
     the full measure, and the three figures label themselves. Four
     columns are kept between 621 and 720 by letting the sale name wrap;
     the two cells that must never break, a price and a date, keep their
     nowrap. */
  .resulttable .rt-auction { white-space: normal; word-break: normal; }
  .resulttable th:nth-child(4), .resulttable .rt-auction { font-size: var(--fs-200); }
  .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; }
  /* And the consignment wizard's submit, whose label is a sentence:
     "Submit for specialist review" measures 268px inside the 267 the
     wizard has at 320, and the page scrolled a pixel sideways for it. */
  .cw-form .btn.xl { 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; }
/* The row's other items flex; the submit's word does not. Without this the
   744px row shrank the button under "Search" and sheared the h off. */
.arc-inputrow .btn { flex: none; }
.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); }
/* THE WELL IS THE RATIO, NOT THE PHOTOGRAPH.

   The aspect-ratio here was already right and was already losing. This is
   a column flex item, so its automatic minimum size is its CONTENT, and a
   scan taller than the ratio pushed the well open rather than being fitted
   into it: measured at 1440 on the seeded archive, six wells in one row
   came out 241.9, 247.6, 251, 291.3 and 315.9 tall, and the metadata under
   them started on five different baselines up to 74px apart. A ruled
   catalogue index whose rules do not line up is the one thing this grid
   cannot be.

   min-height: 0 gives the ratio back its authority; with the height now
   definite, the img's own `max-height: 100%` below finally resolves and
   the scan is fitted rather than accommodated. It also fixes the well's
   height before the image loads, so the row no longer reflows on arrival. */
.arc-img {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 5 / 6.4;
  min-height: 0;
  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 color-mix(in srgb, var(--dark) 20%, transparent); }
.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);
  /* Sentence case: "No public scan on record" is a fact about the
     archive, and uppercase dressed it as an error plate. */
  color: var(--mut); font-size: 11px; letter-spacing: 0.02em; 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-family: var(--font-m); font-weight: 500; font-size: var(--fs-300); color: var(--ink); margin-top: 2px; }
/* The source label beside it stays in the body face. It is prose, not a
   figure, and inheriting the mono turned "TCGplayer market" into terminal
   output. */
.arc-price em { font-family: var(--font-b); 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 color-mix(in srgb, var(--dark) 24%, transparent); }
.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; }

/* One row needs ~700px of content: the query field's useful minimum plus two
   full-label selects plus the button. Below 960 the field takes its own deck —
   at 744 the single row had squeezed the query field to 60px and the button
   under its own word. */
@media (max-width: 960px) {
  .arc-inputrow { flex-wrap: wrap; }
  .arc-inputrow .searchbox { flex-basis: 100%; }
  .arc-inputrow .sortsel { flex: 1; }
}
@media (max-width: 720px) {
  .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, reserve chips,
   extended bidding, specialist card, catalogue notes
   ============================================================ */
/* --font-serif moved to the one token block at the head of the file. */

/* 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: tombstone — the sale-number block left the markup. */

/* 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; }
/* THE SPECIALIST'S CONTROL KEEPS ITS WHOLE LABEL.
   The phone type floor at the foot of this file raises this button from
   10.5px to 12px, and .btn is nowrap, so the row ran out of width before
   the word did: measured on a lot page, "Ask a question" needs 136px of
   content box at 320 and gets 113, 144/130 at 360, 147/136 at 375 and
   151/142 at 390 — the plate reads "ASK A QUESTIO" on every phone in
   common use. It fits from 430 up. So on the phone the card stacks: the
   name and its line keep the first row and the control takes the second
   at its natural width. Nothing moves at desktop, where it already fits. */
@media (max-width: 420px) {
  .speccard { flex-wrap: wrap; row-gap: 12px; }
  .speccard .btn { flex: none; margin-left: 0; }
}
/* ---------- the reader's own thread with the desk ----------
   It sits directly under the specialist card and belongs to it: same
   panel ground, same hairline, joined to the card by having no gap of
   its own above. Hidden entirely when there is nothing in it — an
   empty heading under a card is a promise the page cannot keep.

   Nothing here is public. The server serves an account its own rows
   and no others, so this region can never show one bidder what another
   asked, and the answer is set as speech from the house rather than as
   a status: it is a sentence a person wrote. */
.specthread { border: 1px solid var(--line); border-radius: var(--r-m); background: var(--panel); padding: 2px 16px 14px; margin: 10px 0 4px; }
.specthread-h { font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 700; color: var(--mut); margin: 14px 0 10px; }
.specq + .specq { border-top: 1px solid var(--line); margin-top: 12px; padding-top: 12px; }
.specq-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.specq-head time { font-size: var(--fs-100); color: var(--mut); font-variant-numeric: tabular-nums; }
.specq-state { font-size: 10.5px; letter-spacing: 0.07em; text-transform: uppercase; font-weight: 700; color: var(--mut); }
.specq-state.ans { color: var(--up); }
.specq-body { font-size: 13px; line-height: 1.6; color: var(--ink); margin: 6px 0 0; white-space: pre-wrap; }
/* The desk's reply is set in the house serif and carries the brass rule
   the letters use for the same job: it is the house speaking, and it
   should not read like another line of the reader's own note. */
.specq-answer { border-left: 2px solid var(--brass); padding-left: 12px; margin-top: 10px; }
.specq-answer b { display: block; font-size: 10.5px; letter-spacing: 0.07em; text-transform: uppercase; color: var(--brass-ink); }
.specq-answer p { font-family: var(--font-serif); font-size: 14px; line-height: 1.65; color: var(--ink); margin: 4px 0 0; white-space: pre-wrap; }

.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; }
/* The 18px rule is a link from one step to the next. Once the four steps
   stop sharing a row the last rule on every wrapped line points at
   nothing — a connector into the margin. Read vertically the ladder does
   not need it; the padding still spaces the steps. */
@media (max-width: 720px) {
  .cw-steps li:not(:last-child)::after { content: none; }
}

.cw-grid { display: grid; grid-template-columns: 1fr 300px; gap: 34px; align-items: start; }
/* min-width: 0, same reason as .legal-layout's: a grid item floors at
   its max-content without it, and the graded/raw chip row is the widest
   unbreakable thing on a 320px phone — the whole document scrolled a
   pixel sideways to honour it. */
.cw-grid > * { min-width: 0; }
.cw-form .field { min-width: 0; }
.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: tombstone — the wizard footnote left the markup; the print
   list below keeps the name so an old cached page still prints clean. */
.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; }
/* The intake address is a postal block, not a sentence: the line breaks
   the house wrote are the ones that go on the parcel. */
.cw-addr { white-space: pre-line; line-height: 1.45; }
.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 squared at the component site. */

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

/* one visible focus language everywhere — no default blue ring.
   The list is the register of everything interactive; a control that
   is not on it (or covered by the global rule at the head of the
   file) is a defect. The audit found a dozen absent — providers,
   the modal close, the copy button, the theme options, the whole
   portfolio control rail — and they are on the roll now. */
.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, a.pf-cardtitle:focus-visible,
.mh-dateopen:focus-visible, .mh-cal-day:focus-visible, .mh-cal-btn:focus-visible,
.provider:focus-visible, .watchrow button:focus-visible, .modal .m-close:focus-visible,
.paybox .copybtn:focus-visible, .copybtn:focus-visible, .toast .tact:focus-visible,
.legal-toc a:focus-visible, .themepop button:focus-visible, .acct-row:focus-visible,
.iconbtn:focus-visible, .utilbar nav a:focus-visible, .utilink:focus-visible,
.catbar button:focus-visible, .pchart-windows button:focus-visible,
.filter-toggle:focus-visible, .pf-privtoggle:focus-visible, .pf-chips button:focus-visible,
.pf-densbtn:focus-visible, .pfoe-x:focus-visible, .peerframe-out:focus-visible,
.bidrow .amt input:focus-visible,
.cw-check input:focus-visible, .acct-check input:focus-visible,
input[type="range"]:focus-visible, .fundpresets button:focus-visible,
.crumbbar a:focus-visible, .lot-thumbs button:focus-visible,
.pf-importrow input[type="file"]:focus-visible {
  outline: 2px solid var(--focus-ring);
  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 */
.sellhero :focus-visible, .consign :focus-visible,
footer.site :focus-visible, .utilbar :focus-visible { outline-color: var(--band-fg); }
/* The signed-in account link is more specific than `.utilbar :focus-visible`
   (`.utilbar nav a:focus-visible` is also present in the focus register), so
   name it at the same specificity here. Otherwise the day rooms draw their
   near-black --focus-ring on the permanently dark utility band. */
.utilbar nav a:focus-visible { outline-color: var(--band-fg); }

/* 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. */
/* 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;
}
.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: 0; width: 10px; height: 9px;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}

/* 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 */
@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); width: 11px; height: 11px; }
.facet .opt input:checked + .box.radio::after { width: 6px; height: 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; }

/* ============================================================
   Shared material system.

   Neutral surfaces carry the content. Foil appears on narrow frame,
   navigation and selected-state edges, plus the featured slab mount.
   Dark editorial bands use the low-opacity material tint so Midnight's
   mineral hues and Vault's patina remain distinct across the site.
   Prices, status fills, field interiors, focus rings and collectible
   images keep flat, legible colors. The original masthead logo has its
   own unchanged foreground roles and receives no foil layer.

   Decorative layers never intercept input. Nothing shimmers continuously;
   existing pointer responses stand down under reduced motion.
   ============================================================ */

body {
  position: relative;
  isolation: isolate;
  min-height: 100vh;
  background: var(--canvas);
}
/* Paper's fibre. A room that owns no grain sets --grain-opacity to 0 and
   this layer paints nothing; no rule names a room. Fixed, monochrome,
   soft-light, and still. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--grain) 0 0 / 160px 160px;
  mix-blend-mode: soft-light;
  opacity: var(--grain-opacity);
}


/* .rchip.notmet needs no night patch now that it is --warn on --warn-tint:
   both tokens are already retuned per theme. */
/* 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. */
/* .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(--surface-raised); border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-2); min-width: 212px; 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(--text-muted); padding: 7px 14px 3px; }
.themepop button {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  padding: 8px 14px; font-size: 12.5px; font-weight: 600; color: var(--text-primary);
}
.themepop button:hover { background: var(--surface-2); }
/* THE SWATCH IS THE ROOM. Each swatch carries its own room's roles (the
   theme blocks at the head of this file scope to .tp-swatch.<room>), so
   what it shows is the room's actual canvas, its surface plate, its
   accent and its foil — read from the same declarations that paint the
   page, never from a copy. Two pseudo-elements and a border: the plate
   with its accent chip (one gradient layer over the surface), and the
   room's foil as a hairline along the foot. */
.tp-swatch {
  flex: none;
  position: relative;
  width: 32px; height: 22px;
  overflow: hidden;
  background: var(--canvas);
  border: 1px solid var(--border-strong);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--surface-raised) 50%, transparent);
}
.tp-swatch::before {
  content: "";
  position: absolute;
  left: 5px; top: 4px;
  width: 15px; height: 11px;
  border: 1px solid var(--border-subtle);
  background:
    linear-gradient(var(--accent), var(--accent)) right 1px top 1px / 4px 4px no-repeat,
    var(--surface-1);
  box-shadow: var(--shadow-1);
}
.tp-swatch::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--foil-spectrum);
  background-size: 300% 100%;
  background-position: 50% 50%;
}
/* Checked is three things, none of them a hue: the swatch takes a 2px
   ring in the room's ink, the name goes to the heavier weight, and a
   drawn check sits at the row's end. aria-checked is the state the
   shell paints (js/shell.js paintThemeRadios), so every control that
   shows the set agrees with the document by construction. */
.themepop button[aria-checked="true"],
.morepop [role="radiogroup"] button[aria-checked="true"] { font-weight: 700; background: var(--surface-2); }
.themepop button[aria-checked="true"] .tp-swatch,
.morepop [role="radiogroup"] button[aria-checked="true"] .tp-swatch {
  outline: 2px solid var(--text-primary);
  outline-offset: 1px;
}
.themepop button[aria-checked="true"]::after,
.morepop [role="radiogroup"] button[aria-checked="true"]::after {
  content: "";
  flex: none;
  margin-left: auto;
  width: 6px; height: 11px;
  border: solid var(--text-primary);
  border-width: 0 2px 2px 0;
  transform: translateY(-2px) rotate(45deg);
}


/* The phone overflow. Hidden wherever the full action set fits; below
   540px it carries Portfolio, Info and the theme radios so the action
   row can share the wordmark's line. Same panel materials as the theme
   popover it partly replaces. */
.morebtn { position: relative; display: none; }
.morepop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  background: var(--surface-raised); border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-2); min-width: 216px; padding: 6px 0;
  display: none;
}
.morepop.open { display: block; }
.morepop > a {
  display: flex; align-items: center; min-height: 44px; padding: 0 14px;
  font-size: 13px; font-weight: 600; color: var(--ink);
}
.morepop > a:hover { background: var(--wash); }
.morepop .tp-h {
  display: block; font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  font-weight: 700; color: var(--mut); padding: 9px 14px 3px;
  border-top: 1px solid var(--line); margin-top: 4px;
}
.morepop [role="radiogroup"] button {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  min-height: 40px; padding: 0 14px; font-size: 12.5px; font-weight: 600; color: var(--text-primary);
}
.morepop [role="radiogroup"] button:hover { background: var(--surface-2); }


/* ============================================================
   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; }
/* The five group headings over the account stack; the negative bottom
   margin offsets the grid's 34px gap so a heading sits 12px above its
   first section rather than a full gap away. */
.acct-grid > h2.acct-group {
  font-size: 13px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink); margin: 12px 0 -22px;
}
/* Deadlines are --warn, never red: red stays reserved for a refusal. */
.acct-grid .acct-urgent b { color: var(--warn); }
.dash-plumb > summary { cursor: pointer; color: var(--mut); font-size: 12.5px; }
.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; }
.acct-layout > * { min-width: 0; }
@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; }
  /* scrollbar-gutter, because the rail's inner width was two different
     numbers depending on a setting the reader made in their operating
     system: with classic scrollbars 15-17px came off every child, which
     is what turned a date cell from one line into three. Reserving the
     gutter makes it measure the same for everyone.

     ON THE ACCOUNT RAIL ONLY, by id. `.acct-dash` is the portfolio's
     rail too (js/portfolio.js), and on a container that does not
     overflow `stable` reserves the gutter anyway — dead space on a rail
     whose problem this never was. The account card always scrolls: hero,
     money rows, escrow controls, the step list, the wallet list and the
     fine print exceed 980px on a 1080p screen. */
  #acct-dash { scrollbar-gutter: stable; }
}
.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 account rail is a ledger, not a row of portfolio headlines.
   Grid gives the label the flexible track and keeps the amount aligned
   without letting either item's min-content widen the 340px sidebar.
   The leverage rule is explanatory copy, so it gets its own compact
   two-line value instead of inheriting money-sized, no-wrap typography.
   Together these rules keep #acct-dash's scrollWidth equal to its
   clientWidth: overflow-y:auto must never silently become a horizontal
   scroller that lets a sideways swipe cut every label off the card. */
#acct-dash .dash-row:not(.dash-hero) {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
}
#acct-dash .dash-label, #acct-dash .dash-num { min-width: 0; }
#acct-dash .dash-num { text-align: right; }
#acct-dash .dash-tier { align-items: start; }
#acct-dash .dash-tier .dash-label {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-1);
}
#acct-dash .dash-tier .acct-chip { margin: 0; }
#acct-dash .dash-rate {
  display: flex; flex-direction: column; align-items: flex-end;
  max-width: 148px; white-space: normal; line-height: 1.2;
}
#acct-dash .dash-rate strong { font-size: var(--fs-500); font-weight: 700; }
#acct-dash .dash-rate small {
  font-size: var(--fs-200); font-weight: 500; line-height: 1.35; color: var(--mut);
}
/* 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; }
/* WITHDRAWING IS TWO TRANSACTIONS, and a bidder who thinks it is one
   believes step 1 finished it. It did not: step 1 starts a timelock and
   removes the amount from bidding power, and only step 2 moves USDC to
   the wallet — until it confirms, a lock can still draw the pending
   amount back into collateral.
   Two numbered rows rather than another sentence, because structure
   states "you are not done" more reliably than prose a bidder skims. The
   live row is the only one that takes --ink and the caution colour, so
   the eye lands on the step still owed.
   Not the marketing `.steps` grid: that is a four-across band with 22px
   padding and a display face, built for the guide page. This lives in a
   dense money panel and borrows its rules from .dash-line's tier. */
.esc-steps { list-style: none; margin: var(--s-3) 0 0; padding: 0; border-top: 1px solid var(--line); }
.esc-steps li { display: flex; align-items: baseline; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--line); font-size: var(--fs-200); line-height: 1.5; }
.esc-steps b { font-weight: 600; color: var(--mut); }
/* NO --faint here, and the temptation was real: a settled row "wants" to
   recede further. --faint measures 3.59:1 on --panel against a 4.5 floor
   for body text, which this is — the same finding the .dash-fine comment
   above records. The settled row keeps --mut and the live row takes --ink;
   that step is enough to separate them without dropping a real sentence
   about a bidder's money below AA. */
.esc-steps .st { margin-left: auto; color: var(--mut); text-align: right; }
.esc-steps .now b { color: var(--ink); }
.esc-steps .now .st { color: var(--warn); }
/* The consequence, once, under the rows it belongs to. */
.esc-steps + .esc-after { margin: 10px 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: 0;
  padding-top: var(--s-3);
  border-top: 0;
}
#escrow-panel > :first-child { margin-top: 0; }
.dash-money-actions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-2);
  margin-top: 0;
}
.dash-money-actions .dash-money-action {
  width: 100%; min-height: 52px; padding: 12px 10px;
  font-size: 12px; letter-spacing: .08em;
}
.dash-action-wrap { position: relative; min-width: 0; display: block; }
/* Production funding controls remain focusable while unavailable, with
   their existing reason reachable by hover, keyboard focus, and touch. */
.dash-action-tip {
  position: absolute; left: 0; top: calc(100% + 7px); z-index: 8;
  width: max-content; max-width: min(260px, calc(100vw - 48px));
  padding: 7px 9px; background: var(--ink); color: var(--on-ink);
  box-shadow: var(--shadow-1); font-size: var(--fs-100); line-height: 1.4;
  letter-spacing: normal; text-transform: none;
  opacity: 0; pointer-events: none; transform: translateY(-3px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.dash-action-wrap:last-child .dash-action-tip { left: auto; right: 0; }
.dash-action-wrap:hover .dash-action-tip,
.dash-action-wrap:focus-within .dash-action-tip { opacity: 1; transform: none; }
.dash-action-reason {
  display: block; margin-top: var(--s-2); color: var(--mut);
  font-size: var(--fs-100); line-height: 1.4;
  letter-spacing: normal; text-transform: none; overflow-wrap: anywhere;
}
.dash-action-reason-shared { grid-column: 1 / -1; margin-top: 0; }
@media (max-width: 360px) {
  .dash-money-actions { grid-template-columns: 1fr; }
  .dash-action-wrap .dash-action-tip { left: 0; right: auto; }
}
.dash-secondary-actions { margin-top: var(--s-3); }
.wallet-link-note { margin-top: var(--s-2); }
.dash-wallets {
  list-style: none; padding: 0;
  border-top: 1px solid var(--line); margin: var(--s-4) 0 0;
}
/* 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; }
.dash-wal-primary { justify-self: end; color: var(--mut); font-size: var(--fs-100); }
/* 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);
}
.dash-wallet-action {
  flex-direction: column; align-items: stretch;
  margin-top: var(--s-4); padding-top: var(--s-4);
  border-top: 1px solid var(--line);
}
.dash-wallet-action .linkline { align-self: flex-start; }
/* 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: var(--shadow-2);
  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; }
/* A CARD'S OWN NAME IS THE LONGEST THING IN ANY OF THESE TABLES, and it
   is the one cell that can afford an ellipsis: the reference beside it
   identifies the row and the whole title is one click away. Without a
   ceiling the Submitted-for-review table drew 1,097px inside 834 at
   1280 and scrolled sideways on a page whose complaint was that it felt
   cramped. Measured against the account column at its narrowest
   two-column width, not against the widest. */
/* IT WRAPS, IT DOES NOT CLIP. An ellipsis here would be shearing: this
   table carries no title attribute and no expander, so a clipped name
   would be a value with no way back to it — which is the rule
   tools/table-fit.js exists to enforce, and it fails the sweep loudly.
   Two lines of card name in a submissions table costs a row's height
   and loses nothing. */
.acct-table td.acct-cardcell { white-space: normal; max-width: 240px; }
/* Two status chips are two words, and nowrap made them one 336px line.
   They are the only cells on the page carrying more than one chip, so
   they wrap where a money figure or a date never may. */
.acct-table td.acct-chipcell { white-space: normal; max-width: 220px; }
/* "$200 remained pending" is a sentence with a figure in it, and .num
   pins a cell nowrap below 860px so a price can never shatter. Pinned,
   this one pushed the withdrawal-changes table past a phone's width. It
   keeps the column's right alignment and gives up the pin. */
.acct-table th.acct-pendcell, .acct-table td.acct-pendcell { text-align: right; white-space: normal; }
/* The two chain ledgers are siblings in .acct-grid, and a grid gap
   cannot reach between two <section>s inside one host div. */
#acct-escrow-log > section + section { margin-top: var(--s-6); }
.acctlink { font-weight: 700; }



/* ============================================================
   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); }
/* Air, in both directions. The chips sat 2px apart and the strip's rule
   pressed straight against the section row above, so the tier read as a
   second line of the same nav rather than the quieter row inside it.
   Six pixels above and below let the chips float in their band; a full
   spacing step between them lets each be read as its own word; and the
   chip's inset matches the section row's (16px), so "All" starts under
   "Auction" instead of four pixels proud of it. The same numbers serve a
   phone: the strip scrolls sideways there, and the touch floor is the
   chip's own 44px, not the band's. */
.catbar .wrap { display: flex; align-items: center; gap: var(--s-2); overflow-x: auto; scrollbar-width: none; padding-top: 6px; padding-bottom: 6px; }
.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 16px; 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; }
/* A CATEGORY WITH NOTHING IN IT IS STILL A CATEGORY.
   At 0.34 the chip measured 1.68:1 against the strip behind it — dim past
   reading, so an empty category read as a smudge rather than as a room
   with nothing in it today. It is still unmistakably disabled: it carries
   the disabled attribute, it takes no pointer, its count says 0, and at
   0.55 it sits at less than half the ink of the chips beside it (2.46:1
   against their 6.x). WCAG 2.2 1.4.3 exempts an inactive component from
   the 4.5 floor, which is the only reason this is allowed to sit under
   it; dimming further is what the exemption permits, not what it asks
   for. */
.catbar button:disabled { opacity: 0.55; cursor: default; }

.browse-toolbar { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.browse-toolbar .count { margin-right: auto; }
/* THE OFFER LINE.

   A fixed-price listing's bottom rail. It has been, in order: a green
   tracked-caps word in the display face, and then the same word with a
   state diamond in front of it — availability dressed first as a gain
   and then as a dashboard status. Neither is what a house says. A
   catalogue does not stamp AVAILABLE on a plate; it tells you, in its
   own voice, that the piece can be had.

   So the row is set as catalogue matter: the serif, italic, at reading
   size, in the room's own ink. The only ornament is the house's one
   decorative motif — a short rule of the room's foil, its whole
   spectrum compressed into fourteen pixels the way the kit's gem holds
   a scheme in one small stone. It sits on the baseline beside the
   phrase like a printer's dash, and it is the only thing on the card
   besides the plate's top edge that carries colour.

   Colour says nothing here. The pending state is the same line held
   quieter, and a closed listing keeps the muted words it always had:
   nothing on this row needs a hue to be understood, which is why it
   finally reads as an auction house rather than a status board. */
.lotcard .bnstate {
  display: inline-flex; align-items: baseline; gap: 9px;
  font-family: var(--font-serif);
  font-weight: 500;
  font-style: italic;
  font-size: 13.5px;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink2);
}
.lotcard .bnstate.avail::before {
  content: "";
  flex: none;
  width: 15px; height: 2px;
  align-self: center;
  background-image: var(--foil-spectrum);
  background-size: 320% 100%;
  background-position: 50% 50%;
}
/* Held, not offered: the rule steps back to a hairline of the room's
   own line colour and the phrase goes quiet with it. */
.lotcard .bnstate.pending { color: var(--mut); }
.lotcard .bnstate.pending::before {
  content: "";
  flex: none;
  width: 15px; height: 1px;
  align-self: center;
  background: var(--line2);
}
.lotcard.buynow.closed .bnstate { color: var(--mut); font-style: italic; }
.soldtag.pending { background: var(--accent); color: var(--accent-foreground); }

/* 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); grid-template-columns: minmax(0, 1fr); }
.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: 100%; }

@media (max-width: 620px) {
  .overlay.sheet-overlay { padding: 0; }
  .modal.sheet {
    width: 100%; max-width: none;
    height: 100vh;
    height: 100dvh;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .modal.sheet .m-head {
    min-height: 58px;
    padding: max(8px, env(safe-area-inset-top)) 12px 8px 16px;
  }
  .peerframe { height: 100%; }
}

/* 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;
  /* the cover wears the room, not white — a white flash was the one
     moment the night rooms broke character. The FRAME below stays
     white: the remote checkout paints white and pretending otherwise
     would flash at handover instead. */
  background: var(--panel);
  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: 9px; height: 8px;
  background: var(--brass); margin-right: 18px;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}
/* The separator is the mark now. The diamond was the gem out of the
   M's valley; the whole mini M takes its place — the same letterform
   the masthead, the loader and the brand kit carry, struck small in
   brass. Nine pixels wide, because the chamfer and the gem punch have
   to survive: any smaller and it reads as a smudge, any bigger and
   punctuation starts shouting. 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 mark. */
.sep:empty {
  display: inline-block; width: 9px; height: 8px;
  background: var(--brass); margin: 0 7px; vertical-align: middle;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}
/* Inside the micro lines the mark comes down a step, and inside a
   status chip it takes the chip's own voice — a fixed brass M inside
   a tinted chip would outrank the word it punctuates, and the status
   marks' rule is that everything in a chip is color:inherit. */
.fmvline .sep:empty, .pf-asof .sep:empty, .pf-cardmeta .sep:empty,
.pf-estmeta .sep:empty, .pf-estcell .sep:empty,
.pf-chgwin .sep:empty, .arc-meta .sep:empty,
.bb-note .sep:empty, .acct-sub .sep:empty, .status-facts .sep:empty,
footer.site .fine .sep:empty, .authfoot .sep:empty {
  width: 7px; height: 6px; margin: 0 4px;
}
.acct-chip .sep:empty, .arc-status .sep:empty, .rchip .sep:empty {
  width: 7px; height: 6px; margin: 0 4px;
  background: currentColor; opacity: .8;
}
/* 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; }
/* The datum label, in the house's own hand. This one was an eighth
   variant of a tier the file otherwise sets one way: 10.5px in the body
   sans at .1em, sitting a rail apart from .fmvpanel .fmvconf directly
   beneath it, which is fs-100 Archivo 600 at .08em — the same form as
   .pf-figlab, .pf-chgwin and .co-ordershead. One rank ruled by two hands
   in one column reads as assembled rather than typeset. */
.pchart-label {
  font-family: var(--font-d);
  font-size: var(--fs-100); font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--mut);
}
/* Money is set in the register hand. This figure is the SAME number as
   the bid box's, one rail away on the same page, and it was the only one
   of the pair not in the mono: 26px Archivo 800 beside 25px Plex Mono
   500, so the louder, heavier instance of "$8,200" was the chart's
   restatement rather than the control a bidder acts on. -.04em is not a
   new value either; it is what .bb-val and .hero .bidblock .val already
   carry, so the two now match exactly. */
.pchart-val {
  font-family: var(--font-m); font-weight: 500; font-size: var(--fs-700); line-height: 1.1;
  font-variant-numeric: tabular-nums; letter-spacing: -.04em;
}
.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; }
.pchart-data { margin: 0 8px 8px; border-top: 1px solid var(--line); }
.pchart-data > summary {
  list-style: none; min-height: 44px; display: flex; align-items: center;
  cursor: pointer; color: var(--mut); font-family: var(--font-d);
  font-size: var(--fs-100); font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase;
}
.pchart-data > summary::-webkit-details-marker { display: none; }
.pchart-data > summary:hover { color: var(--ink); }
.pchart-data > summary:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.pchart-data-table { max-height: 300px; overflow: auto; border-top: 1px solid var(--line); }
.pchart-data-table table { width: 100%; border-collapse: collapse; font-size: var(--fs-200); }
.pchart-data-table caption { padding: 10px 8px; text-align: left; color: var(--mut); }
.pchart-data-table th, .pchart-data-table td { padding: 7px 8px; border-top: 1px solid var(--line); text-align: left; }
.pchart-data-table th:last-child, .pchart-data-table td:last-child { text-align: right; font-variant-numeric: tabular-nums; }

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

/* .rt-demo (the bordered demo-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 — the
   mini M, quiet in --line2 here because these are the doors almost
   nobody needs and brass would promote them. */
.authsep {
  display: inline-block; width: 8px; height: 7px;
  background: var(--line2);
  margin: 0 2px; vertical-align: middle; flex: none;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}
#authlede { margin-bottom: 14px; }
#authmsg[role="alert"] { margin-top: 10px; color: var(--live); }
/* The enquiry dialog's refusal line, painted by the same rule the auth
   dialog's is. Id-scoped for the same reason: the element is a .m-note
   until something goes wrong, and only the alert state is red. */
#enq-note[role="alert"] { margin-top: 10px; color: var(--live); }
/* The two doors a signed-out reader is offered. Side by side on a
   laptop, stacked where .m-btnrow would run its two buttons under the
   phone type floor. */
.enq-doors { display: flex; gap: 10px; margin: 16px 0 4px; }
.enq-doors .btn { flex: 1; }
@media (max-width: 420px) { .enq-doors { flex-direction: column; } }
/* The enquiry dialog's own rhythm. .m-note carries no margin except
   between consecutive notes, which is right for a dialog that is all
   prose and wrong for one that alternates a line of prose, a field, a
   counter and a control: the label sat on the note above it and the
   send button sat on the sentence above that. Stated once here rather
   than as five inline styles at the call site. */
.enqform .field { margin-top: 16px; }
.enqform .btn.full { margin-top: 18px; }
.enqform .btn.full + .m-note { margin-top: 12px; }
.enqform > p:not(.m-note) { margin-top: 12px; line-height: 1.6; }

/* ============================================================
   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;
}
/* THERE IS NO DIAMOND HERE ANY MORE. It is the house's own letter.

   The history is worth keeping, because it explains the shape of this
   rule. The mark began as a 5px square under transform: rotate(45deg);
   a transform does not change layout, so the rotated corners stuck out
   about 1px past the box on every side, and any ancestor with
   overflow: hidden sheared 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 points sliced
   flat on every page. clip-path fixed that by cutting the rhombus out
   of a box that already contained it.

   The mask now does the same job and answers the better question: a
   rotated square is the diamond every framework ships, and it said
   nothing about this house. `--mh-mark-mask` is the mini M — the same
   letterform as the masthead, the loader, `.sep` and `.assure` — struck
   at 8x7 so it keeps the 7px optical weight the chips were built
   around. Still entirely inside its own box, so the ticker fix holds.
   The colour is still the only thing a mark sets for itself. */
.livetag::before, .rchip::before, .extchip::before,
.acct-chip::before, .ad-chip::before {
  content: "";
  flex: none;
  width: 8px;
  height: 7px;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
  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); }
/* THE LIVE MARK IS THE HOUSE ITSELF. Every other chip keeps the state
   diamond; this one is the house announcing its own sale, so it wears
   the mini M — and not the flat gold one. It carries the room's foil
   compressed to one slice, the way the kit's gem holds the whole
   scheme in one small stone: ten pixels of spectrum beside the word
   LIVE, which pops on every ground precisely because nothing else at
   this size is allowed colour like it. The word carries the meaning;
   the mark signs it. */
.livetag::before {
  clip-path: none;
  width: 10px; height: 9px;
  background-color: transparent;
  background-image: var(--foil-spectrum);
  background-size: 340% 100%;
  background-position: 50% 50%;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}
/* 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: 7px;
  height: 6px;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
  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; }
.pf-dash-more > summary {
  list-style: none; min-height: 44px; display: flex; align-items: center;
  cursor: pointer; border-top: 1px solid var(--line);
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--mut);
}
.pf-dash-more > summary::after {
  content: ""; width: 7px; height: 7px; margin-left: auto; margin-right: 3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-2px); transition: transform 140ms ease;
}
.pf-dash-more[open] > summary::after { transform: rotate(225deg) translate(-1px, -1px); }
.pf-dash-more > summary::-webkit-details-marker { display: none; }
.pf-dash-more > summary:hover { color: var(--ink); }
.pf-dash-more > summary:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
@media (min-width: 1180px) { .pf-dash-more[open] > summary { display: none; } }

/* 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: 7px; height: 6px;
  margin-right: 6px; vertical-align: 0;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
  background: var(--mut);
}
.pf-conf.hi::before { background: var(--ink); }
.pf-conf.med::before { background: var(--brass); }
.pf-conf.low::before { background: var(--faint); }
/* No mark at all for no-figure states: an empty outlined box beside
   "No estimate" read as a broken glyph, and it carried no information
   the words do not. */
.pf-conf.none::before { content: none; }
.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;
  color: var(--mut);
}
/* The two cautionary kinds in --brass-ink, not --warn: the same word
   stands on the register's panel AND on the lot page's wash-tinted FMV
   panel, and --warn on paper's wash measures 4.02:1 at this size. One
   token that is AA on both surfaces (and --brass in the night rooms). */
.pf-evd.ask, .pf-evd.ovr { color: var(--brass-ink); }
.pf-evd.sale { color: var(--ink); }
.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-4); flex-wrap: wrap; margin-bottom: var(--s-3); }
@media (max-width: 620px) {
  .pf-chips {
    flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-inline: contain;
    scrollbar-width: thin; padding-bottom: 2px;
  }
  .pf-chips button { flex: 0 0 auto; }
}
/* Quiet catalogue tabs, the register's own voice — the pill row read
   as stock dashboard furniture. The chosen filter is ink over a brass
   rule; the rest are muted words. */
.pf-chips button {
  appearance: none; background: none; border: 0;
  padding: 10px 2px 8px; cursor: pointer;
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut);
  box-shadow: inset 0 -1px var(--line);
  transition: color var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
}
.pf-chips button:hover { color: var(--ink); }
.pf-chips button.on { color: var(--ink); box-shadow: inset 0 -2px var(--brass); }

/* density: compact halves the row air, nothing else changes. The
   toggle is a quiet word at the end of the line in the filter tabs'
   voice — the bordered box it wore made a third framed control on a
   line that already had two, and it is a preference, not a field. */
.pf-densbtn {
  appearance: none; background: none; border: 0; margin-left: auto;
  height: 44px; padding: 0 2px; cursor: pointer;
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--mut);
  text-decoration: underline; text-underline-offset: 4px;
  text-decoration-thickness: 1px; text-decoration-color: var(--line2);
  transition: color var(--dur-base) var(--ease), text-decoration-color var(--dur-base) var(--ease);
}
.pf-densbtn:hover { color: var(--ink); text-decoration-color: var(--ink2); }
.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 */
/* One height on the line. The search field, the sort select and the
   density toggle each arrived at their own height (41 / 44 / 31px) and
   the row read as three controls from three products; the select's 44
   is the house height for a control, so the others take it. */
.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; height: 44px; padding: 0 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; }
/* The card cell stays a TABLE CELL. display:flex on the <td> itself
   took it out of the row's cell model — its bottom hairline, its hover
   wash and its vertical centring were all measured against its own
   content height rather than the row's, and WebKit drew the rule under
   the card a line above the rule under the figures on every row taller
   than the card. The flex row lives on the wrapper inside the cell. */
.pf-cell-card { min-width: 220px; }
.pf-cardcell { display: flex; gap: var(--s-3); align-items: center; min-width: 0; }
.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; }
#pf-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; }
/* the figure this screen exists to answer, one step up and struck in
   ink while its neighbours sit at panel weight */
.pf-figval.lead { font-size: var(--fs-600); font-weight: 500; color: var(--ink); }
.pf-fig:has(.pf-figval.lead) .pf-figlab { color: var(--brass-ink); }
.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); }
/* A note is a sentence, not a cell: the three note fields span the row. */
.pf-formgrid .field.wide { grid-column: 1 / -1; }
.pf-importrow { margin-top: var(--s-3); }
.pf-importrow input[type="file"] { min-height: 44px; font-size: var(--fs-300); color: var(--ink2); }
.pf-import { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.pf-import > summary {
  list-style: none; min-height: 44px; display: flex; align-items: center;
  justify-content: space-between; gap: var(--s-3); cursor: pointer;
  font-family: var(--font-d); font-size: var(--fs-100); font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink);
}
.pf-import > summary::-webkit-details-marker { display: none; }
.pf-import > summary::after {
  content: ""; width: 8px; height: 8px; flex: none;
  border-right: 1px solid currentColor; border-bottom: 1px solid currentColor;
  transform: rotate(45deg) translate(-2px, 2px);
  transition: transform var(--dur-fast) var(--ease);
}
.pf-import[open] > summary::after { transform: rotate(225deg) translate(-2px, 2px); }
.pf-import > summary:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.pf-import-body { padding: var(--s-3) 0 var(--s-4); }

/* 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; }
  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. */

a.pf-cardtitle:hover, a.pf-cardtitle:focus-visible { 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: 160px; max-width: 190px; }
/* 160, not 128: the lane must hold "$2,335.47 ◇ MEDIUM" on one line and
   "INDEX ◇ as of 8/13 ET" on the next, so the cell is a two-line stack
   in every engine. At 128 Chrome — which hands the card column every
   spare pixel and the rest exactly their minimum — folded the reading
   line and then the provenance line, a four-line stack beside a
   two-line card, while WebKit (which spreads slack across the auto
   columns) already read it at ~155. The stated width is what makes the
   two engines agree.

   The only place 160 does not fit is the first sixty pixels of the
   two-column layout (1180–1239), where the register sits beside the
   340px rail with ~750px to itself and a sixty-character title clamped
   at 29ch already carried the table 20px past its box. There, and only
   there, the title clamp comes in to 23ch — measured to zero sideways
   scroll at 1180 with the longest titles the archive prints. */
@media (min-width: 1180px) and (max-width: 1239px) {
  .pf-table .pf-cardtitle { max-width: 23ch; }
}
/* At the next desktop step the 340px balance rail still leaves the
   holdings table just under its natural width. Keep every column in view
   instead of asking for a 40px sideways scroll: only the gutters and the
   two declared market lanes tighten, and their contents already wrap at
   the boundaries below. */
@media (min-width: 1180px) and (max-width: 1339px) {
  .pf-holdings th, .pf-holdings td { padding-left: 8px; padding-right: 8px; }
  .pf-holdings .pf-estcell { min-width: 150px; }
  .pf-holdings .pf-sparkcell { width: 110px; min-width: 110px; }
}
/* 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; }
/* Touch floors for the calendar and its neighbours: a 32px day under a
   thumb is a misfire waiting to happen. */
@media (max-width: 720px) {
  .mh-cal { width: 308px; }
  .mh-cal-day { height: 42px; }
  .mh-cal-btn { width: 40px; height: 40px; }
  .pfoe-x { width: 40px; height: 40px; }
  .pf-privtoggle { padding: 8px 10px; }
}
.mh-cal {
  position: fixed; z-index: 300; width: 268px;
  background: var(--panel); border: 1px solid var(--line2);
  box-shadow: var(--shadow-2);
  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. The
   chevron image is the --chev token, stated per room in the theme
   blocks — a data-URI cannot read var(), so the token carries the
   whole url(). The old pair froze one purple-grey for day and one
   for night, and porcelain wore paper's warm grey. */
.field select, .sortsel select {
  appearance: none; -webkit-appearance: none;
  background-image: var(--chev);
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 10px 6px;
  padding-right: 34px;
}

/* 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.

   AND THAT SENTENCE IS THE WHOLE STORY OF A DEFECT, so it is worth
   recording rather than deleting. The only two tables that ever matched
   this selector were the account's chain ledgers — escrow activity and
   withdrawal changes — and they are not label-and-value pairs. They are
   three columns of operation, status and time asking for about 384px of
   max-content, in a rail that gives a table 292px, or 277px once the
   reader's scrollbar is a classic one. With nowrap off and overflow-x
   off, that deficit had nowhere to go but line breaks: "Settle $1,450"
   on one line and its lot on the next, the status chip alone in its
   cell, the date and its tx link broken across three.

   The ledgers moved into the main column (js/account.js, renderBacking),
   so nothing matches this any more. It stays anyway: it is the only
   thing standing between the next rail table and a sideways scrollbar
   inside a sticky panel, which is the interface admitting it laid the
   thing out wrong. What it is NOT is a licence to put a grid in here. */
.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);
    /* The floated label sat flush against the right-aligned figure the
       moment a row got narrow: "COST$500", one word. */
    margin-right: 10px;
  }
  .pf-holdings td:not(.pf-cell-card) { text-align: right; padding: 3px 0; }
  .pf-holdings .pf-sparkcell { width: auto; min-width: 0; }
  /* max-width too: the desktop lane's 190px ceiling leaked into the
     stack and pinned the Estimate to the left 190px of a row whose
     Change and Gain sit flush right. */
  .pf-holdings .pf-estcell { min-width: 0; max-width: none; }
  .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; }
  /* Gain is the fifth cell of a two-column grid, so auto-placement put
     it in the FIRST column and its figure stopped mid-row while every
     figure above it sat on the right rule. It spans the row too. */
  .pf-holdings tr > td:last-child { grid-column: 1 / -1; }
  .pf-holdings .pf-noval, .pf-holdings .pf-estval, .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 HEADING over the price may break; the price may not. Both carry
     class rt-price, and `.resulttable .rt-price` (two classes) outranks
     the `.resulttable th` rule above, so the heading was holding
     "PRICE REALIZED" on one 129px line and it was the single widest
     thing in the ledger. Naming the element as well as the class outranks
     it back, for the heading only — the figures below keep their nowrap
     from the line above. */
  .resulttable th.rt-price { white-space: normal; }

}

/* 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; }
}

/* THE LEDGER AS A RECORD, BELOW THE WIDTH FOUR COLUMNS NEED.

   The Auction column used to be deleted at 720px, and with it the printed
   word "demonstration" that js/home.js puts in every fixture row so that
   "a screen reader and a sceptic read the same caveat" — its comment, and
   the reason the cell exists. On a phone neither of them got it, because
   display:none removes an element from the page and from the
   accessibility tree together.

   Keeping the column as a column does not work at this width and the
   attempts are worth recording so they are not tried again. Measured on
   the seeded ledger at 390px: the four columns ask for 371px inside 341.
   Three of the asks are irreducible — "$2,870,000" and "Jun 2026" must
   not break, and the sale name's floor is the word "demonstration"
   itself. Letting the title column give (overflow-wrap: anywhere) fits
   the table and shreds it: the Lot column lands at 56px and "Championship"
   sets as "Cham/pions/hip". table-layout: fixed fits it by clipping a
   nowrap price to 78px of an 89px figure. A ledger that fits by
   truncating money, or by hyphenating the name of the card, is not one.

   So the row stops being four cells across and becomes one record down —
   the same device .pf-holdings uses one block up, for the same reason and
   with the same parts: the head is hidden by clip and not by display, so
   it stays in the accessibility tree; the title takes the full measure;
   and every figure names itself from data-label, so no number is orphaned
   from what it measures. Nothing is dropped, at any width. */
@media (max-width: 620px) {
  .resulttable thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .resulttable, .resulttable tbody, .resulttable tr, .resulttable td { display: block; width: auto; }
  .resulttable tr {
    display: grid; grid-template-columns: 1fr auto; gap: 2px 12px; align-items: baseline;
    padding: 13px 2px 12px; border-bottom: 1px solid var(--line);
  }
  .resulttable tr:last-child { border-bottom: 0; }
  .resulttable td { border: 0; padding: 0; }
  .resulttable .rt-title {
    grid-column: 1 / -1; margin-bottom: 6px; max-width: none; white-space: normal;
    font-size: var(--fs-400);
  }
  /* Each figure names itself. The label floats so the value keeps the
     right rule and the two never touch. */
  .resulttable td:not(.rt-title)::before {
    content: attr(data-label); float: left;
    font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
    color: var(--mut); margin-right: 10px;
  }
  .resulttable td:not(.rt-title) { grid-column: 1 / -1; text-align: right; padding: 3px 0; }
  /* the sale name is the one that runs to two lines; it keeps the left
     rule for its own text so the caveat reads as a sentence */
  .resulttable .rt-auction { text-align: right; }
  /* the skeleton rows are the same shape while they wait */
  .resulttable .arc-skel td { padding: 3px 0; }
}

@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.

   This layer used to carry its own :root and theme token blocks,
   which re-declared most of the header's tokens and won by cascade
   order — two generations of truth in one file. The layers are
   merged: every colour lives in the semantic contract at the top of
   this file, and the salon's spectral composites are gone with the
   rest of the rainbow (see THE FOIL SYSTEM). What remains below is
   the component language the salon introduced.
   ============================================================ */

/* The ground is the canvas, stated once on body in THE FOIL SYSTEM block;
   the salon's ground layers were re-declared here when it shipped, then
   folded, and then retired with the rest of the rainbow. */

/* precision type and lines */
h1, h2, h3 { text-wrap: balance; font-kerning: normal; }
p { text-wrap: pretty; }
.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);
}
/* The button glint is retired: a specular pass on EVERY control —
   Place bid, Fund, Subscribe — is decoration on transactional surfaces,
   which the material direction reserves for signature objects. The
   engraved rest state and brass hover border carry the register. */
.btn:hover:not([disabled]) {
  transform: translateY(-1px);
  border-color: var(--brass);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--surface-raised) 35%, transparent) inset, 0 10px 24px rgb(var(--shadow-color) / 0.16);
}
.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: var(--surface-1);
  border-bottom-color: var(--border-strong);
}
.wordmark .wm-mark { color: var(--brass-ink); }
.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: var(--surface-1);
  border-bottom-color: var(--border-strong);
}
.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; }



/* section rhythm and catalogue furniture */
section.band { padding-top: 56px; padding-bottom: 60px; }
/* a washed band is the second surface, flat: a tonal step and two rules,
   not a wash */
section.band.washed { background: var(--surface-2); border-color: var(--border-subtle); }
.band-head { position: relative; padding-bottom: 18px; margin-bottom: 30px; border-bottom: 1px solid var(--border-subtle); }
/* the short rule under a section title is the room's metal — an accent,
   at the nine-percent budget, not a spectral one at the one */
.band-head::after {
  content: "";
  position: absolute;
  left: 0; bottom: -1px;
  width: 86px; height: 1px;
  background: var(--accent);
}
.band-head h1, .band-head h2 { font-size: clamp(28px, 3vw, 38px); }
/* The card's own plate is stated once at the component site now; only
   the salon-era CHILD refinements below still live here. */
.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: 18px; line-height: 1.35; 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; font-size: var(--fs-200); border-color: var(--border-subtle); }
.lotcard .watch { width: 44px; height: 44px; border: 1px solid var(--line); box-shadow: var(--shadow-1); }
/* .cattile's salon generation folded into the component site (the serif
   face travelled with it, at the editorial layer's 19px). */

/* browse room */
.browsehead {
  background:
    linear-gradient(110deg, color-mix(in srgb, var(--surface-1) 50%, transparent), transparent 54%),
    var(--surface-2);
  border-bottom-color: var(--border-strong);
}
.browsehead .wrap { padding-top: 36px; padding-bottom: 30px; }
.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: 44px; row-gap: 0; padding-top: 36px; }
.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(--border-subtle);
  background: linear-gradient(180deg, var(--surface-2), var(--surface-inset));
  box-shadow: var(--shadow-1);
}
.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); }
/* The numeral hand belongs to the numerals. This slot holds a price and a
   countdown, and on a Buy Now lot it holds the word "Available" — which
   came out in Plex Mono with -.04em tracking, i.e. a status word typeset
   as a figure. The weight stays shared: letting the bare .bb-val fall
   back to the 700 above makes "Available" heavier than the price beside
   it, which is the same fault pointed the other way. */
.bidbox .bb-val { font-weight: 500; }
.bidbox .bb-val.price, .bidbox .bb-val.cd { font-family: var(--font-m); letter-spacing: -.04em; }
.bidbox .bb-mid { background: color-mix(in srgb, var(--wash) 84%, transparent); }
.quickbids button, .shiprow, .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 */
/* .legal-nav and .arc-searchbox left this list: live markup uses
   .legal-toc and .arc-search. */
.dash-card, .acct-row, .acct-tablewrap, .pchart,
.guide-tablewrap, .feetable {
  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: var(--overlay); }
.modal { border: 1px solid var(--border-strong); box-shadow: var(--shadow-2); }
/* The modal lintel is retired: dialogs here are transactional (bid
   review, wallet, reservation) and carry no spectral trim. */
.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 { flex: 0 0 44px; 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);
}
.field input[aria-invalid="true"], .bidrow input[aria-invalid="true"] {
  border-color: var(--live);
  box-shadow: 0 0 0 3px var(--live-tint);
}

/* the dark furniture is the band surface, flat. The three radial holo
   washes and the glint that used to sit over all of it are gone; the
   only texture any of it may carry is the vault's engraving, on the
   consignor's stage and the footer, which every other room sets to 0. */
.consign, .sellhero, footer.site { position: relative; isolation: isolate; overflow: hidden; }
.sellhero::before, footer.site::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--engrave) center top / 72px 72px;
  opacity: var(--engrave-opacity);
  -webkit-mask-image: linear-gradient(180deg, #000, transparent 88%);
  mask-image: linear-gradient(180deg, #000, transparent 88%);
}
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; }
  /* A BID SLIP IS A SLIP, NOT A PAGE-WIDE FORM.
     Once .lot-layout drops to one column the bid box has no measure at
     all and simply takes the page: measured at 940 it is 892px wide, the
     currency field 716px and each quick-bid chip 279px — a six-character
     figure in a box wide enough for a paragraph. 560 is not a new number;
     it is the measure the front page's decision block already states
     (.hero .bidblock, width: min(100%, 560px)), so the site's two bid
     surfaces answer to one figure. .lot-panel is display: contents, so
     the slip stops at 560 on the column's own left rail and the title,
     meta line and everything below stay aligned with it. */
  .bidbox { max-width: 560px; }
  #specialist { grid-row: 6; }
  .lot-tabs { grid-row: 7; }
  .tabpane { grid-row: 8; }
  .lot-stage { padding: 28px clamp(28px, 12vw, 72px); }
}

/* A ONE-COLUMN HERO IS DRESSED AS A ONE-COLUMN HERO. The centre rule
   and the copy-side wedge are two-column furniture; once the hero stacks
   at 940 the stage is the plain canvas and the plate keeps its place
   behind the slab. */
@media (max-width: 940px) {
  .hero::after { display: none; }
  .hero { background: var(--canvas); }
  .hero::before { -webkit-mask-image: none; mask-image: none; }
}

@media (max-width: 720px) {
  .hero .wrap { min-height: 0; padding-top: 36px; padding-bottom: 40px; gap: 32px; }
  .hero-media .slabwrap { width: min(240px, 70%); }
  .hero-media::after { inset-inline: 12%; }
  .hero h1 { font-size: clamp(38px, 11vw, 54px); }
  section.band { padding-top: 40px; padding-bottom: 44px; }
  .band-head h1, .band-head h2 { font-size: 30px; }
  .browsehead .wrap { padding-top: 28px; padding-bottom: 24px; }
  .browsehead h1 { font-size: 38px; }
  .facet .opt, .catbar button { min-height: 44px; }
  .watchrow button { min-height: 44px; }
}

@media (max-width: 540px) {
  /* Two rows, not three: Theme and Portfolio fold into the overflow, so
     the two controls a transaction needs — Watchlist and Wallet — share
     the wordmark's line and 44px of masthead comes back to the page. */
  .masthead .wrap {
    height: auto;
    grid-template-columns: minmax(0, 1fr) auto;
    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: 2;
    grid-row: 1;
    position: relative;
    gap: 8px;
    justify-content: flex-end;
  }
  .themebtn, #portfoliobtn { display: none; }
  .morebtn { display: inline-flex; }
  .morebtn .iconbtn { width: auto; min-width: 52px; padding: 0 8px; }
  .morepop { max-width: calc(100vw - 32px); }
  .iconbtn { width: 44px; min-width: 44px; padding: 0; justify-content: center; }
  #walletbtn { min-width: 44px; min-height: 44px; }
  .searchbox { grid-column: 1 / -1; grid-row: 2; 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; }
  /* Four optional lot tabs used to wrap 3 + 1 on common 375–390px
     phones. Two even tracks keep the same two-row height and 44px tap
     targets, but remove the orphaned Shipping tab. */
  .lot-tabs:has(> button:nth-child(4)) {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0 1px;
  }
  .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) {
  /* nothing in the resting interface animates; the lifts stand down too */
  .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: tombstone — no page renders a kicker; the theme pair went with it. */
.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;
}

/* THE MERCHANDISE IS ON THE FIRST SCREEN, WHEREVER THE SIDEBAR STOPS
   BEING ONE.

   The facet rail becomes a stacked panel at 940 and the disclosure that
   folds it into a FILTER LOTS control only started at 720, so between 721
   and 940 the browse page opened on four expanded filter groups and no
   merchandise at all: measured, the first lot plate's offsetTop is 994px
   at 768 and 820 against a 900px viewport, and 578px at 720. An iPad in
   portrait met the catalogue as a form.

   The disclosure moves to the width the layout actually changes at. It is
   a presentation change only: every facet, every count and the toggle
   itself are exactly as they were, one tap away instead of open by
   default, which is already the contract on a phone.

   .facets { min-height: 340px } stays where it is up in the 940 block —
   it now reserves the sheet once a visitor opens it rather than the
   on-load stack, and its measurement note is still the record of how 340
   was derived. */
@media (max-width: 940px) {
  .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; }
}

@media (max-width: 720px) {
  /* Kept as the record of the order these two used to be forced into.
     The override moved up to the 940 block, where the hero stacks; DOM
     order is now the only order and this pair is a no-op. */
  .hero-copy { order: 1; }
  .hero-media { order: 2; }
  .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's editorial generation folded into the component site. */

/* Auction lots are object plates: square, precise, and quiet until the
   cursor reaches them. */
.lotgrid, .browse-grid { gap: 20px 18px; }
.lotcard .meta { font-size: var(--fs-200); letter-spacing: .055em; gap: 8px; flex-wrap: wrap; }



/* 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;
}
/* FOUR STEPS GO 1 -> 2x2 -> 4, NEVER 3+1.
   auto-fit's three-across band leaves step 04 alone beside two empty
   tracks for the whole 738-977px stretch — the consignment ladder ending
   in an orphan, on every tablet. The guard is the hidden deposit step, so
   /guide's three-box case keeps the auto-fit row the note above defends.
   Both bounds are load-bearing: below 541 the single column is already
   right, and this selector's specificity would otherwise outrank it and
   overflow a 320px phone; at 978 four tracks fit on their own. */
@media (min-width: 541px) and (max-width: 977px) {
  .steps:not(:has(> .step[hidden])) { grid-template-columns: repeat(2, 1fr); }
}
.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(--accent);
}
.step .n {
  margin: 0 0 24px;
  color: var(--brass-ink);
  font: 400 32px/.9 var(--font-serif);
  letter-spacing: -.03em;
}
.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(--maxw);
  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(--accent-on-band) 48%, transparent);
  color: var(--accent-on-band);
  background: color-mix(in srgb, var(--band-surface) 90%, transparent);
  box-shadow: 0 0 0 9px color-mix(in srgb, var(--band-bg) 85%, transparent), 0 0 0 10px color-mix(in srgb, var(--accent-on-band) 26%, transparent), 0 28px 80px rgb(0 0 0 / 0.34);
  transform: rotate(1.2deg);
}
/* the engraving, where a seal would carry it; zero outside the vault */
.sell-seal::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: var(--engrave) center / 72px 72px;
  opacity: var(--engrave-opacity);
}
.sell-seal::after {
  content: "";
  position: absolute;
  inset: 18px;
  border: 1px solid color-mix(in srgb, var(--accent-on-band) 22%, transparent);
  pointer-events: none;
}
.sell-seal svg { width: 88px; height: 78px; filter: drop-shadow(0 10px 26px rgb(0 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 td.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;
}
/* The ghost is right-margin marginalia, and on a phone the band has no
   right margin left: the clamp's 44px floor parks "SELLER / ZERO" across
   the top border of the CONSIGN A CARD button, and at 320 it wraps to two
   lines and runs through the heading as well. Same gesture, moved to the
   only margin a phone band has — the strip under the button. nowrap is
   the load-bearing half: without it 320 wraps again wherever it sits. */
@media (max-width: 540px) {
  .results-consign::after {
    top: auto;
    bottom: 14px;
    transform: none;
    white-space: nowrap;
    font-size: clamp(30px, 9.2vw, 44px);
  }
}
.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: 17px; font-weight: 500; line-height: 1.35; }
.arc-meta { font-family: var(--font-b); font-size: 12px; line-height: 1.5; }

/* 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%;
}
/* A brass hairline, not a spectrum: legal text is the one register
   where the material must stay entirely quiet. */
.legal-body h2::before { content: ""; position: absolute; left: 0; top: -1px; width: 72px; height: 1px; background: linear-gradient(90deg, var(--brass-soft), transparent); }
.legal-body .callout { border-radius: 0; border-left: 1px 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; }
/* The component names are short static labels, not data: at 320px "Bidding
   and closing" clipped under the inherited nowrap-ellipsis with nothing
   behind it. A label wraps; truncation is for values a click can recover. */
#status-rows .acct-main b { white-space: normal; }
#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; }
  /* The full selector list, matching the salon layer's own — a bare
     .step loses the specificity race there, which left the FIRST step's
     padding at 0 and painted the serif numeral over its heading. */
  .step, .step:first-child, .step[hidden] + .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;
}

/* ============================================================
   STATES & CATALOGUE RANK — the third pass.
   The audit's ledger, settled: every interactive answers press and
   keyboard the same way everywhere; the decision numbers take the
   rank the catalogue always meant them to have; the native controls
   that still wore vendor chrome are dressed by the house.
   ============================================================ */

/* ---- pressed. One press language for the small controls: the ground
   firms under the finger for the fast duration, the way the engraved
   .btn already flattens. A press is contact, not travel. */
.iconbtn:active, .quickbids button:active, .lotcard .watch:active,
.pchart-windows button:active, .catbar button:active, .themepop button:active,
.pf-chips button:active, .facet .clear:active, .lot-thumbs button:active,
.filter-toggle:active, .modal .m-close:active, .copybtn:active,
.fundpresets button:active, .provider:active, .mh-cal-day:active,
.mh-cal-btn:active, .pf-densbtn:active, .pf-privtoggle:active {
  background: var(--wash2);
  transition-duration: var(--dur-fast);
}

/* ---- disabled, said plainly. Dimming a control keeps its colours and
   whispers; a disabled control changes state. (The engraved register's
   own doctrine — the sortsel block solved this for selects years of
   commits ago.) */
.btn[disabled] {
  opacity: 1;
  background: var(--wash);
  color: var(--mut);
  border-color: var(--line2);
  box-shadow: none;
}
/* Funding actions use the platform's disabled state. Their reason stays
   in the page beneath the control, so pointer, touch, keyboard and screen
   reader users do not have to activate an impossible money movement to
   learn why it is unavailable. */
.dash-money-action[disabled],
.dash-money-action[disabled]:hover,
.dash-money-action[disabled]:active,
.dash-money-action[aria-disabled="true"],
.dash-money-action[aria-disabled="true"]:hover,
.dash-money-action[aria-disabled="true"]:active {
  opacity: 1;
  background: var(--wash);
  color: var(--mut);
  border-color: var(--line2);
  box-shadow: none;
  transform: none;
  cursor: not-allowed;
}
.dash-money-action[aria-disabled="true"],
.dash-money-action[aria-disabled="true"]:hover,
.dash-money-action[aria-disabled="true"]:active { cursor: help; }
.btn.ondark[disabled], .sellhero .btn[disabled], .consign .btn[disabled],
footer.site .btn[disabled] {
  background: var(--dark2);
  color: var(--dark-fg-dim);
  border-color: var(--dark-line);
}
.quickbids button[disabled] { color: var(--faint); background: var(--wash); border-color: var(--line); cursor: default; }

/* ---- working. A button that has been pressed and is waiting keeps
   its word and runs a brass thread under it; the thread is the only
   thing that moves, and it stops with the preference. */
.btn[aria-busy="true"] { pointer-events: none; }
.btn[aria-busy="true"]::after {
  content: "";
  position: absolute;
  left: 18px; right: 18px; bottom: 7px;
  height: 1px;
  background: var(--brass-soft);
  transform-origin: left;
  animation: mh-busy 1.1s ease-in-out infinite;
}
@keyframes mh-busy {
  0% { transform: scaleX(0); transform-origin: left; }
  55% { transform: scaleX(1); transform-origin: left; }
  56% { transform-origin: right; }
  100% { transform: scaleX(0); transform-origin: right; }
}
@media (prefers-reduced-motion: reduce) {
  .btn[aria-busy="true"]::after { animation: none; transform: none; }
}

/* ---- keyboard reaches what the pointer reaches. The hover lifts and
   washes mirror onto focus, so a tab stop is never invisible. */
/* The ring sits on the CARD: the link inside fills the plate and the
   plate clips, so a ring drawn on the link was never seen. */
.lotcard:focus-within { transform: translateY(-2px); border-color: var(--border-strong); box-shadow: var(--shadow-2); outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.lotcard:focus-within::before { background: var(--foil-edge); opacity: 1; }
.lotcard:focus-within .title { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
.cattile:focus-within { transform: translateX(4px); background: color-mix(in srgb, var(--panel) 34%, transparent); }
.cattile:focus-within::before { opacity: 1; transform: scaleY(1.16); }
.acct-row:focus-within { transform: translateX(3px); border-color: var(--brass); background: var(--wash); }
.acct-table tr:focus-within td, .compstable tr:focus-within td,
.resulttable tr:focus-within td { background: color-mix(in srgb, var(--wash) 70%, transparent); }
@media (prefers-reduced-motion: reduce) {
  .lotcard:focus-within, .cattile:focus-within, .acct-row:focus-within { transform: none; }
}

/* ---- selection is not hover. The crop strip's chosen frame wore the
   same style as the frame under the pointer, so selection vanished the
   moment anyone reached for it; the chosen frame is brass-kept now. */
.lot-thumbs button { position: relative; overflow: hidden; }
.lot-thumbs button.active { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.lot-thumbs button.active::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 0;
  height: 2px;
  background: var(--foil-edge);
  pointer-events: none;
}

/* ---- the theme popover arrives instead of appearing */
.themepop.open { animation: mh-pop var(--dur-fast) ease-out; }
@keyframes mh-pop { from { opacity: 0; transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) { .themepop.open { animation: none; } }

/* ---- the copy button answers in the up colour when it has actually
   copied — the word changed before, but the word alone is what every
   toolbar on the web does */
.copybtn.ok { color: var(--up); }
.copybtn.ok::before {
  content: ""; display: inline-block; width: 7px; height: 6px;
  margin-right: 5px; background: var(--up); vertical-align: 0;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}

/* ---- CATALOGUE RANK: the decision numbers ---- */
/* The estimate as a catalogue fact — small-caps label, tabular range —
   wherever js writes .estline (the hero sub-line, the lot bid block).
   It was a clause inside prose that CSS could not reach. */
.estline { white-space: nowrap; }
.estline .est-lbl {
  font-family: var(--font-d); font-weight: 700; font-size: 10px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--mut);
}
.estline .est-fig { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink2); }

/* the note-line figures that carry real money — the next minimum and
   the sealed maximum — step up off note weight without growing the note */
.bidbox .bb-fig { color: var(--ink); font-size: 13.5px; font-variant-numeric: tabular-nums; }

/* the sale channel is a WORD, not a tinted state and not a ringed one
   — "Buy Now" wore the reserve chip's clothes, then a hairline box; the
   brass-ink eyebrow is the house's own way to set a word like this */
.rchip.channel { color: var(--brass-ink); background: transparent; }

/* the neutral notice, distinct from success-adjacent confirm: panel
   ground under a brass lintel, the modal's own language */
.bidstate.info {
  display: block;
  background: color-mix(in srgb, var(--panel) 82%, transparent);
  color: var(--ink2);
  box-shadow: inset 0 2px 0 color-mix(in srgb, var(--brass-soft) 55%, transparent);
}

/* ---- urgency, in the house voice. Under an hour the countdown leans
   on weight (.soon, set in js/shell.js); under five minutes it enters
   the anti-snipe window and takes brass (.imminent). Never red: red
   stays reserved for a refused or losing bid. */
.cd.imminent { color: var(--brass-ink); font-weight: 700; }
.bidbox .bb-val.cd.imminent { color: var(--brass-ink); }

/* the ledger's own footnotes, declassed from inline styles */
.bidhist .bh-foot .who { color: var(--mut); font-weight: 400; }

/* the invoice's binding column: Total is what the bidder owes and
   outranks Hammer; a due date inside 48 hours warms up before it is
   allowed to be late */
.acct-table td.grand { font-weight: 700; color: var(--ink); }
.acct-table td.duesoon { color: var(--warn); font-weight: 600; }

/* The estimate uses the body face; the clock retains tabular numerals. */
.lotcard .clock .est { font-style: normal; }

/* an empty state always spans the grid it interrupts; the inline
   style each call site carried says so here instead */
.emptystate { grid-column: 1 / -1; }

/* ---- toasts join the status-mark language: the hairline keeps the
   colour, and the mark before the sentence is the same diamond every
   status wears. Cream-mixed, because the plate is dark in all four
   rooms. */
.toast.good::before, .toast.out::before {
  content: ""; flex: none;
  width: 8px; height: 7px; margin-top: 6px;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}
.toast.good::before { background: color-mix(in srgb, var(--up) 55%, var(--cream)); }
.toast.out::before { background: color-mix(in srgb, var(--live) 60%, var(--cream)); }

/* the one popover that skipped the shadow ladder */
.dash-tip { box-shadow: var(--shadow-2); }

/* ---- native controls, dressed: the last vendor chrome ---- */
/* The reserve slider — the one control where a consignor sets their
   only price protection — was a stock browser range. House track, and
   the thumb is the gem: the same diamond the status marks carry. */
input[type="range"] {
  width: 100%; height: 28px;
  appearance: none; -webkit-appearance: none;
  background: transparent; cursor: pointer;
}
input[type="range"]::-webkit-slider-runnable-track { height: 2px; background: var(--line2); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px; height: 18px; margin-top: -8px;
  /* Flat brass: foil left this thumb with the material direction —
     a range input is a form control, not a collectible. (The old hover
     also reset background via shorthand and silently dropped the image,
     so the foil half-worked at best.) */
  background: var(--brass);
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}
input[type="range"]:hover::-webkit-slider-thumb { background: var(--accent-hover); }
input[type="range"]::-moz-range-track { height: 2px; background: var(--line2); }
input[type="range"]::-moz-range-thumb {
  width: 20px; height: 18px; border: 0; border-radius: 0;
  background: var(--brass);
  background-image: var(--foil-spectrum); background-size: 320% 100%; background-position: 50% 50%;
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
}
input[type="range"]:hover::-moz-range-thumb { background: var(--accent-hover); }

/* The wizard and account checkboxes take the facet box's language —
   engraved square, brass gem when held — instead of accent-color's
   vendor mark. State-driven transitions only; nothing here self-moves. */
.cw-check input, .acct-check input {
  appearance: none; -webkit-appearance: none;
  width: 16px; height: 16px;
  border: 1px solid var(--line2); background: var(--panel);
  display: inline-grid; place-content: center;
  transition: border-color var(--dur-fast) var(--ease);
}
.cw-check input::before, .acct-check input::before {
  content: ""; width: 10px; height: 9px;
  transform: scale(0);
  background: var(--brass);
  -webkit-mask: var(--mh-mark-mask) center / contain no-repeat;
  mask: var(--mh-mark-mask) center / contain no-repeat;
  transition: transform var(--dur-fast) var(--ease);
}
.cw-check input:hover, .acct-check input:hover { border-color: var(--ink2); }
.cw-check input:checked, .acct-check input:checked { border-color: var(--ink); }
.cw-check input:checked::before, .acct-check input:checked::before { transform: scale(1); }

/* the consignor's reserve, set on the house slider: a figure, in the
   money face, above the fine print rather than inside it */
.cw-resfig {
  display: block;
  margin-top: var(--s-1);
  font-family: var(--font-m);
  font-size: var(--fs-500);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  color: var(--ink);
}

/* ---- forced colors. Every mark this house draws with a background
   revealed through a mask disappears when the platform repaints the
   world — the mini-M separators, the diamond pips, the drawn hairline.
   They are exempted and given the system ink, so high-contrast readers
   keep the punctuation everyone else has. */
@media (forced-colors: active) {
  /* Extended when the status chips, pips, gems and the slider thumb
     stopped being rotated squares and clip-path rhombi and became the
     mask like everything else. A clip-path mark keeps a real background
     and the platform repaints it; a MASKED mark has nothing to repaint
     and vanishes outright, so every selector converted has to be named
     here or high-contrast readers lose the mark completely. */
  .sep:empty, .authsep, .assure li + li::before,
  .nil::before, .toast.good::before, .toast.out::before,
      .cw-check input::before, .acct-check input::before, .cw-radios input::before,
  .copybtn.ok::before, .livetag::before,
  .rchip::before, .extchip::before, .acct-chip::before, .ad-chip::before,
  .susptag::before, .pf-conf::before, .cw-track li .pip,
  .facet .opt input:checked + .box::after {
    forced-color-adjust: none;
    background: CanvasText;
  }
  /* Pre-existing gap, found while auditing the list above: the loader's
     mark has always been a mask, has never been exempted, and therefore
     showed high-contrast readers an empty box where every other reader
     sees the house waiting. The sheen is a background-image and drops;
     the letter stays. */
  .mhload .mk {
    forced-color-adjust: none;
    background-image: none;
    background: CanvasText;
    animation: none;
  }
  /* The thumb carries room foil, which is a background-image: forced
     colors drops it and the control would be an invisible 20px gap on
     the track. Flat system ink instead, mark intact. */
  input[type="range"]::-webkit-slider-thumb,
  input[type="range"]::-moz-range-thumb {
    forced-color-adjust: none;
    background-image: none;
    background: CanvasText;
  }
}

/* ============================================================
   THE LOUPE — the inspection instrument on the showcase stage.
   js/loupe.js is the mechanism; this is the material. A grader's
   loupe is round, so this is the one round instrument in a square
   house — an object held over the page, not a component of it.
   ============================================================ */
.lot-stage { position: relative; }
.loupe-btn {
  position: absolute;
  right: 10px; bottom: 10px;
  z-index: 5;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border: 1px solid var(--line2);
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  color: var(--ink2);
  border-radius: var(--r-0);
  box-shadow: var(--shadow-1);
  transition: color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
}
.loupe-btn svg { width: 18px; height: 18px; }
/* the author display above would beat the UA's [hidden] rule and undo
   the too-small-to-matter guard in js/loupe.js — stated explicitly */
.loupe-btn[hidden] { display: none; }
.loupe-btn:hover { border-color: var(--brass); color: var(--ink); background: var(--panel); }
.loupe-btn:active { background: var(--wash2); }
.loupe-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* pressed is unmistakable and quiet: the control becomes an ink plate,
   the same register as every selected state in the house */
.loupe-btn[aria-pressed="true"] {
  background: var(--ink);
  color: var(--on-ink);
  border-color: var(--ink);
}

.loupe-lens {
  position: absolute;
  left: 0; top: 0;
  z-index: 4;
  width: clamp(120px, 44%, 200px);
  aspect-ratio: 1;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.18s var(--ease);
  border: 1px solid var(--brass);
  background: var(--wash);
  /* depth, and a struck top light inside the rim */
  box-shadow:
    inset 0 1px 0 color-mix(in srgb, var(--brass-lit) 45%, transparent),
    0 0 0 3px color-mix(in srgb, var(--brass) 14%, transparent),
    var(--shadow-2);
}
.loupe-lens.show { opacity: 1; }
.loupe-glass {
  position: absolute; inset: 0;
  border-radius: 50%;
  overflow: hidden;
}
.loupe-glass > * { position: absolute; left: 0; top: 0; max-width: none; }
/* the rim carries one quiet turn of the room's own spectrum — a real
   loupe's coating flashes at its edge, and each room flashes in its
   own scheme. Two pixels, masked to the rim, never over the glass. */
.loupe-lens::after {
  content: "";
  position: absolute; inset: -1px;
  border-radius: 50%;
  pointer-events: none;
  background: var(--foil-ring);
  opacity: 0.45;
  -webkit-mask-image: radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
  mask-image: radial-gradient(closest-side, transparent calc(100% - 3px), #000 calc(100% - 2px));
}

/* the hand that holds it: a drawn loupe cursor over the inspectable
   area while the mode is on — ink in the day rooms, cream at night.
   The hotspot sits at the glass's centre, which is also where the
   lens centres, so the cursor points at the very detail it magnifies. */
.lot-stage.inspecting {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26' viewBox='0 0 26 26'%3E%3Ccircle cx='10' cy='10' r='6.5' fill='none' stroke='%23130f0b' stroke-width='1.8'/%3E%3Cpath d='M15 15 L21 21' stroke='%23130f0b' stroke-width='1.8' stroke-linecap='round'/%3E%3Ccircle cx='10' cy='10' r='6.5' fill='none' stroke='%23fff0bd' stroke-width='.6' opacity='.8'/%3E%3C/svg%3E") 10 10, zoom-in;
}
html[data-theme="midnight"] .lot-stage.inspecting,
html[data-theme="vault"] .lot-stage.inspecting {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='26' height='26' viewBox='0 0 26 26'%3E%3Ccircle cx='10' cy='10' r='6.5' fill='none' stroke='%23fff8e7' stroke-width='1.8'/%3E%3Cpath d='M15 15 L21 21' stroke='%23fff8e7' stroke-width='1.8' stroke-linecap='round'/%3E%3Ccircle cx='10' cy='10' r='6.5' fill='none' stroke='%23130f0b' stroke-width='.6' opacity='.8'/%3E%3C/svg%3E") 10 10, zoom-in;
}

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


/* ============================================================
   THE DISPLAYS THAT HAVE THE ROOM

   Every container on this site is capped at --maxw, and from 1280 all the
   way to 2560 the page was the identical 1264px strip: at 2560 the
   catalogue is a third of the screen and the rest is ground. The bands,
   the hero and the footer already run full-bleed, so what is marooned is
   the content inside them.

   One step, at one width, and only for the surfaces that hold objects.
   1620 is the floor because 1560 of column plus the 48 of gutter needs
   1608 before it can be honoured at all, and a breakpoint that starts
   below what it can deliver just re-centres the same column.

   What deliberately does NOT take the step: the prose. A legal document,
   the guide and the terms are read, not scanned, and their measure is
   already set per tier in this file. .legal-layout is held at --maxw so
   the contract pages keep the composition they were typeset for, and
   every prose cap inside them is untouched.

   Column counts are not relitigated here. The archive, the category index
   and the lot grid keep the counts they were given against their content;
   the browse grid gains its fourth track because the arithmetic above
   says the plate does not have to shrink to get it. */
@media (min-width: 1620px) {
  .wrap { max-width: var(--maxw-wide); }
  .browse-grid { grid-template-columns: repeat(4, 1fr); }
  .legal-layout { max-width: var(--maxw); }
  /* THE RAIL GETS ITS 60px WHERE THEY ARE FREE, AND ONLY THERE.

     340px is tight for a card carrying a hero figure, six money rows,
     two-across funding buttons, a wallet list and the fine print, and
     the obvious fix — widen the track — is wrong between 1180 and 1619:
     .wrap is capped at 1264 there, so every pixel the rail gains comes
     straight out of a main column this stylesheet has already had to
     patch twice for being too narrow at exactly those widths (the
     portfolio card title and the holdings register, below). At 1620
     .wrap goes to 1560 and the main column gains 296px it never asked
     for, so 60 of them can be spent here for nothing: 1064px of ledgers
     — still the widest the main column is anywhere — beside a rail whose
     content box goes 294 → 354. Redeclare the tracks only; sticky,
     max-height, overflow and the phone stacking are untouched.
     .acct-layout is portfolio.html's rail too, and it gains the same. */
  .acct-layout { grid-template-columns: minmax(0, 1fr) 400px; }
}

/* ============================================================
   THE LOT-PAGE CATEGORY PREVIEW

   Eight related lots are a compact index, not a second browse page. The
   shared card renderer marks only these cards with .related-card, so the
   tighter plate, type and spacing cannot leak into the catalogue, home rails
   or watchlist. The slab SVG keeps its proportions throughout; extra side
   inset makes the object smaller without cropping it.
   ============================================================ */
#similar-grid {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  align-items: stretch;
}
#similar-grid .related-card .thumb { padding: 12px 46px 10px; }
#similar-grid .related-card .body { padding: 12px 13px 11px; gap: 6px; }
#similar-grid .related-card .meta { font-size: var(--fs-200); }
#similar-grid .related-card .title {
  min-height: 2.5em;
  font-size: 14px;
  line-height: 1.25;
}
#similar-grid .related-card .gradeline { gap: 4px; }
#similar-grid .related-card .gradetag { font-size: 11px; padding: 2px 5px; }
#similar-grid .related-card .bid { font-size: 15.5px; }
#similar-grid .related-card .bids { font-size: var(--fs-200); }
#similar-grid .related-card .clock {
  margin: 3px -13px -11px;
  padding: 8px 13px;
  font-size: 10.5px;
}
#similar-grid .related-card .watch { width: 36px; height: 36px; }

@media (max-width: 900px) {
  #similar-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }
  #similar-grid .related-card .thumb { padding: 10px 18px 8px; }
  #similar-grid .related-card .body { padding: 11px 10px 10px; gap: 5px; }
  #similar-grid .related-card .title { font-size: 15px; }
  #similar-grid .related-card .clock {
    margin: 3px -10px -10px;
    padding: 8px 10px;
    font-size: 10px;
  }
}

/* ============================================================
   INFO — the short, collector-facing guide.

   This page is intentionally more spacious than the legal register and
   denser than the marketing home page. Four numbered chapters, one plain-
   language contract explanation, and no decorative component that does not
   help a reader find or understand an answer.
   ============================================================ */
.info-hero {
  position: relative;
  overflow: hidden;
  background:
    linear-gradient(112deg, color-mix(in srgb, var(--surface-1) 56%, transparent), transparent 58%),
    var(--surface-2);
  border-bottom: 1px solid var(--border-strong);
}
.info-hero::after {
  content: "";
  position: absolute;
  right: clamp(24px, 7vw, 120px);
  bottom: 0;
  width: 180px;
  height: 1px;
  background: var(--accent);
}
.info-hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(300px, .8fr);
  gap: clamp(48px, 8vw, 112px);
  align-items: center;
  min-height: 540px;
  padding-top: 82px;
  padding-bottom: 86px;
}
.info-hero-copy { max-width: 760px; }
.info-hero h1 {
  max-width: 10.8em;
  margin: 0 0 22px;
  font-family: var(--font-serif);
  font-size: clamp(48px, 6.2vw, 80px);
  font-weight: 400;
  line-height: .98;
  letter-spacing: -.035em;
}
.info-lede {
  max-width: 58ch;
  color: var(--text-secondary);
  font-size: clamp(16px, 1.6vw, 20px);
  line-height: 1.65;
}
.info-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }

.info-ledger {
  position: relative;
  padding: 26px 0 2px;
  border-top: 2px solid var(--accent);
  border-bottom: 1px solid var(--border-strong);
}
.info-ledger-title {
  display: block;
  margin-bottom: 12px;
  color: var(--accent-ink);
  font: 700 10px/1 var(--font-d);
  letter-spacing: .18em;
  text-transform: uppercase;
}
.info-ledger dl > div {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  padding: 16px 0;
  border-top: 1px solid var(--border-subtle);
}
.info-ledger dt { color: var(--text-muted); font-size: 12px; }
.info-ledger dd {
  font-family: var(--font-m);
  font-size: 14px;
  font-weight: 500;
  text-align: right;
}
.info-ledger p { padding: 14px 0 17px; color: var(--text-muted); font-size: 11.5px; line-height: 1.55; }

.info-deploy { background: var(--caution-tint); border-bottom: 1px solid var(--border-strong); }
.info-deploy[hidden] { display: none; }
.info-deploy .wrap {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 22px;
  align-items: center;
  padding-top: 16px;
  padding-bottom: 16px;
}
.info-deploy-label {
  color: var(--text-primary);
  font: 800 10px/1 var(--font-d);
  letter-spacing: .14em;
  text-transform: uppercase;
}
.info-deploy p { color: var(--text-secondary); font-size: 12.5px; line-height: 1.55; }

.info-jumps { background: var(--surface-1); border-bottom: 1px solid var(--border-strong); }
.info-jumps .wrap {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  padding-top: 0;
  padding-bottom: 0;
}
.info-jumps a {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 62px;
  padding: 10px 20px;
  border-left: 1px solid var(--border-subtle);
  color: var(--text-secondary);
  font: 700 12px/1.25 var(--font-d);
}
.info-jumps a:last-child { border-right: 1px solid var(--border-subtle); }
.info-jumps a:hover { background: var(--surface-2); color: var(--text-primary); }
.info-jumps a span { color: var(--accent-ink); font: 500 10px/1 var(--font-m); }

.info-section { padding: 94px 0 104px; scroll-margin-top: 58px; }
.info-section-washed {
  background: var(--surface-2);
  border-top: 1px solid var(--border-subtle);
  border-bottom: 1px solid var(--border-subtle);
}
.info-section-head {
  display: grid;
  grid-template-columns: 86px minmax(0, 780px);
  gap: 28px;
  align-items: start;
  margin-bottom: 48px;
}
.info-section-no {
  display: block;
  padding-top: 7px;
  color: var(--accent-ink);
  font: 400 28px/1 var(--font-m);
}
.info-section-head h2 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(38px, 4.5vw, 56px);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -.025em;
}
.info-section-head p { max-width: 68ch; margin-top: 13px; color: var(--text-secondary); font-size: 16px; line-height: 1.7; }

.info-flow {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-top: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
  list-style: none;
}
.info-flow li {
  min-width: 0;
  min-height: 230px;
  padding: 26px 24px 30px;
  border-left: 1px solid var(--border-subtle);
}
.info-flow li:first-child { border-left: 0; }
.info-flow-no { color: var(--accent-ink); font: 500 10px/1 var(--font-m); }
.info-flow h3 { margin: 24px 0 9px; font-family: var(--font-serif); font-size: 23px; font-weight: 500; }
.info-flow p { color: var(--text-muted); font-size: 14px; line-height: 1.65; }

.info-chain {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(320px, .88fr);
  gap: clamp(40px, 6vw, 88px);
  margin-top: 72px;
  padding: 54px clamp(34px, 5vw, 72px);
  color: var(--band-fg);
  background: var(--band-bg);
  border: 1px solid var(--band-border);
  box-shadow: var(--shadow-1);
}
.info-chain h3 { max-width: 16em; margin: 0 0 19px; font-family: var(--font-serif); font-size: clamp(28px, 3vw, 40px); font-weight: 400; line-height: 1.08; }
.info-chain-copy p { max-width: 64ch; margin-top: 12px; color: var(--band-fg-2); font-size: 14px; line-height: 1.75; }
.info-chain-map { border-top: 1px solid var(--band-border); }
.info-chain-map > div { padding: 16px 0 17px; border-bottom: 1px solid var(--band-border); }
.info-chain-map dt { margin-bottom: 6px; color: var(--accent-on-band); font: 700 10px/1 var(--font-d); letter-spacing: .13em; text-transform: uppercase; }
.info-chain-map dd { color: var(--band-fg-2); font-size: 13.5px; line-height: 1.55; }

.info-rule-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1px; margin-top: 1px; background: var(--border-subtle); }
.info-rule-grid article { min-width: 0; padding: 28px 26px 30px; background: var(--surface-1); }
.info-rule-grid h3 { margin-bottom: 8px; font-family: var(--font-serif); font-size: 20px; font-weight: 500; }
.info-rule-grid p { color: var(--text-muted); font-size: 14px; line-height: 1.65; }

.info-fee-layout { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(300px, .65fr); gap: 28px; align-items: stretch; }
.info-fee-table { padding: 16px 0; }
.info-fee-table .feetable th:last-child,
.info-fee-table .feetable td:last-child { width: 24%; text-align: right; }
.info-fee-example {
  display: flex;
  flex-direction: column;
  padding: 28px 30px;
  color: var(--band-fg);
  background: var(--band-bg);
  border-top: 2px solid var(--accent-on-band);
}
.info-fee-example h3 { margin: 0 0 24px; color: var(--band-fg); font-family: var(--font-serif); font-size: clamp(24px, 2.8vw, 34px); font-weight: 400; line-height: 1.15; }
.info-fee-example dl { border-top: 1px solid var(--band-border); }
.info-fee-example dl > div { display: flex; justify-content: space-between; gap: 18px; padding: 12px 0; border-bottom: 1px solid var(--band-border); }
.info-fee-example dt { color: var(--band-fg-muted); font-size: 12.5px; }
.info-fee-example dd { font: 500 13px/1.3 var(--font-m); }
.info-fee-example .info-fee-total { color: var(--accent-on-band); }
.info-fee-example p { margin-top: auto; padding-top: 22px; color: var(--band-fg-muted); font-size: 13px; line-height: 1.55; }

.info-terms-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 48px; margin-top: 44px; border-top: 1px solid var(--border-strong); }
.info-terms-list > div { min-width: 0; padding: 20px 0 22px; border-bottom: 1px solid var(--border-subtle); }
.info-terms-list dt { margin-bottom: 7px; color: var(--text-primary); font: 700 13px/1.35 var(--font-d); }
.info-terms-list dd { color: var(--text-muted); font-size: 14px; line-height: 1.65; }
.info-terms-list dd strong { color: var(--accent-ink); font-family: var(--font-m); font-weight: 500; }
.info-terms-note { max-width: 920px; margin-top: 38px; padding: 20px 24px; background: var(--surface-1); border-left: 1px solid var(--accent); }
.info-terms-note p { color: var(--text-secondary); font-size: 13px; line-height: 1.65; }
.info-terms-note p + p { margin-top: 8px; }
.info-terms-note .linkline { display: inline-block; margin-top: 12px; }

.info-consign-flow { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; list-style: none; }
.info-consign-flow li { position: relative; min-width: 0; padding: 28px 24px 30px; border: 1px solid var(--border-strong); box-shadow: var(--shadow-1); }
.info-consign-flow li::before { content: ""; position: absolute; left: -21px; top: 48px; width: 20px; height: 1px; background: var(--border-strong); }
.info-consign-flow li:first-child::before { display: none; }
.info-consign-flow span { color: var(--accent-ink); font: 500 11px/1 var(--font-m); }
.info-consign-flow h3 { margin: 22px 0 8px; font-family: var(--font-serif); font-size: 21px; font-weight: 500; line-height: 1.15; }
.info-consign-flow p { color: var(--text-muted); font-size: 14px; line-height: 1.65; }
.info-seller-terms { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; margin-top: 42px; background: var(--border-subtle); border: 1px solid var(--border-subtle); }
.info-seller-terms > div { padding: 30px 32px 34px; background: var(--surface-2); }
.info-seller-terms h3 { margin: 0 0 8px; font-family: var(--font-serif); font-size: 23px; font-weight: 500; }
.info-seller-terms p { color: var(--text-secondary); font-size: 14px; line-height: 1.65; }
.info-section-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 22px; margin-top: 32px; }

.info-faq-list { display: grid; grid-template-columns: minmax(0, 920px); gap: 12px; align-items: start; }
.info-faq-list details { min-width: 0; background: var(--surface-1); border: 1px solid var(--border-strong); box-shadow: var(--shadow-1); }
.info-faq-list details[hidden] { display: none; }
.info-faq-list summary {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 64px;
  padding: 14px 54px 14px 20px;
  color: var(--text-primary);
  font: 700 13px/1.35 var(--font-d);
  cursor: pointer;
  list-style: none;
}
.info-faq-list summary::-webkit-details-marker { display: none; }
.info-faq-list summary::before,
.info-faq-list summary::after { content: ""; position: absolute; right: 22px; top: 50%; width: 13px; height: 1px; background: var(--accent-ink); transition: transform var(--dur-base) var(--ease); }
.info-faq-list summary::after { transform: rotate(90deg); }
.info-faq-list details[open] summary::after { transform: rotate(0); }
.info-faq-list details[open] summary { border-bottom: 1px solid var(--border-subtle); }
.info-faq-list details:hover { border-color: var(--accent); }
.info-faq-list details p { padding: 17px 20px 20px; color: var(--text-secondary); font-size: 14px; line-height: 1.7; }

.info-docs-cta { color: var(--band-fg); background: var(--band-bg); border-top: 1px solid var(--band-border); }
.info-docs-cta .wrap { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 48px; align-items: center; padding-top: 62px; padding-bottom: 66px; }
.info-docs-cta h2 { margin: 0 0 10px; font-family: var(--font-serif); font-size: clamp(30px, 3.4vw, 44px); font-weight: 400; }
.info-docs-cta p { max-width: 68ch; color: var(--band-fg-2); font-size: 14px; line-height: 1.65; }

@media (max-width: 1000px) {
  .info-hero-grid { grid-template-columns: minmax(0, 1fr) minmax(270px, .65fr); gap: 48px; min-height: 480px; }
  .info-flow, .info-consign-flow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .info-flow li:nth-child(3) { border-left: 0; }
  .info-flow li:nth-child(n+3) { border-top: 1px solid var(--border-subtle); }
  .info-consign-flow li:nth-child(3)::before { display: none; }
  .info-chain { grid-template-columns: 1fr; }
  .info-fee-layout { grid-template-columns: minmax(0, 1.2fr) minmax(280px, .8fr); }
}

@media (max-width: 760px) {
  .info-hero-grid { grid-template-columns: 1fr; min-height: 0; padding-top: 62px; padding-bottom: 66px; }
  .info-hero h1 { max-width: 9.5em; }
  .info-ledger { max-width: 560px; }
  .info-jumps .wrap { grid-template-columns: 1fr 1fr; }
  .info-jumps a:nth-child(odd) { border-left: 1px solid var(--border-subtle); }
  .info-jumps a:nth-child(2) { border-right: 1px solid var(--border-subtle); }
  .info-jumps a:nth-child(-n+2) { border-bottom: 1px solid var(--border-subtle); }
  .info-section { padding: 72px 0 80px; }
  .info-section-head { grid-template-columns: 54px minmax(0, 1fr); gap: 16px; margin-bottom: 38px; }
  .info-section-no { font-size: 21px; }
  .info-fee-layout { grid-template-columns: 1fr; }
  .info-fee-example p { margin-top: 24px; }
  .info-terms-list { grid-template-columns: 1fr; }
  .info-rule-grid { grid-template-columns: 1fr; }
  .info-seller-terms { grid-template-columns: 1fr; }
  .info-docs-cta .wrap { grid-template-columns: 1fr; gap: 28px; }
  .info-docs-cta .btn { justify-self: start; }
}

@media (max-width: 540px) {
  .info-hero-grid { padding-top: 50px; padding-bottom: 56px; gap: 38px; }
  .info-hero h1 { font-size: clamp(43px, 13vw, 58px); }
  .info-lede { font-size: 16px; }
  .info-actions .btn { flex: 1 1 100%; justify-content: center; }
  .info-deploy .wrap { grid-template-columns: 1fr; gap: 8px; }
  .info-jumps a { min-height: 58px; padding: 9px 12px; font-size: 11px; }
  .info-section { padding-top: 60px; padding-bottom: 66px; }
  .info-section-head { grid-template-columns: 40px minmax(0, 1fr); gap: 12px; }
  .info-section-no { padding-top: 0; font-size: 18px; }
  .info-section-head h2 { font-size: 40px; }
  .info-section-head p { font-size: 14px; }
  .info-flow, .info-consign-flow { grid-template-columns: 1fr; }
  .info-flow li, .info-flow li:nth-child(3) { min-height: 0; padding: 22px 4px 26px; border-left: 0; border-top: 1px solid var(--border-subtle); }
  .info-flow li:first-child { border-top: 0; }
  .info-flow h3 { margin-top: 16px; }
  .info-chain { margin-top: 48px; padding: 34px 24px 38px; }
  .info-chain h3 { font-size: 30px; }
  .info-rule-grid article { padding: 23px 20px 25px; }
  .info-fee-example { padding: 26px 22px; }
  .info-terms-list { margin-top: 36px; }
  .info-consign-flow { gap: 12px; }
  .info-consign-flow li { padding: 24px 20px 26px; }
  .info-consign-flow li::before { display: none; }
  .info-consign-flow h3 { margin-top: 18px; }
  .info-seller-terms > div { padding: 25px 22px 28px; }
  .info-section-actions .btn { flex: 1 1 100%; justify-content: center; }
  .info-faq-list summary { min-height: 60px; padding-left: 16px; }
  .info-faq-list details p { padding-left: 16px; padding-right: 16px; }
  .info-docs-cta .wrap { padding-top: 48px; padding-bottom: 52px; }
  .info-docs-cta .btn { width: 100%; justify-content: center; }
}

/* Presentation refinements shared by the storefront's existing surfaces. */
html[data-theme][data-mh-loading]::before { background: var(--canvas); }
html[data-theme][data-mh-loading]::after {
  background-image: linear-gradient(112deg, var(--mark-holo) 0% 34%, var(--mark-holo-lit) 50%, var(--mark-holo) 66% 100%);
}
body[data-nav] { caret-color: var(--text-primary); }
body[data-nav] :is(.rail, .resulttable, .compstable, .lot-thumbs) {
  scrollbar-color: var(--border-strong) var(--surface-2);
}
body[data-nav] .btn { box-shadow: 0 2px 4px rgb(var(--shadow-color) / .08); }
body[data-nav] .btn.ghost { box-shadow: none; }
body[data-nav] .btn:hover:not([disabled]) { transform: none; }
body[data-nav] .btn[disabled] { box-shadow: none; }
body[data-nav] .btn:active:not([disabled]) { box-shadow: none; }
body[data-nav] .searchbox input { border-color: var(--border-strong); background: var(--surface-2); }
body[data-nav] .searchbox input:focus { background: var(--surface-1); }
body[data-nav] :is(.field input, .field select, .field textarea, .searchbox input, .bidrow .amt input):focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 3px;
  box-shadow: none;
}
body[data-nav] .catnav a[aria-current="page"] { background: var(--surface-2); }
body[data-nav] :is(.resulttable, .compstable) { font-variant-numeric: tabular-nums; }
body[data-nav] :is(.resulttable, .compstable) td { line-height: 1.5; }
.lotcard .priceline > *, .lotcard .fmvline > * { min-width: 0; max-width: 100%; }
.lotcard .clock { align-items: baseline; gap: 6px 12px; flex-wrap: wrap; }
.lotcard .clock > * { min-width: 0; overflow-wrap: anywhere; }
.lotcard .fmvline { overflow-wrap: anywhere; }
@media (max-width: 460px) {
  .lotcard .body { padding: 14px 12px 13px; gap: 8px; }
  .lotcard .title { font-size: 16px; }
  .lotcard .clock { margin: 4px -12px -13px; padding: 10px 12px; font-size: 11px; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-media::after { transition: none; }
  html[data-theme][data-mh-loading]::after { animation: none; }
}

/* Shared material and control refinement. Brand lettering remains original. */
.masthead .wordmark .wm-mark { color: var(--brand-mark); }
.masthead .wordmark .wm-main { color: var(--brand-type); }
footer.site .brandcol :is(.wm-main, .wm-mark) { color: var(--brand-type-on-band); }

body[data-nav] .btn {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .015em;
  text-transform: none;
  line-height: 1.3;
}
body[data-nav] .btn.sm { font-size: 12px; }
body[data-nav] .btn.xl { font-size: 14px; padding: 15px 26px; }
body[data-nav] :is(.iconbtn, .copybtn, .loupe-btn, .modal .m-close) {
  transition: color var(--dur-base), background-color var(--dur-base), border-color var(--dur-base);
}
body[data-nav] :is(.iconbtn, .copybtn, .loupe-btn, .modal .m-close):hover {
  transform: none;
  background-color: var(--surface-hover);
  border-color: var(--border-strong);
}
body[data-nav] :is(.quickbids button, .fundpresets button, .pf-densbtn, .pf-privtoggle, .pf-chartmode button) {
  min-height: 36px;
  border-color: var(--border-strong);
}
body[data-nav] :is(.quickbids button, .fundpresets button):not([disabled]):not(.active):hover {
  background-color: var(--surface-hover);
}
body[data-nav] :is(.field label, .bidlabel) { letter-spacing: .035em; }
body[data-nav] .field :is(input, select, textarea) { line-height: 1.45; }
body[data-nav] .field textarea { resize: vertical; }
body[data-nav] :is(.themepop, .morepop, .search-pop) { border-color: var(--border-strong); }
body[data-nav] :is(.search-pop a.hit, .morepop > a):hover { background-color: var(--surface-hover); }
body[data-nav] .catnav a { letter-spacing: .015em; }
body[data-nav] .catnav a[aria-current="page"] {
  background-image: var(--material-edge);
  background-size: 100% 2px;
  background-position: bottom;
  background-repeat: no-repeat;
  border-bottom-color: var(--border-strong);
}
body[data-nav] :is(.lot-tabs button.active, .pf-chartmode button[aria-pressed="true"]) {
  background-color: var(--surface-selected);
}
body[data-nav] :is(.lot-tabs button, .pchart-windows button, .pf-controls button) { font-size: 12px; }
body[data-nav] .lotcard::before { background: var(--material-edge); opacity: var(--frame-foil-opacity); }
body[data-nav] .lotcard:is(:hover, :focus-within)::before { opacity: 1; }
body[data-nav] :is(.arc-card, .dash-card, .acct-tablewrap, .pf-import, .pchart) {
  border-color: var(--border-subtle);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--foil-b) 24%, transparent) inset;
}
body[data-nav] .arc-card:is(:hover, :focus-within) { border-color: var(--border-strong); }
body[data-nav] :is(.feetable, .resulttable, .compstable, .acct-table, .pf-table) th {
  color: var(--text-secondary);
  letter-spacing: .055em;
}
body[data-nav] :is(.feetable, .resulttable, .compstable, .acct-table, .pf-table) tbody tr:last-child td { border-bottom-color: transparent; }
body[data-nav] .modal:not(.sheet) .m-head { background: var(--surface-2); border-bottom-color: var(--border-subtle); }
body[data-nav] .modal:not(.sheet) .m-note { line-height: 1.65; }
body[data-nav] .auth-intro { font-size: 10px; letter-spacing: .1em; }
body[data-nav] .auth-mintmark { box-shadow: none; }
body[data-nav] :is(#confirm-app, #unsub-app, #reset-app) > .emptystate { padding: 28px 24px; }
body[data-nav] :is(.private-page-head, .status-page > h1) { text-wrap: balance; }
body[data-nav] :is(.info-faq-list details, .pf-import)[open] { border-color: var(--border-strong); }
body[data-nav] .info-faq-list details[open] summary { background: var(--surface-selected); }
body[data-nav] .info-jumps a:hover { background: var(--surface-hover); }
body[data-nav] :is(.guide-tablewrap, .info-ledger, .results-panel) { border-color: var(--border-subtle); }
body[data-nav] :is(.cw-steps li, .cw-item) { line-height: 1.5; }
body[data-nav] .cw-steps li.now span { border-color: var(--border-strong); }

/* Dark bands share a material language, with a separate invitation surface. */
.consign { background: var(--material-tint), var(--band-surface); border-top: 1px solid var(--band-border); }
.consign .wrap { grid-template-columns: minmax(0, 1fr) auto; padding-top: 44px; padding-bottom: 48px; gap: 32px; }
.consign .terms { margin-top: 18px; row-gap: 10px; font-size: 14px; color: var(--band-fg-2); }
.consign .terms b { font-size: 17px; font-weight: 600; }
.consign .terms span:not(:last-child) { border-color: var(--band-border); margin-right: 16px; padding-right: 16px; }
.consign .btn { min-width: 190px; }
footer.site { background: var(--material-tint), var(--band-bg); }
footer.site .cols { padding-top: 44px; column-gap: 28px; }
footer.site h2 { color: var(--band-fg); font-size: 12px; letter-spacing: .1em; }
footer.site ul { gap: 12px; }
footer.site ul a { color: var(--band-fg-muted); text-underline-offset: 4px; text-decoration-thickness: 1px; }
footer.site ul a:hover { text-decoration: underline; }
footer.site .brandcol p { font-size: 14px; line-height: 1.65; }
footer.site .brief-blurb { margin-top: 8px; font-size: 14px; }
footer.site .briefform input { background: var(--band-surface); border-color: var(--band-fg-faint); border-radius: 0; }
footer.site .briefform .btn { padding-inline: 20px; }
footer.site :is(.fine, .legalrow) { color: var(--band-fg-muted); font-size: 12px; }
footer.site .legalrow { padding-bottom: 26px; }
footer.site .brief-said.bad { color: var(--band-urgent); }
body[data-nav] :is(.info-chain, .info-docs-cta, .info-fee-example, .sellhero, .results-consign) {
  background-image: var(--material-tint);
  border-color: var(--band-border);
}
body[data-nav] :is(.info-chain, .info-docs-cta, .results-consign) {
  box-shadow: inset 0 1px 0 color-mix(in srgb, var(--foil-b) 40%, transparent);
}

@media (min-width: 941px) {
  footer.site .cols { grid-template-columns: 1.6fr repeat(4, minmax(0, 1fr)); row-gap: 30px; }
  footer.site .cols:has(> .briefcol) { grid-template-columns: 1.6fr repeat(5, minmax(0, 1fr)); }
  footer.site .briefcol {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(300px, 440px);
    column-gap: 32px;
    border-top: 1px solid var(--band-border);
    padding-top: 26px;
  }
  footer.site .briefcol h2 { grid-column: 1; grid-row: 1; margin-bottom: 0; }
  footer.site .briefcol .brief-blurb { grid-column: 1; grid-row: 2; }
  footer.site .briefcol .briefform { grid-column: 2; grid-row: 1 / 3; align-self: center; margin-top: 0; }
  footer.site .briefcol .brief-said { grid-column: 2; }
}
@media (max-width: 940px) {
  .consign .wrap { grid-template-columns: 1fr; gap: 24px; padding-top: 36px; padding-bottom: 40px; }
  .consign .cta { justify-self: start; }
  footer.site .cols { row-gap: 28px; padding-top: 36px; }
  footer.site .briefcol { padding-top: 20px; border-top: 1px solid var(--band-border); }
}
@media (max-width: 720px) {
  body[data-nav] :is(.quickbids button, .fundpresets button, .pf-densbtn, .pf-privtoggle, .pf-chartmode button) { min-height: 44px; }
  .mh-cal { width: min(308px, calc(100vw - 24px)); }
  .mh-cal-day { height: 42px; }
  .mh-cal-btn { width: 40px; height: 40px; }
}
@media (max-width: 540px) {
  .consign h2 { font-size: 34px; }
  .consign .terms { line-height: 1.6; }
  .consign .terms span:not(:last-child) { margin-right: 0; padding-right: 0; border-right: 0; }
  footer.site .briefform { flex-wrap: wrap; }
  footer.site .briefform input { flex-basis: 180px; }
}
@media (prefers-reduced-motion: reduce) {
  body[data-nav] :is(.iconbtn, .copybtn, .loupe-btn, .modal .m-close) { transition: none; }
}
