/* MERIDIAN terminal. Dense, instant, no decorative chrome. North star: mcmaster.com. */

:root {
  --ink: #111111;
  --muted: #6b6b6b;
  --faint: #999999;
  --bg: #ffffff;
  --panel-bg: #fafafa;
  --line: #d8d8d8;
  --accent: #0a3450;       /* midnight meridian — deep navy blue, replaces burnt orange */
  --accent-soft: #c2d4db;  /* same hue, hover-only, one click lighter than --accent */
  --accent-ink: #ffffff;
  --accent-ink-muted: #bccca8; /* soft moss — secondary text/borders (kind-tag, .sub) on --accent */
  --sold: #1a1a1a;
  --bought-in: #b3261e;
  --withdrawn: #8a8a8a;
  --private: #1f5fa8;
  --museum: #1f5fa8;
  --commercial: #6b6b6b;
  --tier1: #111111;
  --tier2: #444444;
  --tier3: #888888;
  --tier4: #bbbbbb;
  --reveal-accent: #b3261e; /* magic-switch indicator (fork-only) — reuses the existing "bought-in"
                               alert red so a revealed session reads as unmistakably "hot" */
}

/* Night mode — late 90s/early 2000s BMW dashboard aesthetic. Three-tone orange/red palette
   (owner's call, 2026-07-18), deliberately spaced apart by role rather than picking near-
   identical hues: #ff5a1f (body ink, brightest — primary reading color), #ff6a00 (accent/CTA,
   same brightness but warmer/more yellow — the 605nm dashboard orange), #9c2413 (meta/
   secondary, pulled darker + redder so it visibly recedes instead of competing with body
   text). An earlier pass used a racing-green (--muted: #4e9760, --faint: #3a7048) for
   secondary/meta text; kept here as a backup pair in case this reads poorly in practice.
   Single override block on the same custom properties every rule already reads from — no
   per-rule dark variants needed. */
body.night-mode {
  --ink: #ff5a1f;
  --muted: #9c2413;  /* backup: #4e9760 (racing green) */
  --faint: #9c2413;  /* backup: #3a7048 (racing green, dimmer) */
  --bg: #171310;
  --panel-bg: #1d1712;
  --line: #55493d;
  --accent: #ff6a00;
  --accent-soft: #a34600;
  --accent-ink: #171310;
  --accent-ink-muted: #171310; /* was --ink (orange-on-orange read too faint on the selected
                                   row at small size); matching --accent-ink gives the subtitle
                                   full contrast, same as the title — .name's existing 600 weight
                                   vs. .sub's 400 is what still tells them apart, not color */
}

* { box-sizing: border-box; }

html {
  height: 100%;
  /* Safari's rubber-band bounce on the outermost page is unreliably suppressed by
     overscroll-behavior alone (a known WebKit gap — works in Chrome/Firefox, and on nested
     scroll containers like the three panes below, but not reliably at the html/body viewport
     level). Removing the page itself as a scroll target is the Safari-proof fix: with zero
     content overflow here (see .layout below), this clips nothing. */
  overflow: hidden;
}

body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: "SF Mono", "Menlo", "Consolas", ui-monospace, monospace;
  font-size: 13px;
  line-height: 1.35;
  overscroll-behavior: none;
  overflow: hidden;
  /* Neither 100vh nor 100dvh nor position:fixed;inset:0 held up on a real iPhone (15 Pro Max and
     a second, differently-sized device, both iOS 26) — vh/dvh left a gap in standalone mode, and
     position:fixed turned out worse: it introduced the same gap in a normal Safari tab too,
     which is a known mobile-Safari quirk — fixed-position elements are computed against a
     viewport that doesn't reliably track Safari's own dynamic toolbar. Sidestepping all of that:
     app.js measures the real visible height in JS (window.innerHeight, kept live via a resize
     listener) and writes it as --app-height, which nothing above has ever gotten wrong. 100vh
     stays as the pre-JS/no-JS fallback so there's no flash of a zero-height page. */
  height: 100vh;
  height: var(--app-height, 100vh);
  display: flex;
  flex-direction: column;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

