/**
 * ECOZA — COMPONENTS
 *
 * Hand-written. Consumes assets/css/tokens.css (generated — do not edit that one).
 * Governing rules: docs/DESIGN-DOCTRINE.md
 *
 *   Rule 1  one elevated surface per region; shadows only on things that FLOAT
 *   Rule 2  90/8/2 — brand green is a highlighter, not a wash
 *   Rule 3  8 inside a group / 24 between groups / 48 between sections
 *   Rule 5  four animations; hover is INSTANT
 *   Rule 6  money is tabular, right-aligned, lakh-grouped, — when empty
 *
 * Two registers. Pick one before writing markup:
 *   .desk   working surface — crisp, dense, quiet, no shadows
 *   .lobby  surfaces that leave the building — cream, soft, generous
 */

/* Components below set `display`, which would otherwise beat the [hidden] attribute.
   Toggle visibility with el.hidden — never by editing style.display. */
[hidden] { display: none !important; }

/* ==========================================================================
   APP SHELL
   ========================================================================== */
.app { display: flex; min-height: 100vh; background: var(--bg); }

.app-main {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column;
}

.page {
  flex: 1;
  padding: var(--sp-6) var(--sp-8) var(--sp-16);
  max-width: var(--desk-content-max);
  width: 100%;
}
.page > * + * { margin-top: var(--sp-between-sections); }

.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap;
  margin-bottom: var(--sp-between-groups);
}
.page-head h1 { font: var(--t-head-lg); letter-spacing: var(--t-head-lg-track); margin: 0; }
.page-head .sub { font: var(--t-body-sm); color: var(--text-dim); margin-top: var(--sp-1); }
.page-head .actions { display: flex; gap: var(--sp-2); align-items: center; }

/* Section = a group of related things. Space does the grouping, not a box. */
.section > * + * { margin-top: var(--sp-between-groups); }
.section-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--border);
}
.section-head h2 { font: var(--t-head-md); letter-spacing: var(--t-head-md-track); margin: 0; }

/* ==========================================================================
   SIDEBAR — 248px expanded, 72px rail, off-canvas below md
   ========================================================================== */
.sidebar {
  width: var(--desk-sidebar-width); flex-shrink: 0;
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
  z-index: var(--z-sticky);
}
.sidebar .brand {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.sidebar .brand img { width: 30px; height: 30px; border-radius: var(--r-pill); }
.sidebar .brand span { font: var(--t-head-sm); line-height: 1.15; }
.sidebar .brand small { display: block; font: var(--t-caption); color: var(--text-dim); }

.sidebar nav { flex: 1; overflow-y: auto; padding: var(--sp-3) var(--sp-2); }
.nav-group { margin-top: var(--sp-4); }
.nav-group:first-child { margin-top: 0; }
.nav-group-label {
  font: var(--t-overline); letter-spacing: var(--t-overline-track); text-transform: uppercase;
  color: var(--text-faint);
  padding: 0 var(--sp-3) var(--sp-2);
}
.sidebar a {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 0 var(--sp-3); height: 34px;
  border-radius: var(--r-desk);
  font: var(--t-body); font-weight: 500;
  color: var(--text-dim); text-decoration: none;
  /* Rule 5 — hover is instant */
}
.sidebar a svg { width: var(--desk-icon-in-nav); height: var(--desk-icon-in-nav); flex-shrink: 0; }
.sidebar a:hover { background: var(--surface-sunken); color: var(--text); }
/* 8% budget: this is one of the four places brand green is allowed */
.sidebar a[aria-current="page"] { background: var(--accent-wash); color: var(--accent); font-weight: 600; }
.sidebar a .count {
  margin-left: auto; font: var(--t-caption); font-variant-numeric: tabular-nums;
  color: var(--text-faint);
}
.sidebar-foot { padding: var(--sp-2); border-top: 1px solid var(--border); }

.sidebar-scrim { display: none; }
/* Only exists in the mobile drawer. Esc closes it too, but a phone has no Esc.
   Scoped to .sidebar so it outranks `.icon-btn { display: inline-flex }`, which is
   declared later in this file — the same ordering trap that hid the nav labels. */
.sidebar .sidebar-close { display: none; }

/* ==========================================================================
   TOPBAR
   ========================================================================== */
.topbar {
  height: var(--desk-topbar-height); flex-shrink: 0;
  display: flex; align-items: center; gap: var(--sp-4);
  padding: 0 var(--sp-8) 0 var(--sp-6);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: var(--z-sticky);
}
.topbar .spacer { flex: 1; }
.hamburger { display: none; }

.searchbox { position: relative; width: 360px; max-width: 100%; }
.searchbox svg {
  position: absolute; left: 10px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: var(--text-faint); pointer-events: none;
}
.searchbox input { padding-left: 32px; }
.searchbox kbd {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  font: var(--t-caption); color: var(--text-faint);
  border: 1px solid var(--border); border-radius: var(--r-dense);
  padding: 1px 5px; background: var(--surface-sunken);
}

.user-chip {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-2); border-radius: var(--r-desk);
  cursor: pointer; background: none; border: 0; color: inherit; text-align: left;
}
.user-chip:hover { background: var(--surface-sunken); }
.user-chip img { width: 26px; height: 26px; border-radius: var(--r-pill); }
.user-chip .who { font: var(--t-body-sm); font-weight: 600; line-height: 1.2; }
.user-chip .who span { display: block; font-weight: 400; color: var(--text-dim); font-size: 11.5px; }

