/* Cellar — application layer on top of the Classical design system.
 *
 * ``classical.css`` is the design system (vendored verbatim from
 * ``design/classical.css`` — treat it as read-only and retune the
 * look there, not here). This file adds only what the cellar app
 * needs on top of it:
 *
 *   - the app shell (desktop top nav, mobile bottom tab bar),
 *   - the bottle plate — the design's hero motif,
 *   - the cellar browser in its two densities (plates / ledger),
 *   - the stat tiles, window bars and facet rail,
 *   - a handful of layout utilities that replace the Tailwind CDN
 *     the prototype used to load.
 *
 * Every value here comes from a ``classical.css`` token. If you
 * find yourself typing a hex or a raw px that the tokens already
 * carry, reach for the variable instead.
 */

/* ══════════════════════════════════════════════════════════════
   1. Layout utilities
   Tailwind is gone; these are the handful of utilities the
   templates actually used. Deliberately small — anything that
   recurs as a *thing* becomes a component class below instead.
   ══════════════════════════════════════════════════════════════ */

.row      { display: flex; align-items: center; gap: var(--space-2); }
.row-top  { display: flex; align-items: flex-start; gap: var(--space-3); }
.row-wrap { flex-wrap: wrap; }
.col      { display: flex; flex-direction: column; gap: var(--space-2); }
.grow     { flex: 1; min-width: 0; }
.push     { margin-left: auto; }
.gap-1 { gap: var(--space-1); } .gap-3 { gap: var(--space-3); }
.mt-2 { margin-top: var(--space-2); } .mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); } .mt-6 { margin-top: var(--space-6); }
.mb-0 { margin-bottom: 0; } .mb-1 { margin-bottom: var(--space-1); }
.mb-2 { margin-bottom: var(--space-2); } .mb-3 { margin-bottom: var(--space-3); }
.mb-4 { margin-bottom: var(--space-4); }
.mx-1 { margin-inline: var(--space-1); }

/* Free-text the user typed keeps the line breaks they put in it. */
.prewrap { white-space: pre-wrap; }

/* Figures set tabular wherever they stand as numbers — the design
   system's type note. Applied via a class so prose keeps its text
   figures. */
.num { font-variant-numeric: tabular-nums; }
.nowrap { white-space: nowrap; }
.small { font-size: 13px; }
.tiny  { font-size: 11px; }

/* The kicker — a small uppercase accent label. It opens nearly
   every section in the designs, so it earns a class. */
.kicker {
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--color-accent); font-variant-numeric: tabular-nums;
}
.section { margin-bottom: var(--space-6); }
.section > .kicker { display: block; margin-bottom: var(--space-2); }

/* ══════════════════════════════════════════════════════════════
   2. App shell
   Desktop: the design-system ``.nav`` bar across the top.
   Mobile (<768px): that bar collapses to a brand-only strip and a
   five-tab bottom bar takes over, per artboards 1a–1d.
   ══════════════════════════════════════════════════════════════ */

body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.shell-main {
  flex: 1;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: var(--space-6) var(--space-4) var(--space-8);
}

.topnav { position: sticky; top: 0; z-index: 30; background: var(--color-bg); }
.topnav a[aria-current='page'] { box-shadow: inset 0 -2px 0 var(--color-accent); }
.topnav .nav-actions { display: flex; align-items: center; gap: var(--space-2); }

/* The bottom tab bar. Five tabs, 54px tall, the active one marked
   by a 2px accent rule along its top edge. */
.tabbar { display: none; }
@media (max-width: 767px) {
  .topnav .nav-link { display: none; }
  .shell-main { padding: var(--space-4) var(--space-3) 84px; }
  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    display: grid; grid-template-columns: repeat(5, 1fr);
    background: var(--color-bg);
    border-top: 1px solid var(--color-divider);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .tabbar a {
    min-height: 54px; display: flex; align-items: center; justify-content: center;
    font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase;
    text-decoration: none; text-align: center; line-height: 1.2;
    color: color-mix(in srgb, var(--color-text) 55%, transparent);
    border-top: 2px solid transparent;
  }
  .tabbar a[aria-current='page'] {
    color: var(--color-accent);
    border-top-color: var(--color-accent);
  }
}