.topbar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  /* Standalone mode's status bar is black-translucent (index.html), meaning content draws
     underneath it rather than Safari reserving that space itself — without this the topbar can
     sit flush under the notch/Dynamic Island. max() keeps the normal 10px on devices/modes
     where the inset is 0 (a plain browser tab, desktop, older iPhones). */
  padding-top: max(10px, env(safe-area-inset-top));
  border-bottom: 2px solid var(--ink);
  flex-shrink: 0;
}

.wordmark {
  font-weight: 700;
  letter-spacing: 0.08em;
  font-size: 14px;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
}
.wordmark:hover { text-decoration: none; color: var(--ink); }

.wordmark .dot { color: var(--accent); }

/* Fork-only "magic switch" owner-visible safety indicator (see meridian/reveal.py,
   static/reveal.js) — legible at a glance, deliberately not garish: the prime mark and the
   topbar's rule both shift to one alert color, nothing else on the page changes. */
body.revealed .wordmark .dot { color: var(--reveal-accent); }
body.revealed .topbar { border-bottom-color: var(--reveal-accent); }

#search-input {
  flex: 1;
  min-width: 0; /* flex items default to min-width:auto (their intrinsic content size), which
                   silently blocks shrinking below a bare <input>'s ~180px default — invisible
                   on desktop's wide topbar, but exactly what caused a few px of horizontal
                   overflow at a 375px mobile width */
  max-width: 480px;
  font-family: inherit;
  font-size: 13px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  background: var(--panel-bg);
  color: var(--ink);
}
#search-input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

.hint { color: var(--faint); font-size: 11px; }
.hint kbd {
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  padding: 0 4px;
  font-size: 10px;
  border-radius: 2px;
  background: var(--panel-bg);
}

.import-link {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  border: 1px solid var(--line);
  padding: 4px 8px;
}
.import-link:hover { color: var(--accent); border-color: var(--accent); text-decoration: none; }
.edit-status-btn {
  font-family: inherit; background: none; cursor: pointer;
}
.edit-status-btn:hover { color: var(--accent); border-color: var(--accent); }

.text-toggle-btn {
  font-family: inherit;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  border: 1px solid var(--line);
  background: none;
  padding: 4px 8px;
  cursor: pointer;
}
.text-toggle-btn:hover { color: var(--accent); border-color: var(--accent); }
/* Hides narrative/prose text site-wide (press text, artist notes, bios) while keeping
   structural facts — titles, dates, names, prices — untouched. One class, applied wherever a
   template renders free-text prose, so newly-swapped htmx content is covered automatically by
   this single descendant selector without any per-swap JS re-application. */
body.text-off .narrative-text { display: none; }
body.price-off .price-value { display: none; }
/* Hides sold/nfs rows anywhere a [data-availability] row exists — opt-in via the settings
   menu rather than a topbar button like text/price, since this one changes which rows exist
   rather than just redacting content within them, and is expected to be used less often. */
body.hide-unavailable [data-availability="sold"],
body.hide-unavailable [data-availability="nfs"] { display: none; }

.settings-menu { position: relative; }
.settings-panel {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 6px;
  background: var(--bg);
  border: 1px solid var(--line);
  z-index: 10;
  display: flex;
  flex-direction: column;
  min-width: 170px;
}
/* Stacked flush — each toggle is its own full-width block sharing borders with its
   neighbors, same button vocabulary as the topbar (uppercase, bordered, highlighted when
   on) rather than a checkbox list, per request. */
.settings-toggle {
  font-family: inherit;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  background: none;
  border: none;
  border-bottom: 1px solid var(--line);
  padding: 8px 12px;
  text-align: left;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
}
.settings-toggle:last-child { border-bottom: none; }
.settings-toggle:hover { color: var(--accent); background: var(--accent-soft); }
body.text-off #text-toggle-btn,
body.price-off #price-toggle-btn,
body.hide-unavailable #hide-unavailable-toggle {
  color: var(--accent-ink);
  background: var(--accent);
}

/* Mobile-only duplicates of the topbar's trailing links, physically inside .settings-panel so
   they open/close with the rest of the dropdown (see index.html) — hidden above the breakpoint,
   where .topbar-links shows the standalone versions instead. */
.settings-panel-link { display: none; }

/* Standalone source-archive/import/trash/edit-mode links as they appear directly in the topbar
   on desktop — hidden below the breakpoint in favor of the .settings-panel-link duplicates. */