.icon-btn {
  width: var(--desk-control-height); height: var(--desk-control-height);
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: var(--r-desk);
  background: none; color: var(--text-dim); cursor: pointer; position: relative;
}
.icon-btn:hover { background: var(--surface-sunken); color: var(--text); }
.icon-btn svg { width: var(--desk-icon-in-control); height: var(--desk-icon-in-control); }
.icon-btn .dot {
  position: absolute; top: 6px; right: 6px; width: 6px; height: 6px;
  border-radius: var(--r-pill); background: var(--st-amber-600);
}

/* ==========================================================================
   BUTTONS — one primary per view (Rule 2)
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  height: var(--desk-control-height); padding: 0 var(--sp-4);
  font: var(--t-body); font-weight: 600;
  border: 1px solid transparent; border-radius: var(--r-desk);
  cursor: pointer; white-space: nowrap;
  /* Half the buttons in this product are <a> (New booking, Invoice, Day sheet).
     Without this they carry a link underline and stop reading as buttons. */
  text-decoration: none;
}
.btn svg { width: var(--desk-icon-in-control); height: var(--desk-icon-in-control); }
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:active { background: var(--accent-hover); filter: brightness(.94); }
.btn-default { background: var(--surface); border-color: var(--border-strong); color: var(--text); }
.btn-default:hover { background: var(--surface-sunken); }
.btn-quiet { background: none; color: var(--text-dim); }
.btn-quiet:hover { background: var(--surface-sunken); color: var(--text); }
.btn-danger { background: var(--st-red-600); color: #fff; }
.btn-danger:hover { background: var(--st-red-700); }
.btn-sm { height: var(--desk-control-height-sm); padding: 0 var(--sp-3); font-size: 12.5px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
/* Rule: a disabled control always carries its reason. See [data-why]. */

.btn-group { display: inline-flex; }
.btn-group .btn { border-radius: 0; margin-left: -1px; }
.btn-group .btn:first-child { border-radius: var(--r-desk) 0 0 var(--r-desk); margin-left: 0; }
.btn-group .btn:last-child { border-radius: 0 var(--r-desk) var(--r-desk) 0; }

/* ==========================================================================
   FIELDS
   ========================================================================== */
.field { display: flex; flex-direction: column; gap: var(--sp-1); }
.field > label { font: var(--t-label); letter-spacing: var(--t-label-track); }
.field .req { color: var(--st-red-600); }
.field .help { font: var(--t-caption); color: var(--text-dim); }
.field .err { font: var(--t-caption); font-weight: 600; color: var(--st-red-700); }

/* Fields inside a group sit 8px apart and need no box around them (Rule 3). */
.field-group { display: flex; flex-direction: column; gap: var(--sp-in-group); }
.field-row { display: flex; gap: var(--sp-in-group); flex-wrap: wrap; }
.field-row > .field { flex: 1 1 180px; }

.ipt {
  height: var(--desk-control-height); width: 100%;
  padding: 0 var(--sp-3);
  font: var(--t-body);
  color: var(--text); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--r-desk);
}
textarea.ipt { height: auto; min-height: 76px; padding: var(--sp-2) var(--sp-3); resize: vertical; line-height: 1.5; }
.ipt::placeholder { color: var(--text-faint); }
.ipt:hover { border-color: var(--n-400); }
.ipt:disabled { background: var(--surface-sunken); color: var(--text-faint); cursor: not-allowed; }
.ipt[aria-invalid="true"] { border-color: var(--st-red-500); }
select.ipt { appearance: none; padding-right: var(--sp-8); background-image: none; }
.select { position: relative; }
.select::after {
  content: ''; position: absolute; right: 12px; top: 50%; pointer-events: none;
  width: 6px; height: 6px; border-right: 1.5px solid var(--text-dim); border-bottom: 1.5px solid var(--text-dim);
  transform: translateY(-70%) rotate(45deg);
}

/* Money input — ৳ is a unit, the amount is the information */
.money-field { position: relative; }
.money-field .money-sym { position: absolute; left: var(--sp-3); top: 50%; transform: translateY(-50%); pointer-events: none; }
.money-field .ipt { padding-left: 26px; text-align: right; font-variant-numeric: tabular-nums slashed-zero; }

/* ==========================================================================
   FILTER BAR + CHIPS
   ========================================================================== */
.filter-bar {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
  position: sticky; top: var(--desk-topbar-height); background: var(--bg); z-index: var(--z-sticky);
}
.seg {
  display: inline-flex; background: var(--surface-sunken);
  border: 1px solid var(--border); border-radius: var(--r-desk); padding: 2px;
}
.seg button {
  height: 26px; padding: 0 var(--sp-3);
  font: var(--t-body-sm); font-weight: 600; color: var(--text-dim);
  background: none; border: 0; border-radius: var(--r-dense); cursor: pointer;
}
.seg button[aria-pressed="true"] { background: var(--surface); color: var(--text); box-shadow: var(--sh-raised); }

.chips { display: flex; gap: var(--sp-1); flex-wrap: wrap; align-items: center; }
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  height: 24px; padding: 0 var(--sp-2);
  font: var(--t-caption); font-weight: 600;
  background: var(--surface-sunken); border: 1px solid var(--border);
  border-radius: var(--r-dense); color: var(--text-dim);
}
.chip button { background: none; border: 0; cursor: pointer; color: inherit; line-height: 1; padding: 0; }
.chip--note { background: var(--st-amber-50); border-color: var(--st-amber-200); color: var(--st-amber-700); }

/* ==========================================================================
   STATUS BADGE — colour is never alone. Every state carries a SHAPE. (D-007)
   ========================================================================== */