.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-4);
}
.page-head h1 { margin: 0; font-size: 32px; font-weight: 400; }
.page-head .sub {
  margin: 5px 0 0; font-size: 13px;
  color: color-mix(in srgb, var(--color-text) 65%, transparent);
}
.page-head .count {
  font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--color-accent); font-variant-numeric: tabular-nums;
}
.page-actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }

.footer {
  border-top: 1px solid var(--color-divider);
  padding: var(--space-4); text-align: center; font-size: 12px;
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
@media (max-width: 767px) { .footer { margin-bottom: 60px; } }

/* ══════════════════════════════════════════════════════════════
   3. The bottle plate
   The design's hero motif: a bottle sitting on a surface-coloured
   plate. When the release has a primary photo we show it through
   the design system's ``.plate`` grade; otherwise we draw a
   generic bottle tinted to the wine's colour, with the vintage on
   the label. Sizes are driven by --plate-h so one rule set serves
   the grid, the ledger row and the detail hero.
   ══════════════════════════════════════════════════════════════ */

.plate-box {
  --plate-h: 132px;
  display: flex; align-items: flex-end; justify-content: center;
  height: var(--plate-h);
  background: var(--color-surface);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.plate-box img {
  width: 100%; height: 100%;
  /* Bottle photos are displayed in wide cellar cards, narrow ledger
     rows and the portrait detail hero. Filling each frame with a
     centred cover crop avoids the letterbox bars those differing
     ratios previously produced. The crop is deliberately mild for
     the usual centred label shot, while the original remains
     available untouched in the lightbox. */
  object-fit: cover;
  object-position: center;
  filter: sepia(0.22) saturate(0.82) contrast(1.05);
}

/* The drawn fallback. Neck and body share --glass; the label is
   the warm paper tone the designs use for it. Every dimension is
   a ratio of --plate-h so the bottle scales with its plate. */
.bottle {
  --glass: var(--color-neutral-700);
  display: flex; flex-direction: column; align-items: center;
  padding-bottom: calc(var(--plate-h) * 0.076);
}
.bottle .neck {
  width: calc(var(--plate-h) * 0.091);
  height: calc(var(--plate-h) * 0.258);
  background: var(--glass);
}
.bottle .body {
  width: calc(var(--plate-h) * 0.348);
  height: calc(var(--plate-h) * 0.561);
  background: var(--glass);
  border-radius: calc(var(--plate-h) * 0.045) calc(var(--plate-h) * 0.045) var(--radius-sm) var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
}
.bottle .label {
  width: 78%; padding: calc(var(--plate-h) * 0.023) 0;
  background: #f4efe4; color: var(--color-neutral-900);
  font-size: calc(var(--plate-h) * 0.068);
  text-align: center; font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

/* Wine-colour glass tints, shared by the bottle and the colour
   swatch dots in the facet rail. */
.glass-red       { --glass: #3b1220; }
.glass-white     { --glass: #93956a; }
.glass-orange    { --glass: #a87231; }
.glass-rose      { --glass: #c98c84; }
.glass-sparkling { --glass: #3f4130; }
.glass-other     { --glass: var(--color-neutral-400); }

.swatch {
  width: 9px; height: 9px; flex: none; border-radius: 50%;
  background: var(--glass, var(--color-neutral-400));
}

/* ══════════════════════════════════════════════════════════════
   4. The cellar browser
   Two densities off the same data: ``plates`` (artboard 1a / 1e)
   and ``ledger`` (artboard 1b).
   ══════════════════════════════════════════════════════════════ */

.wine-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--space-6) var(--space-4);
}
@media (max-width: 767px) {
  .wine-grid { grid-template-columns: 1fr 1fr; gap: var(--space-4) var(--space-3); }
}

.wine-card {
  display: flex; flex-direction: column; gap: 7px;
  text-decoration: none; color: inherit;
}
/* The plate is taller on desktop, where there's room for the
   bottle to stand properly (artboard 1e's 184px vs 1a's 132px). */
.wine-card .plate-box { --plate-h: 184px; }
@media (max-width: 767px) { .wine-card .plate-box { --plate-h: 132px; } }
.wine-card:hover .plate-box { border-color: var(--color-accent); }
.wine-card .producer {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 17px; line-height: 1.15;
}
.wine-card .cuvee {
  font-size: 13px; line-height: 1.35;
  color: color-mix(in srgb, var(--color-text) 72%, transparent);
}
.wine-card .meta {
  font-size: 12px; font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
@media (max-width: 767px) {
  .wine-card .producer { font-size: 15px; }
  .wine-card .cuvee { font-size: 12px; }
}

.ledger { display: flex; flex-direction: column; }
.ledger-row {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 11px var(--space-2);
  border-bottom: 1px solid var(--color-divider);
  text-decoration: none; color: inherit;
}
.ledger-row:hover { background: color-mix(in srgb, var(--color-text) 4%, transparent); }
.ledger-row .plate-box { --plate-h: 52px; width: 34px; flex: none; }
.ledger-row .title {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 15px; line-height: 1.2;
}
.ledger-row .meta {
  font-size: 11px; margin-top: 3px;
  color: color-mix(in srgb, var(--color-text) 62%, transparent);
}
.ledger-row .right {
  flex: none; display: flex; flex-direction: column;
  align-items: flex-end; gap: 4px; text-align: right;
}

/* Density toggle — the design system's .seg, wired to two links. */
.density { display: inline-flex; border: 1px solid var(--color-divider); border-radius: var(--radius-md); overflow: hidden; }
.density a {
  padding: 7px 12px; font-size: 13px; text-decoration: none;
  color: var(--color-text);
}
.density a + a { border-left: 1px solid var(--color-divider); }
.density a[aria-current='true'] { color: var(--color-accent); box-shadow: inset 0 0 0 1px var(--color-accent); }
.density a:not([aria-current='true']):hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }

/* ══════════════════════════════════════════════════════════════
   5. Facets
   Desktop: a 232px rail beside the results (artboard 1e).
   Mobile: the same options as wrapping chips (artboards 1a / 1b).
   ══════════════════════════════════════════════════════════════ */

.with-rail { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 0; }
.rail {
  border-right: 1px solid var(--color-divider);
  padding: 0 var(--space-4) var(--space-4) 0;
  display: flex; flex-direction: column; gap: var(--space-4);
  align-self: start;
}
.rail-group { display: flex; flex-direction: column; gap: 9px; }
.rail-group a {
  font-size: 14px; min-height: 28px; display: flex; align-items: center;
  gap: 9px; text-decoration: none; color: var(--color-text);
}
.rail-group a:hover { color: var(--color-accent); }
.rail-group a[aria-current='true'] { color: var(--color-accent-700); }
.rail-group a .box {
  width: 9px; height: 9px; flex: none;
  border: 1px solid var(--color-divider); background: transparent;
}
.rail-group a[aria-current='true'] .box {
  border-color: var(--color-accent); background: var(--color-accent-100);
}
.rail-results { padding-left: var(--space-4); }

.chips { display: flex; gap: 7px; flex-wrap: wrap; }
.chip {
  min-height: 32px; display: inline-flex; align-items: center; gap: 7px;
  padding: 0 12px; font-size: 12px; letter-spacing: 0.02em;
  border: 1px solid var(--color-divider); border-radius: var(--radius-sm);
  color: var(--color-text); text-decoration: none;
}
.chip:hover { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
.chip[aria-current='true'] {
  border-color: var(--color-accent); color: var(--color-accent-700);
  background: var(--color-accent-100);
}
.facet-block { display: flex; flex-direction: column; gap: 7px; }
.facet-block > .kicker { margin: 0; }

@media (max-width: 767px) {
  .with-rail { grid-template-columns: minmax(0, 1fr); }
  .rail { display: none; }
  .rail-results { padding-left: 0; }
}
/* The chip strip is the mobile face of the rail — hidden on
   desktop, where the rail does the same job with more room. */
.facets-mobile { display: none; }
@media (max-width: 767px) {
  .facets-mobile {
    display: block;
    padding-bottom: var(--space-3); margin-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-divider);
  }
  .facets-mobile > summary {
    display: flex; align-items: baseline; gap: var(--space-2);
    min-height: 44px; padding: var(--space-2) 0;
    cursor: pointer; list-style: none;
    font-family: var(--font-heading); font-weight: var(--font-heading-weight);
    font-size: 14px; color: var(--color-accent);
  }
  .facets-mobile > summary::-webkit-details-marker { display: none; }
  /* A caret drawn from type, so it turns with the disclosure and
     needs no icon asset. */
  .facets-mobile > summary::after {
    content: "\203A"; margin-left: auto;
    transition: transform 120ms ease;
  }
  .facets-mobile[open] > summary::after { transform: rotate(90deg); }
  .facets-mobile > summary .summary-value {
    font-family: var(--font-body); font-weight: 400; font-size: 13px;
    color: color-mix(in srgb, var(--color-text) 60%, transparent);
  }
  .facets-mobile > .facet-block { margin-top: var(--space-3); }
}

/* ══════════════════════════════════════════════════════════════
   6. Stats
   ══════════════════════════════════════════════════════════════ */

.stat-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1px; background: var(--color-divider); border: 1px solid var(--color-divider);
}
@media (max-width: 767px) { .stat-grid { grid-template-columns: 1fr 1fr; } }
.stat {
  background: var(--color-bg); padding: var(--space-4);
  text-decoration: none; color: inherit; display: block;
}
a.stat:hover { background: color-mix(in srgb, var(--color-accent) 7%, transparent); }
.stat .value {
  font-family: var(--font-heading); font-weight: 400;
  font-size: 46px; line-height: 1.05; font-variant-numeric: tabular-nums;
}
.stat .foot {
  font-size: 12px;
  color: color-mix(in srgb, var(--color-text) 60%, transparent);
}
@media (max-width: 767px) { .stat .value { font-size: 34px; } .stat { padding: var(--space-3); } }

/* The wine detail's hero: plate beside the identity block. */
.wine-hero { display: flex; align-items: flex-start; gap: var(--space-4); }
.wine-hero .plate-box { flex: none; width: 96px; }
.wine-hero > a,
.wine-hero .plate-drop > a { display: block; width: 96px; }
.wine-hero > a:hover .plate-box,
.wine-hero .plate-drop > a:hover .plate-box { border-color: var(--color-accent); }

/* The plate doubles as a drop target for the wine's label photo:
   drop, paste or pick and it becomes the primary. The button below it
   is the same action for touch and keyboard, where dragging isn't
   available. */
.plate-drop { width: 96px; position: relative; }
.plate-drop .plate-box { transition: border-color 120ms ease; }
.plate-drop.is-over .plate-box {
  border-color: var(--color-accent);
  border-style: dashed;
  background: color-mix(in srgb, var(--color-accent) 8%, var(--color-surface));
}
.plate-drop.is-busy { opacity: 0.6; pointer-events: none; }

.plate-drop-cta {
  display: block; width: 100%; margin-top: var(--space-1);
  padding: 2px 0;
  background: none; border: 0; cursor: pointer;
  color: var(--color-neutral-600);
  text-align: center;
}
.plate-drop-cta:hover:not(:disabled) { color: var(--color-accent); }
.plate-drop-cta:disabled { cursor: default; }

/* Tabs — a hairline rail with the current tab underscored in the
   accent. Same shape as the top nav's current-page marker, so the
   two read as the same idea at two levels. */
.tabs {
  display: flex; gap: var(--space-1); overflow-x: auto;
  border-bottom: 1px solid var(--color-divider);
}
.tabs button {
  flex: none; padding: var(--space-2) var(--space-3);
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 14px; color: var(--color-text);
  background: transparent; border: 0; border-bottom: 2px solid transparent;
  margin-bottom: -1px; cursor: pointer;
}
.tabs button:hover { color: var(--color-accent); }
.tabs button[aria-selected='true'] {
  color: var(--color-accent); border-bottom-color: var(--color-accent);
}

/* Two columns of roughly equal weight, stacking on a phone. Used
   by the Stats screen and the wine detail. */
.two-col {
  display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: var(--space-8);
}
@media (max-width: 767px) { .two-col { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); } }

/* Horizontal bars — "by drinking status" on the stats screen. */
.bars { display: flex; flex-direction: column; gap: 13px; }
.bar-row { display: flex; flex-direction: column; gap: 6px; }
.bar-row .bar-head { display: flex; font-size: 13px; }
.bar-row .bar-head .n {
  margin-left: auto; font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--color-text) 60%, transparent);
}
.bar-track {
  height: 7px; background: var(--color-surface);
  border: 1px solid var(--color-divider);
}
.bar-fill { height: 100%; background: var(--color-accent-300); }

/* The drinking-window bar — same track, a darker fill, and the
   two years captioned beneath it. */
.window-bar { display: flex; flex-direction: column; gap: 4px; }
.window-bar .bar-track { height: 5px; position: relative; }
.window-bar .bar-fill { background: var(--color-accent-400); }
.window-bar .ends {
  display: flex; font-size: 10px; letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
.window-bar .ends span:last-child { margin-left: auto; }

/* Simple label/value rows — "Elsewhere" on stats, the fact table
   on the wine detail. */
.facts { width: 100%; border-collapse: collapse; font-size: 14px; }
.facts td { padding: var(--space-2); border-bottom: 1px solid var(--color-divider); vertical-align: top; }
.facts td:first-child {
  width: 42%; color: color-mix(in srgb, var(--color-text) 60%, transparent);
}
.facts tr:last-child td { border-bottom: 0; }

/* ══════════════════════════════════════════════════════════════
   7. Tags — the app's semantic pills, on the design system's .tag
   The ``pill-*`` class names are semantic hooks (they say what the
   pill *means*, and the page tests assert on them); .tag and its
   variants carry the look. The palette stays mono, per the design
   system: colour is a swatch dot, never a filled pill.
   ══════════════════════════════════════════════════════════════ */

.tag { white-space: nowrap; }

/* Drinking status. Ready reads as an outline (a quiet "yes"),
   drink-soon takes the accent tint (the one that wants action),
   hold and unknown sit back in neutral. */
.pill-status-ready     { border: 1px solid var(--color-accent); color: var(--color-accent); }
.pill-status-past_peak { background: var(--color-accent-100); color: var(--color-accent-800); }
.pill-status-hold      { background: var(--color-neutral-100); color: var(--color-neutral-800); }
.pill-status-unknown   { background: var(--color-neutral-100); color: var(--color-neutral-600); }

/* Coravin session status, and the "N on Coravin" indicator. */
.pill-status-active    { border: 1px solid var(--color-accent); color: var(--color-accent); }
.pill-status-finished  { background: var(--color-neutral-100); color: var(--color-neutral-700); }
.pill-status-abandoned { background: var(--color-neutral-200); color: var(--color-neutral-700); }
.pill-coravin { background: var(--color-accent-100); color: var(--color-accent-800); }

.pill-tier-everyday, .pill-tier-premium, .pill-tier-occasion,
.pill-loc-home, .pill-loc-bond, .pill-loc-other {
  background: var(--color-neutral-100); color: var(--color-neutral-800);
}

/* Wine colour. The design shows colour as a dot, not a fill, so
   the pill is neutral and carries a tinted swatch. */
.pill-colour-red, .pill-colour-white, .pill-colour-orange,
.pill-colour-rose, .pill-colour-sparkling, .pill-colour-other {
  gap: 6px; background: transparent;
  color: color-mix(in srgb, var(--color-text) 72%, transparent);
  padding-inline: 0;
}

/* A review / tasting score. Set as a figure in the accent, not a
   badge — the design keeps large fills off the page. */
.score { font-variant-numeric: tabular-nums; color: var(--color-accent-700); }
.pill-score { font-variant-numeric: tabular-nums; color: var(--color-accent-700); font-size: 14px; }

/* ══════════════════════════════════════════════════════════════
   8. Forms
   ``.field`` / ``.input`` / ``.seg`` come from the design system;
   these add the grid the app's longer forms sit on, and bring
   <select> into line with .input (which the system only styles for
   text inputs).
   ══════════════════════════════════════════════════════════════ */

select.input {
  appearance: none; padding-right: 26px;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 12px center, right 7px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.form-row { display: flex; gap: var(--space-3); }
.form-row > .field { flex: 1; min-width: 0; }
.form-actions {
  display: flex; gap: var(--space-2); justify-content: flex-end;
  margin-top: var(--space-3);
}
/* Touch targets on the small screen — the designs set every
   primary control to 44px there. */
@media (max-width: 767px) {
  .btn { min-height: 44px; }
  .form-row { flex-direction: column; gap: var(--space-2); }
}

/* The filter bar on the reference pages, which keep their
   select-based filtering rather than the chip rail. */
.filter-bar {
  display: flex; align-items: flex-end; flex-wrap: wrap; gap: var(--space-3);
  padding: var(--space-3) 0 var(--space-4);
  border-bottom: 1px solid var(--color-divider);
  margin-bottom: var(--space-4);
}
.filter-bar .field { min-width: 150px; margin: 0; }
.filter-bar .filter-actions { margin-left: auto; display: flex; gap: var(--space-2); }

/* ══════════════════════════════════════════════════════════════
   9. Lists, groups and empty states
   ══════════════════════════════════════════════════════════════ */

/* The Manage hub's row list, and any other "name / hint / count /
   chevron" navigation list. */
.nav-list { display: flex; flex-direction: column; border-top: 1px solid var(--color-divider); }
.nav-list a {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: 52px; padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-divider);
  text-decoration: none; color: inherit;
}
.nav-list a:hover { background: color-mix(in srgb, var(--color-text) 4%, transparent); }
.nav-list .name { font-size: 15px; }
.nav-list .hint {
  font-size: 11px;
  color: color-mix(in srgb, var(--color-text) 58%, transparent);
}
.nav-list .count {
  font-size: 12px; font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
.nav-list .chev { color: var(--color-accent); }

/* A location group on the cellar ledger — a hairline header rather
   than the prototype's filled bar. */
.loc-group { margin-bottom: var(--space-6); }
.loc-group > header {
  display: flex; align-items: baseline; gap: var(--space-2);
  padding-bottom: var(--space-2); margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-divider);
}
.loc-group > header .name {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 17px;
}
.loc-group > header .count {
  margin-left: auto; font-size: 11px; font-variant-numeric: tabular-nums;
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
}

.empty {
  text-align: center; padding: var(--space-8) var(--space-4);
  border: 1px dashed var(--color-divider); border-radius: var(--radius-md);
  color: color-mix(in srgb, var(--color-text) 60%, transparent);
}
.empty .empty-title {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 17px; color: var(--color-text);
}

/* Region tree — nested <ul>s, indented by depth. */
.region-tree { list-style: none; padding-left: var(--space-4); margin: 0; }
.region-tree > li { margin: var(--space-1) 0; }

/* ══════════════════════════════════════════════════════════════
   10. Overlays — modal, lightbox, toast
   The modal reuses the design system's .dialog; these add the
   backdrop behaviour the app's Alpine components toggle.
   ══════════════════════════════════════════════════════════════ */

.modal-backdrop {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 8vh var(--space-4) var(--space-4);
  background: color-mix(in srgb, var(--color-neutral-900) 50%, transparent);
}
.modal {
  width: min(560px, 100%); max-height: 80vh; overflow: auto;
  display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-4); border-radius: var(--radius-lg);
  background: var(--color-surface); border: 1px solid var(--color-divider);
  box-shadow: var(--shadow-lg);
}
.modal-title {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 20px;
}

.lightbox {
  position: fixed; inset: 0; z-index: 100; cursor: zoom-out;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--color-neutral-900) 88%, transparent);
}
.lightbox img { max-width: 92%; max-height: 92%; object-fit: contain; }