.topbar-links { display: contents; }

.layout {
  display: grid;
  grid-template-columns: 150px 260px 1fr;
  flex: 1;
  min-height: 0; /* lets a flex child actually shrink to fit instead of overflowing by its content size */
}

.nav-pane, .results-pane {
  border-right: 1px solid var(--line);
  overflow-y: auto;
  /* Only overflow-y is meant to scroll here — but per the CSS Overflow spec, setting one axis
     to a clipping value forces the other off 'visible' too, so leaving overflow-x unset would
     silently pick up 'auto' and let these panes scroll sideways (and bounce there in Safari) on
     any accidental horizontal overflow. Explicit hidden, not just omitted. */
  overflow-x: hidden;
  overscroll-behavior: none;
}

/* Sticks a page's header block (breadcrumb + title, or just the browse-hint label) to the
   top of its own scrolling pane — added as an extra class, never a standalone selector, so a
   template controls exactly which block (results list header vs. dossier header) sticks
   without nested-sticky elements fighting over the same scroll container. */
.sticky-header {
  position: sticky;
  top: 0;
  background: var(--bg);
  z-index: 2;
  /* .dossier-pane's own top padding is deliberately zero (see below) — carried here instead,
     inside the sticky box's own opaque background, so a tall unstuck row scrolled near the top
     can never paint through a gap the pane's padding would otherwise leave uncovered above the
     sticky header. */
  padding-top: 16px;
}

.result-item {
  padding: 8px 12px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}
.result-item .name { font-weight: 600; }
.result-item .sub { color: var(--muted); font-size: 11px; }
.result-item:hover:not(.selected) { background: var(--accent-soft); }
.result-item.selected { background: var(--accent); color: var(--accent-ink); }
.result-item.selected .sub { color: var(--accent-ink-muted); }

.kind-tag {
  display: inline-block;
  margin-left: 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--faint);
  border: 1px solid var(--line);
  padding: 0 4px;
  vertical-align: middle;
}
.result-item.selected .kind-tag { color: var(--accent-ink-muted); border-color: var(--accent-ink-muted); }
.result-item.kind-gallery .name, .result-item.kind-fair .name { font-weight: 500; }

/* Sticks each letter directly under .results-pane's own .sticky-header (label + count row,
   ~27.5px tall in both templates that use this divider — _results.html and
   _exhibitions_list.html) so the current letter rides at the top of the pane as you scroll,
   and the next letter naturally displaces it the moment its own row reaches that same offset —
   plain CSS sticky-stacking, no JS required. Right-justified per owner's request: easier to
   spot at a glance than reading left-to-right past the row's own content. */
.letter-divider {
  padding: 6px 12px 2px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--faint);
  background: var(--panel-bg);
  text-align: right;
  position: sticky;
  top: 27.5px;
  z-index: 1;
}
table.data-table tr.letter-divider-row td {
  padding: 4px 8px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--faint);
  background: var(--panel-bg);
  border-bottom: 1px solid var(--line);
  text-align: right;
}
table.data-table tr.letter-divider-row:hover td { background: var(--panel-bg); }

.results-empty, .dossier-empty {
  padding: 16px 12px;
  color: var(--faint);
}

.breadcrumb {
  font-size: 11px;
  color: var(--faint);
  margin-bottom: 8px;
}
.breadcrumb a { color: var(--faint); }
.breadcrumb a:hover { color: var(--accent); }

.tag-current {
  background: var(--ink);
  color: var(--bg);
  border-color: var(--ink);
}

.press-text {
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink);
  max-width: 640px;
  margin-bottom: 16px;
  white-space: pre-wrap;
}
.contact-block {
  max-width: 420px;
  margin-bottom: 16px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-left: 2px solid var(--accent);
  background: var(--bg);
}
.contact-block-title {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin-bottom: 4px;
}
.contact-name { font-weight: 600; margin-right: 6px; }
.contact-address { white-space: pre-line; }
.contact-actions { margin-top: 6px; }
.contact-inquire {
  font-size: 12px;
  color: var(--accent);
  text-decoration: underline;
}
.contact-inquire-inline {
  font-size: 10px;
  color: var(--accent);
}
.contact-block-empty { border-left-color: var(--line); }
[x-cloak] { display: none !important; }
.tab-row {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--line);
  margin: 18px 0 12px;
}
.tab-btn {
  font-family: inherit;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 6px 4px;
  margin-bottom: -1px;
  cursor: pointer;
}
.tab-btn:hover { color: var(--accent); }
.tab-btn.active { color: var(--ink); border-bottom-color: var(--accent); }
.byline {
  font-size: 10px;
  text-transform: none;
  letter-spacing: normal;
  color: var(--faint);
  font-weight: 400;
  margin-left: 6px;
}
.text-toggle {
  display: block;
  margin-top: 6px;
  font-family: inherit;
  font-size: 11px;
  color: var(--accent);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
}