.badge {
  display: inline-flex; align-items: center; gap: 6px;
  font: var(--t-caption); font-weight: 600;
  white-space: nowrap;
}
.badge::before { content: ''; flex-shrink: 0; display: block; }
.badge[data-shape="dot"]::before   { width: 7px; height: 7px; border-radius: var(--r-pill); background: currentColor; }
.badge[data-shape="ring"]::before  { width: 7px; height: 7px; border-radius: var(--r-pill); border: 1.5px solid currentColor; }
.badge[data-shape="bar"]::before   { width: 8px; height: 3px; border-radius: 1px; background: currentColor; }
.badge[data-shape="slash"]::before { width: 2px; height: 9px; border-radius: 1px; background: currentColor; transform: rotate(22deg); }

.badge[data-hue="teal"]    { color: var(--st-teal-700); }
.badge[data-hue="emerald"] { color: var(--st-emerald-700); }
.badge[data-hue="amber"]   { color: var(--st-amber-700); }
.badge[data-hue="red"]     { color: var(--st-red-700); }
.badge[data-hue="blue"]    { color: var(--st-blue-700); }
.badge[data-hue="neutral"] { color: var(--text-dim); }

/* ⟳ marker on rows the status engine moved, not a person (REQ-27) */
.auto-mark { color: var(--st-blue-600); font-size: 11px; cursor: help; }

/* ==========================================================================
   TABLE — no container box. A top rule and consistent alignment is enough.
   ========================================================================== */
/* NOT overflow:auto at desktop. An overflow container becomes the sticky scrollport,
   which pushes the sticky <thead> DOWN by its own top offset instead of pinning it to
   the page. Horizontal scroll is only needed below lg, where the header is not sticky. */
.table-scroll { overflow-x: visible; }
.dtable { width: 100%; border-collapse: collapse; }
.dtable th {
  font: var(--t-overline); letter-spacing: var(--t-overline-track); text-transform: uppercase;
  color: var(--text-faint); text-align: left;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border-strong);
  white-space: nowrap;
  /* Sticks under the topbar AND the sticky filter bar. The filter bar is 53px tall
     (12px padding-block + 28px control + 1px rule), measured, not guessed. */
  position: sticky; top: calc(var(--desk-topbar-height) + 53px);
  background: var(--bg); z-index: 1;
}
.dtable td {
  height: var(--desk-row-height);
  padding: 0 var(--sp-3);
  border-bottom: 1px solid var(--border);
  font: var(--t-body);
  vertical-align: middle;
}
.dtable tbody tr:hover { background: var(--surface-sunken); }   /* instant — Rule 5 */
.dtable tbody tr[aria-selected="true"] { background: var(--accent-wash); }
.dtable tbody tr[data-conflict] { box-shadow: inset 3px 0 0 var(--st-red-500); }
.dense .dtable td { height: var(--desk-row-height-compact); }

/* The identity column never scrolls away. */
.dtable .col-guest { position: sticky; left: 0; background: inherit; }
.dtable tbody tr:hover .col-guest { background: var(--surface-sunken); }

.guest-cell { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.guest-cell b { font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 22ch; }
/* Phone NEVER truncates — a half phone number is worse than useless. */
.guest-cell span { font: var(--t-caption); color: var(--text-dim); white-space: nowrap; font-variant-numeric: tabular-nums; }
.repeat-mark { color: var(--st-teal-600); font-size: 10px; }

.empty-cell { color: var(--text-faint); }

/* ==========================================================================
   THE MONEY STRIP — signature moment S2.
   Total / Received / Due as ONE typographic object, not three cards.
   Same shape in the form, the drawer, the invoice and the day sheet.
   ========================================================================== */
.money-strip {
  display: flex; align-items: flex-end; gap: var(--sp-8);
  padding: var(--sp-4) 0;
  border-top: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border);
}
.money-strip .cell { display: flex; flex-direction: column; gap: 2px; }
.money-strip .cell > span {
  font: var(--t-overline); letter-spacing: var(--t-overline-track); text-transform: uppercase;
  color: var(--text-faint);
}
.money-strip .cell > b { font: var(--t-num-lg); letter-spacing: var(--t-num-lg-track); font-variant-numeric: tabular-nums slashed-zero; }
.money-strip .op { font: var(--t-num-lg); color: var(--text-faint); padding-bottom: 2px; }
/* Due is the number the desk cares about, so Due is the largest. */
.money-strip .cell--due > b { font: var(--t-num-hero); letter-spacing: var(--t-num-hero-track); }
.money-strip .cell--due[data-settled="true"] > b { color: var(--st-emerald-700); }
.money-strip .cell--due[data-settled="false"] > b { color: var(--st-red-700); }
.money-strip .attribution { font: var(--t-caption); color: var(--text-faint); margin-top: var(--sp-1); }

/* ==========================================================================
   DRAWER — REQ-20: no second click to see a booking
   ========================================================================== */
.drawer-scrim {
  position: fixed; inset: 0; background: rgba(20,30,20,.35);
  z-index: var(--z-drawer);
}
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: 480px; max-width: 100%;
  background: var(--surface); border-left: 1px solid var(--border);
  box-shadow: var(--sh-floating);
  z-index: var(--z-drawer);
  display: flex; flex-direction: column;
  animation: drawer-in var(--dur-slow) var(--ease-standard);
}
@keyframes drawer-in { from { transform: translateX(24px); opacity: 0; } }
.drawer__head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4);
  border-bottom: 1px solid var(--border);
}
.drawer__body { flex: 1; overflow-y: auto; padding: var(--sp-4); }
.drawer__body > * + * { margin-top: var(--sp-between-groups); }
.drawer__foot {
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border);
  display: flex; gap: var(--sp-2); justify-content: flex-end;
}

/* ==========================================================================
   KEY-VALUE, NOTES
   ========================================================================== */