/* Crop-before-upload dialog. The viewport is square because primary
   bottle photos are normalised to a square source before the various
   grid, ledger and hero frames apply their own centred cover crop. */
.cropper-lightbox {
  position: fixed; inset: 0; z-index: 110;
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4);
  background: color-mix(in srgb, var(--color-neutral-900) 74%, transparent);
}
.cropper-panel {
  width: min(100%, 460px); padding: var(--space-4);
  background: var(--color-bg); border: 1px solid var(--color-divider);
  box-shadow: 0 12px 40px color-mix(in srgb, var(--color-neutral-900) 26%, transparent);
}
.cropper-panel h2 { margin: 0 0 var(--space-1); font-size: 23px; }
.cropper-panel > p { margin: 0 0 var(--space-3); }
.cropper-viewport {
  position: relative; width: min(72vw, 380px); aspect-ratio: 1;
  margin: 0 auto var(--space-3); overflow: hidden;
  background: var(--color-surface); cursor: grab; touch-action: none;
}
.cropper-viewport:active { cursor: grabbing; }
.cropper-viewport::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  border: 1px solid var(--color-accent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-bg) 55%, transparent);
}
.cropper-viewport img {
  position: absolute; top: 50%; left: 50%; max-width: none;
  user-select: none; pointer-events: none;
}
.cropper-zoom { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-4); font-size: 13px; }
.cropper-zoom input { flex: 1; accent-color: var(--color-accent); }

