/* ============================================================================
   Wine Locker Platform — Shared styles (prototype)
   THEME: Bowdie's "Liquid Glass" — the same spine as the Staff Training
   Reference (lux-theme.css v42/v66/v67). Glass surfaces over warm charcoal,
   four-edge lensing, a disciplined radius scale, three elevation tiers,
   spring-eased micro-interactions, and the reference's three-font rhythm.
     Display  : Playfair Display (serif)        — names, page titles
     Accent   : Cormorant Garamond (italic)     — subtitles, tasting notes
     UI labels: Josefin Sans (uppercase, spaced) — buttons, tags, section labels
     Surfaces : warm near-black charcoal; gold-tinted hairline borders
   Rules carried from the reference: blur only on singletons (top bar, modal,
   toast, tabbar) — never on card lists; no infinite animations; no card
   transforms; solid charcoal base (no imagery/grain).
   ========================================================================== */

:root {
  /* ── surfaces — warm ivory / parchment ───────────────────────────── */
  --charcoal:  #F7F1E6;   /* page canvas — light, bright ivory */
  --bg:        #F2EBDC;
  --bg-2:      #FAF5EC;
  --card:      #FFFCF6;   /* near-white cream card */
  --card-2:    #FFFFFF;

  /* ── antique gold (legible on light) ─────────────────────────────── */
  --gold:      #7C5A36;
  --gold-soft: #916E45;
  --gold-dim:  #614729;

  /* ── espresso ink — dark accents + primary buttons (logo's charcoal) ─ */
  --ink:       #2B251E;
  --ink-hi:    #3A3329;
  /* legacy aliases (formerly bordeaux) now map to gold — no red in the brand */
  --wine:      #7C5A36;
  --wine-soft: #916E45;

  /* ── warm hairline borders ───────────────────────────────────────── */
  --line:      rgba(122,94,42,0.22);
  --line-soft: rgba(122,94,42,0.13);
  --stroke-hi: rgba(154,123,44,0.45);

  /* ── text — espresso on ivory ────────────────────────────────────── */
  --text:      #2C2620;   /* primary */
  --text-dim:  #6B6051;   /* muted */
  --text-mute: #9B8F79;   /* faint */

  /* ── semantic accents (muted for light) ──────────────────────────── */
  --green:     #4F6E4A;   /* in-house redemption */
  --red:       #8C5A3E;   /* muted clay (no true red in the brand) */
  --byo:       #7A4E86;   /* client-supplied */

  /* ── soft cream "glass" surfaces ─────────────────────────────────── */
  --lx-glass:  linear-gradient(160deg, #FCF8EF, #F6EFE1);
  --glass-btn: linear-gradient(160deg, #FBF6EC, #F3EBDA);
  --glass-btn-hi: linear-gradient(160deg, #FFFDF7, #F7F0E2);
  --lens: inset 0 1px 0 rgba(255,255,255,.65);
  --elev-1: 0 1px 2px rgba(74,54,28,.05), 0 6px 18px -10px rgba(74,54,28,.13);
  --elev-2: 0 12px 30px -16px rgba(74,54,28,.18);
  --elev-3: 0 26px 60px -28px rgba(74,54,28,.28);

  /* ── radius scale (one discipline) ───────────────────────────────── */
  --r-s:    12px;
  --r-m:    16px;
  --r-l:    20px;
  --r-pill: 24px;
  --radius: 16px;   /* legacy alias used by inline markup → maps to --r-m */
  --shadow: var(--elev-2);   /* legacy alias used by inline markup */

  /* ── motion ──────────────────────────────────────────────────────── */
  --ease:   cubic-bezier(.22,1,.36,1);
  --spring: cubic-bezier(.34,1.56,.64,1);

  /* ── type ────────────────────────────────────────────────────────── */
  --display: "Playfair Display", "Hoefler Text", Georgia, serif;
  --serif:   "Cormorant Garamond", "Hoefler Text", Georgia, serif;
  --sans:    "Josefin Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
html, body { margin: 0; padding: 0; height: 100%; touch-action: manipulation; }
html { background: var(--charcoal); }
body {
  background: var(--charcoal);
  color: var(--text);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  line-height: 1.55;
  /* Lock the page so the .app container does all scrolling — no body bounce,
     no fighting Safari's dynamic toolbar (mirrors the Training Reference). */
  position: fixed; top: 0; left: 0; right: 0; bottom: 0;
  overflow: hidden; overscroll-behavior: none;
}

::selection { background: color-mix(in srgb, var(--gold) 22%, transparent); color: #2C2620; }
:focus-visible { outline: 2px solid var(--stroke-hi); outline-offset: 2px; }

/* ----- Layout shell --------------------------------------------------- */
.app {
  position: fixed; top: 0; bottom: 0; left: 0; right: 0;
  max-width: 480px; margin: 0 auto;
  overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: none;
  padding-bottom: calc(82px + var(--sab, env(safe-area-inset-bottom)));
}
/* All pages share the one 480px phone-mimic column; admin matches home/Members. */
.app--wide { max-width: 480px; padding-bottom: calc(28px + var(--sab, env(safe-area-inset-bottom))); }
/* login screens are a fixed, non-scrolling screen (no tab bar, no bottom padding) */
/* The wine image vignettes to the exact page ivory at its edges, so only its
   center (the glass + red pour) reads. The sign-in card sits over that center,
   so the image is dropped lower here than on the home — the glass clears the
   card into the open band beneath it. Same size as the home; position differs. */
.app--login { overflow: hidden; padding-bottom: 0; background: var(--charcoal) no-repeat center calc(100% - 10px); background-size: 100% auto; }
/* The home/login wine photo shows only under the Classic theme; other themes get a clean page color. */
html[data-theme="classic"] .app--login { background-image: url('classic-home.webp?v=1'); background-position: center calc(50% + 10px); }
/* Midnight gets its own purpose-built dark cellar photo (already vignettes to the page color). */
html[data-theme="midnight"] .app--login { background-image: url('midnight-home.webp?v=1'); }
/* Beige & Tan — its own warm ledge photo (vignettes to the exact beige page color #E2D4BB).
   Centered across app, site, and laptop: this theme-scoped rule outranks the all-theme
   .app--login position rules (standalone / ≥540px) by specificity, so it stays centered everywhere. */
html[data-theme="beige"] .app--login { background-image: url('beige-home.webp?v=2'); background-position: center calc(50% + 10px); }
/* Midnight photo placement — browser only, so the installed app's position is left as-is:
   centered on laptop, lifted ~30px on the mobile site. */
@media (display-mode: browser) {
  html[data-theme="midnight"] .app--login { background-position: center calc(100% - 40px); }
}
@media (display-mode: browser) and (min-width: 540px) {
  html[data-theme="midnight"] .app--login { background-position: center calc(50% + 10px); }
}
/* Installed app (standalone) only: lift the Midnight photo up to centered. */
/* Installed app (standalone) ONLY: the login photo sits CENTERED for every theme. */
@media (display-mode: standalone) {
  html[data-theme="classic"] .app--login,
  html[data-theme="beige"] .app--login,
  html[data-theme="midnight"] .app--login { background-position: center center; }
}
/* Phone WEBSITE only (browser, < 540px): bottom-anchor the login photo for EVERY theme, mirroring
   Midnight's placement, so the admin login, member login, and home splash all share one position
   regardless of how tall each screen's content is. Laptop site and the installed app keep theirs above. */
@media (display-mode: browser) and (max-width: 539.98px) {
  html[data-theme="classic"] .app--login,
  html[data-theme="beige"] .app--login,
  html[data-theme="midnight"] .app--login { background-position: center calc(100% - 55px); }
}

/* ── Dark-theme home/login photo mute ───────────────────────────────────────
   The home photo is inherently light. On DARK presets (set via branding.js →
   html[data-pagetone="dark"]) it would read as a bright blob against the dark
   page, so we lay a wash of the page color (--charcoal) over the background
   image to sink it into the scene. The wash is a pseudo-element pinned BEHIND
   the element's own children (z-index:0), and the direct children are lifted to
   z-index:1 so the crest/logo, sign-in card, headings and buttons stay fully
   legible. ALL of this is scoped to data-pagetone="dark"; light themes (every
   current preset) never get position/z-index/overlay → render is unchanged. */
html[data-pagetone="dark"] .app--login,
html[data-pagetone="dark"] .splash { position: relative; }
html[data-pagetone="dark"] .app--login::after,
html[data-pagetone="dark"] .splash::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: var(--charcoal); opacity: .5;
}
html[data-pagetone="dark"] .app--login > *,
html[data-pagetone="dark"] .splash > * { position: relative; z-index: 1; }
/* Midnight's photo is built for the dark page, so skip the muting wash that exists
   to tame the light Classic photo on dark themes. */
html[data-theme="midnight"] .app--login::after,
html[data-theme="midnight"] .splash::after { opacity: 0; }

.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 12px;
  padding: calc(14px + var(--sat, env(safe-area-inset-top))) 18px 14px;
  background: var(--topbar-grad, linear-gradient(180deg, rgba(248,242,231,.90), rgba(244,236,222,.74)));
  border-bottom: 1px solid var(--line);
  -webkit-backdrop-filter: blur(10px) saturate(125%); backdrop-filter: blur(10px) saturate(125%);
}
/* Per-page logo lockup — mirrors the reference's #top-bar: the "Bowdie's"
   wordmark (Josefin, uppercase) with the section word beneath it in gold
   Playfair italic (e.g. "Wine" replaces "Chophouse"). */
.top-bar-logo { display: inline-block; text-align: left; line-height: 1; }
.top-bar-wordmark { display: block; font-family: var(--sans); font-size: 18px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--text); }
/* section word sits below the wordmark, right-aligned to its right edge
   (below-and-to-the-right), matching the reference top-bar lockup */
.top-bar-section { display: block; text-align: right; font-family: var(--display); font-style: italic; font-size: 13px; font-weight: 400; color: var(--header-color, var(--gold)); letter-spacing: .04em; margin-top: 1px; }

/* Shared brand lockup for the login / account-select screens — matches the
   landing crest exactly (left-aligned wordmark + right-weighted gold section). */
.brand { display: inline-block; text-align: left; line-height: 1; }
.brand .brand-name { display: block; font-family: var(--sans); font-weight: 600; font-size: clamp(38px,11vw,54px); line-height: 1; letter-spacing: .08em; text-transform: uppercase; color: var(--text); }
.brand .brand-sect { display: block; text-align: right; font-family: var(--display); font-style: italic; font-weight: 400; font-size: clamp(22px,6vw,38px); color: var(--gold); margin-top: 6px; }
/* Back-to-roles pill on login screens — mirrors the launcher's "Reset demo" button */
.login-back { position: fixed; top: calc(12px + var(--sat, env(safe-area-inset-top))); right: 14px; z-index: 60;
  font-family: var(--sans); font-size: 9.5px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-dim); background: color-mix(in srgb, var(--card) 82%, transparent); border: 1px solid var(--line); border-radius: 999px;
  padding: 8px 14px; cursor: pointer; -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  -webkit-tap-highlight-color: transparent; transition: color .25s, border-color .25s; }
.login-back:hover { color: var(--gold-soft); border-color: var(--gold-dim); }
.topbar .spacer { flex: 1; }
.topbar .loc { font-size: 12px; color: var(--text-dim); text-align: right; }
/* settings-page back control (lives in the top bar) */
.settings-back { display: inline-flex; align-items: center; gap: 8px; background: transparent; border: 0; cursor: pointer; padding: 4px 2px;
  font-family: var(--sans); font-size: 11px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--text-dim); }
.settings-back .sb-ico { line-height: 0; }
.settings-back .sb-ico svg { width: 18px; height: 18px; stroke: var(--gold-dim); fill: none; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.settings-back:hover { color: var(--gold-soft); }
.settings-back:hover .sb-ico svg { stroke: var(--gold-soft); }

.wrap { padding: 14px 16px; }

/* ----- Typography ----------------------------------------------------- */
h1,h2,h3 { font-family: var(--display); font-weight: 600; margin: 0; letter-spacing: .3px; color: var(--text); }
.section-title { font-size: 10.5px; letter-spacing: .26em; text-transform: uppercase; color: var(--gold-dim); font-family: var(--sans); font-weight: 600; margin: 22px 0 10px; }
.muted { color: var(--text-dim); }
.tiny { font-size: 12px; }
/* "Selected" tag on theme / locker-finish cards — kept small (~60% of .tiny) and no-wrap so
   it never crowds a longer card title into a second line. flex:none so it holds its width. */
.chip-sel { font-size: 7.5px; font-weight: 600; letter-spacing: .03em; color: var(--gold); white-space: nowrap; flex: none; }

/* ----- Cards (glass) --------------------------------------------------
   Card fill is kept fairly opaque on purpose: a translucent card lets the
   previous card's drop shadow bleed through its top edge, which reads as
   the cards overlapping. Opaque glass + a contained shadow keeps them
   cleanly separated while still looking like lensed glass. */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r-l);
  /* one soft elevation + a single top highlight only — no directional edge
     insets or heavy bottom inset, so every card's outline is an identical
     crisp 1px the whole way down the list */
  box-shadow: var(--elev-1), inset 0 1px 0 rgba(255,246,226,.10);
  overflow: hidden;
  transition: border-color .4s var(--ease), box-shadow .4s var(--ease);
}
@media (hover:hover) { .card:hover { border-color: var(--stroke-hi); } }
.card + .card { margin-top: 10px; }
.card-body { padding: 15px 16px; }

/* ----- Bottle row ----------------------------------------------------- */
.bottle { display: flex; gap: 14px; align-items: flex-start; }
.bottle .thumb {
  width: 54px; height: 72px; flex: 0 0 54px; border-radius: var(--r-s);
  display: flex; align-items: center; justify-content: center;
  font-size: 26px;
  background: linear-gradient(160deg, rgba(38,36,32,0.55), rgba(24,22,19,0.42));
  border: 1px solid var(--line);
  box-shadow: var(--lens);
}
.bottle .info { flex: 1; min-width: 0; }
.bottle .name { font-family: var(--display); font-weight: 600; font-size: 21px; line-height: 1.12; color: var(--text); }
.bottle .meta { font-size: 12px; color: var(--text-dim); margin-top: 4px; letter-spacing: .3px; }
.bottle .note { font-size: 14px; color: var(--text-dim); margin-top: 8px; font-family: var(--serif); font-style: italic; line-height: 1.4; }
.bottle .qty { text-align: center; flex: 0 0 auto; }
.bottle .qty b { display:block; font-family: var(--display); font-size: 28px; color: var(--gold-soft); line-height: 1; }
.bottle .qty span { font-size: 9px; letter-spacing: .18em; text-transform: uppercase; color: var(--text-mute); }

/* generic name helper (history/request titles use class="name") */
.name { font-family: var(--display); color: var(--text); }

/* ----- Tags / chips (pills) ------------------------------------------- */
.tag { display:inline-block; font-family: var(--sans); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; padding: 4px 10px; border-radius: var(--r-pill); border: 1px solid var(--line); background: color-mix(in srgb, var(--gold-soft) 6%, transparent); color: var(--text); font-weight: 600; }
.tag--house { color: var(--gold-soft); border-color: color-mix(in srgb, var(--gold-soft) 45%, transparent); }
.tag--byo   { color: var(--byo); border-color: rgba(182,144,218,.45); background: rgba(182,144,218,.07); }
.tag--open  { color: var(--gold-soft); border-color: color-mix(in srgb, var(--gold-soft) 45%, transparent); }
.tag--inhouse { color: var(--green); border-color: rgba(122,154,138,.5); background: rgba(122,154,138,.07); }
/* R117: cellar-readiness pill — rides the Drink Window (or Serving) line */
.rdy { display: inline-block; font-family: var(--sans); font-size: 9px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; padding: 3px 9px; border-radius: var(--r-pill); border: 1px solid var(--line); vertical-align: 2px; margin-left: 6px; }
.rdy--ready { color: var(--green); border-color: rgba(122,154,138,.5); background: rgba(122,154,138,.08); }
.rdy--peak  { color: var(--gold-soft); border-color: color-mix(in srgb, var(--gold-soft) 45%, transparent); background: color-mix(in srgb, var(--gold-soft) 8%, transparent); }
/* R118: 'grace' replaces the red 'soon' — a late-window bottle is an invitation, not a warning */
.rdy--grace { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 50%, transparent); background: color-mix(in srgb, var(--gold) 9%, transparent); }
.tag--offsite { color: var(--text-dim); }

/* ----- Buttons (glass; gold-outline signature) ----------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  font-family: var(--sans); font-size: 12px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
  padding: 11px 18px; border-radius: var(--r-m); border: 1px solid var(--line);
  background: var(--glass-btn); color: var(--text); cursor: pointer;
  text-decoration: none; box-shadow: var(--lens);
  transition: transform .35s var(--spring), border-color .3s var(--ease), background .3s var(--ease), color .3s var(--ease);
}
.btn:hover { border-color: var(--gold); color: var(--gold-soft); background: var(--glass-btn-hi); }
.btn:active { transform: scale(.96); filter: brightness(1.12); }
/* "Primary" = gold OUTLINE on glass (the reference never fills a button gold).
   Border + text carry the gold; a soft gold glow gives it weight. */
/* "Primary"/selected = a gold OUTLINE (no fill change) that enhances on tap —
   used for primary actions and selected filters/nav. */
.btn--gold {
  background: color-mix(in srgb, var(--gold) 8%, transparent);
  color: var(--gold-dim); border-color: var(--gold);
  box-shadow: var(--lens);
}
.btn--gold:hover { border-color: var(--gold-soft); color: var(--gold);
  background: color-mix(in srgb, var(--gold) 14%, transparent); }
.btn--gold:active { background: color-mix(in srgb, var(--gold) 22%, transparent); border-color: var(--gold-soft); filter: brightness(1.04); }
.btn--ghost { background: transparent; border-color: var(--line); color: var(--text-dim); box-shadow: none; }
.btn--ghost:hover { color: var(--gold-soft); border-color: var(--gold-dim); background: color-mix(in srgb, var(--gold) 4%, transparent); }
.btn--block { display: flex; width: 100%; }
.btn--sm { padding: 8px 13px; font-size: 10px; letter-spacing: .1em; }
.btn[disabled] { opacity: .4; pointer-events: none; }
/* inline icon for buttons / table cells — inherits the host's text colour so it
   always matches, replacing the stray +/✎/→ glyphs with the SVG icon set */
svg.ic, .btn svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; flex: 0 0 auto; vertical-align: -2px; }
.btn--sm svg { width: 13px; height: 13px; }
.table svg.ic { width: 15px; height: 15px; }

/* ----- Forms ---------------------------------------------------------- */
label.field { display:block; margin: 14px 0; }
label.field span { display:block; font-family: var(--sans); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--gold); margin-bottom: 7px; font-weight: 600; }
input, select, textarea {
  width: 100%; padding: 12px 13px; border-radius: var(--r-s);
  border: 1px solid var(--line);
  background: var(--card-2);
  color: var(--text);
  font-family: var(--sans); font-size: 15px;
  box-shadow: inset 0 1px 0 rgba(255,248,232,.10);
  transition: border-color .35s var(--ease), box-shadow .35s var(--ease);
}
input:focus, select:focus, textarea:focus { outline: none; border-color: var(--stroke-hi);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--gold-soft) 12%, transparent), inset 0 1px 0 rgba(255,248,232,.18); }
/* Placeholder (e.g. the Browse search hint) follows the theme instead of staying browser-gray. */
input::placeholder, textarea::placeholder { color: var(--text-mute); opacity: 1; }
textarea { resize: vertical; min-height: 70px; }
/* Native date inputs (e.g. Overview custom range) render their own UI; tell the browser to draw
   them dark under Midnight so the field + calendar icon match the theme instead of staying white. */
html[data-theme="midnight"] input[type="date"] { color-scheme: dark; }

/* ----- Bottom nav (client) ------------------------------------------- */
.tabbar {
  position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
  width: 100%; max-width: 480px; display: flex;
  background: var(--topbar-grad, linear-gradient(180deg, rgba(248,242,231,.82), rgba(245,238,224,.94)));
  border-top: 1px solid var(--line); z-index: 30;
  padding-bottom: var(--sab, env(safe-area-inset-bottom));
  -webkit-backdrop-filter: blur(10px) saturate(125%); backdrop-filter: blur(10px) saturate(125%);
}
.tabbar a {
  position: relative;
  flex: 1; text-align: center; padding: 12px 4px 14px; text-decoration: none;
  color: var(--text-mute); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; cursor: pointer;
  transition: color .3s var(--ease);
}
/* notification count — pinned to the icon's upper-right so it never shifts the
   centered tab label */
.tab-badge {
  position: absolute; top: 5px; left: calc(50% + 5px);
  min-width: 16px; height: 16px; padding: 0 4px; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  background: var(--gold); color: #FBF4E2;
  border-radius: 999px; font-size: 9px; font-weight: 700; letter-spacing: 0; line-height: 1;
  box-shadow: 0 1px 4px rgba(74,54,28,.35);
}
.tabbar a .ico { display:block; margin: 0 auto 5px; line-height: 0; width: 19px; height: 19px; }
.tabbar a .ico svg { width: 19px; height: 19px; display: block; stroke: currentColor; fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.tabbar a:active { transform: scale(.94); }
.tabbar a.active { color: var(--gold-soft); }
/* Inline page nav for the admin app — the client tab-bar look, but sitting in the flow
   right below the header instead of fixed to the bottom (the vine divides it from the body).
   Scoped .tabbar.tabbar--inline so it outranks the desktop .tabbar overrides. */
.tabbar.tabbar--inline { position: static; left: auto; right: auto; bottom: auto; transform: none;
  width: 100%; max-width: none; margin: 2px 0 0; padding-bottom: 0; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r-m);
  background: var(--lx-glass, linear-gradient(180deg, rgba(248,242,231,.82), rgba(245,238,224,.94)));
  box-shadow: var(--lens), var(--elev-1); }
.tabbar.tabbar--inline a { padding: 9px 4px 10px; }
.tabbar.tabbar--inline a + a { border-left: 1px solid var(--line-soft); }
.tabbar.tabbar--inline a.active::after { content: ""; position: absolute; left: 22%; right: 22%; bottom: 3px; height: 2px; border-radius: 2px; background: var(--gold-soft); }

/* ----- Pills / stat row ---------------------------------------------- */
.stats { display: flex; gap: 10px; margin: 16px 0 4px; }
.stat { flex: 1; background: var(--lx-glass); border: 1px solid var(--line); border-radius: var(--r-m); padding: 14px; text-align: center;
  box-shadow: inset 0 1px 0 rgba(255,248,232,.11), var(--elev-2); }
.stat b { display:block; font-family: var(--display); font-size: 22px; color: var(--gold); }
.stat span { font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase; color: var(--text-mute); }

/* ----- Modal (glass sheet) ------------------------------------------- */
.modal-bg { position: fixed; inset: 0; background: rgba(54,40,22,.34);
  -webkit-backdrop-filter: blur(10px) saturate(115%); backdrop-filter: blur(10px) saturate(115%);
  display: flex; align-items: flex-start; justify-content: center; z-index: 50;
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .26s var(--ease), visibility .26s var(--ease); }
.modal-bg.open { opacity: 1; visibility: visible; pointer-events: auto; }
.modal {
  background: var(--card-2);
  border: 1px solid var(--line); border-radius: 0 0 var(--r-l) var(--r-l);
  width: 100%; max-width: 480px; padding: calc(20px + var(--sat, env(safe-area-inset-top))) 22px calc(24px + var(--sab, env(safe-area-inset-bottom)));
  max-height: 92vh; max-height: 90dvh; overflow-y: auto;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  box-shadow: var(--elev-3);
  transform: translateY(-100%);
  transition: transform .34s var(--ease);
}
.modal-bg.open .modal { transform: translateY(0); }
.modal--center { border-radius: 0 0 var(--r-l) var(--r-l); }
.modal h2 { font-size: 22px; margin-bottom: 4px; }