.kv { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-2) var(--sp-4); }
.kv dt { font: var(--t-caption); color: var(--text-faint); text-transform: uppercase; letter-spacing: .06em; }
.kv dd { margin: 0; font: var(--t-body); }

/* Side note (REQ-12). The cook reads this, so it is set larger than meta. */
.sidenote {
  border-left: 3px solid var(--st-amber-500);
  background: var(--st-amber-50);
  padding: var(--sp-3);
  border-radius: 0 var(--r-desk) var(--r-desk) 0;
  font: var(--t-body-lg);
}
.sidenote .label {
  display: block; font: var(--t-overline); letter-spacing: var(--t-overline-track);
  text-transform: uppercase; color: var(--st-amber-700); margin-bottom: var(--sp-1);
}

/* ==========================================================================
   FEEDBACK
   ========================================================================== */
.banner {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  padding: var(--sp-3) var(--sp-4);
  border: 1px solid; border-radius: var(--r-desk);
  font: var(--t-body);
  color: var(--text);
}
.banner > svg { flex-shrink: 0; margin-top: 2px; }
.banner--info  { background: var(--st-blue-50); border-color: var(--st-blue-200); }
.banner--warn  { background: var(--st-amber-50); border-color: var(--st-amber-200); }
.banner--error { background: var(--st-red-50); border-color: var(--st-red-200); }
.banner--info  > svg { color: var(--st-blue-500); }
.banner--warn  > svg { color: var(--st-amber-500); }
.banner--error > svg { color: var(--st-red-500); }

.toast {
  position: fixed; bottom: var(--sp-6); left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: var(--sp-4);
  background: var(--n-900); color: #fff;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-desk);
  box-shadow: var(--sh-floating); z-index: var(--z-toast);
  font: var(--t-body);
  animation: toast-in var(--dur-base) var(--ease-enter);
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 8px); } }
.toast button { background: none; border: 0; color: var(--brand-400); font: var(--t-body); font-weight: 700; cursor: pointer; }

/* Empty state — Lobby warmth inside a Desk screen. Names what is missing,
   why, and the one action that fixes it. Never "No data found". */
.empty {
  text-align: center;
  padding: var(--sp-16) var(--sp-8);
  background: var(--paper);
  border: 1px solid var(--border);
  border-radius: var(--r-lobby);
}
.empty h3 { font: var(--t-lobby-md); letter-spacing: var(--t-lobby-md-track); margin: 0 0 var(--sp-2); }
.empty p { font: var(--t-body); color: var(--text-dim); margin: 0 auto var(--sp-4); max-width: 42ch; }
.empty .hill { margin: 0 auto var(--sp-4); display: block; color: var(--brand-200); }

.skel { background: var(--surface-sunken); border-radius: var(--r-dense); animation: shimmer var(--dur-shimmer) ease infinite; }
@keyframes shimmer { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }

/* ==========================================================================
   LOBBY REGISTER — invoice, day sheet, login, confirmation
   ========================================================================== */
.lobby {
  background: var(--paper);
  color: var(--text);
}
.lobby h1, .lobby h2 { font: var(--t-lobby-lg); letter-spacing: var(--t-lobby-lg-track); margin: 0; font-weight: 400; }
.lobby .doc {
  max-width: 820px; margin: 0 auto;
  background: var(--paper);
  border-radius: var(--r-lobby);
  padding: var(--sp-12);
}
.lobby .doc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-6); }
.lobby .doc-head img { width: 56px; height: 56px; }

/* The hill-contour rule — the brand's ONE ornamental device.
   Permitted: document headers, the login hero, empty states, section breaks
   inside Lobby surfaces. Forbidden everywhere else. */
.hill-rule {
  display: block; width: 100%; height: 12px;
  color: var(--brand-600); opacity: .55;
  margin: var(--sp-4) 0;
}

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */

/* The icon rail is a TABLET state and is scoped to the tablet range on purpose.
   It used to be `max-width: 1023px` undone by a `display: revert` at mobile — but the
   hide selector carried `:not(.count)`, which outranks the restore on specificity, so
   the labels could never come back and the mobile drawer was icon-only. A range query
   removes the fight instead of winning it. */

/* ==========================================================================
   FORM LAYOUT — booking-new. Principle P2: one screen, no wizard, 45 seconds.
   ========================================================================== */
.form-layout { display: grid; grid-template-columns: minmax(0,1fr) 320px; gap: var(--sp-8); align-items: start; }
.form-col > * + * { margin-top: var(--sp-between-sections); }

/* A form section is a GROUP: 8px inside, 48px between. No boxes. (Rule 3) */
.fset { border: 0; padding: 0; margin: 0; }
/* `.fset{margin:0}` ties with `.form-col > * + *` on specificity and wins on source
   order, which flattened the 48px between sections. Restate it with more weight. */
.form-col > .fset + .fset,
.tabpanel > .fset + .fset { margin-top: var(--sp-between-sections); }
.rail > .fset { margin-top: var(--sp-between-groups); }
.fset > legend {
  font: var(--t-overline); letter-spacing: var(--t-overline-track); text-transform: uppercase;
  color: var(--text-faint);
  padding: 0 0 var(--sp-2); margin-bottom: var(--sp-3);
  border-bottom: 1px solid var(--border); width: 100%;
}
.fgrid { display: grid; grid-template-columns: repeat(12, 1fr); gap: var(--sp-in-group) var(--sp-3); }
.c3 { grid-column: span 3; } .c4 { grid-column: span 4; } .c6 { grid-column: span 6; }
.c8 { grid-column: span 8; } .c12 { grid-column: span 12; }