.browse-hint {
  padding: 10px 12px 4px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--faint);
}
.category-tile {
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
  font-weight: 600;
}
.category-tile:hover { background: var(--accent); color: var(--accent-ink); }
.category-tile.selected { background: var(--accent); color: var(--accent-ink); }

.dossier-pane {
  padding: 0 24px 16px;
  overflow-y: auto;
  /* Horizontal scroll used to live here, but .sticky-header only sticks vertically — scrolling
     the pane sideways to see a wide table's right-hand columns dragged the page title and
     breadcrumb off-screen with it. Scoped down to table.data-table below instead, so only the
     table itself scrolls and the header stays put. */
  overflow-x: hidden;
  overscroll-behavior: none;
}

.dossier-header { border-bottom: 2px solid var(--ink); padding-bottom: 10px; margin-bottom: 14px; }
.dossier-header .name { font-size: 20px; font-weight: 700; }
.dossier-header .name .legal-name { font-size: 15px; font-weight: 400; color: var(--muted); }
.dossier-header .attrs { color: var(--muted); margin-top: 4px; }
.dossier-header .attrs span { margin-right: 14px; }
.tag {
  display: inline-block;
  border: 1px solid var(--line);
  padding: 0 5px;
  font-size: 10px;
  letter-spacing: 0.04em;
  margin-right: 4px;
  color: var(--muted);
}

.owned-toggle, .owned-badge {
  display: inline-block;
  font-size: 12px;
  width: 14px;
  color: var(--faint);
  background: none;
  border: none;
  padding: 0;
  margin-right: 4px;
  cursor: pointer;
  vertical-align: middle;
}
.owned-toggle.owned, .owned-badge { color: var(--accent); }
.owned-toggle:hover { color: var(--accent); }

.hide-toggle {
  display: inline-block;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  background: none;
  border: 1px solid var(--line);
  padding: 1px 5px;
  margin-right: 4px;
  cursor: pointer;
  vertical-align: middle;
}
.hide-toggle:hover { color: var(--accent); border-color: var(--accent); }
.hide-toggle.hidden-state { color: var(--accent); border-color: var(--accent); }

.delete-form {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  margin-top: 4px;
}
.delete-password-input, .delete-reason-input {
  font-size: 11px;
  padding: 2px 4px;
  border: 1px solid var(--line);
  width: 110px;
}

.fair-tag {
  display: inline-block;
  border: 1px solid var(--accent);
  padding: 0 5px;
  font-size: 10px;
  letter-spacing: 0.03em;
  color: var(--accent);
  font-weight: 600;
}
.fair-tag:hover { background: var(--accent); color: var(--accent-ink); text-decoration: none; }

.section-title {
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin: 18px 0 6px;
  border-bottom: 1px solid var(--line);
  padding-bottom: 3px;
}