/* ----- Table (admin) -------------------------------------------------- */
.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th { text-align: left; font-family: var(--sans); font-size: 10px; letter-spacing: .22em; text-transform: uppercase; color: var(--gold); padding: 11px 12px; border-bottom: 1px solid var(--line); font-weight: 600; }
.table td { padding: 13px 12px; border-bottom: 1px solid var(--line-soft); color: var(--text); }
.table tr:last-child td { border-bottom: 0; }
.table tr:hover td { background: color-mix(in srgb, var(--gold) 8%, transparent); cursor: pointer; }
.table b { font-family: var(--display); font-weight: 600; }

/* ----- Misc ----------------------------------------------------------- */
.row { display: flex; gap: 10px; align-items: center; }
.row--between { justify-content: space-between; }
.divider { height: 1px; background: var(--line); margin: 16px 0; border: 0; }
.empty { text-align: center; color: var(--text-mute); padding: 40px 20px; font-style: italic; font-family: var(--serif); font-size: 16px; }
/* admin card-list rows (replacing the old utilitarian tables) */
.ad-tap { cursor: pointer; }
.ad-row .card-body { display: flex; align-items: center; gap: 12px; }
.ad-text { flex: 1; min-width: 0; }
.ad-text .card-sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ad-count { text-align: center; flex: 0 0 auto; }
.ad-count b { display: block; font-family: var(--display); font-weight: 600; font-size: 20px; color: var(--gold-soft); line-height: 1; }
.ad-count span { font-size: 9px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-mute); }
/* Grouped bottle card (admin locker detail): tap to reveal each physical bottle + its QR label */
.ad-bottle { cursor: pointer; }
.ad-bottle-hint { margin-top: 11px; display: flex; align-items: center; gap: 5px; font-family: var(--sans); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--text-mute); }
.ad-bottle-caret { transition: transform .2s var(--ease); }
.ad-bottle.expanded .ad-bottle-caret { transform: rotate(180deg); }
.ad-bottle-detail { margin-top: 12px; border-top: 1px solid var(--line); padding-top: 6px; cursor: default; }
.ad-bottle-li { padding: 9px 0; border-top: 1px solid var(--line-soft); }
.ad-bottle-li:first-child { border-top: 0; }
/* login account picker — names in normal-case serif so long names never wrap */
.login-pick { justify-content: space-between; align-items: center; text-align: left; padding: 13px 16px; }
.login-pick-name { flex: 1; min-width: 0; font-family: var(--display); font-weight: 600; font-size: 15px; letter-spacing: .01em; text-transform: none; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.login-pick-meta { flex: 0 0 auto; margin-left: 12px; font-family: var(--sans); font-size: 9.5px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--text-mute); white-space: nowrap; }

/* ----- Brand logo lockup on the login screens (matches the home) ----- */
/* Login crest — same fixed-footprint logo box as the splash (see index.html). Logo is
   bottom-anchored, can't exceed the box width, and a squarer logo grows UPWARD until it
   hits max-height. "Chophouse" is live Playfair text tucked at the lower-right; blank
   suffix (`.is-bare`) drops the logo to the very bottom. */
.login-brand { position: relative; display: inline-block; container-type: inline-size; width: clamp(240px, 70vw, 330px); aspect-ratio: 100 / 29; overflow: visible; }
.login-brand > img { position: absolute; left: 0; right: 0; margin: 0 auto; bottom: 11cqw; width: auto; height: auto; max-width: 100%; max-height: 46cqw; object-fit: contain; object-position: center bottom; }
.login-brand.is-bare > img { bottom: 0; }
.login-brand .bm-sect { position: absolute; right: -8.25cqw; left: auto; top: 15.8cqw; margin-top: 6px; font-family: var(--display); font-style: italic; font-weight: 400; color: var(--suffix-color, #B5913F); line-height: 1; font-size: 10.6cqw; white-space: nowrap; }
.login-brand.is-bare .bm-sect { display: none; }
/* Center-suffix option (data-suffix-center on <html>): suffix sits centered under the
   wordmark instead of its tucked lower-right spot. Applies to the home + login crests. */
html[data-suffix-center] .brand-sect,
html[data-suffix-center] .login-brand .bm-sect { left: 0; right: 0; text-align: center; }
/* Roomier screens support a taller logo top. */
@media (min-width: 540px) { .login-brand > img { max-height: 60cqw; } }
.app--login .vine-divider { display: block; margin: -8px auto 0; }
.top-bar-logo-img { display: block; height: 15px; width: auto; }
/* When the header has NO section word, the logo+word lockup collapses to just the 15px logo,
   which the flex centering then floats in the middle of the bar ("moves down"). With nothing
   stacked beneath it, let the logo grow to fill the bar — but bounded TWO ways so a wide mark
   can't run across the bar: it stops at ~28px tall (≈ the logo+word lockup height, so the bar
   height is unchanged when the word is toggled) OR at 1/3 of the header width, whichever it
   reaches first, keeping aspect ratio and staying left-aligned. */
.top-bar-logo.is-bare { max-width: 33%; }
.top-bar-logo.is-bare .top-bar-logo-img { height: auto; width: auto; max-height: 28px; max-width: 100%; }
/* Login page mirrors the home splash vertically: crest pinned to the TOP at the
   same padding-top as .splash, and the demo card pinned to the BOTTOM (via
   space-between) so its lower edge lands exactly where the home's bottom button
   does — that's the home's padding-bottom plus the button's 12px margin.
   Browser: 32+12 = 44px.  Installed app: 97+12 = 109px. */
.login-wrap { display: flex; flex-direction: column; justify-content: space-between; min-height: 100vh; min-height: 100svh;
  padding: calc(var(--sat, env(safe-area-inset-top)) + 80px) 16px calc(var(--sab, env(safe-area-inset-bottom)) + 44px); }
@media (display-mode: standalone) {
  .login-wrap { padding-top: calc(var(--sat, env(safe-area-inset-top)) + 95px); padding-bottom: calc(var(--sab, env(safe-area-inset-bottom)) + 109px); }
  .app--login { background-position: center center; }  /* match the home image's installed-app (centered) position */
}

/* ── Website (browser) only: let the document scroll so Safari's URL/tool bars
   recede ("liquid glass"). The installed standalone app keeps the locked shell
   above untouched. Mirrors the Training Reference: no body lock, no inner scroller. ── */
@media (display-mode: browser) {
  html, body { overscroll-behavior: none; }   /* no rubber-band bounce on the document scroll */
  body { position: static; overflow: visible; }
  /* The document scrolls (so Safari's bars can recede). Reorder the shell so the
     client tab bar rides at the TOP, just under the vine, instead of as a fixed
     footer — header, vine, tabs and body all scroll away together. */
  .app { position: static; overflow: visible; min-height: 100vh; min-height: 100svh;
         display: flex; flex-direction: column;
         padding-bottom: calc(24px + var(--sab, env(safe-area-inset-bottom))); }
  /* Login is a single screen: don't let the .app wrapper's min-height + padding
     stack on top of .login-wrap's own 100svh (that overflow is what scrolled it). */
  .app--login { min-height: 0; padding-bottom: 0; overflow: visible; }
  .app > * { order: 4; flex: 0 0 auto; }      /* body content */
  .app > .topbar { order: 1; }
  .app > .tabbar { order: 2; }                 /* page-switch tabs ride up here */
  .app > .vine-band-wrap { order: 3; }         /* vine divides the tabs from the body */
  /* No baked-in header bar on the site: the logo + account/location controls sit
     directly on the page and scroll away, with just a line to set them apart. */
  .topbar { position: static; background: none; -webkit-backdrop-filter: none; backdrop-filter: none;
            border-bottom: 1px solid var(--line); }
  /* Client website nav: match the admin side's inline nav — a bordered, rounded glass card in
     the flow under the header, instead of a plain background-less row. The vine beneath divides
     it from the body. (The standalone app keeps its fixed bottom tab bar — intentionally different.
     Admin's own .tabbar--inline rules outrank these by specificity, so the admin is unaffected.) */
  .tabbar { position: static; left: auto; right: auto; bottom: auto; transform: none;
            width: auto; max-width: none; margin: 8px 16px 0; overflow: hidden;
            border: 1px solid var(--line); border-radius: var(--r-m);
            background: var(--lx-glass, linear-gradient(180deg, rgba(248,242,231,.82), rgba(245,238,224,.94)));
            box-shadow: var(--lens), var(--elev-1);
            -webkit-backdrop-filter: none; backdrop-filter: none; padding-bottom: 0; }
  .tabbar a { padding: 9px 4px 10px; }
  .tabbar a + a { border-left: 1px solid var(--line-soft); }
  .tabbar a.active::after { content: ""; position: absolute; left: 22%; right: 22%; bottom: 3px; height: 2px; border-radius: 2px; background: var(--gold-soft); }
  /* Vine sits just under the nav card as a slim divider, aligned to the card's edges. */
  .vine-band-wrap { padding: 10px 0 4px; }   /* rev 58: edge to edge on mobile too */
}

/* warm the empty states with a small plum grape mark */
.empty::before { content: ""; display: block; width: 26px; height: 28px; margin: 2px auto 12px; opacity: .72;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 26 28'%3E%3Cpath d='M13 8V3' stroke='%236F7E55' stroke-width='1.4' fill='none' stroke-linecap='round'/%3E%3Cg transform='translate(13 2) rotate(22)'%3E%3Cpath d='M0 0 Q5 -4 11 -1 Q5 4 0 0Z' fill='%2384935F'/%3E%3C/g%3E%3Ccircle cx='13' cy='11' r='3.3' fill='%237A4E86'/%3E%3Ccircle cx='8.2' cy='9' r='3.3' fill='%238C5E96'/%3E%3Ccircle cx='17.8' cy='9' r='3.3' fill='%237A4E86'/%3E%3Ccircle cx='10.4' cy='15.4' r='3.3' fill='%237A4E86'/%3E%3Ccircle cx='15.6' cy='15.4' r='3.3' fill='%238C5E96'/%3E%3Ccircle cx='13' cy='20.4' r='3' fill='%236E4279'/%3E%3C/svg%3E") no-repeat center / contain; }
.badge-count { background: color-mix(in srgb, var(--gold-soft) 12%, transparent); color: var(--gold-soft); border: 1px solid var(--gold); font-size: 10px; font-weight: 700; border-radius: 999px; padding: 0 6px; margin-left: 6px; letter-spacing: 0; }
.toast { position: fixed; bottom: 100px; left: 50%; transform: translateX(-50%);
  background: var(--lx-glass); border: 1px solid var(--gold-dim); color: var(--gold-soft);
  -webkit-backdrop-filter: blur(10px) saturate(130%); backdrop-filter: blur(10px) saturate(130%);
  padding: 12px 22px; border-radius: var(--r-m); font-family: var(--sans); font-weight: 600;
  font-size: 12px; letter-spacing: .08em; text-transform: uppercase; z-index: 60;
  box-shadow: var(--elev-2), inset 0 1px 0 rgba(255,248,232,.14);
  opacity: 0; transition: opacity .25s var(--ease); pointer-events: none; }
.toast.show { opacity: 1; }
/* R105: messaging */
.msg-picker{max-height:200px;overflow-y:auto;border:1px solid var(--line);border-radius:12px;padding:4px 12px;background:color-mix(in srgb,var(--gold) 3%,transparent)}
.msg-pick{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line);font-size:14px;color:var(--text);cursor:pointer}
.msg-pick:last-child{border-bottom:0}
/* R110: the global `input{width:100%;padding:12px}` rule was inflating each
   checkbox into a full-width padded box, shoving the row off-screen */
.msg-pick input{width:18px;height:18px;flex:0 0 auto;padding:0;margin:0;box-shadow:none;accent-color:var(--gold)}
.msg-pick .tiny{margin-left:auto}
.newsbar{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.chat-bubble-btn{flex:0 0 auto;margin-top:2px;background:color-mix(in srgb,var(--card) 82%,transparent);border:1px solid var(--line);border-radius:999px;width:40px;height:40px;display:flex;align-items:center;justify-content:center;color:var(--gold);cursor:pointer;-webkit-tap-highlight-color:transparent}
.chat-bubble-btn svg{width:19px;height:19px}
.chat-ref{border:1px solid var(--line);border-left:3px solid var(--gold);border-radius:12px;padding:10px 13px;margin-bottom:10px;background:color-mix(in srgb,var(--gold) 5%,transparent)}
.chat-ref .ann-type{font-size:9.5px}
.chat-ref-title{font-family:var(--display);font-size:15.5px;color:var(--text);margin-top:5px}
.chat-ref-body{font-family:var(--serif);font-size:13px;line-height:1.45;color:var(--text-dim);margin-top:3px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.chat-thread{display:flex;flex-direction:column;gap:10px;padding:6px 2px 12px;max-height:56svh;overflow-y:auto;-webkit-overflow-scrolling:touch}
.chat-msg{max-width:84%;display:flex;flex-direction:column}
.chat-msg.mine{align-self:flex-end;align-items:flex-end}
.chat-msg.theirs{align-self:flex-start;align-items:flex-start}
.chat-bubble{padding:10px 13px;border-radius:16px;font-size:14.5px;line-height:1.45;color:var(--text);border:1px solid var(--line);font-family:var(--serif)}
.chat-msg.mine .chat-bubble{background:color-mix(in srgb,var(--gold) 15%,var(--card));border-bottom-right-radius:5px}
.chat-msg.theirs .chat-bubble{background:var(--card);border-bottom-left-radius:5px}
.chat-meta{font-size:10.5px;color:var(--text-mute);margin-top:3px}
.chat-input-row{display:flex;gap:8px;margin-top:6px;padding-bottom:calc(var(--sab,env(safe-area-inset-bottom)) + 4px)}
.chat-input{flex:1;min-width:0;border:1px solid var(--line);background:var(--card);border-radius:999px;padding:11px 15px;font-size:14.5px;color:var(--text);font-family:var(--serif)}
.chat-input:focus{outline:none;border-color:var(--gold-dim,var(--gold))}
.chat-send{border-radius:999px;padding:11px 18px}
.chat-back{background:none;border:none;color:var(--gold-soft);font-family:var(--sans);font-size:11px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;padding:4px 0 8px;cursor:pointer}
.chat-archive{background:none;border:1px solid var(--line);border-radius:999px;color:var(--text-mute);font-family:var(--sans);font-size:10px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;padding:5px 12px;cursor:pointer;-webkit-tap-highlight-color:transparent}
.chat-archive:hover{color:var(--gold-soft);border-color:var(--gold-dim,var(--gold))}
.ann-ask{margin-top:9px;background:none;border:1px solid var(--line);color:var(--gold-soft);border-radius:999px;padding:6px 13px;font-family:var(--sans);font-size:10.5px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;cursor:pointer}
/* R104: the resting locker page is exactly one screen — no scroll, no bounce */
#app.scroll-lock{overflow:hidden !important;overscroll-behavior:contain}
/* R103: purchase receipts */
.card--tap{cursor:pointer;-webkit-tap-highlight-color:transparent}
.rcpt-rows{border:1px solid var(--line);border-radius:12px;padding:2px 14px;background:color-mix(in srgb,var(--gold) 3%,transparent)}
.rcpt-row{display:flex;justify-content:space-between;align-items:baseline;gap:12px;padding:9px 0;border-bottom:1px solid var(--line);font-size:14px;color:var(--text)}
.rcpt-row:last-child{border-bottom:0}
.rcpt-row--total{font-size:15.5px}
#rcptPrint,#expPrint{display:none}
@media print{ body > *:not(#rcptPrint):not(#expPrint){display:none !important} #rcptPrint,#expPrint{display:block !important;padding:24px} }
.proto-flag { background: color-mix(in srgb, var(--gold) 4%, transparent); border: 1px solid var(--line); color: var(--gold-soft); font-family: var(--serif); font-style: italic; font-size: 14px; padding: 11px 15px; border-radius: var(--r-s); margin: 16px 0 4px; text-align: center;
  box-shadow: inset 0 1px 0 rgba(255,248,232,.08); }

a { color: var(--gold-soft); }

/* thin gold divider rule, like the site's title underline */
.rule-gold { width: 80px; height: 1px; background: linear-gradient(90deg, transparent, var(--gold), transparent); margin: 16px auto; border: 0; }

/* sage-green grapevine divider — the brand's organic motif, used on the entry
   screens (landing + logins). Muted olive vine, plum grapes (our secondary). */
.vine-divider { display: block; margin: 18px auto; }
/* full-width vine band threaded under the top bar on every in-app page.
   rev 58 (Gabe): EDGE TO EDGE — side padding gone here and at the mobile
   rule; the path itself now spans the full viewBox in both apps. The
   admin inline variant escapes its .wrap padding with negative margins. */
.vine-band-wrap { padding: 9px 0 2px; }
.vine-band-wrap--inline { padding: 2px 0 12px; margin-left:-16px; margin-right:-16px; }
.vine-band { display: block; width: 100%; opacity: .62; }

/* rev 58: the idle vine hugs the stat cards; after "Got it" it SETTLES
   up from the envelope's old footprint in one smooth motion */
.nb-bleed--idle{margin-top:0;margin-bottom:0}
.nb-bleed--idle.nb-settle{animation:nbSettle .65s cubic-bezier(.4,0,.2,1) both}
/* R103: the settle now travels the full height the envelope block used to
   occupy — the page glides back up into its non-scrollable rest state */
@keyframes nbSettle{from{margin-top:118px;opacity:.25}to{margin-top:0;opacity:1}}

/* ----- Native select theming (caret + dark option list) -------------- */
select {
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath fill='%23C9A84C' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 14px center;
}
select option { background: #15110C; color: var(--text); }
* { accent-color: var(--gold); }

/* ----- Custom dropdown (fully themed; used for location + view-as) ---- */
.dd { position: relative; display: inline-block; }
.dd-btn {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--sans); font-size: 11px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text); cursor: pointer;
  padding: 10px 14px; border-radius: var(--r-m); border: 1px solid var(--line);
  background: var(--glass-btn); box-shadow: var(--lens);
  transition: border-color .3s var(--ease), color .3s var(--ease);
}
.dd-btn:hover { border-color: var(--gold); color: var(--gold-soft); }
.dd-btn .dd-caret { color: var(--gold); font-size: 9px; transition: transform .25s var(--ease); }
.dd.open .dd-btn { border-color: var(--gold); color: var(--gold-soft); }
.dd.open .dd-btn .dd-caret { transform: rotate(180deg); }
.dd-sub { font-family: var(--serif); font-style: italic; text-transform: none; letter-spacing: 0; color: var(--gold); font-size: 12px; margin-left: 2px; }
.dd-overlay { position: fixed; inset: 0; z-index: 40; background: transparent; }
.dd-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 41; min-width: 220px;
  background: var(--card-2);
  border: 1px solid var(--line); border-radius: var(--r-m); overflow: hidden;
  box-shadow: var(--elev-3), inset 0 1px 0 rgba(255,248,232,.10);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
.dd-menu.left { right: auto; left: 0; }
.dd-item {
  display: block; width: 100%; text-align: left; cursor: pointer;
  padding: 12px 15px; background: transparent; border: 0; border-top: 1px solid var(--line-soft);
  color: var(--text); font-family: var(--sans); font-size: 13px; letter-spacing: .02em;
  transition: background .2s var(--ease), color .2s var(--ease);
}
.dd-item:first-child { border-top: 0; }
.dd-item:hover { background: color-mix(in srgb, var(--gold-soft) 12%, transparent); color: var(--gold-soft); }
.dd-item.active { color: var(--gold-soft); }
.dd-item .dd-item-sub { display: block; font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-mute); margin-top: 3px; }

/* ----- Role chip ------------------------------------------------------ */
.role-chip {
  display: inline-block; font-family: var(--sans); font-size: 9px; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase; padding: 3px 9px; border-radius: var(--r-pill);
  border: 1px solid var(--line); color: var(--text-dim); background: color-mix(in srgb, var(--gold) 4%, transparent);
}
.role-chip.admin { color: var(--gold-soft); border-color: var(--gold); }

/* ----- Permission toggle switch -------------------------------------- */
.switch {
  display: inline-flex; align-items: center; gap: 0; cursor: pointer;
  width: 42px; height: 24px; border-radius: 999px; border: 1px solid var(--line);
  background: rgba(122,94,42,.20); position: relative; transition: background .25s var(--ease), border-color .25s var(--ease);
  flex: 0 0 auto;
}
.switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%;
  background: var(--text-mute); transition: transform .25s var(--spring), background .25s var(--ease);
}
.switch.on { background: color-mix(in srgb, var(--gold-soft) 20%, transparent); border-color: var(--gold); }
.switch.on::after { transform: translateX(18px); background: var(--gold-soft); }
.switch.locked { opacity: .45; cursor: default; }

/* permission / assignment rows */
.perm-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 11px 0; border-top: 1px solid var(--line-soft); }
.perm-row:first-of-type { border-top: 0; }
.perm-row .perm-label { font-size: 14px; color: var(--text); }
.perm-row .perm-hint { font-size: 11px; color: var(--text-mute); margin-top: 2px; }

/* location-assignment chips */
.loc-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.loc-chip {
  font-family: var(--sans); font-size: 10px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  padding: 7px 12px; border-radius: var(--r-pill); border: 1px solid var(--line);
  background: color-mix(in srgb, var(--gold) 3%, transparent); color: var(--text-dim); cursor: pointer;
  transition: border-color .25s var(--ease), color .25s var(--ease), background .25s var(--ease);
}
.loc-chip.on { color: var(--gold-soft); border-color: var(--gold); background: color-mix(in srgb, var(--gold-soft) 10%, transparent); }

/* Loading overlay — slight dim over the content with a spinning wine glass, centered. Reusable
   for any noticeable delay (e.g. building the share / print images). */
.load-ov { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center;
  background: rgba(18,12,6,.38); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity .22s var(--ease); }
.load-ov.show { opacity: 1; }
.load-box { display: flex; flex-direction: column; align-items: center; gap: 13px; }
.load-glass { width: 46px; height: 46px; color: var(--gold-soft); fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; transform-origin: 50% 50%; animation: glassSpin 1.05s linear infinite; }
@keyframes glassSpin { to { transform: rotate(360deg); } }
.load-msg { font-family: var(--sans); font-size: 10.5px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase; color: var(--gold-soft); }

/* Personalize cards — sentence-case titles + readable descriptions (no all-caps), consistent
   left swatch / center text / right "Selected" layout for every row. */
.pz-card { display: block; width: 100%; text-align: left; cursor: pointer; margin: 0 0 10px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-m); padding: 14px 16px;
  font-family: var(--sans); text-transform: none; letter-spacing: 0; color: var(--text);
  box-shadow: var(--elev-1); transition: border-color .25s var(--ease), background .25s var(--ease); -webkit-tap-highlight-color: transparent; }
.pz-card.on { border-color: var(--gold); background: color-mix(in srgb, var(--gold-soft) 10%, transparent); }
.pz-card:active { transform: scale(.995); }
.pz-row { display: flex; align-items: center; gap: 13px; }
.pz-swatch { display: inline-flex; gap: 5px; flex: none; }
.pz-body { flex: 1 1 auto; min-width: 0; }
.pz-title { display: block; font-family: var(--display); font-weight: 600; font-size: 17px; line-height: 1.2; color: var(--text); }
.pz-desc { display: block; font-family: var(--serif); font-style: italic; font-size: 13.5px; line-height: 1.45; color: var(--text-dim); margin-top: 4px; }
.pz-sel { flex: none; align-self: center; font-family: var(--sans); font-size: 8.5px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--gold); white-space: nowrap; }

/* read-only access note */
.access-note { font-family: var(--serif); font-style: italic; font-size: 13px; color: var(--text-mute); padding: 4px 0 0; }

/* ----- Announcements -------------------------------------------------- */
/* Member-facing card (prominent, "From the Wine Director") */
.ann-wrap { margin: 2px 0 6px; }
/* Tier 2 — informational. One shared "feature" surface (same tone as the stat
   tiles), distinguished by a gold accent stripe + gold eyebrow rather than a
   different fill. Event announcements carry the purple stripe instead. */
/* "All announcements" sits in a box that mirrors the Browse search input's exact
   footprint (same margins, padding, border, font metrics), so the first announcement
   card lands at the same y as the first Browse card in any browser. */
/* Aligns the first News card with the first Browse card at EVERY width (measured live
   at 360/390/440/480px → delta 0): the title bar is exactly the Browse search input's
   height (41px), and both intro lines reserve a fixed 2-line height (.intro-2line),
   so the leading above the first card is identical in both tabs regardless of wrapping. */