.flash {
  position: fixed; bottom: var(--space-4); right: var(--space-4); z-index: 200;
  max-width: 22rem; padding: var(--space-2) var(--space-3);
  background: var(--color-surface); color: var(--color-text);
  border: 1px solid var(--color-accent); border-radius: var(--radius-md);
  box-shadow: var(--shadow-md); font-size: 14px;
}
.flash.error { border-color: var(--color-neutral-700); }
@media (max-width: 767px) { .flash { bottom: 70px; left: var(--space-3); right: var(--space-3); max-width: none; } }

/* ══════════════════════════════════════════════════════════════
   11. Photos
   Every content photograph goes through the design system's
   ``.plate`` wrapper, per its image rule.
   ══════════════════════════════════════════════════════════════ */

.photo-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: var(--space-2);
}
.photo-grid .photo-cell { position: relative; }
/* The photo is wrapped in a button so the lightbox is keyboard-
   reachable; the button itself is invisible chrome. */
.photo-open {
  display: block; width: 100%; padding: 0;
  background: none; border: 0; cursor: zoom-in;
}
.photo-grid img { width: 100%; aspect-ratio: 1; object-fit: cover; display: block; }
.photo-grid .primary-badge {
  position: absolute; top: 8px; left: 8px;
  background: var(--color-bg); color: var(--color-accent-800);
  font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  padding: 2px 7px; border: 1px solid var(--color-accent);
}