table.data-table {
  width: 100%;
  border-collapse: collapse;
  /* Scrolls itself sideways when its columns' content is wider than the pane (see
     .dossier-pane above) — display:block lets this box clip/scroll independently of table
     layout while the browser still generates an anonymous table around the retained
     table-row/table-cell children, so column alignment is unaffected. */
  display: block;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
table.data-table th {
  text-align: left;
  font-size: 10px;
  text-transform: uppercase;
  color: var(--faint);
  letter-spacing: 0.04em;
  padding: 3px 8px 3px 0;
  border-bottom: 1px solid var(--line);
}
table.data-table td {
  padding: 5px 8px 5px 0;
  border-bottom: 1px solid #efefef;
  vertical-align: top;
}
table.data-table tr:hover td { background: var(--panel-bg); }
table.data-table tr.selected td { background: var(--accent); color: var(--accent-ink); }
table.data-table tr.selected td a { color: var(--accent-ink); }

.work-group-header {
  font-size: 12px;
  color: var(--ink);
  font-weight: 600;
  margin: 16px 0 4px;
}
.work-group-header .sub { font-weight: 400; color: var(--faint); margin-left: 6px; }
.work-group-header:first-of-type { margin-top: 4px; }

.checklist-work-count { font-size: 10px; color: var(--faint); text-transform: uppercase; letter-spacing: 0.04em; }
.checklist-works { list-style: none; margin: 4px 0 0; padding: 0; }
.checklist-works li { padding: 2px 0; font-size: 11px; color: var(--muted); }
.checklist-works .work-title { color: var(--ink); }

.status-badge {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 1px 5px;
  border: 1px solid currentColor;
}
.status-sold { color: var(--sold); }
.status-bought_in { color: var(--bought-in); }
.status-withdrawn { color: var(--withdrawn); }
.status-private_sale { color: var(--private); }

/* primary-market price_type: realized is the trusted anchor (black, like an auction sale);
   offers are closer to a real transaction than a printed ask, so they get the accent color;
   hold/reserved signal demand (blue, same family as institutional); ask is the neutral
   baseline; on_request carries no number at all. */
.price-realized_sale { color: var(--sold); font-weight: 700; }
.price-offer, .price-discounted_offer { color: var(--accent); font-weight: 700; }
.price-hold, .price-reserved { color: var(--private); font-weight: 700; }
.price-ask { color: var(--muted); }
.price-on_request { color: var(--faint); font-style: italic; }
.price-nfs { color: var(--faint); font-style: italic; }
.price-note-marker { color: var(--muted); cursor: help; margin-left: 1px; }
.row-nfs { opacity: 0.55; }
.row-nfs a { color: inherit; }

.venue-museum, .venue-biennial { color: var(--museum); font-weight: 600; }
.venue-gallery, .venue-art_fair, .venue-institution, .venue-other { color: var(--commercial); }

.tier-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 4px;
  vertical-align: middle;
}
.tier-1 { background: var(--tier1); }
.tier-2 { background: var(--tier2); }
.tier-3 { background: var(--tier3); }
.tier-4 { background: var(--tier4); border: 1px solid var(--tier3); }

.censored { color: var(--muted); font-style: italic; }
.num { font-variant-numeric: tabular-nums; }

.legend {
  margin-top: 20px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
  color: var(--faint);
  font-size: 10px;
}
.legend span { margin-right: 14px; }

/* Import page */
.import-page { max-width: 640px; padding: 24px; }

.import-label {
  display: block;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin-bottom: 4px;
}

#import-form select {
  font-family: inherit;
  font-size: 13px;
  padding: 6px 8px;
  border: 1px solid var(--line);
  background: var(--panel-bg);
  color: var(--ink);
  width: 100%;
  margin-bottom: 14px;
}

.dropzone {
  border: 2px dashed var(--line);
  padding: 32px 16px;
  text-align: center;
  color: var(--muted);
  cursor: pointer;
  margin-bottom: 14px;
}
.dropzone.dragover { border-color: var(--accent); background: var(--panel-bg); color: var(--accent); }
.dropzone.has-file { border-style: solid; border-color: var(--ink); color: var(--ink); font-weight: 600; }

#import-submit {
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.03em;
  padding: 8px 18px;
  background: var(--ink);
  color: var(--bg);
  border: none;
  cursor: pointer;
}
#import-submit:hover { background: var(--accent); }

.import-error {
  border: 1px solid var(--bought-in);
  color: var(--bought-in);
  padding: 8px 10px;
  margin-bottom: 14px;
  font-size: 12px;
}

/* Same box as .import-error, accent instead of alert-red — used once on /demo/admin to hand
   back a freshly-minted meeting password (see meridian/demo_access.py), which is never shown
   again after this page render since only its hash is persisted. */
.import-success {
  border: 1px solid var(--accent);
  color: var(--accent);
  padding: 8px 10px;
  margin-bottom: 14px;
  font-size: 12px;
}