/* Stepper — pax and meal heads. Meal count is independent of pax (REQ-06). */
.stepper { display: flex; align-items: center; }
.stepper button {
  width: var(--desk-control-height); height: var(--desk-control-height);
  border: 1px solid var(--border-strong); background: var(--surface); color: var(--text);
  cursor: pointer; font: var(--t-body); font-weight: 600;
}
.stepper button:first-child { border-radius: var(--r-desk) 0 0 var(--r-desk); }
.stepper button:last-child { border-radius: 0 var(--r-desk) var(--r-desk) 0; }
.stepper button:hover { background: var(--surface-sunken); }
.stepper input {
  width: 56px; height: var(--desk-control-height); text-align: center;
  border: 1px solid var(--border-strong); border-left: 0; border-right: 0;
  background: var(--surface); color: var(--text);
  font: var(--t-num); font-variant-numeric: tabular-nums;
}

/* Bengali quick-chips on the side note — the client's own words from the call. */
.quick-chips { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-2); }
.quick-chips button {
  height: 26px; padding: 0 var(--sp-2);
  font: var(--t-body-sm);
  background: var(--surface-sunken); border: 1px solid var(--border);
  border-radius: var(--r-dense); color: var(--text-dim); cursor: pointer;
}
.quick-chips button:hover { border-color: var(--accent); color: var(--accent); }

/* The summary rail. Sticky, because the total is what you glance at while typing. */
.rail { position: sticky; top: calc(var(--desk-topbar-height) + var(--sp-6)); }
.rail > * + * { margin-top: var(--sp-between-groups); }
.rail .money-strip { flex-direction: column; align-items: stretch; gap: var(--sp-3); }
.rail .money-strip .op { display: none; }
.rail .money-strip .cell { flex-direction: row; justify-content: space-between; align-items: baseline; }

.form-foot {
  position: sticky; bottom: 0;
  display: flex; justify-content: flex-end; gap: var(--sp-2); align-items: center;
  padding: var(--sp-3) var(--sp-8);
  margin: var(--sp-8) calc(var(--sp-8) * -1) 0;
  background: var(--surface); border-top: 1px solid var(--border-strong);
  z-index: var(--z-sticky);
}
.form-foot .hint { margin-right: auto; font: var(--t-caption); color: var(--text-faint); }

/* A disabled control ALWAYS carries its reason. */
.why { display: inline-flex; align-items: center; gap: var(--sp-2); font: var(--t-caption); color: var(--text-faint); }

/* ==========================================================================
   DAY SHEET — signature moment S3. The artifact that leaves the building.
   ========================================================================== */
.date-stepper { display: flex; align-items: center; gap: var(--sp-2); }
.date-stepper b { font: var(--t-head-lg); letter-spacing: var(--t-head-lg-track); min-width: 12ch; text-align: center; }

.kpi-strip { display: flex; gap: var(--sp-8); flex-wrap: wrap; padding: var(--sp-4) 0; border-top: 1px solid var(--border-strong); border-bottom: 1px solid var(--border); }
.kpi-strip .cell { display: flex; flex-direction: column; gap: 2px; }
.kpi-strip .cell > span { font: var(--t-overline); letter-spacing: var(--t-overline-track); text-transform: uppercase; color: var(--text-faint); }
.kpi-strip .cell > b { font: var(--t-num-lg); letter-spacing: var(--t-num-lg-track); font-variant-numeric: tabular-nums; }
/* One hero. The cook's number and the cash number are what the day turns on. */
.kpi-strip .cell--hero > b { font: var(--t-num-hero); letter-spacing: var(--t-num-hero-track); }

.sheet-block > * + * { margin-top: var(--sp-3); }
.sheet-block h2 { font: var(--t-head-md); margin: 0; display: flex; align-items: baseline; gap: var(--sp-2); }
.sheet-block h2 .n { font: var(--t-caption); color: var(--text-faint); font-variant-numeric: tabular-nums; }

/* Kitchen summary — the cook reads this across a room, so it is the largest text here. */
.kitchen { background: var(--st-amber-50); border: 1px solid var(--st-amber-200); border-radius: var(--r-desk); padding: var(--sp-4); }
.kitchen .heads { font: var(--t-num-hero); letter-spacing: var(--t-num-hero-track); font-variant-numeric: tabular-nums; }
.kitchen ul { margin: var(--sp-3) 0 0; padding-left: var(--sp-4); font: var(--t-body-lg); }
.kitchen li + li { margin-top: var(--sp-2); }

/* ==========================================================================
   TABS — D-002 merged thin pages into tabs. This is that structure.
   ========================================================================== */
.tabs { display: flex; gap: var(--sp-1); border-bottom: 1px solid var(--border-strong); }
.tabs button {
  background: none; border: 0; cursor: pointer;
  padding: var(--sp-2) var(--sp-3);
  font: var(--t-body); font-weight: 600; color: var(--text-dim);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tabs button:hover { color: var(--text); }
.tabs button[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }
.tabpanel[hidden] { display: none; }

/* ==========================================================================
   UNIT CARD — inventory. Rule 8: a gradient NEVER stands in for a photograph.
   ========================================================================== */
.unit-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--sp-4); }
.unit-card { border: 1px solid var(--border); border-radius: var(--r-desk); overflow: hidden; background: var(--surface); }
.unit-card__img { aspect-ratio: 4/3; background: var(--surface-sunken); position: relative; display: block; object-fit: cover; width: 100%; }
/* No photograph yet: the logo's own line language, stated plainly. Not a gradient. */
.unit-card__placeholder {
  aspect-ratio: 4/3; background: var(--surface-sunken);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-2);
  color: var(--n-400); border-bottom: 1px solid var(--border);
}
.unit-card__placeholder span { font: var(--t-caption); }
.unit-card__body { padding: var(--sp-3); }
.unit-card__body h3 { font: var(--t-head-sm); margin: 0 0 2px; }
.unit-card__meta { font: var(--t-body-sm); color: var(--text-dim); }
.unit-card__foot {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-top: var(--sp-3); padding-top: var(--sp-2); border-top: 1px solid var(--border);
}
.unit-card__foot b { font: var(--t-num-lg); letter-spacing: var(--t-num-lg-track); font-variant-numeric: tabular-nums; }
.unit-card__foot span { font: var(--t-caption); color: var(--text-faint); }
.unit-card[data-inactive] { opacity: .6; }