/* Sortable drag handle (producer lists). */
.sortable-ghost { opacity: 0.4; background: var(--color-accent-100) !important; }
.drag-handle {
  cursor: grab; user-select: none; padding: 0 var(--space-2);
  color: color-mix(in srgb, var(--color-text) 45%, transparent);
}
.drag-handle:active { cursor: grabbing; }

/* ══════════════════════════════════════════════════════════════
   12. Sign-in — the one page outside the shell
   ══════════════════════════════════════════════════════════════ */

.signin {
  width: min(420px, calc(100% - var(--space-6)));
  margin: 12vh auto var(--space-8);
  display: flex; flex-direction: column; gap: var(--space-3);
}
.signin .brand {
  font-family: var(--font-heading); font-weight: 400;
  font-size: 42px; line-height: 1.05; margin: 0;
}
.signin .lede {
  font-size: 14px; margin: 0 0 var(--space-2);
  color: color-mix(in srgb, var(--color-text) 70%, transparent);
}

[x-cloak] { display: none !important; }

/* The producer typeahead's result list (partials/producer_options). */
.producer-option { cursor: pointer; padding: var(--space-2); }
.producer-option:hover { background: color-mix(in srgb, var(--color-accent) 10%, transparent); }
.producer-options {
  list-style: none; margin: 0; padding: 0;
  max-height: 16rem; overflow: auto;
  border: 1px solid var(--color-divider); border-radius: var(--radius-md);
}

/* A form's error notice. Drawn as a bordered block rather than a red
   fill: the system applies colour as stroke, and a rejected value is
   a correction, not an alarm. */
.form-error, .signin-error {
  margin: var(--space-3) 0 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-neutral-700);
  border-radius: var(--radius-md);
  background: var(--color-neutral-100);
  color: var(--color-neutral-900);
}

/* The OAuth consent notice. Bordered, not filled — this is the one
   block on the page the reader must not skim, and a hairline box
   holds the eye without shouting. */
.consent-notice {
  padding: var(--space-3);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-md);
  background: var(--color-accent-100);
  color: var(--color-accent-900);
}