.ann-titlebar { margin: 14px 0 10px; height: 41px; display: flex; align-items: center; }
.ann-titlebar .section-title { margin: 0; }
.intro-2line { min-height: 3.1em; }
.ann-card {
  background: var(--card);
  border: 1px solid var(--line); border-radius: var(--r-l); padding: 17px 16px 17px 19px;
  box-shadow: inset 3px 0 0 var(--gold-soft), var(--elev-1), inset 0 1px 0 rgba(255,246,226,.12);
}
.ann-card--event { box-shadow: inset 3px 0 0 var(--byo), var(--elev-1), inset 0 1px 0 rgba(255,246,226,.12); }
.ann-card + .ann-card { margin-top: 10px; }
/* Collapsed cards are pinned to a uniform height so a ruler measures every announcement
   card and every Browse wine card at the exact same 201px (the measured tallest card). */
.ann-card:not(.open) { min-height: 201px; }
.ann-type { display: inline-block; font-family: var(--sans); font-size: 9px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase; padding: 3px 9px; border-radius: var(--r-pill); border: 1px solid var(--gold-dim); color: var(--gold-soft); }
.ann-type.event { color: var(--byo); border-color: rgba(182,144,218,.45); background: rgba(182,144,218,.07); }
.ann-title { font-family: var(--display); font-weight: 600; font-size: 18px; color: var(--text); margin: 9px 0 4px; }
.ann-body { font-family: var(--serif); font-style: italic; font-size: 15px; color: var(--text-dim); line-height: 1.5; }
.ann-meta { font-family: var(--sans); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-mute); margin-top: 11px; }
.ann-dates { font-family: var(--sans); font-size: 11px; letter-spacing: .02em; color: var(--text-mute); margin-top: 9px; }
.ann-meta b { color: var(--gold-soft); font-weight: 600; }

/* Admin strip (subtle, manager awareness) */
.ann-strip {
  display: flex; gap: 11px; align-items: flex-start;
  background: color-mix(in srgb, var(--gold-soft) 6%, transparent); border: 1px solid var(--line); border-radius: var(--r-m);
  padding: 10px 14px; margin-bottom: 16px;
}
.ann-strip .ann-ico { font-size: 13px; line-height: 1.5; }
.ann-strip .ann-list { flex: 1; }
.ann-strip .ann-line { font-size: 12.5px; color: var(--text-dim); }
.ann-strip .ann-line b { color: var(--text); font-family: var(--display); font-weight: 600; }
.ann-strip .ann-line + .ann-line { margin-top: 4px; }

/* Client profile chip (top-right) + sign-out menu */
.profile-chip { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; background: transparent; border: 0; cursor: pointer; padding: 2px 2px 0; }
.profile-chip .profile-name { font-family: var(--display); font-weight: 600; font-size: 16px; color: var(--text); line-height: 1.1; }
.profile-chip .profile-sub { font-family: var(--sans); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-mute); }
.profile-chip.open .profile-name { color: var(--gold-soft); }
.profile-menu {
  position: fixed; top: 70px; right: 14px; z-index: 60; min-width: 210px;
  background: var(--card-2);
  border: 1px solid var(--line); border-radius: var(--r-m); padding: 14px 16px;
  box-shadow: var(--elev-3), inset 0 1px 0 rgba(255,248,232,.10);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
.profile-menu-name { font-family: var(--display); font-weight: 600; font-size: 17px; color: var(--text); }
.profile-menu-sub { font-family: var(--sans); font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-mute); margin-top: 2px; }

/* Announcement card — expandable + dismissable (client) */
.ann-card { position: relative; cursor: pointer; }
.ann-card .ann-head { cursor: pointer; padding-right: 28px; }
.ann-when { display: inline-block; font-family: var(--sans); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-mute); margin-left: 8px; }
.ann-collapse { overflow: hidden; }
.ann-card:not(.open) .ann-collapse { display: none; }
/* collapsed: show only the first two lines of the message; the rest reveals on expand */
.ann-card:not(.open) .ann-body { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
.ann-details { font-family: var(--serif); font-size: 14.5px; color: var(--text-dim); line-height: 1.55; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line-soft); }
.ann-more { font-family: var(--sans); font-size: 10px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--gold); margin-top: 12px; cursor: pointer; }
.ann-x {
  position: absolute; top: 12px; right: 12px; width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--line); background: rgba(122,94,42,.10); color: var(--text-mute);
  font-size: 17px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: color .2s var(--ease), border-color .2s var(--ease); z-index: 2;
}
.ann-x:hover { color: var(--gold-soft); border-color: var(--gold-dim); }

/* "New" pill that marks the bottle on its (light) locker card */
.tag--new { color: var(--gold-soft); border-color: var(--gold); background: color-mix(in srgb, var(--gold-soft) 14%, transparent); }

/* animated grapevine reveal — full-bleed: a vine across the screen with an
   envelope to tap; tapping blooms branches + bottles. No card. */
.nb-bleed { margin: 18px -16px 8px; }
.nb-teaser { cursor: pointer; -webkit-tap-highlight-color: transparent; }
.nb-svg { display: block; width: 100%; }
.nb-headline { text-align: center; font-family: var(--display); font-weight: 600; font-size: 19px; color: var(--gold-soft); letter-spacing: .3px; margin: 2px 0 2px; }
.nbv { fill: none; stroke: #6F7E55; stroke-linecap: round; stroke-width: 2; }
/* drawing branches use butt caps — round caps render a stray dot at the path
   end while the stroke-dash animation is at its hidden start */
.nbdraw { stroke-linecap: butt; }
.nb-env { transform-box: fill-box; transform-origin: 50% 50%; }
.nb-open-body { padding: 2px 16px 0; }
/* wine label by its bloomed bottle — bottom-aligned so the lowest line always
   sits the same distance above the bottle whether the name is one line or two */
.nb-lab { height: 100%; box-sizing: border-box; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; text-align: center; line-height: 1.12; font-family: var(--display); font-weight: 600; font-size: 11px; color: var(--text); overflow: hidden; }
.nb-lab .q { color: var(--gold-dim); white-space: nowrap; }
/* names list shown below the bloom when there are 5+ wines (or 8+ overflow) */
.nb-list { margin-bottom: 2px; }
.nb-li { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 7px 0; border-top: 1px solid rgba(122,94,42,.15); }
.nb-li:first-of-type { border-top: 0; }
.nb-li-name { font-family: var(--display); font-weight: 600; font-size: 14px; color: var(--text); }
.nb-li-qty { font-family: var(--display); font-weight: 600; font-size: 13px; color: var(--gold-dim); flex: 0 0 auto; }
/* hide-then-reveal only on the first open (.nb-anim) and only when motion is
   allowed — otherwise everything renders in its final visible state */
@media (prefers-reduced-motion: no-preference) {
  .nb-teaser .nb-env { animation: nbpulse 1.9s ease-in-out infinite; }
  .nb-anim .nbdraw { stroke-dasharray: 1; stroke-dashoffset: 1; animation: nbdraw 1s ease forwards; }
  .nb-anim .nbpop { opacity: 0; transform: scale(.5); transform-box: fill-box; transform-origin: 50% 100%; animation: nbpop .55s cubic-bezier(.34,1.56,.64,1) forwards; }
  .nb-anim .nbfade { opacity: 0; animation: nbfade .5s ease forwards; }
}
@keyframes nbpulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.05); } }
@keyframes nbdraw { to { stroke-dashoffset: 0; } }
@keyframes nbpop { to { opacity: 1; transform: scale(1); } }
@keyframes nbfade { to { opacity: 1; } }