.status-tag {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border: 1px solid var(--line);
}
.status-tag.status-active { color: var(--accent); border-color: var(--accent); }
.status-tag.status-expired,
.status-tag.status-revoked { color: var(--faint); }

.import-note {
  color: var(--muted);
  font-size: 12px;
  margin-bottom: 8px;
}

.import-errors {
  margin: 0;
  padding-left: 18px;
  color: var(--bought-in);
  font-size: 12px;
}

.import-summary td:first-child { color: var(--muted); }

code {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 11px;
  word-break: break-all;
}

/* Mobile single-pane view (fork-only, TRAVEL-PACKAGE-PLAN.md Part 3 — the app isn't installed to
   a home screen in production, so this never needs mirroring to ../meridian). Base/hidden state;
   the flex child slots into body's existing flex-column layout (same pattern .topbar already
   uses) so it reserves its own height automatically — no fixed-position + manual bottom-padding
   math needed to keep it from overlapping pane content. */
.mobile-tabbar { display: none; }

@media (max-width: 700px) {
  /* Keyboard shortcuts are meaningless without a physical keyboard; the trailing topbar links
     move into the settings dropdown instead of trying to wrap in place (see index.html and the
     .settings-panel-link / .topbar-links rules above). */
  .hint { display: none; }
  .topbar-links { display: none; }
  .settings-panel-link { display: flex; }

  /* iOS Safari auto-zooms the whole viewport on focus for any input under 16px font-size — and
     with viewport-fit=cover's fixed no-scroll layout (see index.html), zooming in leaves the page
     stuck pannable/zoomed with no easy way back out. Desktop keeps the tighter 13px terminal
     look (#search-input's base rule above); this only bumps it past the zoom threshold on
     mobile, where the trigger actually happens. */
  #search-input { font-size: 16px; }

  .layout {
    grid-template-columns: 1fr;
  }

  /* Scoped to direct children of .layout, not just the class name — fair-drilldown templates
     (_fair_brand.html, _fair_edition.html) reuse .results-pane for its list styling on a nested
     div *inside* the dossier pane (editions/galleries list), which isn't one of the three
     top-level panes this rule toggles. A bare `.results-pane` selector caught that nested div
     too, hiding it permanently since it never receives .pane-active. */
  .layout > .nav-pane, .layout > .results-pane, .layout > .dossier-pane {
    display: none;
    border-right: none;
  }
  .layout > .nav-pane.pane-active, .layout > .results-pane.pane-active, .layout > .dossier-pane.pane-active {
    display: block;
  }

  .mobile-tabbar {
    display: flex;
    flex-shrink: 0;
    border-top: 2px solid var(--ink);
    /* Room for the iPhone home-indicator gesture area — viewport-fit=cover (index.html's
       viewport meta) is what makes env() resolve to a real value instead of 0. */
    padding-bottom: max(0px, env(safe-area-inset-bottom));
  }
  .mobile-tab {
    flex: 1;
    font-family: inherit;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 12px 4px;
    border: none;
    border-right: 1px solid var(--line);
    background: none;
    color: var(--muted);
    cursor: pointer;
  }
  .mobile-tab:last-child { border-right: none; }
  .mobile-tab.active { color: var(--accent-ink); background: var(--accent); }

  /* Wide data tables (primary market, sales, exhibitions, checklists) side-scroll on desktop
     (table.data-table above) — awkward on a phone competing with the page's own vertical
     scroll, so each row stacks into a card instead: one labeled line per column, using the
     header text app.js's labelTableCells() copies onto every <td> as data-label. First-pass
     approach (2026-07-19) — review after real use; if rows read too tall/cluttered, fall back
     to showing only priority columns with the rest behind a tap-to-expand. */
  table.data-table { overflow-x: visible; }
  table.data-table thead { display: none; }
  table.data-table tbody, table.data-table tr, table.data-table td {
    display: block;
    width: 100%;
  }
  table.data-table tr {
    padding: 8px 0;
    border-bottom: 1px solid var(--line);
  }
  table.data-table td {
    border-bottom: none;
    padding: 2px 0 2px 42%;
    position: relative;
    min-height: 16px;
  }
  table.data-table td[data-label]::before {
    content: attr(data-label);
    position: absolute;
    left: 0;
    top: 2px;
    width: 38%;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--faint);
    font-weight: 700;
  }
}