/* Cost calculator row — settings > messaging */
.calc { display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap; font: var(--t-body); }
.calc .out { font: var(--t-num-lg); letter-spacing: var(--t-num-lg-track); font-variant-numeric: tabular-nums; }

/* Checklist — BTRC approval steps */
.checklist { list-style: none; padding: 0; margin: 0; }
.checklist li { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); font: var(--t-body); }
.checklist li:last-child { border-bottom: 0; }

/* ==========================================================================
   AVAILABILITY MATRIX — signature moment S1, drag to book.
   The client called room-by-room selection প্যারা. One gesture replaces four
   selections: drag across a unit's row, release, the form opens pre-filled.
   ========================================================================== */
.avail {
  --avail-unit-col: 190px;
  --avail-cell: 40px;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-desk);
  background: var(--surface);
}
.avail-row { display: grid; grid-template-columns: var(--avail-unit-col) repeat(var(--days), minmax(var(--avail-cell), 1fr)); }
.avail-row + .avail-row { border-top: 1px solid var(--border); }

/* `top` must be 0 here, NOT the page offset. `.avail` has overflow-x:auto, which makes
   the element its own scrollport — a page-sized offset pushes the header DOWN over the
   first rows instead of pinning it to the viewport. The sticky that actually earns its
   keep on this grid is the unit column (left), which survives horizontal scrolling. */
.avail-head { position: sticky; top: 0; z-index: 2; background: var(--surface-sunken); }
.avail-head .avail-cell,
.avail-head .avail-unit { font: var(--t-caption); color: var(--text-dim); text-align: center; padding: var(--sp-2) 0; }
.avail-head .avail-cell b { display: block; font: var(--t-body-sm); font-weight: 700; font-variant-numeric: tabular-nums; }
.avail-head .avail-cell[data-weekend] { color: var(--st-amber-700); }

.avail-unit {
  position: sticky; left: 0; z-index: 1;
  background: var(--surface);
  padding: var(--sp-2) var(--sp-3);
  border-right: 1px solid var(--border-strong);
  display: flex; flex-direction: column; justify-content: center;
}
.avail-unit b { font: var(--t-body); font-weight: 600; }
.avail-unit span { font: var(--t-caption); color: var(--text-faint); }

.avail-cell { height: var(--avail-cell); border-right: 1px solid var(--border); position: relative; cursor: crosshair; }
.avail-cell:last-child { border-right: 0; }
.avail-cell[data-state="booked"] { background: var(--st-teal-50); cursor: not-allowed; }
.avail-cell[data-state="booked"]::after {
  content: attr(data-guest);
  position: absolute; inset: 3px 0;
  font: var(--t-caption); color: var(--st-teal-700);
  display: flex; align-items: center; padding-left: 6px;
  white-space: nowrap; overflow: hidden;
}
/* Blocked resists the drag with a hard stop rather than silently allowing it. */
.avail-cell[data-state="blocked"] {
  cursor: not-allowed;
  background: repeating-linear-gradient(45deg, transparent, transparent 4px, var(--border) 4px, var(--border) 5px);
}
.avail-cell[data-state="available"]:hover { background: var(--accent-wash); }
/* Declared after :hover on purpose — a selected cell must stay selected while the
   cursor is still over it, and :hover would otherwise win on specificity. */
.avail-cell[data-sel],
.avail-cell[data-sel]:hover { background: var(--accent); }
.avail-row[data-inactive] { opacity: .5; }

.avail-legend { display: flex; gap: var(--sp-4); flex-wrap: wrap; font: var(--t-caption); color: var(--text-dim); margin-top: var(--sp-3); }
.avail-legend i { width: 14px; height: 14px; border-radius: var(--r-dense); display: inline-block; vertical-align: -3px; margin-right: 5px; border: 1px solid var(--border); }
.avail-legend i[data-k="available"] { background: var(--surface); }
.avail-legend i[data-k="booked"] { background: var(--st-teal-50); }
.avail-legend i[data-k="blocked"] { background: repeating-linear-gradient(45deg, transparent, transparent 3px, var(--border) 3px, var(--border) 4px); }
.avail-legend i[data-k="selected"] { background: var(--accent); }

/* Live drag readout — rate and running total while you extend the selection. */
.drag-readout {
  position: fixed; z-index: var(--z-tooltip);
  background: var(--n-900); color: #fff;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-desk);
  font: var(--t-body-sm); pointer-events: none; box-shadow: var(--sh-floating);
}
.drag-readout b { font-variant-numeric: tabular-nums; }

/* ==========================================================================
   LOBBY — login, invoice, confirmation. Surfaces that leave the building.
   ========================================================================== */
.lobby-page { min-height: 100vh; display: grid; grid-template-columns: 1fr 1fr; background: var(--paper); }
.lobby-hero {
  background: var(--brand-800); color: #fff;
  padding: var(--sp-16) var(--sp-12);
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-8);
}
.lobby-hero .mark { display: flex; align-items: center; gap: var(--sp-3); }
/* The logo PNG has a solid cream ground, not transparency. On the dark hero that reads
   as a broken cutout unless we commit to it — so it becomes a deliberate badge. */