/* ----- Expandable wine cards (My Locker + Browse) -------------------- */
.wine-card { cursor: pointer; position: relative; }
/* Same uniform collapsed height as the announcement cards (see .ann-card:not(.open)). */
.wine-card:not(.open) { min-height: 201px; }
/* Save-for-later bookmark, pinned to the card's top-right (price gets right padding to clear it). */
.wine-card .card-category { padding-right: 28px; }
.wine-save { position: absolute; top: 11px; right: 12px; z-index: 2; background: transparent; border: 0; padding: 4px; line-height: 0; cursor: pointer; color: var(--text-mute); -webkit-tap-highlight-color: transparent; transition: color .2s var(--ease); }
.wine-save svg { width: 19px; height: 19px; display: block; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.wine-save.on { color: var(--gold-soft); }
.wine-save.on svg { fill: currentColor; }
/* "Saved" toggle on the list header row (right-aligned). */
.saved-toggle { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 6px; background: transparent; border: 1px solid var(--line); border-radius: var(--r-pill); padding: 7px 13px; cursor: pointer; font-family: var(--sans); font-size: 10px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase; color: var(--text-dim); -webkit-tap-highlight-color: transparent; transition: color .2s var(--ease), border-color .2s var(--ease); }
.saved-toggle svg { width: 14px; height: 14px; stroke: currentColor; fill: none; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.saved-toggle.on { color: var(--gold-soft); border-color: var(--gold-dim); }
.saved-toggle.on svg { fill: currentColor; }
/* Browse filter bar — same size/shape as the search input; three dropdown buttons. Selections
   live as removable chips below (see .fb-chips), so the buttons just show their category label. */
.filter-bar { position: relative; z-index: 10; display: flex; margin: 0 0 20px; border: 1px solid var(--line); border-radius: var(--r-s); background: var(--card-2); box-shadow: inset 0 1px 0 rgba(255,248,232,.10); }
.fb-btn { flex: 1 1 0; min-width: 0; display: flex; align-items: center; justify-content: center; gap: 6px; padding: 12px 8px; background: transparent; border: 0; cursor: pointer; font-family: var(--sans); font-size: 13px; letter-spacing: .02em; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fb-btn + .fb-btn { border-left: 1px solid var(--line-soft); }
.fb-btn.on { color: var(--gold-soft); }
.fb-car { font-size: 9px; opacity: .6; flex: none; }
/* Active-filter chips — little faded boxes, each with an ✕ to remove (supports multiple per filter). */
.fb-chips { display: flex; flex-wrap: wrap; gap: 7px; margin: 0 0 12px; }
.fb-chip { display: inline-flex; align-items: center; gap: 4px; padding: 4px 5px 4px 11px; border-radius: var(--r-pill); background: color-mix(in srgb, var(--gold-soft) 9%, transparent); border: 1px solid var(--line); font-family: var(--sans); font-size: 11.5px; color: var(--text-dim); }
.fb-chip-x { display: inline-flex; align-items: center; justify-content: center; width: 17px; height: 17px; border-radius: 50%; background: transparent; border: 0; cursor: pointer; color: var(--text-mute); font-size: 11px; line-height: 1; padding: 0; -webkit-tap-highlight-color: transparent; }
.fb-chip-x:active { color: var(--gold-soft); }
/* R112: the overlay stops ABOVE the tab bar — while a filter menu is open,
   nav taps land on the tabs instead of dying on an invisible sheet */
.fb-overlay { position: fixed; inset: 0; bottom: calc(58px + var(--sab, env(safe-area-inset-bottom))); z-index: 20; }
.fb-menu { position: absolute; top: calc(100% + 5px); width: 33.333%; max-height: 244px; overflow-y: auto; -webkit-overflow-scrolling: touch; z-index: 35; border: 1px solid var(--line); border-radius: var(--r-s); background: var(--lx-glass, #fff); box-shadow: var(--elev-2); -webkit-backdrop-filter: blur(9px) saturate(125%); backdrop-filter: blur(9px) saturate(125%); }
.fb-col0 { left: 0; } .fb-col1 { left: 33.333%; } .fb-col2 { left: 66.666%; }
/* Varietal & Pairs With menus span two button widths so long option text isn't cut off
   (Varietal runs through the Pairs With button; Pairs With runs through the Price button).
   The Price menu keeps the single-button width. */
.fb-menu.fb-wide { width: 66.666%; }
/* With the extra width, enlarge the option text for readability — still fits the longest
   varietal / food on one line (even on a narrow phone). Price menu keeps its size (no extra room). */
.fb-menu.fb-wide .fb-opt { font-size: 15px; padding: 10px 13px; }
.fb-opt { display: block; width: 100%; text-align: left; padding: 9px 11px; background: transparent; border: 0; border-top: 1px solid var(--line-soft); cursor: pointer; font-family: var(--serif); font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fb-opt:first-child { border-top: 0; }
.fb-opt.on { color: var(--gold-soft); background: color-mix(in srgb, var(--gold-soft) 9%, transparent); }
.wine-card .bottle.wine-head { align-items: center; }
.wine-tags { margin-top: 8px; display: flex; gap: 6px; flex-wrap: wrap; }
.wine-price { font-family: var(--display); font-weight: 600; font-size: 20px; color: var(--gold-soft); flex: 0 0 auto; }
.wine-collapse { overflow: hidden; margin-top: 14px; }
.wine-card:not(.open) .wine-collapse { display: none; }
.wine-collapse .note { font-family: var(--serif); font-style: italic; font-size: 14.5px; color: var(--text-dim); line-height: 1.5; margin-top: 0; }
.wine-detail { font-family: var(--sans); font-size: 12.5px; color: var(--text-dim); margin-top: 8px; }
.wine-detail-k { color: var(--text-mute); text-transform: uppercase; letter-spacing: .1em; font-size: 10px; margin-right: 6px; }
.wine-more { font-family: var(--sans); font-size: 10px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--gold); margin-top: 12px; cursor: pointer; }

/* ============================================================
   PREMIUM CONTENT CARDS — mirrors the Training Reference:
   eyebrow label + hairline rule, serif name, italic subtitle,
   small outlined pill tags, no thumbnail. Used by locker, browse,
   catalog and request cards.
   ============================================================ */
.card-category {
  display: flex; align-items: center; gap: 9px; margin-bottom: 9px;
  font-family: var(--sans); font-size: 9px; font-weight: 600;
  letter-spacing: .2em; text-transform: uppercase; color: var(--gold-dim);
}
.card-category.cat-byo { color: var(--byo); }
.card-category .cat-rule { height: 1px; flex: 1 1 auto; background: var(--line); }
.card-category.cat-byo .cat-rule { background: rgba(122,78,134,.30); }
.card-category .cat-right {
  flex: 0 0 auto; font-family: var(--display); font-weight: 600; font-size: 14px;
  letter-spacing: 0; text-transform: none; color: var(--gold);
}
.enjoyed { color: inherit; white-space: nowrap; }
.card--retired { opacity: .62; }
.card--retired .card-name { color: var(--text-mute); }
.pill-retired {
  display: inline-block; vertical-align: middle; font-family: var(--sans);
  font-size: 8.5px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--text-mute); background: color-mix(in srgb, var(--card) 60%, transparent);
  border: 1px solid var(--line); border-radius: 999px; padding: 2px 7px; margin-right: 2px;
}
.card-name { font-family: var(--display); font-weight: 600; font-size: 17px; line-height: 1.18; color: var(--text); }
.card-sub { font-family: var(--serif); font-style: italic; font-size: 13.5px; color: var(--text-mute); margin-top: 3px; line-height: 1.35; }
.tag-row { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 12px; }
.expand-hint { font-family: var(--sans); font-size: 9px; font-weight: 600; letter-spacing: .16em; text-transform: uppercase; color: var(--gold-dim); margin-top: 13px; cursor: pointer; }

/* expandable detail body for the premium cards */
.card-detail { overflow: hidden; margin-top: 18px; padding-top: 18px; border-top: 1px solid var(--line); }
.wine-card:not(.open) .card-detail,
.pcard:not(.open) .card-detail { display: none; }
/* expanded-card sections — mirrors the reference's section-label + detail-value */
.section-label { font-family: var(--sans); font-size: 9px; font-weight: 600; letter-spacing: .3em; text-transform: uppercase; color: var(--gold-dim); margin: 0 0 8px; }
.detail-value + .section-label, .card-detail .btn + .section-label, .card-detail .kv + .section-label { margin-top: 16px; }
.detail-value { font-family: var(--serif); font-style: italic; font-size: 15px; color: var(--text-dim); line-height: 1.6; }
/* expanded wine-card detail fields — mirrors the Training Reference:
   vintage/price pills, uppercase origin, serif value, gold-barred note */
.detail-pills { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 1px; }
.detail-origin { font-family: var(--sans); font-size: 12px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--text-mute); line-height: 1.5; }
.detail-text { font-family: var(--serif); font-weight: 600; font-style: normal; font-size: 16px; color: var(--text); line-height: 1.45; }
.detail-note { font-family: var(--serif); font-style: italic; font-size: 15px; color: var(--text-dim); line-height: 1.6; border-left: 2px solid var(--gold-soft); padding-left: 14px; }
.detail-pills + .section-label, .detail-origin + .section-label, .detail-text + .section-label, .detail-note + .section-label { margin-top: 16px; }
.card-detail .note { font-family: var(--serif); font-style: italic; font-size: 15px; color: var(--text-dim); line-height: 1.6; }
.card-detail .kv { font-family: var(--sans); font-size: 12.5px; color: var(--text-dim); margin-top: 16px; }
.card-detail .kv-k { color: var(--gold-dim); text-transform: uppercase; letter-spacing: .1em; font-size: 10px; margin-right: 6px; }
/* key/value rows inside a settings card (direct child of card-body) */
.card-body > .kv { font-family: var(--sans); font-size: 13px; color: var(--text); display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; }
.card-body > .kv + .kv { border-top: 1px solid var(--line-soft); }
.card-body > .kv > .kv-k { color: var(--text-mute); text-transform: uppercase; letter-spacing: .1em; font-size: 10px; align-self: center; }

/* profile / settings menu items (client) */
.profile-menu-item {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  background: transparent; border: 0; border-top: 1px solid var(--line-soft);
  color: var(--text); font-family: var(--sans); font-size: 13px; letter-spacing: .01em;
  padding: 12px 2px; cursor: pointer; transition: color .2s var(--ease);
}
.profile-menu-item:first-of-type { border-top: 0; }
.profile-menu-item:hover { color: var(--gold-soft); }
/* Count badge on a menu item (e.g. pending pull requests) — sits at the right edge */
.profile-menu-item .pm-badge { margin-left: auto; flex: 0 0 auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px;
  background: var(--gold); color: #fff; font-family: var(--sans); font-size: 11px; font-weight: 700; line-height: 18px; text-align: center; }
.profile-menu-item .pm-ico { flex: 0 0 auto; line-height: 0; }
.profile-menu-item .pm-ico svg { width: 16px; height: 16px; stroke: var(--gold-dim); fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.profile-menu-item.danger { color: var(--text-dim); }
.profile-menu-item.danger:hover { color: var(--red); }
.profile-menu-item.danger .pm-ico svg { stroke: var(--text-mute); }
/* second group in the account menu (account/settings actions), set off from the page links */
.profile-menu-group { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line); }
.profile-menu-group .profile-menu-item:first-of-type { border-top: 0; }
/* the admin menu carries more items now — let it scroll if it can't fit the viewport */
.profile-menu { max-height: calc(100vh - 88px); overflow-y: auto; -webkit-overflow-scrolling: touch; }

/* admin header selectors live in the top bar (mirrors client profile) */
.topbar-controls { display: flex; flex-direction: column; align-items: flex-end; gap: 0; margin-left: auto; }
.topbar .dd-btn { padding: 1px 0; background: transparent; border: 0; box-shadow: none; gap: 6px; }
.topbar .dd-btn:hover { color: var(--wine); }
.topbar-controls .dd:first-child .dd-btn { font-family: var(--display); font-size: 15px; font-weight: 600; letter-spacing: .01em; text-transform: none; color: var(--text); }
.topbar-controls .dd:last-child .dd-btn { font-size: 9.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--text-mute); }
.topbar-controls .dd-caret { font-size: 8px; }
.topbar-controls .dd.open .dd-btn { color: var(--gold); }
/* When a topbar dropdown is open, lift the whole top bar above the
   click-catching overlay (z-index 40) so menu items are actually tappable —
   but keep it below modals (z-index 50). */
.topbar.dd-active { z-index: 45; }

/* ----- Desktop: present the mobile product as a deliberately framed panel on a
   warm backdrop, instead of a bare narrow column floating on the page. Kicks in
   at ≥540px to MATCH the home page's breakpoint (index.html), so every surface —
   home, login, locker, admin — frames at the exact same width. Phone unchanged. */
@media (min-width: 540px) {
  html, body { background: #D3C5A9; }
  /* Side panels track the THEME (not the transient locker/collection color, which the
     edge-paint guard now leaves alone on the laptop site). Midnight Cellar — including
     Auto / Match-device resolving to it after dark — gets a dark surround so the centered
     panel still reads as elevated, instead of a light tan frame around a dark app. */
  html[data-theme="midnight"], html[data-theme="midnight"] body { background: #14110D; }
  /* Reserve symmetric scrollbar gutters so the scrolling pages (client/admin) stay
     centered exactly like the non-scrolling login/home — no few-pixel shift left. */
  html { scrollbar-gutter: stable both-edges; }
  .app, .splash { background: var(--charcoal);
    box-shadow: 0 0 0 1px rgba(122,94,42,.16), 0 30px 80px -36px rgba(54,40,22,.5); }
  /* Box the locker takeover to the same 480 column as the app. clip-path clips the
     whole subtree — including the position:fixed zoom/fill/contents — to the
     centered panel WITHOUT becoming a containing block, so the zoom keeps its
     viewport coordinates and still grows from the locker. The fill + contents
     reflow to 480 wide; the #D3C5A9 backdrop shows on either side. */
  .locker-takeover { clip-path: inset(0 calc((100% - 480px) / 2)); }
  .lt-fill, .lt-contents { left: 0; right: 0; width: 480px; max-width: 480px; margin-left: auto; margin-right: auto; }
  /* The sign-in screen keeps the home's wine image — the .app solid-charcoal panel
     fill above would otherwise cover it on laptop. Centred in the same 480 column
     and at the same position/size as mobile, so it reads identically across devices. */
  .app--login { background: var(--charcoal) no-repeat center calc(100% + 30px); background-size: 100% auto; }
  /* Laptop: match the home splash's desktop crest height exactly. The splash drops to a
     44px top padding at ≥540px (see index.html), but .login-wrap had no desktop override
     and stayed at its 80px base — so the crest, vine, and tagline sat ~36px lower on the
     login than on the home. Pin it to the same 44px so the two screens line up on entry. */
  .login-wrap { padding-top: calc(var(--sat, env(safe-area-inset-top)) + 44px); }
}

/* ----- Desktop polish ------------------------------------------------- */
@media (min-width:880px) {
  ::-webkit-scrollbar { width: 10px; }
  ::-webkit-scrollbar-track { background: transparent; }
  ::-webkit-scrollbar-thumb { background: color-mix(in srgb, var(--gold-soft) 20%, transparent); border-radius: 8px; border: 3px solid transparent; background-clip: content-box; }
  ::-webkit-scrollbar-thumb:hover { background-color: color-mix(in srgb, var(--gold-soft) 36%, transparent); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* ===================================================================
   v40 — Overview analytics · Activity log · QR labels · Wine list
   =================================================================== */

/* ----- KPI cards ----- */
.kpi-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 4px 0 14px; }
.kpi-grid--3 { grid-template-columns: 1fr 1fr 1fr; }
.kpi { background: var(--lx-glass); border: 1px solid var(--line); border-radius: var(--r-m); box-shadow: var(--lens), var(--elev-1); padding: 14px 15px; }
.kpi-val { font-family: var(--display); font-weight: 600; font-size: 25px; line-height: 1.05; color: var(--text); letter-spacing: -.01em; }
.kpi-label { font-family: var(--sans); font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--gold-dim); font-weight: 600; margin-top: 7px; }
.kpi-sub { font-family: var(--serif); font-style: italic; font-size: 12.5px; color: var(--text-mute); margin-top: 3px; }
@media (max-width: 360px){ .kpi-grid--3 { grid-template-columns: 1fr 1fr; } }

/* ----- split bar + legend ----- */
.splitbar { display: flex; height: 14px; border-radius: 999px; overflow: hidden; border: 1px solid var(--line); background: rgba(122,94,42,.06); margin: 4px 0 10px; }
.sb-house { background: var(--gold-soft); }
.sb-byo   { background: var(--byo); }
.legend { display: flex; flex-wrap: wrap; gap: 14px; font-family: var(--sans); font-size: 11.5px; color: var(--text-dim); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.dot-house { background: var(--gold-soft); }
.dot-byo { background: var(--byo); }

/* ----- bar chart ----- */
.chart { width: 100%; height: auto; display: block; margin: 2px 0 10px; }
.chart .bar { fill: var(--gold-soft); }
.chart .bar--empty { fill: var(--line); opacity: .55; }
.chart .ch-x { fill: var(--text-mute); font-family: var(--sans); font-size: 10px; }
.chart .ch-v { fill: var(--gold-dim); font-family: var(--sans); font-size: 10px; font-weight: 700; }

/* ----- horizontal bars ----- */
.hbar-row { display: grid; grid-template-columns: minmax(96px, 40%) 1fr auto; align-items: center; gap: 10px; padding: 7px 0; border-top: 1px solid var(--line-soft); }
.hbar-row:first-of-type { border-top: 0; }
.hbar-label { font-family: var(--display); font-size: 14px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar-track { height: 8px; border-radius: 999px; background: rgba(122,94,42,.08); overflow: hidden; }
.hbar-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--gold-dim), var(--gold-soft)); }
.hbar-val { font-family: var(--sans); font-size: 12px; font-weight: 600; color: var(--text-dim); white-space: nowrap; }

/* ----- chips (filters) ----- */
.chips-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.chip { font-family: var(--sans); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; font-weight: 600; color: var(--text-dim); background: transparent; border: 1px solid var(--line); border-radius: var(--r-pill); padding: 6px 12px; cursor: pointer; transition: all .18s var(--ease); }
.chip:hover { border-color: var(--gold-dim); color: var(--gold-soft); }
.chip.on { color: var(--gold-soft); border-color: var(--gold); background: color-mix(in srgb, var(--gold-soft) 10%, transparent); }

/* ----- Activity timeline ----- */
.timeline { margin: 2px 0 6px; }
.ev { display: grid; grid-template-columns: 22px 1fr; gap: 2px; }
.ev-spine { position: relative; display: flex; justify-content: center; }
.ev-spine::before { content: ""; position: absolute; top: 0; bottom: 0; width: 1.5px; background: var(--line); }
.ev:first-child .ev-spine::before { top: 9px; }
.ev:last-child .ev-spine::before { bottom: calc(100% - 16px); }
.ev-dot { position: relative; z-index: 1; width: 9px; height: 9px; border-radius: 50%; margin-top: 7px; background: var(--gold-soft); box-shadow: 0 0 0 3px var(--card); }
.ev-pull .ev-dot { background: var(--green); }
.ev-add .ev-dot { background: var(--gold-soft); }
.ev-req .ev-dot { background: var(--byo); }
.ev-cat .ev-dot { background: var(--gold-dim); }
.ev-news .ev-dot { background: var(--text-mute); }
.ev-body { padding: 2px 0 16px 6px; }
.ev-top { display: flex; align-items: center; gap: 9px; }
.ev-badge { font-family: var(--sans); font-size: 8.5px; letter-spacing: .12em; text-transform: uppercase; font-weight: 700; padding: 3px 8px; border-radius: var(--r-pill); border: 1px solid var(--line); color: var(--text-dim); background: rgba(122,94,42,.05); }
.ev-badge.ev-pull { color: var(--green); border-color: rgba(122,154,138,.5); }
.ev-badge.ev-req { color: var(--byo); border-color: rgba(122,78,134,.4); }
.ev-time { font-family: var(--sans); font-size: 11px; color: var(--text-mute); }
.ev-summary { font-family: var(--display); font-size: 15px; color: var(--text); margin-top: 5px; line-height: 1.25; }
.ev-detail { font-family: var(--serif); font-style: italic; font-size: 13.5px; color: var(--text-dim); margin-top: 3px; line-height: 1.4; }
.ev-foot { font-family: var(--sans); font-size: 11px; color: var(--text-mute); margin-top: 6px; }
.ev-photo { color: var(--gold-dim); }
.ev-photo svg { width: 11px; height: 11px; vertical-align: -1px; stroke: currentColor; fill: none; }
.ev-undo .ev-dot { background: var(--red); }
.ev-undo .ev-badge { color: var(--red); border-color: rgba(140,90,62,.45); }
.ev-reversed { font-family: var(--sans); font-size: 8px; letter-spacing: .1em; text-transform: uppercase; font-weight: 700; color: var(--text-mute); border: 1px solid var(--line); border-radius: var(--r-pill); padding: 2px 8px; }
.ev.is-reversed .ev-summary { text-decoration: line-through; opacity: .6; }
.ev-undo-btn { padding: 5px 12px; font-size: 9.5px; }

/* ----- QR bottle labels ----- */
.qr-sheet { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 6px; }
.qr-card { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-m); padding: 14px 12px 12px; text-align: center; box-shadow: var(--lens), var(--elev-1); }
.qr-canvas { width: 122px; height: 122px; margin: 0 auto 10px; display: flex; align-items: center; justify-content: center; }
.qr-canvas img, .qr-canvas canvas, .qr-canvas table { margin: 0 auto; }
.qr-fallback { width: 110px; height: 110px; display: flex; align-items: center; justify-content: center; border: 1px dashed var(--line); border-radius: 8px; font-family: var(--sans); font-size: 11px; color: var(--text-mute); word-break: break-all; padding: 8px; }
.qr-name { font-family: var(--display); font-weight: 600; font-size: 14.5px; color: var(--text); line-height: 1.2; }
.qr-sub { font-family: var(--sans); font-size: 10.5px; letter-spacing: .04em; color: var(--gold-dim); margin-top: 4px; text-transform: uppercase; }
.qr-loc { font-family: var(--serif); font-style: italic; font-size: 12.5px; color: var(--text-mute); margin-top: 4px; }
.qr-sheet-head { grid-column: 1 / -1; font-family: var(--display); font-size: 15px; color: var(--text); border-bottom: 1px solid var(--line); padding-bottom: 8px; margin-bottom: 2px; }
/* Blank pre-printed label preview — mirrors the print: QR left, "Locker:" line lower-right. */
.qr-card--blank { display: flex; align-items: baseline; gap: 11px; text-align: left; padding: 16px 14px; }
.qr-card--blank .qr-canvas { margin: 0; width: 96px; height: 96px; flex: 0 0 auto; }
.qr-code-txt { writing-mode: vertical-rl; transform: rotate(180deg); align-self: center; flex: 0 0 auto; height: 96px; text-align: center; font-family: ui-monospace, "Courier New", monospace; font-size: 19px; letter-spacing: .5px; color: var(--text-mute); }
.qr-blank-line { flex: 1 1 auto; display: flex; align-items: baseline; gap: 6px; }
.qr-blank-line .qbl-lbl { font-family: var(--serif); font-size: 15px; line-height: 1; color: var(--text); white-space: nowrap; }
.qr-write { flex: 1 1 auto; border-bottom: 1px solid var(--text-mute); margin-right: 6px; transform: translateY(-3px); }
/* Scan-now landing — a single tap target centered on the page. */
.scan-now-wrap { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 58vh; padding: 24px 16px; text-align: center; }
.scan-now { width: 208px; height: 208px; border-radius: 50%; border: 1px solid var(--gold-dim); background: var(--lx-glass); box-shadow: var(--lens), var(--elev-2); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; cursor: pointer; -webkit-tap-highlight-color: transparent; transition: transform .25s var(--ease), box-shadow .25s var(--ease), border-color .25s var(--ease); }
@media (hover:hover) { .scan-now:hover { transform: scale(1.03); border-color: var(--gold); } }
.scan-now:active { transform: scale(.98); }
.scan-now-ico svg { width: 48px; height: 48px; stroke: var(--gold); fill: none; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.scan-now-txt { font-family: var(--display); font-size: 22px; letter-spacing: .01em; color: var(--text); }
.scan-now-sub { margin-top: 20px; max-width: 290px; font-family: var(--serif); font-style: italic; font-size: 13.5px; line-height: 1.5; color: var(--text-mute); }
.lbl-row { display: flex; align-items: center; gap: 12px; padding: 10px 4px; border-top: 1px solid rgba(0,0,0,.07); }
.lbl-row:first-child { border-top: 0; }
.lbl-row.off { opacity: .5; }
.lbl-check { width: 18px; height: 18px; flex: 0 0 auto; accent-color: var(--gold, #9A7B2C); }
.lbl-info { flex: 1 1 auto; min-width: 0; }
.lbl-name { font-weight: 600; }
.lbl-step { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.lbl-pm { width: 27px; height: 27px; border: 1px solid var(--line); border-radius: 7px; background: #fff; font-size: 15px; line-height: 1; cursor: pointer; color: var(--text); }
.lbl-pm:disabled { opacity: .35; cursor: default; }
.lbl-num { width: 48px; text-align: center; font: inherit; font-size: 13px; padding: 5px; border: 1px solid var(--line); border-radius: 7px; }

/* ----- scan modal ----- */
.scan-wrap { position: relative; border-radius: var(--r-s); overflow: hidden; background: #1a1712; aspect-ratio: 1 / 1; display: flex; align-items: center; justify-content: center; margin-top: 4px; }
.scan-wrap video { width: 100%; height: 100%; object-fit: cover; }
.scan-reticle { position: absolute; inset: 18%; border: 2px solid rgba(255,253,247,.9); border-radius: 16px; box-shadow: 0 0 0 100vmax rgba(20,16,10,.28); }

/* ----- Wine list (screen + print) ----- */
.wine-list { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-m); padding: 22px 22px 16px; box-shadow: var(--lens), var(--elev-1); }
.wl-head { text-align: center; border-bottom: 1.5px solid var(--gold); padding-bottom: 12px; margin-bottom: 10px; }
.wl-brand { font-family: var(--display); font-weight: 700; font-size: 23px; letter-spacing: .02em; color: var(--text); }
.wl-loc { font-family: var(--sans); font-size: 10.5px; letter-spacing: .22em; text-transform: uppercase; color: var(--gold-dim); margin-top: 5px; }
.wl-section { margin-top: 16px; }
.wl-cat { font-family: var(--sans); font-size: 11px; letter-spacing: .22em; text-transform: uppercase; color: var(--gold-dim); font-weight: 600; margin: 0 0 8px; border-bottom: 1px solid var(--line-soft); padding-bottom: 5px; }
.wl-item { margin-bottom: 11px; }
.wl-row { display: flex; align-items: baseline; gap: 6px; }
.wl-name { font-family: var(--display); font-weight: 600; font-size: 15.5px; color: var(--text); }
.wl-dots { flex: 1; border-bottom: 1px dotted var(--line); transform: translateY(-3px); }
.wl-price { font-family: var(--sans); font-size: 13px; font-weight: 600; color: var(--gold-dim); }
.wl-meta { font-family: var(--serif); font-style: italic; font-size: 13px; color: var(--text-mute); margin-top: 1px; }
.wl-note { font-family: var(--serif); font-size: 13px; color: var(--text-dim); line-height: 1.5; margin-top: 4px; border-left: 2px solid var(--gold-soft); padding-left: 11px; }
.wl-foot { text-align: center; font-family: var(--sans); font-size: 10px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-mute); margin-top: 18px; border-top: 1px solid var(--line-soft); padding-top: 10px; }

/* ----- print plumbing ----- */
.print-only { display: none; }
@media print {
  @page { margin: 14mm; }
  body { background: #fff; }
  .topbar, .vine-band-wrap, .row.row--between.no-print, .no-print, .badge-count { display: none !important; }
  .app, .app--wide, .wrap { max-width: none !important; width: auto !important; padding: 0 !important; margin: 0 !important; box-shadow: none !important; }
  body * { visibility: hidden; }
  .printable, .printable * { visibility: visible; }
  .printable { position: absolute; left: 0; top: 0; width: 100%; }
  .print-only { display: block; }
  .wine-list, .qr-card { border: 1px solid #d8cdb4; box-shadow: none; break-inside: avoid; }
  .qr-sheet { grid-template-columns: 1fr 1fr 1fr; gap: 10px; }
}

/* ===================================================================
   v41 — bottle ratings (Browse-only) + drink window
   =================================================================== */
.stars { display: inline-flex; align-items: center; gap: 1px; line-height: 1; }
.star { color: color-mix(in srgb, var(--gold) 24%, transparent); font-size: 14px; }
.star.on { color: var(--gold-soft); }
.rating-inline { display: inline-flex; align-items: center; gap: 7px; }
.rating-num { font-family: var(--sans); font-size: 12.5px; font-weight: 600; color: var(--text-dim); }
.rating-count { font-family: var(--sans); font-size: 11.5px; color: var(--text-mute); }
.browse-rating { margin-top: 8px; }
.detail-rating { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 2px; }
.rating-note { font-family: var(--serif); font-style: italic; font-size: 12.5px; color: var(--text-mute); }

/* interactive input (History) */
.stars--input { gap: 3px; }
.star-btn { background: none; border: 0; padding: 2px; margin: 0; cursor: pointer; font-size: 21px; line-height: 1; color: color-mix(in srgb, var(--gold) 26%, transparent); transition: color .15s var(--ease), transform .15s var(--spring); }
.star-btn:hover { transform: scale(1.12); }
.star-btn.on { color: var(--gold-soft); }
.rate-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; padding: 11px 0 0; width: 100%; background: none; border: 0; border-top: 1px solid var(--line-soft); cursor: pointer; text-align: left; font: inherit; -webkit-tap-highlight-color: transparent; }
.rate-label { font-family: var(--sans); font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; font-weight: 600; color: var(--gold-dim); }
.rate-right { display: inline-flex; align-items: center; gap: 9px; }
.rate-cta { font-family: var(--sans); font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; font-weight: 600; color: var(--gold-soft); }
.rate-edit { font-family: var(--sans); font-size: 8.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-mute); border: 1px solid var(--line); border-radius: var(--r-pill); padding: 2px 8px; }
.rate-stars-big { display: flex; gap: 6px; justify-content: center; margin: 12px 0 16px; }
.rate-star { background: none; border: 0; padding: 4px; cursor: pointer; font-size: 34px; line-height: 1; color: color-mix(in srgb, var(--gold) 26%, transparent); transition: color .12s var(--ease), transform .12s var(--spring); }
.rate-star.on { color: var(--gold-soft); }
.rate-star:active { transform: scale(1.18); }
.rating-toggle { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; background: none; border: 0; padding: 0; margin-top: 2px; cursor: pointer; width: 100%; text-align: left; -webkit-tap-highlight-color: transparent; }
.rating-more { font-family: var(--sans); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--gold-dim); }
.reviews { margin-top: 12px; display: flex; flex-direction: column; gap: 13px; }
.review { border-left: 2px solid var(--line); padding-left: 12px; }
.review-stars { margin-bottom: 3px; }
.review-msg { font-family: var(--serif); font-style: italic; font-size: 13px; color: var(--text-dim); line-height: 1.5; }
.review-empty { font-family: var(--serif); font-style: italic; font-size: 13px; color: var(--text-mute); }

/* ===================================================================
   v42 — the locker: tap → key twist → door swing → expand to screen
   =================================================================== */
.locker-stage { position: relative; margin: 4px auto 0; max-width: 290px; cursor: pointer; -webkit-tap-highlight-color: transparent; -webkit-touch-callout: none; touch-action: manipulation; }
.locker-stage .lk-root { width: 100%; height: auto; display: block; filter: drop-shadow(0 20px 38px rgba(18,11,4,.42)); }
.lk-hint { text-align: center; margin: 9px 0 2px; font-family: var(--sans); font-size: 10px; letter-spacing: .24em; text-transform: uppercase; color: var(--gold-dim); transition: opacity .4s ease; }
.lk-hint.gone { opacity: 0; }

/* brass lock breathes to invite a tap */
.lk-lockglow { animation: lkPulse 2.6s ease-in-out infinite; }
@keyframes lkPulse { 0%,100% { opacity: 0; } 50% { opacity: .38; } }
.lk-root.unlocking .lk-lockglow, .lk-root.open .lk-lockglow { animation: none; opacity: 0; }

/* key twist */
.lk-key { opacity: 0; transform-box: fill-box; transform-origin: center top; }
.lk-root.unlocking .lk-key { animation: lkKey .6s cubic-bezier(.5,0,.3,1) forwards; }
@keyframes lkKey { 0% { opacity: 0; transform: rotate(-6deg); } 28% { opacity: 1; transform: rotate(-6deg); } 100% { opacity: 1; transform: rotate(80deg); } }

/* door swing (left hinge) — final state set on .open so it holds without 'forwards' */
.lk-door { transform-box: fill-box; transform-origin: left center; }
.lk-bot-art { transition: opacity .22s ease; }   /* eases bottles in on first load; clones start visible */
.lk-root.open .lk-door { transform: scaleX(.10) skewY(-2.5deg); animation: lkDoor 1s cubic-bezier(.42,0,.22,1); }
@keyframes lkDoor { 0% { transform: scaleX(1) skewY(0deg); } 100% { transform: scaleX(.10) skewY(-2.5deg); } }
.lk-root.open .lk-edge { opacity: 1; animation: lkEdge .8s ease; }
@keyframes lkEdge { 0% { opacity: 0; } 30% { opacity: 1; } 100% { opacity: 1; } }
/* The lit-glow swells steadily as the door opens, growing bright + large enough to
   wash the bottles (and their close-up tags) out of view by the time it's fully open.
   It lives behind .lk-door, so it never covers the door itself. Holds at peak (both)
   while the collection fades in over the top. */
.lk-root.open .lk-litglow { transform-box: fill-box; transform-origin: 50% 52%; animation: lkLit 1.05s cubic-bezier(.34,0,.26,1) both; }
@keyframes lkLit { 0% { opacity: 0; transform: scale(.62); } 100% { opacity: 1; transform: scale(1.85); } }
/* rev 38: in the HORREUM the wall locker must NEVER wash out — the camera
   travels into a REAL interior. The legacy swell above was authored for the
   flat interface, where the growing clone was ABOUT TO BECOME the collection
   backdrop, so scaling the glow to 1.85× (past the frame, over the body) and
   holding was invisible by design. On the room's wall svg it dissolved the
   locker into a solid slab at door-open, leaving only the door (Gabe's video,
   frame-by-frame). Here the glow still lifts as the door opens, but stays
   CONTAINED to the interior window; frame, bottles and tags keep their design
   all the way through the travel. */
.hzr-locker-stand .lk-root.open .lk-litglow { animation: lkLitRoom 1.05s cubic-bezier(.34,0,.26,1) both; }
@keyframes lkLitRoom { 0% { opacity: 0; transform: scale(.62); } 100% { opacity: .5; transform: scale(1); } }
/* close = reverse of the open: door swings shut, then the key turns to lock */
.lk-root.closing .lk-door { transform: scaleX(1) skewY(0deg); animation: lkDoorClose .9s cubic-bezier(.42,0,.22,1); }
@keyframes lkDoorClose { 0% { transform: scaleX(.1) skewY(-2.5deg); } 100% { transform: scaleX(1) skewY(0deg); } }
.lk-root.locking .lk-key { animation: lkKeyLock .62s cubic-bezier(.5,0,.3,1) forwards; }
@keyframes lkKeyLock { 0% { opacity: 1; transform: rotate(80deg); } 68% { opacity: 1; transform: rotate(0deg); } 100% { opacity: 0; transform: rotate(0deg); } }
.lk-root.closing .lk-lockglow, .lk-root.locking .lk-lockglow { animation: none; opacity: 0; }

/* full-screen takeover — the locker becomes the background */
.locker-takeover { position: fixed; inset: 0; z-index: 9000; overflow: hidden; transition: opacity .42s ease; }
.locker-takeover.leaving { opacity: 0; }
/* rev 30: 1.25s with a gentler entry — from the horreum wall the locker
   starts roughly HALF the size it did on the old Browse page, so the same
   1s covered twice the growth and read rushed/abrupt. More runway restores
   the pre-horreum glide. */
.lt-zoom { position: fixed; z-index: 0; transform-origin: 50% 46%; transition: transform 1.25s cubic-bezier(.32,.01,.22,1); will-change: transform; }
.lt-zoom svg { width: 100%; height: 100%; display: block; }
/* The backdrop is the SAME wash as the lit-glow (so the glow flows seamlessly into it) and
   it only fades in AFTER the door has opened (delay ~1s) so it never touches the swinging
   door. The collection then fades in over this wash. Every theme now leans into the LOCKER'S
   OWN interior color (no gold flare anywhere): the wash brightens gently toward the finish's
   "lit" interior at the center and eases to its deep interior at the edges — a warm "light
   turns on inside" that's easy on the eyes, then dissolves straight into the collection. */
.lt-fill { position: fixed; inset: 0; z-index: 1; pointer-events: none; background: radial-gradient(125% 95% at 50% 45%, var(--lk-glow,#6b5630) 0%, var(--lk-interior,#241a10) 52%, var(--lk-interior-deep,#150f09) 100%); opacity: 0; transition: opacity .9s cubic-bezier(.55,0,.85,.2) .05s; transform-origin: 50% 45%; }
/* Keep the glow in MOTION for the full reveal beat (~1200ms) so it never blooms early and sits
   frozen — but move it with a tiny scale-UP only, never a resized background tile. A full-bleed
   wash scaled up just OVERSCANS the screen (clipped by the takeover), so there is no tile edge
   and therefore no faint growing rectangle. The expansion is slow early and a touch quicker
   right around 1200ms, exactly where the static hold used to be. If the collection still hasn't
   appeared by 1200ms (rare — the reveal is capped there), 1200→1300ms it drifts out a little
   more so it reads as settling. Opacity/close behaviour is unchanged, so no glow on the way out. */
.locker-takeover.go .lt-fill { opacity: 1; animation: ltGlow 1.3s cubic-bezier(.32,0,.32,1) forwards; }
@keyframes ltGlow { 0% { transform: scale(1); } 70% { transform: scale(1.02); } 92% { transform: scale(1.06); } 100% { transform: scale(1.11); } }
/* Midnight Cellar: the open wash must EASE DARKER as the locker grows, not bloom lighter — the
   bright glow is the day-mode (Classic / Beige) effect and reads as glare at night. This was lost
   when the per-theme .lt-fill override was dropped during the day-mode strain fix; restore it here.
   Same scale-up animation, but a dark-CENTERED gradient: as it blooms outward the cabinet's deepest
   interior expands to fill the surround, so the backdrop settles slightly darker. (Auto / Match-device
   at night resolve to data-theme="midnight", so they inherit this too.) */
html[data-theme="midnight"] .lt-fill { background: radial-gradient(125% 95% at 50% 45%, var(--collection-bg,#14100B) 0%, var(--lk-interior-deep,#150f09) 55%, var(--lk-interior,#241a10) 100%); }
/* The OTHER light source: the locker's own door-open glow (#lkLit, centered on the warm
   --lk-glow cross) flashes in via the lkLit keyframe as the door swings — the "gets brighter
   first" flare. Its Midnight override was dropped in the same commit as the wash; restore it so
   the door opens into a dark pool (deep interior) instead of a gold flare, matching the wash. */
html[data-theme="midnight"] .lk-root.open .lk-litglow { fill: var(--lk-interior-deep, #14110D); }
/* Midnight Cellar — kill the warm ambient top-glow so no stray cast remains against the
   dark theme. The wash/glow color is handled globally above (interior-based, no gold). */
html[data-theme="midnight"] .lk-amb { opacity: 0; }
/* Midnight: lift a couple of golds so they don't read muddy on the dark theme. The
   "Details & request" toggle moves from the dark --gold-dim up to --gold (the read-more
   colour); the home/login picks + arrows and the login's demo sign-in heading step to the
   lighter --gold-soft so they read as bright on the dark backdrop. Suffix untouched. */
/* Midnight: the home + login crests/labels lean CREAM instead of gold — more elegant on the
   dark splash and more complementary with Classic. (Classic keeps its gold.) */
html[data-theme="midnight"] .pick h2,
html[data-theme="midnight"] .pick .arrow,
html[data-theme="midnight"] .app--login .section-title { color: #EDE4D2; }
html[data-theme="midnight"] .expand-hint { color: var(--gold); }
/* Browse cards (Midnight only): the varietal (top-left) takes the same muted neutral as the
   location line beneath the name — no gold — and the price uses the same family a step
   stronger (--text-dim) so it still stands out. Other themes + locker-page cards unaffected. */
html[data-theme="midnight"] #browseList .card-category { color: var(--text-mute); }
html[data-theme="midnight"] #browseList .card-category .cat-right { color: var(--text-dim); }
.lt-cap { position: fixed; left: 0; right: 0; top: 46%; text-align: center; z-index: 2; font-family: var(--display); font-size: 22px; letter-spacing: .03em; color: var(--collection-text, #F4EADB); opacity: 0; transition: opacity .7s ease .85s; }
.locker-takeover.go .lt-cap { opacity: .85; }
.lt-hint2 { position: fixed; bottom: 38px; left: 0; right: 0; text-align: center; font-family: var(--sans); font-size: 10px; letter-spacing: .22em; text-transform: uppercase; color: var(--collection-text, #F4EADB); opacity: 0; z-index: 2; transition: opacity .5s ease 1.2s; }
.locker-takeover.go .lt-hint2 { opacity: .45; }

/* the collection display (revealed after expand) + keepsake */
.lt-contents { position: fixed; inset: 0; z-index: 2; opacity: 0; transform: translateY(12px); transition: opacity .5s ease, transform .5s ease; pointer-events: none; background: var(--collection-bg, #221911); display: flex; flex-direction: column; }
.locker-takeover.show-contents .lt-contents { opacity: 1; transform: none; pointer-events: auto; }
.lt-bar { display: flex; align-items: center; justify-content: space-between; padding: calc(13px + var(--sat, env(safe-area-inset-top))) 15px 13px; border-bottom: 1px solid rgba(214,196,170,.12); flex: 0 0 auto; }
.lt-bar button { display: inline-flex; align-items: center; gap: 6px; background: transparent; border: 1px solid rgba(214,196,170,.24); color: #e6dcce; font-family: var(--sans); font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; font-weight: 600; padding: 8px 14px; border-radius: var(--r-pill); cursor: pointer; transition: background .15s ease; }
.lt-bar button:active { background: rgba(214,196,170,.1); }
.lt-dl { color: #e7d6a8 !important; border-color: rgba(201,168,76,.4) !important; }
.lt-scroll { flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.lt-sheet { background: var(--collection-bg, #221911); padding: 26px 16px calc(32px + var(--sab, env(safe-area-inset-bottom))); min-height: 100%; }
.lt-head { text-align: center; margin-bottom: 25.5px; }
.lt-lockup { position: relative; container-type: inline-size; display: inline-block; width: clamp(220px, 64vw, 268px); text-align: left; }
/* Same width/height constraint as the crest, but html2canvas-safe (max-width/max-height +
   auto = the "contain" technique the keepsake capture supports; no object-fit/aspect-ratio,
   which 1.4.1 won't rasterise). The logo can never exceed the lockup WIDTH, and a tall or
   square uploaded logo is capped in HEIGHT instead of blowing up the header. The locker-#
   (.lt-sect) is the suffix analog, tucked at the lower-right exactly like the crest. */
/* Logo CENTERED and top-anchored (in flow, so a taller logo pushes the rest of the sheet
   down — the box just grows). max-width/max-height keep it contained (html2canvas-safe). */
.lt-logo { display: block; margin: 0 auto; width: auto; height: auto; max-width: 100%; max-height: 40cqw; }
/* Locker # flows right after the logo, so it always sits the SAME distance below whatever
   logo is shown (Bowdie's or an upload). Its horizontal coordinate is fixed (margin-left
   = the Bowdie's tuck position); only its vertical follows the logo. */
.lt-sect { display: inline-block; margin-left: 59cqw; font-family: var(--display); font-style: italic; font-weight: 400; font-size: 10.6cqw; color: #cba84f; line-height: 1; white-space: nowrap; }
/* Center-locker-# option (data-locker-center on <html>): the locker number sits centered under
   the logo instead of its tucked lower-right corner — the collection analog of the suffix toggle. */
html[data-locker-center] .lt-sect { display: block; margin-left: 0; text-align: center; }
.lt-vine { display: block; width: 150px; height: auto; margin: 2px auto 0; }
.lt-coll { font-family: var(--serif); font-style: italic; font-size: 15px; color: #E0D2B2; margin-top: 2px; }
.lt-meta { font-family: var(--sans); font-size: 9.5px; letter-spacing: .18em; text-transform: uppercase; color: #AB9A7C; margin-top: 25.5px; }
.lt-grid { display: flex; flex-direction: column; }
/* Bigger, uniform bottle box for a more immersive collection — and so two slots fill a 9:16 share
   image. The bottle is enlarged and the text column is slimmer to make room; the text sits centered
   beside the taller bottle. The thin separators ride each row's height. */
.lt-item { display: flex; gap: 15px; align-items: center; padding: 19px 2px; border-top: 1px solid rgba(214,196,170,.1); }
.lt-item:first-child { border-top: 0; padding-top: 2px; }
/* Divider between the still-stocked bottles and the fully-enjoyed ones in the collection. */
.lt-divider { display: flex; align-items: center; gap: 12px; margin: 12px 2px 2px; }
.lt-divider .ln { flex: 1; height: 1px; background: var(--collection-text, #F4EADB); opacity: .24; }
.lt-divider .lbl { font-family: var(--sans); font-size: 9.5px; letter-spacing: .22em; text-transform: uppercase; color: var(--collection-text, #F4EADB); opacity: .55; }
.lt-item--pulled { border-top: 0; }
.lt-item--pulled .lt-bottle img { opacity: .5; }
.lt-item--pulled .lt-name, .lt-item--pulled .lt-sub, .lt-item--pulled .lt-region, .lt-item--pulled .lt-note { opacity: .7; }
/* "Your Locker" tab — a fully-enjoyed bottle card reads quieter than the stocked ones. */
.wine-card--pulled { opacity: .82; }
.lt-bottle { flex: 0 0 96px; width: 96px; height: 318px; display: flex; align-items: center; justify-content: center; }
.lt-bottle img { max-width: 100%; max-height: 100%; width: auto; height: auto; display: block; }
/* Print-friendly keepsake (the Print button): white page + black type to save ink and stay
   legible. The vine and bottle art keep their color; only the text goes black. */
.kp-print, .kp-print * { color: #111 !important; }
.kp-print .lt-sect { color: #cba84f !important; }   /* keep the locker # in gold; only the rest goes black */
.kp-print .lt-note { border-left-color: #c4c4c4 !important; }
.lt-bar-actions { display: flex; align-items: center; gap: 8px; }
.bt-svg { width: 50px; height: auto; display: block; }
.lt-info { flex: 1 1 auto; min-width: 0; padding-top: 2px; }
/* Text beside the bottle enlarged for readability (older members). The bottle slot is a fixed
   75×247.5 box and rows are flex-start, so as long as this text block stays within the bottle
   height the slot sizes and thin separator lines don't move — verified against the longest
   tasting notes at phone width. ~24% proportional bump. */
.lt-cat { font-family: var(--sans); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: #CCB488; }
.lt-name { font-family: var(--display); font-weight: 600; font-size: 20px; color: #F7F1E4; line-height: 1.2; margin-top: 4px; }
.lt-sub { font-family: var(--serif); font-style: italic; font-size: 16px; color: #D9C7A1; margin-top: 3px; line-height: 1.3; }
.lt-region { font-family: var(--sans); font-size: 12.5px; color: #BCAC8D; margin-top: 4px; line-height: 1.3; letter-spacing: .01em; }
.lt-note { font-family: var(--serif); font-style: italic; font-size: 15.5px; color: #D5C6A6; line-height: 1.5; margin-top: 9px; border-left: 2px solid rgba(201,168,76,.35); padding-left: 12px; }
.lt-note--empty { font-style: italic; color: #A89A7D; }
.lt-note-edit { margin-top: 8px; font-family: var(--sans); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 600; color: #c9a84c; background: none; border: 0; padding: 4px 0; cursor: pointer; }
.lt-note-ta { width: 100%; margin-top: 9px; min-height: 76px; resize: vertical; box-sizing: border-box; background: #2c2118; color: #e8dcc6; border: 1px solid rgba(201,168,76,.3); border-radius: 8px; padding: 10px 12px; font-family: var(--serif); font-style: italic; font-size: 15.5px; line-height: 1.5; }
.lt-note-ta:focus { outline: none; border-color: rgba(201,168,76,.6); }
.lt-note-actions { display: flex; gap: 8px; margin-top: 9px; }
.lt-note-save, .lt-note-cancel { font-family: var(--sans); font-size: 11px; letter-spacing: .12em; text-transform: uppercase; font-weight: 600; border-radius: 999px; padding: 7px 16px; cursor: pointer; }
.lt-note-save { background: rgba(201,168,76,.16); border: 1px solid rgba(201,168,76,.5); color: #e7cd86; }
.lt-note-cancel { background: none; border: 1px solid rgba(214,196,170,.25); color: #b6a888; }
.lt-dw { font-family: var(--sans); font-size: 11.5px; letter-spacing: .04em; text-transform: uppercase; color: #CCB488; margin-top: 9px; }
/* R119: serving line sits tight under the drink-window line */
.lt-dw--serve { margin-top: 3px; opacity: .82; }
html[data-coll-tone="light"] .lt-dw { color: #8A7550; }
.lt-empty { text-align: center; font-family: var(--serif); color: #BCAC8D; padding: 52px 28px; }
.lt-empty .lt-vine { display: block; margin: 0 auto 18px; opacity: .85; }
.lt-empty-title { font-family: 'Playfair Display', Georgia, serif; font-size: 20px; color: #F1E2B4; margin-bottom: 10px; }
.lt-empty-text { font-size: 14px; line-height: 1.65; max-width: 300px; margin: 0 auto; color: #CCB488; }
.lt-foot { text-align: center; font-family: var(--sans); font-size: 9px; letter-spacing: .16em; text-transform: uppercase; color: #99896C; margin-top: 28px; }

/* Light collection background (e.g. the White finish): darken collection text and
   accents so they stay legible. Dark collections are unaffected (default styles). */
/* Light-collection tone (used only if a finish's collection bg is pale). Kept as the original
   moderate treatment; the four color finishes now use deep image-matched backgrounds (dark tone). */
html[data-coll-tone="light"] .lt-name,
html[data-coll-tone="light"] .lt-empty-title { color: #2C2620; }
html[data-coll-tone="light"] .lt-coll { color: #5E4B37; }
html[data-coll-tone="light"] .lt-meta,
html[data-coll-tone="light"] .lt-sub,
html[data-coll-tone="light"] .lt-region,
html[data-coll-tone="light"] .lt-empty-text { color: #7A6B52; }
html[data-coll-tone="light"] .lt-sect,
html[data-coll-tone="light"] .lt-cat,
html[data-coll-tone="light"] .lt-note-edit,
html[data-coll-tone="light"] .lt-foot { color: #876224; }
html[data-coll-tone="light"] .lt-note { color: #5E4B37; border-left-color: rgba(154,123,44,.4); }
html[data-coll-tone="light"] .lt-dl { color: #876224 !important; border-color: rgba(154,123,44,.45) !important; }
html[data-coll-tone="light"] .lt-bar button { color: #5E4B37; border-color: rgba(122,94,42,.3); }
html[data-coll-tone="light"] .lt-bar { border-bottom-color: rgba(122,94,42,.18); }
html[data-coll-tone="light"] .lt-item { border-top-color: rgba(122,94,42,.14); }

/* close = the door swings shut over the collection, then the key locks */
.lt-door-close { position: fixed; inset: 0; z-index: 6; transform-origin: left center; transform: scaleX(.06) skewY(1.5deg); background: linear-gradient(118deg, #3A2B1D 0%, #271C12 55%, #1d140d 100%); box-shadow: inset 0 0 0 3px rgba(130,100,60,.28), inset 0 0 70px rgba(0,0,0,.5); transition: transform .74s cubic-bezier(.42,0,.2,1); will-change: transform; }
.lt-door-close.shut { transform: scaleX(1) skewY(0deg); }
.ltd-glass { position: absolute; inset: 7% 6%; border-radius: 8px; background: linear-gradient(135deg, rgba(138,154,166,.14) 0%, rgba(20,28,34,.22) 60%, rgba(90,108,120,.14) 100%); box-shadow: inset 0 0 0 2px rgba(0,0,0,.4); }
.ltd-edge { position: absolute; left: 0; top: 0; bottom: 0; width: 5px; background: linear-gradient(90deg, rgba(160,128,78,.5), rgba(160,128,78,0)); }
.ltd-lock { position: absolute; right: 6%; top: 50%; margin-top: -22px; }
.ltd-key { opacity: 0; transform-box: fill-box; transform-origin: center top; transform: rotate(78deg); }
.lt-door-close.locked .ltd-key { animation: ltdKey .42s cubic-bezier(.5,0,.3,1) forwards; }
@keyframes ltdKey { 0% { opacity: 0; transform: rotate(78deg); } 25% { opacity: 1; } 100% { opacity: 1; transform: rotate(0deg); } }

/* ── Prevent long-press "save image" / drag-out callouts app-wide (best practice for a
      PWA; also frees the operator long-press entrance on the home crest). Images stay
      clickable/holdable — only the OS save/drag affordances are suppressed. ── */
img, .brand-logo, .lk-bot-art { -webkit-touch-callout: none; -webkit-user-drag: none; -khtml-user-drag: none; }
.crest, .crest * { -webkit-user-select: none; user-select: none; }

/* ── Browse list — motion & tactility (premium "alive" pass) ─────────────
   One-time staggered entrance (only when Browse is opened, via #browseList.stagger),
   press feedback, and a detail reveal. No content removed. Uses existing
   elevation/ease/type tokens so every theme inherits it automatically. */
:root { --spring: cubic-bezier(.34,1.4,.64,1); --decel: cubic-bezier(.19,.72,.29,1); }
.wine-card { transition: transform .34s var(--spring), border-color .4s var(--ease), box-shadow .4s var(--ease); }
.wine-card:active { transform: scale(.965); }
.wine-card.open { box-shadow: var(--elev-3), inset 0 1px 0 rgba(255,246,226,.14); border-color: var(--stroke-hi); }
.wine-save { transition: color .2s var(--ease), transform .3s var(--spring); }
.wine-save:active { transform: scale(.78); }
@keyframes wcIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
/* R113: THE LIST-VIEW FREEZE. This stagger was written for a dozen wines;
   with the full 117-bottle cellar it scheduled 117 concurrent animations
   (the last delayed 7 seconds, all held at opacity:0 by fill:both) — the
   compositor saturated and the whole page went unresponsive the moment
   list view opened, self-recovering only when the chain finished. Only the
   first twelve cards (the visible fold) animate now; the rest are simply
   there, which is where they were going anyway. */
#browseList.stagger .wine-card:nth-child(-n+12) { animation: wcIn .62s var(--decel) both; animation-delay: calc(var(--i, 0) * 60ms); }
@keyframes wcUnfurl {
  from { max-height: 0; opacity: 0; margin-top: 0; padding-top: 0; }
  to   { max-height: 2400px; opacity: 1; margin-top: 18px; padding-top: 18px; }
}
#browseList .card-detail { display: block; max-height: 0; overflow: hidden; margin: 0; padding: 0; border: 0; transition: max-height .5s var(--ease); }
#browseList .wine-card.open .card-detail { max-height: 1200px; }
#browseList .card-detail::before { content: ""; display: block; height: 1px; margin: 15px 0 13px; background: linear-gradient(90deg, transparent, var(--line), transparent); }
@media (prefers-reduced-motion: reduce) {
  #browseList.stagger .wine-card { animation: none; opacity: 1; }
  #browseList .card-detail { transition: none; }
  .wine-card:active { transform: none; }
}


/* ── Browse — editorial layout (prototype parity) ────────────────────────
   Scoped to #browseList so the locker list + collection keepsake are untouched.
   No content removed — this restyles hierarchy only. */
.browse-hero { margin: 2px 0 20px; }
.browse-eyebrow { font-family: var(--sans); font-weight: 400; font-size: 11px; letter-spacing: .32em;
  text-transform: uppercase; color: var(--gold); margin-bottom: 6px; }
.browse-title { font-family: var(--display); font-weight: 600; font-size: 30px; line-height: 1.06;
  color: var(--text); margin: 0; letter-spacing: -.005em; }
.browse-title i { font-family: var(--serif); font-style: italic; font-weight: 500; color: var(--gold); }
#browseList .wine-card { border-radius: 18px; margin-bottom: 14px; }
#browseList .card-body { padding: 17px 18px; }
#browseList .wine-card { min-height: 0; }
#browseList .wine-head { min-height: 86px; }
#browseList .card-category { display: flex; align-items: center; gap: 8px; letter-spacing: .24em; font-size: 10px; margin-bottom: 7px; white-space: nowrap; overflow: hidden; }
#browseList .card-category .cat-right { font-family: var(--serif); font-weight: 500; font-size: 20px;
  color: var(--gold); letter-spacing: 0; text-transform: none; }
#browseList .card-name { font-size: 20px; line-height: 1.15; }
#browseList .card-sub { font-size: 16px; margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#browseList .browse-rating { margin-top: 9px; font-size: 13px; letter-spacing: 3px; }


/* ── Browse — controls matched to the prototype (pills, search, filled button) ── */
.browse-search { border-radius: 14px; padding: 13px 16px; margin: 14px 0 9px; }
#browseList .card-detail .btn--gold {
  background: linear-gradient(120deg, var(--gold-dim), var(--gold) 52%, var(--gold-dim));
  color: var(--bg); border-color: var(--gold);
  box-shadow: 0 10px 22px -12px rgba(74,54,28,.45), var(--lens);
  letter-spacing: .2em;
}
#browseList .card-detail .btn--gold:hover {
  color: var(--bg); border-color: var(--gold-soft);
  background: linear-gradient(120deg, var(--gold), var(--gold-soft) 52%, var(--gold));
}
#browseList .card-detail .btn--gold:active { filter: brightness(1.05); }


/* ── Browse — light sheen sweep (prototype), gold-tinted for all themes ── */
#browseList .wine-card { overflow: hidden; }
#browseList .wine-card::after { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 42%; pointer-events: none; z-index: 1;
  background: linear-gradient(100deg, transparent, color-mix(in srgb, var(--gold-soft) 26%, transparent), transparent);
  transform: translateX(-140%) skewX(-14deg); opacity: 0; transition: transform 1.1s var(--ease), opacity .9s var(--ease); }
#browseList .wine-card:hover::after { transform: translateX(360%) skewX(-14deg); opacity: 1; }
@media (prefers-reduced-motion: reduce) { #browseList .wine-card::after { display: none; } }


/* ── Browse — timed light sweep over the Request button (prototype) ── */
#browseList .card-detail .btn--gold { position: relative; overflow: hidden; }
#browseList .card-detail .btn--gold::after { content: ""; position: absolute; top: 0; left: -60%; width: 38%; height: 100%; pointer-events: none;
  background: linear-gradient(100deg, transparent, rgba(255,248,232,.55), transparent); transform: skewX(-18deg);
  animation: btnSheen 3.6s var(--ease) 1.2s infinite; }
@keyframes btnSheen { 0% { left: -60%; } 55%, 100% { left: 150%; } }
@media (prefers-reduced-motion: reduce) { #browseList .card-detail .btn--gold::after { display: none; } }


/* ── Browse — face price column + detail spacing matched to prototype ── */
#browseList .wine-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
#browseList .wh-body { flex: 1 1 auto; min-width: 0; }
#browseList .wh-price { flex: 0 0 auto; font-family: var(--serif); font-weight: 500; font-size: 20px; line-height: 1.05; color: var(--gold); white-space: nowrap; padding-right: 26px; }
#browseList .card-category .cat-rule { flex: 0 0 22px; }
#browseList .card-detail .section-label { font-size: 10px; letter-spacing: .24em; color: var(--gold-soft); margin: 18px 0 6px; }
#browseList .card-detail .section-label:first-child { margin-top: 0; }
#browseList .card-detail .detail-note { font-style: normal; font-size: 17px; line-height: 1.5; color: var(--text); border-left: 0; padding-left: 0; }
#browseList .card-detail .detail-text { font-size: 16px; }

/* ===================================================================
   Browse · The Atlas — rotating wine-origin globe (v201)
   Theme-aware via html[data-theme]; midnight = dark, classic/beige = light.
   =================================================================== */
.wrap--globe{--g-panel:rgba(255,252,246,.88);--g-text:#2C2620;--g-dim:#6B6051;
  --g-line:rgba(122,94,42,.20);--g-seal:#7C5A36;padding-bottom:6px}
html[data-theme="midnight"] .wrap--globe{--g-panel:rgba(20,14,8,.84);--g-text:#F1E8D8;--g-dim:#BFB39C;
  --g-line:rgba(222,200,158,.16);--g-seal:#C9A879}
/* the WebGL room's atlas overlay reuses the globe-sheet/zoom components but
   never carried .wrap--globe — its vars resolved to NOTHING, so the sheet
   drew a blur with no panel behind it (rev 23). Same values, darker panel
   (the sheet floats over the dimmed room, not the parchment page). */
.hzr-ov--atlas{--g-panel:rgba(250,245,234,.95);--g-text:#2C2620;--g-dim:#6B6051;
  --g-line:rgba(122,94,42,.20);--g-seal:#7C5A36}
html[data-theme="midnight"] .hzr-ov--atlas{--g-panel:rgba(22,16,10,.95);--g-text:#F1E8D8;--g-dim:#BFB39C;
  --g-line:rgba(222,200,158,.16);--g-seal:#C9A879}
/* LIST MODE in the WebGL atlas (rev 24): the overlay body is
   pointer-events:none so globe drags pass through to the canvas — the
   injected list must claw interaction back, and it fills the view from
   under the header to the bottom edge instead of squatting half-height. */
.hzr-ov--atlas .hzr-list{pointer-events:auto;position:absolute;left:8px;right:8px;top:0;
  bottom:calc(8px + var(--sab,env(safe-area-inset-bottom)));margin:0;z-index:5}
/* rev 25: the list view IS the original Browse — parchment panel so the
   pre-globe cards/search/filters render exactly as designed */
.hzr-list--browse{background:var(--bg,#F2EBDC);border:1px solid var(--line,rgba(122,94,42,.2));
  padding:10px 14px 18px;color:var(--text,#2C2620)}
html[data-theme="midnight"] .hzr-list--browse{background:var(--bg,#14100a)}
.hzr-browse-top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:4px 0 8px}
.hzr-list-x{width:34px;height:34px;flex:none;border-radius:50%;border:1px solid var(--line,rgba(122,94,42,.25));
  background:var(--card,rgba(255,255,255,.6));color:var(--text-dim,#6B6051);font-size:15px;line-height:1;cursor:pointer}
.hzr-list--browse .filter-bar{position:relative}
/* rev 28: the pin-sheet cards are PIXEL-IDENTICAL to the list cards —
   no size overrides of any kind, the same component at the same scale.
   Only the gutters match the list panel's. */
#gsList{padding:6px 14px 14px}
#gsList .wine-card{margin:0 0 10px}
/* classic theme: the list panel is the ORIGINAL light Discover surface */
html:not([data-theme="midnight"]) .hzr-list--browse{background:#F5EFE2}
/* rev 29: while the atlas view is open, the profile chip yields the top
   corner to the ✕ — two controls in one corner read as clutter */
.hzr--gl.hzr-zoomed .hzr-chip{opacity:0;pointer-events:none;transition:opacity .25s ease}
/* rev 55/56: the SHARED browse header — both views use this exact
   geometry. align-items:stretch + space-between on BOTH columns: the
   bookmark's top and the eyebrow share the top line, the toggle's
   bottom and the title's bottom share the bottom line. rev 56 (Gabe):
   the BUTTON column is the taller one at phone width, so the TEXT
   column now distributes too — the title drops to sit on the same
   baseline as the toggle, the air opens between eyebrow and title. */
.globe-head{display:flex;align-items:stretch;justify-content:space-between;gap:12px;margin:2px 0 14px}
.globe-head>div:first-child{display:flex;flex-direction:column;justify-content:space-between;align-items:flex-start}
.globe-head .browse-eyebrow{margin-bottom:0}
.globe-head .browse-title{margin:0}
.browse-hero{margin:0}
.gv-toggle{flex:none;font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--g-seal,var(--gold));
  border:1px solid var(--g-line,var(--line));border-radius:30px;height:34px;padding:0 16px;background:transparent;cursor:pointer;
  display:inline-flex;align-items:center;gap:7px;transition:background .2s,border-color .2s}
.gv-toggle:hover{background:color-mix(in srgb,var(--g-seal,var(--gold)) 8%,transparent)}
.gv-toggle svg{width:14px;height:14px;fill:none;stroke:currentColor;stroke-width:1.6}

/* rev 54: the header's right side is a COLUMN — bookmark above the view
   toggle in BOTH browse views, so "Browse the cellar" holds one line */
/* rev 63: the header buttons sit in ONE ROW (bookmark left of the toggle
   on the list page; the atlas has just its toggle) */
.gv-stack{display:flex;flex-direction:row;align-items:center;gap:8px;flex:none}
.globe-head{align-items:center}
/* rev 54: no zoom buttons on touch — fingers pinch */
@media (pointer:coarse){.globe-stage .globe-zoom{display:none}}

/* rev 53: THE FRAME DISAPPEARS — no border, no radius, no panel wash.
   The stage bleeds to the screen edges (the wrap sheds its side padding
   below) and the sphere itself overscans the width, so the atlas reads
   as open sky, not a card. */
.globe-stage{position:relative;width:100%;height:calc(100dvh - 250px);min-height:400px;max-height:none;
  overflow:hidden;border-radius:0;border:none;background:none;
  touch-action:none;isolation:isolate}
/* rev 57 (Gabe): the header edges must be IDENTICAL between views. The
   old approach zeroed the atlas wrap's padding and re-padded the header
   at 20px — but .wrap pads 16px, so both edges shifted 4px on switch.
   Now the atlas wrap pads like every wrap (header aligns with the list
   view by construction) and ONLY the stage bleeds, via negative margins
   that exactly cancel the wrap's 16px. */
.globe-stage{margin-left:-16px;margin-right:-16px;width:calc(100% + 32px)}
#wineGlobe{position:absolute;inset:0;z-index:1;cursor:grab;display:block}
#wineGlobe:active{cursor:grabbing}
#wineMarks{position:absolute;inset:0;z-index:2;pointer-events:none}
.globe-vig{position:absolute;inset:0;pointer-events:none;z-index:3;border-radius:inherit;
  background:radial-gradient(135% 100% at 50% 44%,transparent 58%,color-mix(in srgb,var(--charcoal) 60%,transparent) 100%)}
.globe-loading{position:absolute;inset:0;z-index:4;display:flex;align-items:center;justify-content:center;
  font-size:10px;letter-spacing:.34em;text-transform:uppercase;color:var(--g-seal);opacity:.85}

/* origin markers — part of the map, minimal jitter */
.wg-mk{position:absolute;top:0;left:0;width:26px;height:26px;will-change:transform;pointer-events:auto;cursor:pointer;
  filter:drop-shadow(0 1px 2px rgba(20,14,6,.45)) drop-shadow(0 0 5px rgba(231,201,126,.4))}
.wg-mk svg{display:block;overflow:visible}
.wg-ring{fill:#F6EBD2;stroke:#9A7636;stroke-width:1}
.wg-glyph *{fill:#20160b}
.wg-halo{fill:rgba(124,90,42,.30);transform-box:fill-box;transform-origin:center;animation:wgPulse 2.6s ease-out infinite}
.wg-badge{fill:#20160b}
.wg-bt{fill:#F6E7BE;font-family:var(--sans);font-size:8px;font-weight:600;text-anchor:middle}
.wg-lbl{font-family:var(--serif);font-style:italic;font-size:13px;fill:#F4E6C4;text-anchor:middle;
  paint-order:stroke;stroke:#0b0805;stroke-width:3px;opacity:0;transition:opacity .3s}
.wg-mk:hover .wg-lbl{opacity:1}
html[data-theme="midnight"] .wg-ring{fill:#C9A24E;stroke:#F6E7BE}
html[data-theme="midnight"] .wg-halo{fill:rgba(231,201,126,.5)}
@keyframes wgPulse{0%{transform:scale(1);opacity:.5}70%{transform:scale(2.2);opacity:0}100%{opacity:0}}

.globe-zoom{position:absolute;right:14px;bottom:16px;z-index:5;display:flex;flex-direction:column;gap:8px}
.globe-zoom button{width:38px;height:38px;border-radius:50%;border:1px solid var(--g-line);color:var(--g-seal);
  background:var(--g-panel);font-size:19px;font-family:var(--serif);cursor:pointer;backdrop-filter:blur(8px);
  display:flex;align-items:center;justify-content:center;line-height:1;transition:filter .15s}
.globe-zoom button:active{filter:brightness(1.06)}
.globe-zoom .gz-rst{font-size:14px}

.globe-sheet{position:absolute;left:8px;right:8px;bottom:8px;z-index:6;background:var(--g-panel);
  backdrop-filter:blur(16px) saturate(130%);border:1px solid var(--g-line);border-radius:24px;
  box-shadow:0 -20px 56px -24px rgba(0,0,0,.5);transform:translateY(130%);
  transition:transform .55s cubic-bezier(.22,1,.36,1),max-height .38s cubic-bezier(.22,1,.36,1);
  max-height:66%;overflow:hidden;display:flex;flex-direction:column}
.globe-sheet.up{transform:none}
/* rev 61/63: the sheet OPENS AT HALF the globe window; the top handle
   TAPS (or swipes) it tall, tap again to shrink */
.globe-sheet{max-height:50%;height:50%}
.globe-sheet.tall{max-height:calc(100% - 16px);height:calc(100% - 16px)}
/* rev 64: chevron removed (Gabe) — the grab line alone marks the handle;
   the zone keeps a generous tap target */
.gs-grab-zone{position:relative;padding:10px 0 8px;cursor:pointer;touch-action:none}
.gs-grab-zone .gs-grab{margin:0 auto}
.gs-cardwrap .wine-card{margin:0 0 14px}
/* rev 61: nearby-pin chips — clustered origins swap cleanly in the header */
.gs-near{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:9px}
.gs-near-lbl{font-family:var(--sans);font-size:9px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;color:var(--g-dim);margin-right:2px}
.gs-chip{font-family:var(--sans);font-size:11px;font-weight:600;color:var(--g-text);background:color-mix(in srgb,var(--g-seal) 9%,transparent);
  border:1px solid var(--g-line);border-radius:999px;padding:4px 11px;cursor:pointer}
.gs-chip:active{background:color-mix(in srgb,var(--g-seal) 18%,transparent)}
/* rev 61: in-sheet wine detail */
.gs-back{display:block;width:100%;text-align:left;background:none;border:none;cursor:pointer;
  font-family:var(--sans);font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--g-dim);padding:12px 20px 6px}
.gs-cardwrap{padding:2px 14px 16px}
.gs-cardwrap .wine-card{margin:0}
/* ── rev 62 (Gabe): the sheet card is PIXEL-IDENTICAL to the list card —
   every #browseList polish rule mirrored for .gs-cardwrap. One template
   (rev 61) + one style surface (here) = one card, two homes. ── */
.gs-cardwrap .card-detail{display:block;max-height:0;overflow:hidden;margin:0;padding:0;border:0;transition:max-height .5s var(--ease)}
.gs-cardwrap .wine-card.open .card-detail{max-height:1200px}
.gs-cardwrap .card-detail::before{content:"";display:block;height:1px;margin:15px 0 13px;background:linear-gradient(90deg,transparent,var(--line),transparent)}
.gs-cardwrap .wine-card{border-radius:18px;min-height:0;overflow:hidden}
.gs-cardwrap .card-body{padding:17px 18px}
.gs-cardwrap .wine-head{min-height:86px;display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.gs-cardwrap .wh-body{flex:1 1 auto;min-width:0}
.gs-cardwrap .wh-price{flex:0 0 auto;font-family:var(--serif);font-weight:500;font-size:20px;line-height:1.05;color:var(--gold);white-space:nowrap;padding-right:26px}
.gs-cardwrap .card-category{display:flex;align-items:center;gap:8px;letter-spacing:.24em;font-size:10px;margin-bottom:7px;white-space:nowrap;overflow:hidden}
.gs-cardwrap .card-category .cat-rule{flex:0 0 22px}
.gs-cardwrap .card-category .cat-right{font-family:var(--serif);font-weight:500;font-size:20px}
html[data-theme="midnight"] .gs-cardwrap .card-category{color:var(--text-mute)}
html[data-theme="midnight"] .gs-cardwrap .card-category .cat-right{color:var(--text-dim)}
.gs-cardwrap .card-name{font-size:20px;line-height:1.15}
.gs-cardwrap .card-sub{font-size:16px;margin-top:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.gs-cardwrap .browse-rating{margin-top:9px;font-size:13px;letter-spacing:3px}
.gs-cardwrap .card-detail .section-label{font-size:10px;letter-spacing:.24em;color:var(--gold-soft);margin:18px 0 6px}
.gs-cardwrap .card-detail .section-label:first-child{margin-top:0}
.gs-cardwrap .card-detail .detail-note{font-style:normal;font-size:17px;line-height:1.5;color:var(--text);border-left:0;padding-left:0}
.gs-cardwrap .card-detail .detail-text{font-size:16px}
.gs-cardwrap .card-detail .btn--gold{position:relative;overflow:hidden;
  background:linear-gradient(120deg,var(--gold-dim),var(--gold) 52%,var(--gold-dim));
  color:var(--bg);border-color:var(--gold);
  box-shadow:0 10px 22px -12px rgba(74,54,28,.45),var(--lens);letter-spacing:.2em}
.gs-cardwrap .card-detail .btn--gold:hover{color:var(--bg);border-color:var(--gold-soft);
  background:linear-gradient(120deg,var(--gold),var(--gold-soft) 52%,var(--gold))}
.gs-cardwrap .card-detail .btn--gold:active{filter:brightness(1.05)}
.gs-cardwrap .card-detail .btn--gold::after{content:"";position:absolute;top:0;left:-60%;width:38%;height:100%;pointer-events:none;
  background:linear-gradient(100deg,transparent,rgba(255,248,232,.55),transparent);transform:skewX(-18deg);
  animation:btnSheen 3.6s var(--ease) 1.2s infinite}
.gs-cardwrap .wine-card::after{content:"";position:absolute;top:0;bottom:0;left:0;width:42%;pointer-events:none;z-index:1;
  background:linear-gradient(100deg,transparent,color-mix(in srgb,var(--gold-soft) 26%,transparent),transparent);
  transform:translateX(-140%) skewX(-14deg);opacity:0;transition:transform 1.1s var(--ease),opacity .9s var(--ease)}
.gs-cardwrap .wine-card:hover::after{transform:translateX(360%) skewX(-14deg);opacity:1}
@media (prefers-reduced-motion: reduce){
  .gs-cardwrap .wine-card::after,.gs-cardwrap .card-detail .btn--gold::after{display:none}
}
/* rev 61: pins get a friendlier fingertip (hit area beyond the art) */
.wg-mk{padding:7px;margin:-7px}
.gs-grab{width:38px;height:4px;border-radius:4px;background:var(--g-line);margin:10px auto 4px}
.gs-x{position:absolute;top:12px;right:16px;width:30px;height:30px;border:none;background:none;color:var(--g-dim);
  font-size:19px;cursor:pointer;z-index:2;line-height:1}
.gs-head{padding:4px 20px 13px;border-bottom:1px solid var(--g-line)}
.gs-eye{font-size:9.5px;letter-spacing:.3em;text-transform:uppercase;color:var(--g-seal)}
.gs-title{font-family:var(--display);font-weight:600;font-size:24px;color:var(--g-text);line-height:1.06;margin-top:3px}
.gs-sub{font-family:var(--serif);font-style:italic;font-size:15px;color:var(--g-dim);margin-top:2px}
/* R115: one scroller for the sheet body (head + list travel together) */
.gs-scroll{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch}
.gs-scroll::-webkit-scrollbar{display:none}
.gs-list{overflow-y:visible;padding:4px 0 12px}
.gs-list::-webkit-scrollbar{display:none}
.gs-row{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:13px 20px;
  border-top:1px solid var(--g-line);cursor:pointer}
.gs-row:first-child{border-top:none}
.gs-row:active{background:color-mix(in srgb,var(--g-seal) 7%,transparent)}
.gs-cat{font-size:9px;letter-spacing:.2em;text-transform:uppercase;color:var(--g-seal)}
.gs-name{font-family:var(--display);font-weight:600;font-size:17px;color:var(--g-text);margin-top:4px}
.gs-vin{font-family:var(--serif);font-style:italic;font-size:14px;color:var(--g-dim);margin-top:2px}
.gs-price{font-family:var(--serif);font-weight:500;font-size:17px;color:var(--g-seal);white-space:nowrap}

/* list-view header: bookmark circle + atlas toggle, aligned heights */
.browse-actions{display:flex;align-items:center;gap:8px}
.saved-circle{width:34px;height:34px;flex:none;border-radius:50%;border:1px solid var(--line);background:transparent;
  color:var(--text-dim);display:flex;align-items:center;justify-content:center;padding:0;cursor:pointer;
  -webkit-tap-highlight-color:transparent;transition:color .2s var(--ease),border-color .2s var(--ease)}
.saved-circle svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.saved-circle.on{color:var(--gold-soft);border-color:var(--gold-dim)}
.saved-circle.on svg{fill:currentColor}
/* ============================================================
   Horreum jungle entry — reusable sign-in backdrop (v203)
   Theme-aware via html[data-theme]; all classes hz- prefixed.
   ============================================================ */
#app.app--login{padding:0;background:#0b0d0a}
.hz-entry{position:relative;width:100%;max-width:440px;margin:0 auto;min-height:100dvh;overflow:hidden;isolation:isolate;
  --sky0:#EDF2DF;--sky1:#DEE7C6;--sky2:#CAD9A9;--canopy:#98b077;--leaf:#5f744a;--leaf2:#7b9256;--leaf3:#96ac6c;--trunk:#7d6a4a;--trunk-l:#9a8666;--trunk-d:#574529;
  --vine:#8a6a3c;--vine-dark:#5f4a29;--shaft:rgba(255,244,206,.5);--gold:#7C5A36;--goldsoft:#9A7636;
  --cta-a:#CBA14C;--cta-b:#7E571F;--cta-ink:#FBF3E2;--e-text:#2B251E;--e-dim:#5b5647;--e-mute:#8a8069;
  --e-panel:rgba(255,252,244,.92);--e-line:rgba(110,90,50,.2);--e-line-hi:rgba(124,90,54,.4);--mote:255,246,214;
  background:linear-gradient(180deg,var(--sky0),var(--sky1) 52%,var(--sky2))}
html[data-theme="beige"] .hz-entry{--sky0:#F2E7CD;--sky1:#E6D6B1;--sky2:#D5C093;--canopy:#b0a074;--leaf:#79713f;--leaf2:#938a52;--leaf3:#ada067;--trunk:#8a6a44;--trunk-l:#a6875f;--trunk-d:#5e4429;--vine:#9a6a34;--vine-dark:#6d4a24;--shaft:rgba(255,238,196,.5);--gold:#8a5a2f;--goldsoft:#A06A38;--cta-a:#D0913B;--cta-b:#84521B;--cta-ink:#FCF3E0;--e-text:#2e2820;--e-dim:#655a44;--e-mute:#8a7c60;--e-panel:rgba(250,242,226,.92);--e-line:rgba(120,90,50,.2);--e-line-hi:rgba(138,90,47,.4);--mote:255,236,190}
html[data-theme="midnight"] .hz-entry{--sky0:#0c1712;--sky1:#081010;--sky2:#040706;--canopy:#173629;--leaf:#224c37;--leaf2:#356a4b;--leaf3:#4e8a68;--trunk:#0e1712;--trunk-l:#20301f;--trunk-d:#070c09;--vine:#b39350;--vine-dark:#7c6531;--shaft:rgba(231,201,126,.14);--gold:#C9A24E;--goldsoft:#E8CB84;--cta-a:#F0D89B;--cta-b:#C69B44;--cta-ink:#1c1206;--e-text:#F1E8D8;--e-dim:#C9BCA3;--e-mute:#91826A;--e-panel:rgba(36,28,21,.92);--e-line:rgba(226,208,176,.16);--e-line-hi:rgba(232,203,126,.34);--mote:238,208,140}   /* R130: card de-greened — espresso panel + warm parchment greys (was grove green-black) */

.hz-entry .hz-scene{position:absolute;inset:0;z-index:1}
.hz-entry .pl-far{opacity:.96}
@keyframes hzDriftA{to{transform:translate(7px,-5px)}}
@keyframes hzDriftB{to{transform:translate(-12px,6px)}}
@keyframes hzDriftC{to{transform:translate(16px,-9px)}}
.hz-entry .hz-motes{position:absolute;inset:0;z-index:2;pointer-events:none}
.hz-entry .hz-grain{display:none;position:absolute;inset:0;z-index:3;pointer-events:none;opacity:.05;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='hzn'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23hzn)'/%3E%3C/svg%3E")}
.hz-entry .hz-vig{position:absolute;inset:0;z-index:3;pointer-events:none;background:radial-gradient(130% 100% at 50% 40%,transparent 50%,rgba(3,6,4,.5) 100%)}

.hz-entry .hz-fg{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;justify-content:space-between;
  padding:calc(env(safe-area-inset-top) + 58px) 30px calc(env(safe-area-inset-bottom) + 34px);max-width:460px;margin:0 auto}
.hz-entry .hz-crest{text-align:center;margin-top:34px}
.hz-entry .hz-glyph-wrap{display:inline-block;width:118px;height:118px;opacity:0;animation:hzRise 1.1s cubic-bezier(.22,1,.36,1) .45s forwards}
.hz-entry .hz-glyph-wrap svg{display:block;width:100%;height:100%;filter:drop-shadow(0 6px 18px rgba(0,0,0,.25))}
.hz-entry .glyphmark{fill:#1A1612}
html[data-theme="midnight"] .hz-entry .glyphmark{fill:#FFFCF6}
.hz-entry .hz-tagline{position:relative;display:inline-block;margin-top:14px;padding:5px 16px;font-family:var(--serif,'Cormorant Garamond',serif);font-style:italic;font-size:19px;color:var(--e-dim);opacity:0;animation:hzRise 1s cubic-bezier(.22,1,.36,1) .9s forwards;text-shadow:0 1px 2px rgba(0,0,0,.32),0 0 10px var(--sky1)}
.hz-entry .hz-tagline::before{content:"";position:absolute;inset:-3px -8px;z-index:-1;border-radius:22px;background:color-mix(in srgb,var(--sky1) 60%,transparent);filter:blur(7px)}

.hz-entry .hz-card{background:var(--e-panel);border:1px solid var(--e-line);border-radius:24px;padding:22px 20px 20px;box-shadow:0 26px 60px -30px rgba(0,0,0,.7);opacity:0;animation:hzRise 1.1s cubic-bezier(.22,1,.36,1) 1.15s forwards}
.hz-entry .hz-eye{font-weight:400;font-size:10px;letter-spacing:.32em;text-transform:uppercase;color:var(--gold);font-family:var(--sans,'Josefin Sans',sans-serif)}
.hz-entry .hz-title{font-family:var(--display,'Playfair Display',serif);font-weight:600;font-size:26px;color:var(--e-text);line-height:1.05;margin-top:6px}
.hz-entry .hz-note{font-family:var(--serif,'Cormorant Garamond',serif);font-style:italic;font-size:14.5px;color:var(--e-mute);margin-top:8px;line-height:1.4}
.hz-entry .hz-cpanel[hidden]{display:none}
.hz-entry .hz-field{display:block;margin-top:16px}
.hz-entry .hz-field span{display:block;font-size:9.5px;letter-spacing:.22em;text-transform:uppercase;color:var(--e-mute);margin:0 0 7px 2px;font-family:var(--sans,'Josefin Sans',sans-serif)}
.hz-entry .hz-field input{width:100%;font-family:var(--sans,'Josefin Sans',sans-serif);font-size:15px;color:var(--e-text);background:rgba(127,127,127,.10);border:1px solid var(--e-line);border-radius:13px;padding:14px 15px;outline:none;transition:border-color .25s,box-shadow .25s}
.hz-entry .hz-field input::placeholder{color:var(--e-mute)}
.hz-entry .hz-field input:focus{border-color:var(--e-line-hi);box-shadow:0 0 0 3px color-mix(in srgb,var(--gold) 16%,transparent)}
.hz-entry .hz-err{font-size:12px;color:#d06a5b;min-height:16px;margin:10px 0 0;text-align:center;font-family:var(--sans,'Josefin Sans',sans-serif)}
.hz-entry .hz-cta{position:relative;width:100%;margin-top:18px;cursor:pointer;overflow:hidden;font-family:var(--sans,'Josefin Sans',sans-serif);font-size:12px;font-weight:600;letter-spacing:.18em;text-transform:uppercase;color:var(--cta-ink);background:linear-gradient(180deg,var(--cta-a),var(--cta-b));border:none;border-radius:13px;padding:16px;box-shadow:0 13px 28px -12px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.4)}
.hz-entry .hz-cta::after{content:"";position:absolute;top:0;left:-60%;width:40%;height:100%;pointer-events:none;background:linear-gradient(105deg,transparent,rgba(255,248,225,.75),transparent);transform:skewX(-18deg);animation:hzSheen 3.6s ease-in-out infinite}
.hz-entry .hz-link{display:block;width:100%;margin-top:14px;text-align:center;font-family:var(--sans,'Josefin Sans',sans-serif);font-size:11px;letter-spacing:.04em;color:var(--e-dim);background:none;border:none;cursor:pointer;padding:6px}
.hz-entry .hz-link b{color:var(--goldsoft);font-weight:600}
.hz-entry .hz-link:hover{color:var(--e-text)}
.hz-entry .hz-alt{display:block;width:100%;margin-top:2px;text-align:center;font-family:var(--sans,'Josefin Sans',sans-serif);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--e-dim);background:none;border:none;cursor:pointer;padding:10px}
.hz-entry .hz-alt:hover{color:var(--goldsoft)}
.hz-entry .hz-pick{display:block;width:100%;text-align:left;margin-top:10px;padding:14px 16px;border-radius:14px;border:1px solid var(--e-line);background:rgba(127,127,127,.08);color:var(--e-text);cursor:pointer;font-family:var(--sans,'Josefin Sans',sans-serif)}
.hz-entry .hz-pick b{display:block;font-family:var(--display,'Playfair Display',serif);font-size:17px;color:var(--gold)}
.hz-entry .hz-pick span{font-size:11px;color:var(--e-mute)}
@keyframes hzRise{from{opacity:0;transform:translateY(14px);filter:blur(4px)}to{opacity:1;transform:none;filter:none}}
@keyframes hzSheen{0%,72%{left:-60%}86%,100%{left:130%}}
@media (prefers-reduced-motion:reduce){.hz-entry *{animation-duration:.001s!important}}

/* ============================================================================
   THE HORREUM FACADE (assets/horreum-entry.js) — the entrance to everything.
   Modeled on the Horrea Epagathiana portal at Ostia. Color is entirely in
   --hzf-* variables: classic = bright morning, beige = golden afternoon,
   midnight = night (stars, lanterns, the oculus glowing from inside).
   ========================================================================== */
.hzf-wrap{position:absolute;inset:0;z-index:1;overflow:hidden;display:flex;align-items:flex-end;justify-content:center;background:var(--hzf-sky0,#BFD2D8)}
.hzf-stage{position:relative;width:100%;flex:none;aspect-ratio:440/1020;transform-origin:50% 51.5%;container-type:inline-size;will-change:transform}
/* R130 (Gabe): theme veil — a translucent wash over the photoreal scene that
   pulls its color grade toward the app palette. Day: cream (classic theme).
   Night: espresso (#14100a, the midnight surface). Transparent enough to keep
   the horreum's detail, present enough to marry the colors to the theme.
   pointer-events:none — the plaque hold and door taps pass straight through;
   the login card lives above the wrap's stacking context and stays untinted. */
.hzf-stage::after{content:'';position:absolute;inset:0;z-index:50;pointer-events:none;background:#F2EBDC;opacity:.45;transition:background .5s ease,opacity .5s ease}   /* R132: strength up per Gabe — theme dominates, detail survives */
html[data-theme="midnight"] .hzf-stage::after{background:#14100a;opacity:.58}   /* R133: night dominance up per Gabe */
/* Portrait screens (R69): the stage is width-cover + bottom-anchored, so any
   height overflow crops from the TOP — the sky. R68's fixed headroom was a
   guess that browser chrome could still eat. This is the guarantee instead:
   push the stage down by the overflow (negative bottom margin = the crop
   moves to the pavement, which meets the frame edge gracefully at any depth),
   capped at 70.45vw (310 design px) so the threshold can never crop.
   231.82vw = stage height (1020/440 · 100vw). dvh tracks the URL bar. */
@media (max-aspect-ratio: 4/5){
  .hzf-stage{
    margin-bottom:clamp(-70.45vw, calc(100vh - 231.82vw), 0px);
    margin-bottom:clamp(-70.45vw, calc(100dvh - 231.82vw), 0px);
  }
}
.hzf-svg{position:absolute;inset:0;width:100%;height:100%;display:block}
/* R90: photoreal layers — offline renders as theme-crossfaded photographs */
.hzf-photo{position:absolute;inset:0;width:100%;height:100%;display:block;-webkit-user-drag:none;user-select:none}
.hzf-leaf-photo{position:absolute;inset:0;width:100%;height:100%;display:block;backface-visibility:hidden;-webkit-backface-visibility:hidden;-webkit-user-drag:none;user-select:none}
.hzf-ph-day,.hzf-ph-night{transition:opacity 1.2s ease}
.hzf-ph-night{opacity:0}
html[data-theme="midnight"] .hzf-ph-day{opacity:0}
html[data-theme="midnight"] .hzf-ph-night{opacity:1}

/* day palette — Bowdie's Classic (bright ivory morning) */
.hzf-stage{
  --hzf-sky0:#D2E4F1; --hzf-sky1:#D3DCD2; --hzf-sky2:#EBDFC3;
  --hzf-brick-mid:#B26F3E; --hzf-brick-hi:#CA8A51; --hzf-brick-lo:#97572E; --hzf-brick-yl:#C79E5E; --hzf-brick-sh:#6E3D20;
  --hzf-mortar:#DCC8A6;
  --hzf-trav:#E4DAC2; --hzf-trav-hi:#F4EDDB; --hzf-trav-lo:#C7BA9D;
  --hzf-tile:#A65E38; --hzf-tile-hi:#C17C4D;
  --hzf-marble:#EFE9DA; --hzf-marble-hi:#FBF7EC; --hzf-marble-lo:#CFC5AE;
  --hzf-wood:#4A3521; --hzf-wood-hi:#6B4E30; --hzf-wood-lo:#2E1F12;
  --hzf-iron:#33302B; --hzf-iron-hi:#6A6154;
  --hzf-grime:#4A3018;
  --hzf-pave:#AC8256; --hzf-pave-line:#7E5A35; --hzf-pave-hi:#C89B67; --hzf-pave-worn:#E6D3AC;
  --hzf-tufa:#B9AA8C; --hzf-tufa-hi:#CBBD9F; --hzf-tufa-sh:#8F8166;
  --hzf-shaft:rgba(255,242,208,.5);
  --hzf-flame:#FFD98A;
  --hzf-oculus:#F0C97E;
  --hzf-weed:#7C8B57;
  --mote:255,240,200;
}
/* golden afternoon — Beige & Tan */
html[data-theme="beige"] .hzf-stage{
  --hzf-sky0:#EFDFB9; --hzf-sky1:#E4CE9E; --hzf-sky2:#D2B67C;
  --hzf-brick-mid:#AC6236; --hzf-brick-hi:#C67F48; --hzf-brick-lo:#8F4E28; --hzf-brick-yl:#BE9455; --hzf-brick-sh:#62351C;
  --hzf-mortar:#D5BE96;
  --hzf-trav:#E0D2B2; --hzf-trav-hi:#F0E6CB; --hzf-trav-lo:#C2B08C;
  --hzf-tile:#9E5630; --hzf-tile-hi:#BA7444;
  --hzf-marble:#EBE2C9; --hzf-marble-hi:#F8F1DE; --hzf-marble-lo:#CBBE9E;
  --hzf-pave:#A67947; --hzf-pave-line:#7A5530; --hzf-pave-hi:#C4945C; --hzf-pave-worn:#E2CC9E;
  --hzf-tufa:#B3A480; --hzf-tufa-hi:#C6B68E; --hzf-tufa-sh:#8A7A5C;
  --hzf-shaft:rgba(255,216,150,.55);
  --mote:255,226,170;
}
/* night — Midnight Cellar */
html[data-theme="midnight"] .hzf-stage{
  --hzf-sky0:#2A354E; --hzf-sky1:#0A111D; --hzf-sky2:#060A12;
  --hzf-brick-mid:#4A3526; --hzf-brick-hi:#654932; --hzf-brick-lo:#37271B; --hzf-brick-yl:#584430; --hzf-brick-sh:#241811;
  --hzf-mortar:#514236;
  --hzf-trav:#6B604A; --hzf-trav-hi:#877A61; --hzf-trav-lo:#4E4636;
  --hzf-tile:#4A3A2E; --hzf-tile-hi:#5F4C3A;
  --hzf-marble:#8B8270; --hzf-marble-hi:#A89D87; --hzf-marble-lo:#645C49;
  --hzf-tufa:#4B4234; --hzf-tufa-hi:#5C523F; --hzf-tufa-sh:#332C21;
  --hzf-wood:#241A10; --hzf-wood-hi:#3A2B1B; --hzf-wood-lo:#150E08;
  --hzf-iron:#1D1A16; --hzf-iron-hi:#4C443B;
  --hzf-grime:#0E0906;
  --hzf-pave:#3E2F20; --hzf-pave-line:#241A10; --hzf-pave-hi:#55402A; --hzf-pave-worn:#5E4A2F;
  --hzf-shaft:rgba(190,210,238,.10);
  --hzf-weed:#3D4A33;
  --mote:238,208,140;
}

/* day/night element switching */
.hzf-night-sky,.hzf-lamp-glow,.hzf-lamp-pool,.hzf-oculus-glow{opacity:0;transition:opacity 1.2s ease}
.hzf-flame{opacity:0}
.hzf-sun{opacity:1;transition:opacity 1.2s ease}
html[data-theme="midnight"] .hzf-night-sky{opacity:1}
html[data-theme="midnight"] .hzf-lamp-glow{opacity:1;animation:hzfBreathe 3.4s ease-in-out infinite}
html[data-theme="midnight"] .hzf-lamp-pool{opacity:.8;animation:hzfBreathe 3.4s ease-in-out infinite}
/* R81: no always-on lunette glow at night — a storehouse at rest is dark
   inside; that much light through the glass read false (Gabe). The
   vestibule glow still ignites when the doors open (enter sequence). */
html[data-theme="midnight"] .hzf-oculus-glow{opacity:0}
html[data-theme="midnight"] .hzf-flame{opacity:1;transform-box:fill-box;transform-origin:50% 100%;animation:hzfFlick 1.9s ease-in-out infinite}
html[data-theme="midnight"] .hzf-sun{opacity:0}
.hzf-leaf-kiss{opacity:0;transition:opacity 1.2s ease}
html[data-theme="midnight"] .hzf-leaf-kiss{opacity:1}
.hzf-star{animation:hzfTwinkle 4.6s ease-in-out infinite}
@keyframes hzfFlick{0%,100%{transform:scale(1) skewX(0)}18%{transform:scale(1.08,1.16) skewX(3deg)}39%{transform:scale(.94,.9) skewX(-2.4deg)}58%{transform:scale(1.05,1.1) skewX(1.6deg)}80%{transform:scale(.97,.95) skewX(-1.2deg)}}
@keyframes hzfBreathe{0%,100%{filter:brightness(1)}50%{filter:brightness(1.22)}}
@keyframes hzfTwinkle{0%,100%{opacity:.25}50%{opacity:.85}}

/* vestibule darkness behind the leaves, and the leaves themselves */
.hzf-inner{position:absolute;left:34.09%;top:40.2%;width:31.82%;height:22.55%;background:#040302;overflow:hidden}
/* R101: the doors open onto a dark entry — candles not yet lit. Only the
   faintest fall of outside light survives the threshold. */
.hzf-inner::after{content:'';position:absolute;inset:0;background:linear-gradient(0deg,rgba(56,40,24,.16),rgba(20,14,9,.05) 34%,transparent 62%)}
.hzf-doorbox{position:absolute;left:34.09%;top:40.2%;width:31.82%;height:22.55%;perspective:820px;transform-style:preserve-3d}
.hzf-leaf{position:absolute;top:0;bottom:0;width:50.6%;will-change:transform;transform-style:preserve-3d}
.hzf-leafL{left:0;transform-origin:left center}
.hzf-leafR{right:0;transform-origin:right center}
.hzf-leaf svg{position:absolute;inset:0;width:100%;height:100%;display:block;backface-visibility:hidden;-webkit-backface-visibility:hidden}
/* The slab: each leaf is ~9px of oak. An end-grain edge plane stands
   perpendicular at the meeting stile (invisible closed, revealed by the
   swing), and a dark unlit back face takes over past 90°. */
.hzf-leaf-back{position:absolute;inset:0;backface-visibility:hidden;-webkit-backface-visibility:hidden;transform:rotateY(180deg) translateZ(9px);background:linear-gradient(90deg,rgba(0,0,0,.55),rgba(0,0,0,.22) 30%,rgba(0,0,0,.22) 70%,rgba(0,0,0,.55)),repeating-linear-gradient(90deg,#221809 0 1px,#38281556 1px 17px,#20150866 17px 18px),#2E2012}
.hzf-leaf-edge{position:absolute;top:0;bottom:0;width:9px;backface-visibility:visible;background:linear-gradient(180deg,transparent 0 33%,rgba(0,0,0,.28) 33% 33.8%,transparent 33.8% 66.2%,rgba(0,0,0,.28) 66.2% 67%,transparent 67%),linear-gradient(180deg,#46331F 0,#4E3A24 8.1%,#1C1712 8.1%,#1C1712 12.6%,#55402A 12.6%,#5C452C 46.6%,#1C1712 46.6%,#1C1712 51.2%,#55402A 51.2%,#5C452C 85.1%,#1C1712 85.1%,#1C1712 89.7%,#46331F 89.7%,#40301D 100%)}
.hzf-leafL .hzf-leaf-edge{right:0;transform-origin:right center;transform:rotateY(-90deg)}
.hzf-leafR .hzf-leaf-edge{left:0;transform-origin:left center;transform:rotateY(90deg)}

/* the marble plaque carries the venue's mark */
.hzf-plaque{position:absolute;left:28.11%;top:26.22%;width:43.78%;height:2.31%;display:flex;align-items:center;justify-content:center;pointer-events:auto}
.hzf-plaque-logo{max-width:88%;max-height:94%;object-fit:contain;filter:drop-shadow(0 1px 0 rgba(255,255,255,.28)) drop-shadow(0 -1px 1px rgba(0,0,0,.34));opacity:.95;-webkit-user-drag:none;user-select:none}
html[data-theme="midnight"] .hzf-plaque-logo{filter:drop-shadow(0 1px 0 rgba(255,255,255,.1)) drop-shadow(0 -1px 1px rgba(0,0,0,.5));opacity:.85}

.hzf-motes{position:absolute;inset:0;z-index:3;pointer-events:none}
.hzf-vig{position:absolute;inset:0;z-index:4;pointer-events:none;background:radial-gradient(135% 96% at 50% 42%,transparent 52%,rgba(8,5,2,.42) 100%)}
.hzf-blackout{position:fixed;inset:0;z-index:9;background:#050302;opacity:0;pointer-events:none}

/* foreground layer on the facade page: inscription + login card at the pavement */
.hzf-fg{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;justify-content:flex-end;padding:0 22px calc(env(safe-area-inset-bottom) + 10px);max-width:440px;margin:0 auto}
.hzf-fg .hzf-inscription{text-align:center;margin:0 0 12px;font-family:var(--serif,'Cormorant Garamond',serif);font-style:italic;font-size:19px;letter-spacing:.05em;color:var(--e-dim);opacity:0;animation:hzRise 1s cubic-bezier(.22,1,.36,1) .7s forwards;text-shadow:0 1px 3px rgba(0,0,0,.4)}
html[data-theme="midnight"] .hzf-fg .hzf-inscription{color:#D9CDAF}
/* R92: the login card is draggable — a grab line at its top; drag it off
   the bottom to see the facade whole, swipe up from the bottom edge to
   summon it back. (Replaces the R91 button per Gabe.) */
.hzf-drag{display:flex;justify-content:center;align-items:center;margin:-17px -20px 6px;padding:5px 0 12px;cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}
.hzf-drag::before{content:'';width:44px;height:4px;border-radius:999px;background:rgba(226,201,156,.42)}
.hzf-drag:active{cursor:grabbing}
.hzf-catch{position:absolute;left:0;right:0;bottom:0;height:60px;z-index:8;pointer-events:none;touch-action:none}
.hzf-demo-row{display:flex;gap:8px;margin-top:12px}
.hzf-demo-row button{flex:1;font-family:var(--sans,'Josefin Sans',sans-serif);font-size:9.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--e-mute);background:none;border:1px dashed var(--e-line);border-radius:12px;padding:10px 6px;cursor:pointer;transition:color .25s,border-color .25s}
.hzf-demo-row button:hover{color:var(--goldsoft);border-color:var(--e-line-hi)}

/* ============================================================================
   THE HORREUM ROOM (assets/horreum-room.js) — the member's interior.
   A CSS-3D cella: swipe to turn 90° between your locker, the Atlas, the
   entry + album, and the records table. Palettes follow data-theme.
   ========================================================================== */
.app--room{overflow:hidden!important;padding-bottom:0!important}
.hzr{position:fixed;inset:0;max-width:480px;margin:0 auto;overflow:hidden;background:var(--hzr-void);touch-action:pan-y;user-select:none;-webkit-user-select:none}
.hzr-viewport{position:absolute;inset:0;perspective:520px;perspective-origin:50% 50%}
.hzr-cube{position:absolute;inset:0;transform-style:preserve-3d;will-change:transform}
/* NOTE: no backface-visibility here — the camera plane sits past the eye
   (translateZ(perspective)), which flips accumulated matrices in Chrome and
   backface:hidden would cull every face. The engine culls the rear wall.
   Walls preserve 3D so props (the pedestal, the globe) stand proud of them. */
/* will-change keeps Chrome from RE-RASTERIZING these planes as the camera
   breath micro-scales them — the re-raster snaps were the DOM half of the
   "objects re-adjust in size and shape" bug (rev 23) */
.hzr-face{position:absolute;left:50%;top:50%;transform-style:preserve-3d;will-change:transform}
.hzr-face>*{will-change:transform}
.hzr-wall{width:1240px;height:930px;background:var(--hzr-plaster)}
.hzr-floor,.hzr-ceil{width:1240px;height:1240px}
.hzr-floor{background:var(--hzr-floor)}
.hzr-ceil{background:var(--hzr-vault)}
/* the baked texture + the thin living layer above it */
.hzr-base{position:absolute;inset:0;width:100%;height:100%;opacity:0;transition:opacity .4s ease}
.hzr-base.on{opacity:1}
.hzr-live{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}

/* palettes — day (classic default) */
.hzr{
  --hzr-void:#0B0805;
  --hzr-plaster:#E2D3B2; --hzr-plaster-hi:#F0E5C9; --hzr-plaster-lo:#C4B08A;
  --hzr-brick:#A96A3C; --hzr-brick-hi:#C08350; --hzr-brick-lo:#8D5229; --hzr-brick-yl:#BD9058; --hzr-mortar:#D8C4A0;
  --hzr-damp:#5C4A30;
  --hzr-alcove:#8D7B58; --hzr-alcove-hi:#B5A17A;
  --hzr-trav:#E3D9C1; --hzr-trav-hi:#F3ECDA; --hzr-trav-lo:#C5B899;
  --hzr-wood:#6B4E30; --hzr-wood-hi:#8A6A44; --hzr-wood-lo:#4A3521;
  --hzr-iron:#3A362F; --hzr-iron-hi:#6E6456;
  --hzr-bronze:#8A6434; --hzr-bronze-hi:#B08A4E; --hzr-bronze-lo:#5E4222;
  --hzr-terra:#B4713F; --hzr-terra-lo:#96552C;
  --hzr-floor:#B08655; --hzr-floor-line:#83603A; --hzr-floor-hi:#CDa06A; --hzr-floor-worn:#E6D0A4;
  --hzr-vault:#D8C8A6; --hzr-vault-hi:#E8DCC0; --hzr-vault-dk:#A8946F;
  --hzr-shaftcol:rgba(255,241,200,.4); --hzr-skyglow:#F2E8CC;
  --hzr-flamecol:#FFD98A;
  --hzr-globe:#C9B183; --hzr-globe-hi:#E4D3AB; --hzr-globe-lo:#94794E;
  --hzr-land:#7C5A32; --hzr-graticule:#8A7248;
  --hzr-album:#EFE7D2; --hzr-album-edge:#A34F35; --hzr-album-ghost:#7A6A50;
  --hzr-papyrus:#E4D6B4; --hzr-papyrus-hi:#F2E9CE; --hzr-papyrus-lo:#C2B08A;
  --hzr-ink:#4A3524; --hzr-incise:#6B5B40;
  --hzr-fresco:#8A5A3C; --hzr-statue:#C9BC9F; --hzr-cloak:#7A4E38;
  --mote:255,240,200;
}
html[data-theme="beige"] .hzr{
  --hzr-plaster:#DCCBA4; --hzr-plaster-hi:#EBDDBB; --hzr-plaster-lo:#BCA67C;
  --hzr-shaftcol:rgba(255,220,156,.46); --hzr-skyglow:#F0DFB4;
  --hzr-vault:#D2BF98; --hzr-vault-hi:#E2D3B0; --hzr-vault-dk:#A08B64;
  --mote:255,226,170;
}
/* night — Midnight Cellar: lamplight does the talking */
html[data-theme="midnight"] .hzr{
  --hzr-void:#040302;
  --hzr-plaster:#413729; --hzr-plaster-hi:#544736; --hzr-plaster-lo:#2E251A;
  --hzr-brick:#4A3526; --hzr-brick-hi:#5E4530; --hzr-brick-lo:#38281C; --hzr-brick-yl:#57452E; --hzr-mortar:#54453A;
  --hzr-damp:#120D08;
  --hzr-alcove:#241D14; --hzr-alcove-hi:#3E3323;
  --hzr-trav:#6E6450; --hzr-trav-hi:#867A62; --hzr-trav-lo:#4E4636;
  --hzr-wood:#3A2B1B; --hzr-wood-hi:#4E3B26; --hzr-wood-lo:#241A10;
  --hzr-iron:#1D1A16; --hzr-iron-hi:#4C443B;
  --hzr-bronze:#6E4E28; --hzr-bronze-hi:#93703C; --hzr-bronze-lo:#42301A;
  --hzr-terra:#6E452A; --hzr-terra-lo:#54331E;
  --hzr-floor:#4A3824; --hzr-floor-line:#31251A; --hzr-floor-hi:#5E4830; --hzr-floor-worn:#6B543A;
  --hzr-vault:#332B20; --hzr-vault-hi:#41372A; --hzr-vault-dk:#211B13;
  --hzr-shaftcol:rgba(178,198,232,.12); --hzr-skyglow:#5A6C8C;
  --hzr-globe:#8A7852; --hzr-globe-hi:#A8946A; --hzr-globe-lo:#5C4C32;
  --hzr-land:#4E3A22; --hzr-graticule:#6E5C3E;
  --hzr-album:#8A8068; --hzr-album-edge:#6E3A28; --hzr-album-ghost:#5A5240;
  --hzr-papyrus:#9C8E6E; --hzr-papyrus-hi:#B0A280; --hzr-papyrus-lo:#7C7056;
  --hzr-ink:#2A1E14; --hzr-incise:#8A7C5E;
  --hzr-fresco:#5E3F2C; --hzr-statue:#7C725C; --hzr-cloak:#4A3024;
  --mote:238,208,140;
}

/* night: flames + glows come alive (opacity-only animations — compositor cheap) */
.hzr .hzr-flame,.hzr .hzr-doorseep{opacity:0;transition:opacity 1.2s ease}
html[data-theme="midnight"] .hzr .hzr-flame{opacity:1;transform-box:fill-box;transform-origin:50% 100%;animation:hzfFlick 1.7s ease-in-out infinite}
html[data-theme="midnight"] .hzr .hzr-doorseep{opacity:.5}
@keyframes hzrGlowPulse{0%,100%{opacity:.72}50%{opacity:1}}
/* lamp glow pools — CSS gradients on the prop layer (reliable in 3D faces) */
.hzr-glowspot{position:absolute;width:420px;height:420px;margin:-210px 0 0 -210px;border-radius:50%;pointer-events:none;opacity:0;transition:opacity 1.2s ease;
  background:radial-gradient(50% 50% at 50% 50%,rgba(255,217,138,.42),rgba(255,217,138,.13) 48%,transparent 74%)}
html[data-theme="midnight"] .hzr-glowspot{opacity:1;animation:hzrGlowPulse 3.8s ease-in-out infinite}
.hzr .hzr-shaft{opacity:.9}
html[data-theme="midnight"] .hzr .hzr-shaft{opacity:.55}
.hzr-pin{fill:var(--gold,#B08A4E);opacity:.95;animation:hzrPinPulse 3.2s ease-in-out infinite}
.hzr-pin:nth-of-type(2n){animation-delay:1.1s}
.hzr-pin:nth-of-type(3n){animation-delay:2.2s}
@keyframes hzrPinPulse{0%,100%{opacity:.55}50%{opacity:1}}
.hzr-globe-spin{animation:hzrSpin 64s linear infinite}
@keyframes hzrSpin{from{transform:translateX(0)}to{transform:translateX(-470px)}}

/* the pedestal on wall 0 — a real 3D travertine block, the locker on top */
/* THE MANTEL + TABLE are single billboard planes with their depth drawn in —
   the one construct every GPU depth-sorts correctly. The locker rides its own
   plane 20px in front of the mantel's. */
/* bottom 256 = the REAL mantel's top slab (rev 16): base at the deck, not
   hung on the wall behind it */
.hzr-locker-stand{position:absolute;left:50%;bottom:256px;width:294px;margin-left:-147px;transform:translateZ(120px);pointer-events:none}
.hzr-locker-stand svg{display:block;width:100%;height:auto}

/* standing props: flat art on their own planes, off the wall */
.hzr-prop{position:absolute;pointer-events:none}
.hzr-prop svg{display:block;width:100%;height:100%}

/* the lanterna lives INSIDE the table billboard (same plane, can never drift) */
.hzr-lant-pane{fill:#241A10;opacity:.92;transition:fill 1.2s ease}
.hzr-lant-flame{fill:var(--hzr-flamecol);opacity:0;transform-box:fill-box;transform-origin:50% 100%;transition:opacity 1.2s ease}
html[data-theme="midnight"] .hzr-lant-pane{fill:#F2C878;opacity:.85}
html[data-theme="midnight"] .hzr-lant-flame{opacity:1;animation:hzfFlick 1.6s ease-in-out infinite}
.hzr-tbb-glow{position:absolute;left:50%;top:37%;width:320px;height:320px;margin:-160px 0 0 -160px;border-radius:50%;opacity:0;transition:opacity 1.2s ease;pointer-events:none;
  background:radial-gradient(50% 50% at 50% 50%,rgba(255,217,138,.38),rgba(255,217,138,.11) 48%,transparent 75%)}
html[data-theme="midnight"] .hzr-tbb-glow{opacity:1;animation:hzrGlowPulse 3.2s ease-in-out infinite}

/* dust hanging in the light shafts */
.hzr-dust{opacity:0;animation:hzrDust 9s linear infinite}
@keyframes hzrDust{0%{opacity:0;transform:translate(0,0)}12%{opacity:.75}55%{opacity:.4}100%{opacity:0;transform:translate(26px,54px)}}
html[data-theme="midnight"] .hzr-dust{animation-duration:14s}

/* ── THE AIR: volumetric light sheets, true 3D children of the cube ──────
   The group MUST carry preserve-3d or every sheet flattens into one plane.
   The sheets are 3D leaves: no opacity, no blend, no filter, no clip-path,
   no mask on them EVER — translucency lives inside their gradients. */
.hzr-air{position:absolute;inset:0;transform-style:preserve-3d;pointer-events:none}
.hzr-air-sheet{position:absolute;left:50%;top:50%;transform-origin:50% 0;pointer-events:none}
.hzr-air-dustplane{background:none!important}
.hzr-airdust{position:absolute;width:5px;height:5px;border-radius:50%;background:var(--hzr-skyglow);opacity:0;animation:hzrAirDust 11s linear infinite}
@keyframes hzrAirDust{0%{opacity:0;transform:translate3d(0,0,0) scale(.7)}14%{opacity:.62}56%{opacity:.34}100%{opacity:0;transform:translate3d(30px,150px,0) scale(1.1)}}
html[data-theme="midnight"] .hzr-airdust{animation-duration:16s}
/* where the beams strike the floor — 2D paint on the floor face, so the
   pools hold perfectly still under any camera angle */
.hzr-floor-pool{position:absolute;pointer-events:none}

/* ── the WebGL room: GL canvas below, ghost DOM stickers above ──────────
   The ghost cube reuses the exact face geometry CSS; its faces hold ONLY
   interactive DOM (locker, banner, hotspots, seat anchor). */
.hzr--gl .hzr-gl{position:absolute;inset:0;z-index:1;display:block}
.hzr--gl .hzr-viewport--ghost{z-index:3;pointer-events:none}
.hzr--gl .hzr-wall--ghost{background:none;pointer-events:none}
.hzr--gl .hzr-wall--ghost .hzr-hotspot{pointer-events:auto}

/* the live Atlas resting in its niche (wall 3) */
.hzr-globe-seat{position:absolute;left:430px;top:300px;width:380px;height:380px;transform:translateZ(26px);pointer-events:none}
.hzr-globe-seat .globe-stage--hzr{position:absolute;inset:0;width:100%;height:100%;min-height:0;max-height:none;background:none;border:none;border-radius:0;box-shadow:none;overflow:visible}
.hzr-globe-seat *{pointer-events:none!important}
.hzr-globe-seat .wg-lbl{display:none}

/* hotspots (invisible, generous) */
.hzr-hotspot{position:absolute;background:none;border:none;cursor:pointer;-webkit-tap-highlight-color:transparent}
.hzr-hot-locker{left:380px;top:300px;width:480px;height:560px}
.hzr-hot-atlas{left:400px;top:300px;width:440px;height:470px}
.hzr-hot-news{left:300px;top:30px;width:640px;height:430px}
.hzr-hot-exit{left:430px;top:480px;width:380px;height:390px}
.hzr-hot-history{left:380px;top:140px;width:490px;height:590px}

/* the album banner (HTML layer on wall 2) */
.hzr-album-live{position:absolute;left:334px;top:44px;width:572px;pointer-events:none}
.hzr-ban-roller{height:20px;border-radius:10px;background:linear-gradient(180deg,var(--hzr-wood-hi),var(--hzr-wood) 55%,var(--hzr-wood-lo));box-shadow:0 3px 6px rgba(0,0,0,.4)}
.hzr-ban-roller::before,.hzr-ban-roller::after{content:"";position:absolute;top:2px;width:14px;height:16px;border-radius:50%;background:radial-gradient(circle at 35% 35%,var(--hzr-bronze-hi),var(--hzr-bronze-lo))}
.hzr-ban-roller::before{left:-8px}.hzr-ban-roller::after{right:-8px}
.hzr-banner{overflow:hidden}
.hzr-ban-cloth{transform-origin:50% 0;transform:scaleY(.045);opacity:.96;background:linear-gradient(180deg,var(--hzr-papyrus-hi),var(--hzr-papyrus) 30%,var(--hzr-papyrus-lo));box-shadow:0 14px 30px rgba(0,0,0,.45);padding:20px 26px 8px;transition:transform .2s}
.hzr[data-facing="2"] .hzr-ban-cloth{animation:hzrUnfurl 1.5s cubic-bezier(.34,1.3,.4,1) .35s forwards}
.hzr-ban-cloth>*{opacity:0;transition:opacity .5s ease 1.2s}
.hzr[data-facing="2"] .hzr-ban-cloth>*{opacity:1}
@keyframes hzrUnfurl{0%{transform:scaleY(.045)}62%{transform:scaleY(1.04)}80%{transform:scaleY(.985)}100%{transform:scaleY(1)}}
.hzr-ban-head{display:flex;align-items:center;gap:10px;font-family:var(--sans);font-size:13px;font-weight:700;letter-spacing:.3em;text-transform:uppercase;color:var(--hzr-ink);opacity:.8;margin-bottom:8px}
.hzr-ban-seal{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:50%;background:radial-gradient(circle at 38% 32%,#B4543A,#7E2F1C);color:#F5E9D4;font-size:13px;letter-spacing:0;box-shadow:0 2px 4px rgba(0,0,0,.4)}
.hzr-ban-item{padding:9px 0;border-top:1px solid rgba(74,53,36,.25);font-family:var(--serif);color:var(--hzr-ink)}
.hzr-ban-item b{display:block;font-family:var(--display);font-size:19px;font-weight:600;line-height:1.2}
.hzr-ban-item span{display:block;font-size:14.5px;font-style:italic;opacity:.8;line-height:1.35;margin-top:2px;max-height:40px;overflow:hidden}
.hzr-ban-empty b{opacity:.75}
.hzr-ban-hem{height:12px;margin:4px -26px 0;background:linear-gradient(180deg,transparent,rgba(0,0,0,.18));clip-path:polygon(0 0,100% 0,100% 40%,96% 100%,90% 45%,84% 100%,78% 50%,71% 100%,64% 45%,57% 100%,50% 50%,43% 100%,36% 45%,29% 100%,22% 50%,16% 100%,10% 45%,4% 100%,0 40%)}

/* overlay chrome */
.hzr-motes{position:absolute;inset:0;z-index:4;pointer-events:none}
.hzr-vig{position:absolute;inset:0;z-index:5;pointer-events:none;background:radial-gradient(120% 92% at 50% 46%,transparent 56%,rgba(5,3,2,.52) 100%)}
.hzr-top{position:absolute;top:calc(10px + var(--sat,env(safe-area-inset-top)));right:12px;z-index:8}
.hzr-chip{font-family:var(--sans);font-size:11px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:#EADFC2;background:rgba(20,14,8,.5);border:1px solid rgba(234,223,194,.28);border-radius:999px;padding:9px 14px;cursor:pointer;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.hzr-chip-car{margin-left:6px;opacity:.7}
.hzr-menu{position:absolute;right:0;top:44px;min-width:190px;background:rgba(24,17,10,.92);border:1px solid rgba(234,223,194,.22);border-radius:14px;padding:6px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);box-shadow:0 18px 40px -12px rgba(0,0,0,.7)}
.hzr-menu button{display:block;width:100%;text-align:left;font-family:var(--sans);font-size:12.5px;letter-spacing:.04em;color:#EADFC2;background:none;border:none;border-radius:9px;padding:11px 12px;cursor:pointer}
.hzr-menu button:hover{background:rgba(234,223,194,.09)}
.hzr-menu button.danger{color:#E0A088}
.hzr-menu-sound{float:right;opacity:.6;text-transform:uppercase;font-size:10px;letter-spacing:.14em}
.hzr-compass{position:absolute;left:50%;bottom:calc(16px + var(--sab,env(safe-area-inset-bottom)));transform:translateX(-50%);z-index:8;display:flex;gap:22px}
.hzr-dot{position:relative;background:none;border:none;padding:10px 2px;cursor:pointer;-webkit-tap-highlight-color:transparent}
.hzr-dot i{display:block;width:7px;height:7px;border-radius:50%;background:rgba(234,223,194,.34);border:1px solid rgba(234,223,194,.4);transition:all .3s var(--ease)}
.hzr-dot.on i{background:var(--gold,#B08A4E);border-color:var(--gold,#B08A4E);box-shadow:0 0 10px rgba(207,164,96,.8)}
.hzr-dot span{position:absolute;bottom:30px;left:50%;transform:translateX(-50%);white-space:nowrap;font-family:var(--sans);font-size:9px;font-weight:600;letter-spacing:.22em;text-transform:uppercase;color:#EADFC2;opacity:0;transition:opacity .3s;pointer-events:none;text-shadow:0 1px 3px rgba(0,0,0,.7)}
.hzr-dot.on span{opacity:.85}
.hzr-chev{position:absolute;top:50%;transform:translateY(-50%);z-index:7;width:40px;height:76px;background:none;border:none;color:rgba(234,223,194,.4);font-size:34px;line-height:1;cursor:pointer;-webkit-tap-highlight-color:transparent;transition:color .25s}
.hzr-chev:hover{color:rgba(234,223,194,.85)}
.hzr-chev-l{left:2px}.hzr-chev-r{right:2px}
.hzr-hint{position:absolute;left:50%;bottom:calc(64px + var(--sab,env(safe-area-inset-bottom)));transform:translateX(-50%);z-index:8;font-family:var(--serif);font-style:italic;font-size:15px;color:#EADFC2;background:rgba(20,14,8,.55);border:1px solid rgba(234,223,194,.2);border-radius:999px;padding:9px 18px;opacity:0;pointer-events:none;transition:opacity .6s ease;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);white-space:nowrap}
.hzr-hint.show{opacity:1;animation:hzrHintSway 2.6s ease-in-out .8s 2}
@keyframes hzrHintSway{0%,100%{transform:translateX(-50%)}30%{transform:translateX(calc(-50% - 12px))}70%{transform:translateX(calc(-50% + 12px))}}
/* rev 35: the locker LIVES IN THE ROOM — at midnight the whole cellar
   dims but the DOM locker sticker kept daylight brightness, floating on
   top like a screenshot. It now takes the room's darkness. */
html[data-theme="midnight"] .hzr--gl .hzr-locker-stand{filter:brightness(.62) saturate(.92)}
/* rev 36: PLAIN takeover (from the horreum) — no clone FLIP, no fill
   morph, no color wash: the collection CROSSFADES over the final stretch
   of the camera's travel into the locker. One motion. */
.locker-takeover.lt-plain{opacity:0;transition:opacity .6s ease}
.locker-takeover.lt-plain.lt-in{opacity:1}
.locker-takeover.lt-plain .lt-zoom{display:none}
/* rev 38: NO fill in plain mode. The pale radial backdrop was the "solid
   color" washing over the view (it was the legacy FLIP's morph target).
   The collection's own opaque background (.lt-contents) is the backdrop;
   it crossfades directly over the REAL magnified interior. One fade. */
.locker-takeover.lt-plain .lt-fill{display:none !important}
.locker-takeover.lt-plain .lt-contents{transition:none !important;transform:none !important}
/* rev 32: the veil is THEME-LOCKED — it was fixed near-black while the
   app boot loader used the page color, so the champagne screen appeared
   to change background between the two. Classic = light, midnight = dark,
   always, both loaders. */
.hzr-arrive{position:absolute;inset:0;z-index:9;background:var(--bg,#F2EBDC);opacity:0;pointer-events:none}
html[data-theme="midnight"] .hzr-arrive{background:#050302}
/* readiness hold: the veil carries THE HOUSE champagne-cork loader while
   the baked building + textures finish arriving — never a half-built room,
   never a stranger's spinner */
.hzr-arrive{display:flex;align-items:center;justify-content:center}
.hzr-arr-glass{width:46px;height:46px;opacity:0;transition:opacity .3s ease}
.hzr-arrive.hold .hzr-arr-glass{opacity:.92}
.hzr-seal{display:none}

/* ── in-horreum overlays: everything stays inside the room ─────────────── */
.hzr-ov{position:absolute;inset:0;z-index:8;display:flex;flex-direction:column;opacity:0;transition:opacity .35s ease}
.hzr-ov.open{opacity:1}
/* the Atlas overlay itself never fades — only its scrim and header do, so
   the traveling globe stays continuously visible through open and close */
.hzr-ov--atlas{opacity:1;transition:none}
.hzr-ov--atlas .hzr-ov-scrim,.hzr-ov--atlas .hzr-ov-head{opacity:0;transition:opacity .35s ease}
.hzr-ov--atlas.open .hzr-ov-scrim,.hzr-ov--atlas.open .hzr-ov-head{opacity:1}
/* NO backdrop-filter here: a full-screen backdrop blur re-composites on every
   canvas frame beneath the spinning globe — it was a rotation-jank source */
.hzr-ov-scrim{position:absolute;inset:0;background:rgba(8,5,3,.74)}
.hzr-ov-head{position:relative;z-index:2;display:flex;align-items:center;gap:10px;padding:calc(10px + var(--sat,env(safe-area-inset-top))) 16px 10px}
.hzr-ov-title{font-family:var(--display);font-size:21px;font-weight:600;color:#EFE5C9;text-shadow:0 1px 3px rgba(0,0,0,.6)}
.hzr-ov-sub{font-family:var(--serif);font-style:italic;font-size:13px;color:rgba(239,229,201,.65)}
.hzr-ov-x{margin-left:auto;width:38px;height:38px;border-radius:50%;border:1px solid rgba(239,229,201,.3);background:rgba(20,14,8,.55);color:#EFE5C9;font-size:16px;cursor:pointer;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.hzr-toggle{display:flex;border:1px solid rgba(239,229,201,.28);border-radius:999px;overflow:hidden;background:rgba(20,14,8,.5);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.hzr-toggle button{font-family:var(--sans);font-size:10px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:rgba(239,229,201,.66);background:none;border:none;padding:9px 15px;cursor:pointer}
.hzr-toggle button.on{color:#221709;background:linear-gradient(180deg,#E8CB84,#C9A24E)}
.hzr-ov-body{position:relative;z-index:1;flex:1;min-height:0;display:flex;flex-direction:column}

/* the Atlas, grown from its niche */
.hzr-ov--atlas .hzr-ov-body{padding:0 6px calc(10px + var(--sab,env(safe-area-inset-bottom)))}
/* the wrap FLIPs between the niche rect and full size at runtime — no keyframes */
.hzr-atlas-stage-wrap{position:relative;flex:1;min-height:0;will-change:transform}
.hzr-atlas-stage-wrap .globe-stage{position:absolute;inset:0;height:auto;min-height:0;max-height:none}

/* the horreum list: wine rows on a dark ledger surface */
.hzr-list{position:relative;flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;margin:2px 10px calc(12px + var(--sab,env(safe-area-inset-bottom)));padding:6px 12px 18px;border-radius:18px;background:linear-gradient(180deg,rgba(30,21,12,.92),rgba(22,15,9,.94));border:1px solid rgba(200,164,96,.22);box-shadow:0 24px 60px -24px rgba(0,0,0,.8)}
.hzr-list-search{position:sticky;top:6px;z-index:2;margin:6px 0 10px}
.hzr-list-search input{width:100%;font-family:var(--sans);font-size:14px;color:#EFE5C9;background:rgba(10,7,4,.8);border:1px solid rgba(200,164,96,.26);border-radius:12px;padding:11px 14px;outline:none}
.hzr-list-search input::placeholder{color:rgba(239,229,201,.4)}
.hzr-row{padding:13px 4px;border-bottom:1px solid rgba(200,164,96,.14);cursor:pointer}
.hzr-row:last-child{border-bottom:none}
.hzr-row-top{display:flex;align-items:baseline;gap:10px}
.hzr-row-name{font-family:var(--display);font-size:16.5px;font-weight:600;color:#EFE5C9;line-height:1.25;flex:1}
.hzr-row-price{font-family:var(--sans);font-size:13px;font-weight:600;color:#C9A24E;white-space:nowrap}
.hzr-row-sub{font-family:var(--serif);font-style:italic;font-size:13.5px;color:rgba(239,229,201,.6);margin-top:2px}
.hzr-row-body{display:none;padding:8px 2px 4px}
.hzr-row.open .hzr-row-body{display:block}
.hzr-row-note{font-family:var(--serif);font-size:14.5px;line-height:1.5;color:rgba(239,229,201,.82)}
.hzr-row-btn{margin-top:12px;width:100%;font-family:var(--sans);font-size:11px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:#221709;background:linear-gradient(180deg,#E8CB84,#C9A24E);border:none;border-radius:11px;padding:13px;cursor:pointer}
.hzr-row.hl{animation:hzrRowHl 2.4s ease}
@keyframes hzrRowHl{0%,60%{background:rgba(201,162,78,.16)}100%{background:none}}
.hzr-list-foot{padding:14px 4px 4px;text-align:center}
.hzr-list-foot button{font-family:var(--serif);font-style:italic;font-size:14.5px;color:#C9A24E;background:none;border:none;cursor:pointer;text-decoration:underline;text-underline-offset:3px}

/* ledger + notices panels: a vellum sheet in the room */
.hzr-panel{position:relative;z-index:1;flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;margin:2px 14px calc(14px + var(--sab,env(safe-area-inset-bottom)));padding:22px 20px 26px;border-radius:6px 6px 16px 16px;
  background:linear-gradient(180deg,var(--hzr-papyrus-hi),var(--hzr-papyrus) 12%,var(--hzr-papyrus) 88%,var(--hzr-papyrus-lo));
  box-shadow:0 26px 60px -22px rgba(0,0,0,.85), inset 0 1px 0 rgba(255,255,255,.4);color:var(--hzr-ink)}
.hzr-panel::before{content:"";position:absolute;left:0;right:0;top:0;height:10px;border-radius:6px 6px 0 0;background:linear-gradient(180deg,var(--hzr-wood-hi),var(--hzr-wood-lo));box-shadow:0 2px 4px rgba(0,0,0,.4)}
.hzr-panel h3{font-family:var(--display);font-size:15px;font-weight:700;letter-spacing:.22em;text-transform:uppercase;text-align:center;margin:8px 0 4px;opacity:.85}
.hzr-panel .hzr-panel-rule{height:1.5px;background:currentColor;opacity:.28;margin:6px 30px 14px}
.hzr-p-item{padding:12px 2px;border-bottom:1px solid rgba(74,53,36,.22)}
.hzr-p-item:last-child{border-bottom:none}
.hzr-p-name{font-family:var(--display);font-size:17px;font-weight:600;line-height:1.25}
.hzr-p-sub{font-family:var(--serif);font-style:italic;font-size:14px;opacity:.75;margin-top:2px;line-height:1.4}
.hzr-p-tag{display:inline-block;font-family:var(--sans);font-size:9px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;border:1px solid currentColor;border-radius:999px;padding:2.5px 9px;opacity:.7;margin-top:6px}
.hzr-p-rate{margin-top:8px;font-family:var(--sans);font-size:10.5px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:#7E2F1C;background:none;border:1px dashed rgba(126,47,28,.5);border-radius:10px;padding:8px 12px;cursor:pointer}
.hzr-p-stars{color:#8A5A20;letter-spacing:2px;font-size:14px}
.hzr-p-dismiss{float:right;font-size:16px;background:none;border:none;color:inherit;opacity:.45;cursor:pointer;padding:2px 6px}
.hzr-p-empty{text-align:center;font-family:var(--serif);font-style:italic;font-size:16px;opacity:.65;padding:30px 10px}
.hzr-p-seal{display:flex;justify-content:flex-end;padding:14px 6px 0}
.hzr-p-seal i{width:40px;height:40px;border-radius:50%;background:radial-gradient(circle at 36% 30%,#B4543A,#7E2F1C);box-shadow:0 2px 5px rgba(0,0,0,.35)}
@media (min-width:540px){.hzr{box-shadow:0 0 64px rgba(20,12,4,.4)}}
/* fingers pinch; buttons are for mice */
@media (pointer:coarse){.hzr-ov--atlas .globe-zoom{display:none}}
@media (prefers-reduced-motion:reduce){
  .hzr-globe-spin,.hzr-pin,.hzr .hzr-flame,.hzr .hzr-lamp-glow,.hzr-lant-flame,.hzr-lant-glow,.hzr-dust{animation:none!important}
  .hzr-ban-cloth{transition:transform .3s ease}
  .hzr[data-facing="2"] .hzr-ban-cloth{animation:none;transform:scaleY(1)}
}

/* ═══════════════════════════════════════════════════════════════════════
   rev 51 · THE RESERVE — palatine design system, flat
   (docs/horreum-reserve-plan.md · the horreum as identity, not geometry)
   ═══════════════════════════════════════════════════════════════════════ */
:root{
  --rsv-paper:#f5f1e8;            /* ivory stucco */
  --rsv-paper-deep:#ece6d8;
  --rsv-ink:#2b2118;              /* espresso */
  --rsv-ink-soft:#5d5142;
  --rsv-brass:#8a6a33;
  --rsv-brass-hi:#c9a961;
  --rsv-brass-lo:#6e5528;
  --rsv-wine:#6e1f2a;             /* oxblood — the single accent */
  --rsv-marble-quiet:url('reserve/marble-quiet.webp');
  --rsv-marble-figured:url('reserve/marble-figured.webp');
  --rsv-walnut:url('reserve/walnut.webp');
}
/* the home breathes on paper with a whisper of quiet marble */
.rsv-home{position:relative}
.rsv-home::before{content:"";position:absolute;inset:-24px -20px;background:var(--rsv-marble-quiet);background-size:420px;opacity:.05;pointer-events:none;z-index:0}
.rsv-home>*{position:relative;z-index:1}

/* THE PLAQUE — engraved brass; the member's name lives in the metal */
.rsv-plaque{position:relative;margin:6px auto 18px;max-width:430px;padding:20px 26px 17px;text-align:center;border-radius:8px;
  background:linear-gradient(168deg,#c9a961 0%,#a8842f 26%,#8a6a33 52%,#a8842f 74%,#c9a961 100%);
  box-shadow:0 2px 4px rgba(43,33,24,.28), 0 10px 26px -14px rgba(43,33,24,.5), inset 0 1px 1px rgba(255,244,214,.75), inset 0 -1px 2px rgba(60,40,10,.45)}
.rsv-plaque::after{content:"";position:absolute;inset:6px;border:1px solid rgba(60,40,10,.34);border-top-color:rgba(255,244,214,.5);border-radius:5px;pointer-events:none}
.rsv-screw{position:absolute;width:9px;height:9px;border-radius:50%;
  background:radial-gradient(circle at 34% 30%,#e8d8a8,#7c5e22 68%,#54400f);box-shadow:0 1px 1px rgba(255,244,214,.5)}
.rsv-screw--tl{top:7px;left:8px}.rsv-screw--tr{top:7px;right:8px}
.rsv-screw--bl{bottom:7px;left:8px}.rsv-screw--br{bottom:7px;right:8px}
.rsv-plaque-locker{font-family:var(--sans);font-size:11px;font-weight:700;letter-spacing:.34em;text-transform:uppercase;
  color:#3d2c0e;text-shadow:0 1px 0 rgba(255,244,214,.55)}
.rsv-plaque-rule{height:1px;margin:9px 22%;background:linear-gradient(90deg,transparent,rgba(60,40,10,.5),transparent)}
.rsv-plaque-name{font-family:var(--display);font-size:23px;font-weight:600;letter-spacing:.02em;
  color:#31240c;text-shadow:0 1px 0 rgba(255,244,214,.6), 0 -1px 1px rgba(50,32,4,.35)}
.rsv-plaque-since{margin-top:7px;font-family:var(--serif);font-style:italic;font-size:12.5px;color:rgba(61,44,14,.85);text-shadow:0 1px 0 rgba(255,244,214,.4)}

/* section titles take a brass hairline */
.rsv-home .section-title{display:flex;align-items:center;gap:12px;letter-spacing:.18em}
.rsv-home .section-title::after{content:"";flex:1;height:1px;background:linear-gradient(90deg,var(--rsv-brass) 0%,transparent 100%);opacity:.45}

/* the locker hero stands on a walnut ledge */
.rsv-home .locker-stage{position:relative;padding-bottom:14px}
.rsv-home .locker-stage::after{content:"";position:absolute;left:6%;right:6%;bottom:0;height:12px;border-radius:3px;
  background:var(--rsv-walnut);background-size:300px;box-shadow:0 3px 8px -3px rgba(43,33,24,.55), inset 0 1px 0 rgba(255,255,255,.16)}