.lobby-hero .mark img { width: 44px; height: 44px; border-radius: var(--r-desk); background: var(--logo-paper); padding: 3px; }
.lobby-hero .mark b { font: var(--t-head-md); }
.lobby-hero h1 { font: var(--t-lobby-xl); letter-spacing: var(--t-lobby-xl-track); font-weight: 400; margin: 0; max-width: 16ch; }
.lobby-hero p { font: var(--t-body-lg); opacity: .78; max-width: 40ch; margin: var(--sp-3) 0 0; }
.lobby-hero .hill-rule { color: #fff; opacity: .4; }

.lobby-form { display: flex; align-items: center; justify-content: center; padding: var(--sp-12) var(--sp-8); }
.lobby-form > div { width: 100%; max-width: 340px; }
.lobby-form h2 { font: var(--t-lobby-md); letter-spacing: var(--t-lobby-md-track); font-weight: 400; margin: 0 0 var(--sp-2); }

/* Invoice / printable document */
.doc {
  max-width: 820px; margin: 0 auto;
  background: var(--paper); border: 1px solid var(--border);
  border-radius: var(--r-lobby); padding: var(--sp-12);
}
.doc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-6); }
.doc-head img { width: 52px; height: 52px; }
.doc-head h1 { font: var(--t-lobby-lg); letter-spacing: var(--t-lobby-lg-track); font-weight: 400; margin: 0; }
.doc-head .meta { text-align: right; font: var(--t-body-sm); color: var(--text-dim); }
.doc section + section { margin-top: var(--sp-between-sections); }

/* ==========================================================================
   DASHBOARD — one hero, then a thin strip. Never three equal cards.
   ========================================================================== */
.today-hero { display: flex; gap: var(--sp-12); flex-wrap: wrap; align-items: flex-end; padding: var(--sp-4) 0; border-bottom: 1px solid var(--border-strong); }
.today-hero .cell { display: flex; flex-direction: column; gap: 2px; }
.today-hero .cell > span { font: var(--t-overline); letter-spacing: var(--t-overline-track); text-transform: uppercase; color: var(--text-faint); }
.today-hero .cell > b { font: var(--t-num-hero); letter-spacing: var(--t-num-hero-track); font-variant-numeric: tabular-nums; }
.today-hero .cell--quiet > b { font: var(--t-num-lg); letter-spacing: var(--t-num-lg-track); }

/* Horizontal bars — occupancy, status breakdown. No chart library. */
.bars { display: flex; flex-direction: column; gap: var(--sp-2); }
.bar-row { display: grid; grid-template-columns: 130px 1fr 52px; align-items: center; gap: var(--sp-3); font: var(--t-body-sm); }
.bar-track { height: 8px; border-radius: var(--r-pill); background: var(--surface-sunken); overflow: hidden; }
.bar-fill { height: 100%; border-radius: var(--r-pill); background: var(--viz-1); }
.bar-row .v { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }

/* Activity / timeline */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li { display: grid; grid-template-columns: 110px 1fr; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--border); font: var(--t-body); }
.timeline li:last-child { border-bottom: 0; }
.timeline time { font: var(--t-caption); color: var(--text-faint); font-variant-numeric: tabular-nums; }

/* Two-column page split used by detail screens */
.split { display: grid; grid-template-columns: minmax(0,1fr) 340px; gap: var(--sp-8); align-items: start; }

/* A cell carrying two bookings. Shown, not hidden — fixture case C13. */
.avail-cell[data-clash] {
  background: repeating-linear-gradient(45deg, var(--st-red-50), var(--st-red-50) 4px, var(--st-red-200) 4px, var(--st-red-200) 5px);
}
.avail-cell[data-clash]::after { color: var(--st-red-700); font-weight: 700; }

/* ==========================================================================
   BREADCRUMBS
   ========================================================================== */
.crumbs { display: flex; align-items: center; gap: var(--sp-2); font: var(--t-body-sm); color: var(--text-dim); }
.crumbs a { color: var(--text-dim); text-decoration: none; }
.crumbs a:hover { color: var(--accent); text-decoration: underline; }
.crumbs span[aria-hidden] { color: var(--text-faint); }

.link { color: var(--accent); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }

/* ==========================================================================
   MODAL — one of the four things allowed to float (Rule 1)
   ========================================================================== */
.modal-scrim { position: fixed; inset: 0; background: rgba(20,30,20,.45); z-index: var(--z-modal); }
.modal {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 92%; max-width: 460px; z-index: var(--z-modal);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-desk); box-shadow: var(--sh-floating);
  animation: overlay-in var(--dur-base) var(--ease-enter);
}
@keyframes overlay-in { from { opacity: 0; transform: translate(-50%, -50%) scale(.97); } }
.modal__head { padding: var(--sp-4) var(--sp-4) var(--sp-3); }
.modal__head h2 { font: var(--t-head-md); letter-spacing: var(--t-head-md-track); margin: 0; }
.modal__body { padding: 0 var(--sp-4); font: var(--t-body); color: var(--text-dim); }
.modal__body p { margin: 0; }
.modal__foot { display: flex; justify-content: flex-end; gap: var(--sp-2); padding: var(--sp-4); }

/* Checkbox / radio rows */
.check-row { display: flex; align-items: center; gap: var(--sp-2); font: var(--t-body); cursor: pointer; }
.check-row input:disabled + *, .check-row:has(input:disabled) { color: var(--text-faint); cursor: not-allowed; }


/* ==========================================================================
   RESPONSIVE — every media query lives here, at the END of the file.

   This is structural, not stylistic. Three separate bugs came from base rules
   being appended *after* a media query and silently winning on source order:
   the mobile nav labels, the sidebar close button, and the form-footer hint.
   Media queries last means a breakpoint rule always beats the base rule it
   is meant to override, without a specificity fight.

   Order: tablet range (768–1023) → mobile (<768) → small (<640).
   ========================================================================== */

@media (max-width: 1023px) {
  .table-scroll { overflow-x: auto; }
  .dtable th { position: static; }
  .page { padding: var(--sp-4) var(--sp-6) var(--sp-12); }
  .searchbox { width: 240px; }
}

@media (min-width: 768px) and (max-width: 1023px) {
  .sidebar { width: var(--desk-sidebar-rail-width); }
  .sidebar .brand span,
  .sidebar nav a > span,
  .sidebar-foot a span,
  .nav-group-label { display: none; }
  .sidebar a { justify-content: center; padding: 0; }
  /* An icon with no label needs its name somewhere. */
  .sidebar a { position: relative; }
}

@media (max-width: 767px) {
  .hamburger { display: inline-flex; }
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0;
    /* Leave a strip of the page visible so the drawer reads as temporary and the
       scrim is tappable without hunting for it. */
    width: min(var(--desk-sidebar-width), 84vw);
    transform: translateX(-100%); transition: transform var(--dur-slow) var(--ease-standard);
    box-shadow: var(--sh-floating); z-index: var(--z-drawer);
  }
  .sidebar .brand { justify-content: space-between; }
  .sidebar .sidebar-close { display: inline-flex; }
  /* 44px touch targets below lg. */
  .sidebar nav a { height: 44px; }
  .sidebar nav { padding: var(--sp-3) var(--sp-2) var(--sp-8); }
  .sidebar[data-open="true"] { transform: none; }
  /* No un-hiding needed — the rail never applies at this width. */
  .sidebar-scrim[data-open="true"] {
    display: block; position: fixed; inset: 0;
    background: rgba(20,30,20,.45); z-index: calc(var(--z-drawer) - 1);
  }

  /* No table on a phone, so no density control. */
  #densityBtn { display: none; }

  .topbar { padding: 0 var(--sp-4); }
  .searchbox { width: auto; flex: 1; }
  .searchbox kbd, .user-chip .who { display: none; }

  .page { padding: var(--sp-4) var(--sp-4) var(--sp-16); }

  /* Table becomes stacked cards. Label comes from data-label. */
  .dtable thead { display: none; }
  .dtable, .dtable tbody, .dtable tr, .dtable td { display: block; width: 100%; }
  .dtable tr {
    border: 1px solid var(--border); border-radius: var(--r-desk);
    padding: var(--sp-3); margin-bottom: var(--sp-2); background: var(--surface);
  }
  /* `.dense .dtable td` (0,2,2) outranks `.dtable td` (0,1,2), so the compact-density
     row height survived into the card layout and clamped every card to 30px — content
     spilled over the row below. Density is a table concept; there is no table here. */
  .dtable td,
  .dense .dtable td { height: auto; padding: 3px 0; border: 0; display: flex; justify-content: space-between; gap: var(--sp-4); }
  .dtable td::before {
    content: attr(data-label);
    font: var(--t-caption); color: var(--text-faint); text-transform: uppercase; letter-spacing: .06em;
  }
  .dtable td:not([data-label])::before { content: none; }
  /* The identity cell carries two lines of its own. Sharing a row with its label
     squeezed the name until it clipped, so on a phone it gets the full width. */
  .dtable td.col-guest,
  .dense .dtable td.col-guest { position: static; display: block; height: auto; }
  .dtable td.col-guest::before { display: block; margin-bottom: 2px; }
  .dtable td.col-guest .guest-cell b { max-width: none; white-space: normal; }

  /* Wrapped, the − and = operators end up orphaned at the end of a line and read as
     noise. On a phone the relationship is carried by the order and the labels. */
  .money-strip { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3) var(--sp-4); }
  .money-strip .op { display: none; }
  .money-strip .cell--due { grid-column: 1 / -1; }

  /* The form footer is the primary action. On a phone it belongs at the bottom of the
     viewport, full width, and the keyboard hint means nothing on a touch device. */
  .form-foot {
    position: fixed; left: 0; right: 0; bottom: 0; margin: 0;
    padding: var(--sp-3) var(--sp-4);
    box-shadow: var(--sh-floating); z-index: var(--z-sticky);
  }
  .form-foot .hint { display: none; }
  .form-foot .btn { flex: 1; }
  /* Room for it, so the last field is never trapped underneath. */
  .form-layout { padding-bottom: 72px; }
  .drawer { width: 100%; top: 10vh; border-radius: var(--r-lobby) var(--r-lobby) 0 0; }

  /* Touch targets */
  .btn, .icon-btn, .sidebar a { min-height: 44px; }
}

@media (max-width: 1023px) {
  .form-layout { grid-template-columns: 1fr; }
  .rail { position: static; }
}

@media (max-width: 767px) {
  .c3, .c4, .c6, .c8 { grid-column: span 12; }
  .form-foot { margin-inline: calc(var(--sp-4) * -1); padding-inline: var(--sp-4); }
}

@media (max-width: 1023px) { .split { grid-template-columns: 1fr; } }

@media (max-width: 767px) {
  .lobby-page { grid-template-columns: 1fr; }
  .lobby-hero { padding: var(--sp-8) var(--sp-4); }
  .bar-row { grid-template-columns: 96px 1fr 48px; }
  .doc { padding: var(--sp-6); border-radius: var(--r-desk); }
}

@media (max-width: 639px) {
  .modal { top: auto; bottom: 0; left: 0; transform: none; width: 100%; max-width: none;
           border-radius: var(--r-lobby) var(--r-lobby) 0 0; animation: none; }
}
