/* ============ TOKENS ============ */
/* Dark is the house look and stays the default — the venue runs in low light.
   Light is opt-in via the ☀/☾ control (see js/theme.js), which stamps
   data-theme="light" on <html> and remembers the choice.
   EVERY colour lives here. Nothing below this block hardcodes one, so the
   whole app re-themes from these two lists alone. */
:root {
  color-scheme: dark;
  --bg: #0B120F;
  --card: #121C18;
  --card-alt: #182521;
  --border: #22322C;
  --green: #49A177;
  --gold: #B8912F;
  --red: #D06A50;
  --red-solid: #A8442F;   /* fill under ivory type */
  --amber: #C2762A;
  --muted: #7C8C84;
  --text: #EDE8DA;

  /* surfaces and scrims */
  --sidebar-bg: #0E1714;
  --felt-well: #0A100D;
  --offline-bg: #241A0C;
  --vignette: transparent;
  --overlay: #050807D9;
  --shadow-strong: #00000066;
  --row-border: #22322C;
  --border-strong: #33453D;   /* controls: inputs, keys, pills */
  --hover-tint: #ffffff0d;
  --dim-opacity: 0.6;
  --on-accent: #F5F1E6;          /* text sitting on a solid red/ball fill */

  /* neutral family: maintenance state and secondary buttons */
  --neutral-solid: #3A4741;
  --neutral-text: #8A9A92;
  --neutral-text-2: #A9B7B0;
  --neutral-15: #3A474115;
  --neutral-20: #3A474120;
  --neutral-33: #3A474133;
  --neutral-44: #3A474144;

  /* table-type identity */
  --type-snooker: #6E9BC4;
  --type-snooker-bd: #2A4560;
  --type-pool: #6FA98A;
  --type-pool-bd: #2C4E3E;

  /* logo mark */
  --logo-ball: #182521;
  --logo-ball-edge: #33453D;
  --logo-ball-core: #0B120F;

  /* Accent washes. The suffix is a WEIGHT STEP, not a literal alpha: dark uses
     it as the alpha directly, while light needs more of it because a dark hue at
     8% over white all but vanishes. Fills stay light; border-weight steps carry
     real contrast. */
  --green-15: #3E8E6815;
  --green-18: #3E8E6818;
  --green-20: #3E8E6820;
  --green-22: #3E8E6822;
  --green-33: #3E8E6833;
  --green-44: #3E8E6844;
  --green-55: #3E8E6855;
  --green-66: #3E8E6866;
  --gold-15: #B8912F15;
  --gold-20: #B8912F20;
  --gold-22: #B8912F22;
  --gold-33: #B8912F33;
  --gold-44: #B8912F44;
  --gold-55: #B8912F55;
  --red-15: #A8442F15;
  --red-20: #A8442F20;
  --red-22: #A8442F22;
  --red-33: #A8442F33;
  --red-44: #A8442F44;
  --red-66: #A8442F66;
  --amber-15: #C2762A15;
  --amber-20: #C2762A20;
  --amber-33: #C2762A33;
  --amber-44: #C2762A44;

  /* Bebas Neue and JetBrains Mono are served from public/fonts (see the
     @font-face block below) — self-hosted, so the venue laptop never makes a
     request for them. The fallbacks still matter: if a font file is ever
     missing the UI degrades to a condensed grotesque rather than breaking.
     Body text is deliberately the system stack: Segoe UI on the club laptop,
     SF on the owner's phone. It is already the right face on every device and
     costs nothing to load. */
  --font-display: 'Bebas Neue', 'Arial Narrow', 'Helvetica Neue Condensed', sans-serif;
  --font-body: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'Cascadia Mono', Consolas, monospace;
}

/* ============ SELF-HOSTED FONTS ============ */
/* Both faces are SIL Open Font Licence, so shipping the .woff2 inside the app
   is permitted. Latin subset only — 45KB for the pair, against ~300KB for the
   full multi-script families we will never render at an Indian pool club.

   font-display: swap means text paints immediately in the fallback and swaps
   when the file arrives. From local disk that is one frame; the alternative
   (block) would give staff a moment of invisible text on every cold load. */
@font-face {
  font-family: 'Bebas Neue';
  src: url('/fonts/bebas-neue-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/fonts/jetbrains-mono.woff2') format('woff2');
  /* One variable file covers the whole range — Google served byte-identical
     files for 400 and 500, so declaring a range here avoids shipping it twice. */
  font-weight: 100 800;
  font-style: normal;
  font-display: swap;
}

/* Daylight: chalk and paper rather than an inversion of the dark palette.
   The accents are darkened until they carry text on white — neon #00FF87 is
   unreadable on a light ground, so it becomes a deep baize green. */
:root[data-theme="light"] {
  color-scheme: light;
  --bg: #E8E4D8;
  --card: #F3F0E7;
  --card-alt: #DFDACB;
  --border: #C3BCA9;
  --green: #2C5C43;
  --gold: #7A5F16;
  --red: #8E3520;
  --red-solid: #8E3520;
  --amber: #8A5310;
  --muted: #5E5A4E;
  --text: #1A1813;

  --sidebar-bg: #E1DCCD;
  --felt-well: #CFC9B8;
  --offline-bg: #F2E6CC;
  --vignette: transparent;
  --overlay: #1A1813CC;
  --shadow-strong: #1a181326;
  --row-border: #C3BCA9;
  --border-strong: #8C8574;
  --hover-tint: #1a18130d;
  --dim-opacity: 0.78;
  --on-accent: #F5F1E6;

  --neutral-solid: #5C5749;
  --neutral-text: #5E5A4E;
  --neutral-text-2: #403C33;
  --neutral-15: #5C574914;
  --neutral-20: #5C57491F;
  --neutral-33: #5C57493D;
  --neutral-44: #5C574952;

  --type-snooker: #2B5077;
  --type-snooker-bd: #9FB4CA;
  --type-pool: #2C5C43;
  --type-pool-bd: #A5C0AF;

  --green-15: #2C5C4315;
  --green-18: #2C5C4355;
  --green-20: #2C5C4320;
  --green-22: #2C5C4366;
  --green-33: #2C5C4399;
  --green-44: #2C5C43AA;
  --green-55: #2C5C43CC;
  --green-66: #2C5C43CC;
  --gold-15: #7A5F1615;
  --gold-20: #7A5F1620;
  --gold-22: #7A5F1666;
  --gold-33: #7A5F16C4;
  --gold-44: #7A5F16AA;
  --gold-55: #7A5F16CC;
  --red-15: #8E352015;
  --red-20: #8E352020;
  --red-22: #8E352066;
  --red-33: #8E3520B8;
  --red-44: #8E3520AA;
  --red-66: #8E3520CC;
  --amber-15: #8A531015;
  --amber-20: #8A531020;
  --amber-33: #8A531099;
  --amber-44: #8A5310AA;

  --logo-ball: #DFDACB;
  --logo-ball-edge: #C3BCA9;
  --logo-ball-core: #F3F0E7;
}

/* ============ THEME TOGGLE ============ */
.theme-btn {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--card-alt); border: 1px solid var(--border); color: var(--muted);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  font-size: 15px; transition: color 0.2s, border-color 0.2s; flex-shrink: 0;
}
.theme-btn:hover { color: var(--gold); border-color: var(--gold); }
.theme-btn:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; }
/* Floating variant for pages with no topbar (login, owner pages) */
.theme-btn.floating { position: fixed; top: 16px; right: 16px; z-index: 200; background: var(--card); }

* { margin: 0; padding: 0; box-sizing: border-box; }
/* Antialiasing matters more than usual here because the default theme is light
   text on a near-black ground, where subpixel rendering makes strokes look
   thick and slightly coloured. Grayscale smoothing keeps them clean. Purely a
   rendering hint — it changes no metrics, so nothing reflows. */
html, body { width: 100%; background: var(--bg); color: var(--text); font-family: var(--font-body); overflow-x: hidden;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
/* No page vignette: a radial wash is exactly the ambient gradient this
   design is avoiding. Depth comes from flat value steps between surfaces. */
button { font-family: var(--font-body); }
input, select, textarea { font-family: var(--font-body); }

.app { min-height: 100vh; display: flex; flex-direction: column; position: relative; z-index: 1; }

/* ============ OFFLINE BANNER ============ */
.offline-banner { background: var(--offline-bg); border-bottom: 1px solid var(--amber-44); color: var(--amber); font-size: 12px; text-align: center; padding: 6px; animation: pulse-amber 2s infinite; display: flex; align-items: center; justify-content: center; gap: 8px; letter-spacing: 0.3px; }
@keyframes pulse-amber { 0%,100% { opacity: 1; } 50% { opacity: 0.6; } }

/* ============ SCREEN TABS ============ */
.screen-tabs { display: flex; gap: 6px; padding: 10px 20px 0; background: var(--card); border-bottom: 1px solid var(--border); flex-shrink: 0; overflow-x: auto; }
.screen-tab { font-size: 12px; font-weight: 500; padding: 8px 14px; border-radius: 2px; cursor: pointer; border: 1px solid transparent; border-bottom: none; color: var(--muted); background: transparent; white-space: nowrap; transition: all 0.15s; }
.screen-tab.active { background: var(--card-alt); color: var(--green); border-color: var(--border); }
.screen-tab:hover:not(.active) { color: var(--text); }

/* ============ TOP BAR ============ */
.topbar { background: var(--card); border-bottom: 1px solid var(--border); padding: 0 20px; height: 56px; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; gap: 12px; }
.topbar-logo { display: flex; align-items: center; gap: 10px; min-width: 0; }
.logo-icon { width: 32px; height: 32px; flex-shrink: 0; }
/* The venue name is owner-editable and can be long ("Masters Pool and Snooker
   Club"), so the wordmark scales with the viewport and truncates in the topbar
   rather than pushing the clock and controls off screen. */
.wordmark { font-family: var(--font-display); font-size: clamp(15px, 2.2vw, 22px); letter-spacing: 1.5px; color: var(--green); line-height: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar-logo > div { min-width: 0; }
.tagline { font-size: 9px; color: var(--muted); letter-spacing: 0.5px; margin-top: -2px; white-space: nowrap; }
.topbar-center { display: flex; flex-direction: column; align-items: center; }
.clock { font-family: var(--font-display); font-size: 28px; color: var(--text); letter-spacing: 3px; line-height: 1; }
.date-label { font-size: 10px; color: var(--muted); letter-spacing: 1px; text-transform: uppercase; }
.topbar-right { display: flex; align-items: center; gap: 14px; }
.staff-info { text-align: right; }
.staff-name { font-size: 13px; font-weight: 500; color: var(--text); }
.staff-shift { font-size: 11px; color: var(--muted); }
.bell-btn { width: 36px; height: 36px; border-radius: 50%; background: var(--card-alt); border: 1px solid var(--border); color: var(--muted); display: flex; align-items: center; justify-content: center; cursor: pointer; position: relative; font-size: 16px; transition: color 0.2s; flex-shrink: 0; }
.bell-btn:hover { color: var(--green); border-color: var(--green-44); }
.bell-badge { position: absolute; top: 2px; right: 2px; min-width: 15px; height: 15px; padding: 0 3px; background: var(--red-solid); border-radius: 50%; font-size: 9px; color: var(--on-accent); display: flex; align-items: center; justify-content: center; font-weight: 600; }

.bell-panel { position: fixed; top: 64px; right: 16px; width: 300px; background: var(--card); border: 1px solid var(--border); border-radius: 2px; padding: 14px; z-index: 150; box-shadow: none; animation: slide-in-right 0.2s ease; }

/* ============ MAIN LAYOUT ============ */
.main-layout { flex: 1; display: grid; grid-template-columns: 1fr 280px; gap: 0; min-height: 0; }
/* A 1366px laptop is the common club machine, and there 280px of sidebar is a
   fifth of the screen taken from the floor. Narrower below 1500px so the tables
   get the room. */
@media (max-width: 1500px) { .main-layout { grid-template-columns: 1fr 240px; } }
.screen-page { flex: 1; padding: 16px; display: flex; flex-direction: column; gap: 14px; max-width: 1200px; width: 100%; margin: 0 auto; }
.page-title { font-family: var(--font-display); font-size: 28px; letter-spacing: 2px; color: var(--text); }
.page-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }

.tables-area { padding: 16px; display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.section-header { font-size: 11px; color: var(--muted); letter-spacing: 1.5px; text-transform: uppercase; margin-bottom: 4px; display: flex; align-items: center; gap: 8px; }
.section-header::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.tables-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 12px; align-content: start; }

/* ============ TABLE CARD ============ */
.table-card { background: var(--card); border: 1px solid var(--border); border-radius: 2px; padding: 14px; display: flex; flex-direction: column; gap: 10px; position: relative; overflow: hidden; transition: transform 0.2s; }
.table-card:hover { border-color: var(--border-strong); }
.card-top { display: flex; align-items: flex-start; justify-content: space-between; }
.table-num { font-family: var(--font-display); font-size: 42px; line-height: 1; color: var(--text); letter-spacing: 2px; }
.status-badge { font-size: 10px; font-weight: 700; letter-spacing: 1.4px; padding: 4px 9px; border-radius: 0; text-transform: uppercase; }
.badge-free { background: var(--green-15); color: var(--green); border: 1px solid var(--green-33); }
.badge-running { background: var(--red-15); color: var(--red); border: 1px solid var(--red-33); }
.badge-billing { background: var(--amber-15); color: var(--amber); border: 1px solid var(--amber-33); }
.badge-booked { background: var(--gold-15); color: var(--gold); border: 1px solid var(--gold-33); }
.badge-maintenance { background: var(--neutral-15); color: var(--neutral-text); border: 1px solid var(--neutral-33); }
/* pulse-red retired: a blinking card is decoration, and the filled status
   block already states the table is live. */

.pool-table-wrap { border-radius: 2px; overflow: hidden; background: var(--felt-well); border: 2px solid var(--border); padding: 4px; position: relative; }

/* ---- scoreboard card ---- */
/* Status is a solid filled block, the way a club match board states it — you
   register the colour before you read the word. */
.status-badge { border: 0; }
.badge-free { background: var(--green); color: var(--bg); border: 0; }
.badge-running { background: var(--red); color: var(--on-accent); border: 0; animation: none; }
.badge-billing { background: var(--amber); color: var(--bg); border: 0; }
.badge-booked { background: var(--gold); color: var(--bg); border: 0; }
.badge-maintenance { background: var(--neutral-solid); color: var(--on-accent); border: 0; }

/* Money and clock carry the weight on a card — they are what staff read. */
.bill { font-size: 20px; font-weight: 600; letter-spacing: -0.02em; }
.timer { font-size: 17px; letter-spacing: 0.02em; }
.table-num { letter-spacing: 1px; }
.table-card { transition: border-color 0.15s; }

/* ---- table photo ---- */
/* A fixed 5:3 box with object-fit: cover, so a replacement photo of any aspect
   drops in without breaking the card grid — it fills and crops instead. */
.table-photo { position: relative; aspect-ratio: 5 / 3; border-radius: 2px; overflow: hidden; }
.table-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.table-photo.tp-maintenance img { filter: grayscale(0.85) brightness(0.45); }
.table-photo.tp-booked img { filter: brightness(0.75); }
.table-photo .tp-mark { position: absolute; inset: 0; width: 100%; height: 100%; }
.table-photo .tp-badge {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-size: 22px; letter-spacing: 3px;
  color: var(--gold); text-shadow: 0 1px 4px rgba(0,0,0,.85);
}
/* A live table gets a slow breath rather than a static frame, so a glance across
   the floor separates "running" from "ready" without reading the badge. */
.table-photo.tp-running::after {
  content: ''; position: absolute; inset: 0; border-radius: 2px; box-shadow: inset 0 0 0 2px var(--red);
}
@media (prefers-reduced-motion: reduce) {
  .table-photo.tp-running::after { animation: none; }
}
/* Ambient reinforcement only — the authoritative status is the text badge on
   each card, so these rings stay deliberately soft in BOTH themes rather than
   ringing every card in heavy colour. */
.card-running { border-color: var(--red); }
.card-free { border-color: var(--border); }
.card-booked { border-color: var(--gold); }
.card-maintenance { filter: saturate(0.3); }

.session-info { display: flex; flex-direction: column; gap: 4px; }
.players { font-size: 12px; color: var(--text); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.timer-row { display: flex; justify-content: space-between; align-items: center; }
.timer { font-family: var(--font-mono); font-size: 16px; color: var(--red); font-weight: 500; }
.bill { font-family: var(--font-mono); font-size: 16px; color: var(--green); font-weight: 500; }
.rate-tag { font-size: 10px; color: var(--muted); }
.booked-info { font-size: 12px; color: var(--gold); }
.booked-time { font-size: 11px; color: var(--muted); }
.maintenance-info { font-size: 11px; color: var(--muted); }

.card-actions { display: flex; gap: 5px; flex-wrap: wrap; margin-top: auto; }
/* Floor actions are the buttons staff hit all shift, often in a hurry and
   sometimes on a touch screen, so they get a real target rather than the
   compact sizing used for table rows and filters elsewhere. Scoped to
   .card-actions on purpose — .btn is shared with the khata and filter rows,
   which should stay compact.
   Every button in the row shares a min-height so a big primary action next to
   a small icon button doesn't leave the row looking broken. */
.card-actions .btn { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
/* Sized to stay on ONE row even in the narrower snooker column — a primary
   button that grabs the spare width pushes the icon button onto a second line
   and costs a card's worth of height across the floor. */
.card-actions .btn-start,
.card-actions .btn-end,
.card-actions .btn-book,
.card-actions .btn-maint {
  font-size: 14px; letter-spacing: 0.4px; padding: 12px 11px; border-radius: 2px; flex: 0 1 auto;
}
/* Secondary actions keep their place but don't compete for width. */
.card-actions .btn-manage { font-size: 12px; padding: 10px 9px; border-radius: 2px; flex: 0 1 auto; }
.btn { font-size: 11px; font-weight: 600; letter-spacing: 0.5px; padding: 6px 11px; border-radius: 2px; border: none; cursor: pointer; transition: all 0.15s; }
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
.btn-start { background: var(--green-20); color: var(--green); border: 1px solid var(--green-44); }
.btn-start:hover:not(:disabled) { background: var(--green); color: var(--bg); }
.btn-end { background: var(--red-20); color: var(--red); border: 1px solid var(--red-44); }
.btn-end:hover:not(:disabled) { background: var(--red-solid); color: var(--on-accent); }
.btn-book { background: var(--gold-20); color: var(--gold); border: 1px solid var(--gold-44); }
.btn-book:hover:not(:disabled) { background: var(--gold); color: var(--bg); }
.btn-manage { background: var(--neutral-20); color: var(--neutral-text-2); border: 1px solid var(--neutral-44); }
.btn-manage:hover:not(:disabled) { background: var(--neutral-solid); color: var(--on-accent); }
.btn-maint { background: var(--amber-20); color: var(--amber); border: 1px solid var(--amber-44); }
.btn-maint:hover:not(:disabled) { background: var(--amber); color: var(--bg); }

/* ============ TABLE TYPE / LAYOUT ============ */
/* The floor stacks by default and only splits into side-by-side clusters when
   there is real room for it (see the 1600px block). Stacked, both clusters span
   the same width, so every card on the floor comes out an identical width at any
   viewport — no fixed card size, no dead strip down the right. */
/* The floor is a MAP of the room: --cols is how many table positions wide it
   is, and each card is placed at its own grid_row / grid_col by dashboard.js.
   An empty cell in the middle is meaningful — it means there is no table there. */
.floor { display: grid; grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
         gap: 12px; align-items: start; }
.floor-col { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.floor-col-title { font-size: 10px; color: var(--muted); letter-spacing: 1.5px; text-transform: uppercase; }
/* auto-FIT, not auto-fill: auto-fill keeps the empty tracks it reserved, so a
   cluster of three cards on a 1300px floor sat in five 248px tracks with two
   tracks' worth of nothing after it. auto-fit collapses the empties and hands
   the room to the real cards.
   The ceiling has to go on the container rather than the track: a definite max
   in minmax() is what auto-fit counts repetitions with, so minmax(240px, 360px)
   fitted 1024px for one 360px column instead of two 350px ones. Capping the
   cluster at what --n cards can occupy keeps the count coming off the 240px
   min. If --n is ever missing the calc is simply invalid and no cap applies. */
.floor-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 12px;
  max-width: calc(var(--n) * 372px - 12px);
}
.floor-cards > .empty-note { grid-column: 1 / -1; }
.type-tag { font-size: 9px; letter-spacing: 1px; text-transform: uppercase; padding: 2px 7px; border-radius: 2px; border: 1px solid var(--border); color: var(--muted); }
.type-tag.snooker { color: var(--type-snooker); border-color: var(--type-snooker-bd); }
.type-tag.mini_pool { color: var(--type-pool); border-color: var(--type-pool-bd); }
.type-tag.pool { color: var(--type-pool); border-color: var(--type-pool-bd); }

/* player management rows */
.player-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--row-border); }
.player-row:last-child { border-bottom: none; }
.player-row.dim { opacity: var(--dim-opacity); }
.player-main { display: flex; align-items: center; gap: 10px; min-width: 0; }
.player-name { font-size: 13px; font-weight: 500; color: var(--text); }
.player-sub { font-size: 10px; color: var(--muted); font-family: var(--font-mono); }
.pcount { font-size: 10px; color: var(--muted); }

/* ============ SIDEBAR ============ */
.sidebar { background: var(--sidebar-bg); border-left: 1px solid var(--border); padding: 14px; display: flex; flex-direction: column; gap: 16px; overflow-y: auto; }
.sidebar-section { display: flex; flex-direction: column; gap: 8px; }
.sidebar-title { font-size: 10px; color: var(--muted); letter-spacing: 1.5px; text-transform: uppercase; display: flex; align-items: center; gap: 6px; }
.sidebar-title span.ic { font-size: 14px; }
.sidebar-title .mini-add { margin-left: auto; font-size: 11px; padding: 2px 8px; }
.wait-item { display: flex; align-items: center; justify-content: space-between; background: var(--card); border: 1px solid var(--border); border-radius: 2px; padding: 8px 10px; gap: 8px; }
.wait-name { font-size: 12px; font-weight: 500; color: var(--text); }
.wait-sub { font-size: 10px; color: var(--muted); }
.wait-time { font-size: 10px; color: var(--amber); font-family: var(--font-mono); white-space: nowrap; }
.wait-actions { display: flex; gap: 4px; }
.icon-btn { background: transparent; border: none; color: var(--muted); cursor: pointer; font-size: 13px; padding: 2px 4px; border-radius: 2px; }
.icon-btn:hover { color: var(--text); background: var(--hover-tint); }
.booking-item { background: var(--card); border: 1px solid var(--gold-22); border-radius: 2px; padding: 8px 10px; cursor: pointer; }
.booking-item:hover { border-color: var(--gold-55); }
.booking-name { font-size: 12px; font-weight: 500; color: var(--gold); }
.booking-detail { font-size: 10px; color: var(--muted); margin-top: 2px; }
.booking-countdown { font-size: 10px; font-family: var(--font-mono); color: var(--amber); margin-top: 2px; }
.action-item { display: flex; flex-direction: column; gap: 2px; padding: 6px 0; border-bottom: 1px solid var(--row-border); }
.action-item:last-child { border-bottom: none; }
.action-text { font-size: 11px; color: var(--text); }
.action-time { font-size: 10px; color: var(--muted); font-family: var(--font-mono); }
.empty-note { font-size: 11px; color: var(--muted); font-style: italic; padding: 4px 0; }

/* ============ BOTTOM BAR ============ */
.bottom-bar { background: var(--card); border-top: 1px solid var(--border); padding: 10px 20px; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; gap: 10px; flex-wrap: wrap; }
.stat-group { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; }
.stat-item { display: flex; flex-direction: column; align-items: center; }
.stat-label { font-size: 9px; color: var(--muted); letter-spacing: 1px; text-transform: uppercase; }
.stat-val { font-family: var(--font-mono); font-size: 14px; font-weight: 500; }
.stat-green { color: var(--green); }
.stat-gold { color: var(--gold); }
.stat-red { color: var(--red); }
.stat-amber { color: var(--amber); }
.stat-divider { width: 1px; height: 30px; background: var(--border); }
.conn-note { font-size: 10px; color: var(--muted); }

/* ============ MODALS ============ */
.modal-overlay { position: fixed; inset: 0; background: var(--overlay); backdrop-filter: blur(4px); z-index: 100; display: flex; align-items: center; justify-content: center; padding: 16px; overflow-y: auto; }
.modal-box { background: var(--card); border: 1px solid var(--border); border-radius: 2px; width: 100%; max-width: 560px; padding: 24px; animation: slide-up 0.25s ease; max-height: 92vh; overflow-y: auto; }
.modal-box.wide { max-width: 680px; }
@keyframes slide-up { from { transform: translateY(24px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.modal-title { font-family: var(--font-display); font-size: 24px; color: var(--text); letter-spacing: 2px; margin-bottom: 16px; }
.modal-sub { font-size: 11px; color: var(--muted); margin-bottom: 8px; letter-spacing: 0.5px; text-transform: uppercase; }
.modal-row { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 14px; }
.modal-player-chip { display: flex; align-items: center; gap: 6px; background: var(--card-alt); border: 1px solid var(--green-33); border-radius: 2px; padding: 4px 10px; }
.chip-ball { width: 22px; height: 22px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: var(--on-accent); flex-shrink: 0; text-shadow: 0 0 2px rgba(0,0,0,.85), 0 1px 1px rgba(0,0,0,.6); }
.chip-name { font-size: 12px; color: var(--text); }
.chip-remove { font-size: 14px; color: var(--muted); cursor: pointer; margin-left: 2px; background: none; border: none; }
.chip-remove:hover { color: var(--red); }
.session-type-row { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
.type-pill { padding: 7px 14px; border-radius: 2px; font-size: 12px; font-weight: 500; cursor: pointer; border: 1px solid var(--border); color: var(--muted); background: transparent; transition: all 0.15s; }
.type-pill.active { background: var(--green-15); color: var(--green); border-color: var(--green-44); }
.type-pill.gold.active { background: var(--gold-15); color: var(--gold); border-color: var(--gold-44); }
.type-rate { font-size: 11px; color: var(--muted); margin-bottom: 14px; }
.btn-break { width: 100%; padding: 14px; font-family: var(--font-display); font-size: 20px; letter-spacing: 3px; background: var(--green); color: var(--bg); border: none; border-radius: 2px; cursor: pointer; transition: all 0.15s; }
.btn-break:hover:not(:disabled) { filter: brightness(1.08); }
.btn-break:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-break.red { background: var(--red-solid); color: var(--on-accent); }
.btn-break.red:hover:not(:disabled) { }
.modal-cancel { display: block; text-align: center; margin-top: 12px; color: var(--muted); font-size: 12px; cursor: pointer; background: none; border: none; width: 100%; }
.modal-cancel:hover { color: var(--text); }
.modal-input { width: 100%; background: var(--bg); border: 1px solid var(--border-strong); border-radius: 2px; padding: 10px 12px; font-size: 13px; color: var(--text); margin-bottom: 10px; outline: none; }
.modal-input:focus { border-color: var(--green); outline: 2px solid var(--green); outline-offset: 1px; }
.modal-input.mono { font-family: var(--font-mono); }
select.modal-input { appearance: none; }
.field-label { font-size: 10px; color: var(--muted); letter-spacing: 1px; text-transform: uppercase; margin-bottom: 4px; display: block; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
.suggest-box { position: relative; }
.suggest-list { position: absolute; top: 100%; left: 0; right: 0; background: var(--card-alt); border: 1px solid var(--border); border-radius: 2px; z-index: 20; overflow: hidden; margin-top: -8px; }
.suggest-item { padding: 8px 12px; font-size: 12px; cursor: pointer; display: flex; justify-content: space-between; gap: 8px; }
.suggest-item:hover { background: var(--green-15); }
.suggest-item .ph { color: var(--muted); font-family: var(--font-mono); font-size: 11px; }

/* ============ BILLING MODAL ============ */
.bill-summary { background: var(--bg); border: 1px solid var(--border); border-radius: 2px; padding: 14px; margin-bottom: 14px; }
.bill-line { display: flex; justify-content: space-between; align-items: center; padding: 4px 0; font-size: 13px; color: var(--muted); }
.bill-line .v { font-family: var(--font-mono); color: var(--text); }
.bill-total-row { display: flex; justify-content: space-between; align-items: baseline; border-top: 1px solid var(--border); margin-top: 8px; padding-top: 10px; }
.bill-total-label { font-size: 12px; letter-spacing: 1px; color: var(--muted); text-transform: uppercase; }
.bill-total { font-family: var(--font-display); font-size: 40px; color: var(--green); letter-spacing: 1px; line-height: 1; }
.pay-split { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 6px; }
.pay-cell { background: var(--bg); border: 1px solid var(--border); border-radius: 2px; padding: 10px; text-align: center; }
.pay-cell label { font-size: 10px; letter-spacing: 1px; text-transform: uppercase; display: block; margin-bottom: 6px; }
.pay-cell.cash label { color: var(--green); }
.pay-cell.upi label { color: var(--gold); }
.pay-cell.udhar label { color: var(--amber); }
.pay-cell input { width: 100%; background: transparent; border: none; outline: none; color: var(--text); font-family: var(--font-mono); font-size: 20px; text-align: center; }
.quick-row { display: flex; gap: 6px; margin: 8px 0 14px; flex-wrap: wrap; }
.remaining { font-size: 12px; font-family: var(--font-mono); text-align: right; margin-bottom: 10px; }
.remaining.ok { color: var(--green); }
.remaining.err { color: var(--red); }
/* Explanatory line under a field (e.g. what an udhar limit means) */
.field-hint { font-size: 11px; color: var(--muted); line-height: 1.45; margin: -4px 0 10px; }

/* Consent checkbox on the new-customer form. Deliberately a full-width row with
   a real tap target: it records a customer agreeing to be messaged, and a
   mis-tap here means messaging somebody who never asked. */
.optin-row { display: flex; align-items: flex-start; gap: 10px; margin-top: 12px; padding: 10px 12px;
  background: var(--card-alt); border: 1px solid var(--border); border-radius: 2px;
  font-size: 12px; color: var(--text); cursor: pointer; min-height: 40px; }
.optin-row input { width: 18px; height: 18px; margin-top: 1px; flex-shrink: 0; accent-color: var(--green); }
.optin-row .field-hint { display: inline; }.split-link { background: none; border: none; color: var(--gold); font-size: 12px; cursor: pointer; padding: 6px 0; display: inline-block; }
.split-link:hover { color: var(--amber); text-decoration: underline; }
.udhar-row { display: flex; align-items: flex-start; gap: 8px; padding: 8px; border: 1px solid var(--border); border-radius: 2px; margin-bottom: 8px; background: var(--bg); }
.udhar-row .udhar-row-amt { flex-shrink: 0; }

/* ============ KHATA ============ */
.summary-cards { display: flex; gap: 12px; flex-wrap: wrap; }
.summary-card { border-radius: 2px; padding: 12px 20px; flex: 1; min-width: 160px; border: 1px solid var(--border); background: var(--card); }
.summary-card.red { background: var(--red-15); border-color: var(--red-33); }
.summary-card.green { background: var(--green-15); border-color: var(--green-33); }
.summary-card .lbl { font-size: 10px; letter-spacing: 1px; text-transform: uppercase; }
.summary-card.red .lbl { color: var(--red); }
.summary-card.green .lbl { color: var(--green); }
.summary-card .val { font-family: var(--font-display); font-size: 32px; }
.summary-card.red .val { color: var(--red); }
.summary-card.green .val { color: var(--green); }
.filter-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.data-table-wrap { background: var(--card); border: 1px solid var(--border); border-radius: 2px; overflow-x: auto; }
.data-table { width: 100%; border-collapse: collapse; font-size: 12px; min-width: 560px; }
.data-table thead tr { border-bottom: 1px solid var(--border); background: var(--card-alt); }
.data-table th { padding: 10px 14px; text-align: left; color: var(--muted); font-weight: 500; letter-spacing: 0.5px; }
.data-table th.r { text-align: right; }
.data-table th.c { text-align: center; }
.data-table td { padding: 10px 14px; }
.data-table tbody tr { border-bottom: 1px solid var(--row-border); cursor: pointer; }
.data-table tbody tr:hover { background: var(--card-alt); }
.avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--card-alt); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; font-size: 11px; color: var(--green); font-weight: 600; flex-shrink: 0; }
.cust-cell { display: flex; align-items: center; gap: 8px; }
.cust-name { font-size: 13px; font-weight: 500; color: var(--text); }
.amount-big { font-family: var(--font-display); font-size: 18px; }
.khata-entry { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--row-border); gap: 10px; }
.khata-entry:last-child { border-bottom: none; }
.entry-note { font-size: 12px; color: var(--text); }
.entry-date { font-size: 10px; color: var(--muted); font-family: var(--font-mono); }
.entry-amt { font-family: var(--font-mono); font-size: 13px; white-space: nowrap; }
.entry-amt.debit { color: var(--amber); }
.entry-amt.credit { color: var(--green); }
.outstanding-banner { display: flex; justify-content: space-between; align-items: center; background: var(--bg); border: 1px solid var(--border); border-radius: 2px; padding: 12px 16px; margin-bottom: 14px; }

/* ============ ACCOUNTS ============ */
.acc-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; }
.acc-card { background: var(--card); border: 1px solid var(--border); border-radius: 2px; padding: 12px; text-align: center; }
.acc-card.hl { background: var(--card-alt); border-color: var(--green-33); }
.acc-card .lbl { font-size: 10px; color: var(--muted); letter-spacing: 0.5px; margin-bottom: 6px; }
.acc-card .val { font-family: var(--font-display); font-size: 26px; }
.panel { background: var(--card); border: 1px solid var(--border); border-radius: 2px; padding: 14px; }
.panel-title { font-size: 11px; color: var(--muted); letter-spacing: 1px; text-transform: uppercase; margin-bottom: 10px; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.split-line { display: flex; justify-content: space-between; align-items: center; padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 12px; }
.split-line:last-child { border-bottom: none; }
.split-line .k { color: var(--muted); }
.split-line .v { font-family: var(--font-mono); font-size: 14px; }
.chart-bars { display: flex; align-items: flex-end; gap: 8px; height: 130px; padding: 0 4px; overflow-x: auto; }
.chart-col { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 1; min-width: 34px; height: 100%; justify-content: flex-end; }
.chart-stack { width: 100%; max-width: 44px; display: flex; flex-direction: column-reverse; border-radius: 2px; overflow: hidden; }
.chart-val { font-family: var(--font-mono); font-size: 10px; color: var(--muted); }
.chart-lbl { font-size: 10px; color: var(--muted); white-space: nowrap; }
.legend-row { display: flex; gap: 16px; margin-top: 8px; flex-wrap: wrap; }
.legend-row span { font-size: 10px; }
.exp-row { display: flex; justify-content: space-between; align-items: center; padding: 5px 0; border-bottom: 1px solid var(--row-border); gap: 8px; }
.exp-row .lbl { font-size: 12px; color: var(--text); }
.exp-row .amt { font-family: var(--font-mono); font-size: 13px; color: var(--red); white-space: nowrap; }
.add-inline { display: flex; gap: 8px; margin-top: 10px; }
.add-inline input { margin-bottom: 0; }

/* ============ SETTINGS ============ */
.settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
.list-row { display: flex; justify-content: space-between; align-items: center; padding: 8px 0; border-bottom: 1px solid var(--row-border); gap: 10px; }
.list-row:last-child { border-bottom: none; }
.list-row .nm { font-size: 13px; font-weight: 500; }
.list-row .meta { font-size: 10px; color: var(--muted); }
.role-chip { font-size: 9px; letter-spacing: 1px; text-transform: uppercase; padding: 2px 8px; border-radius: 2px; border: 1px solid var(--border); color: var(--muted); }
.role-chip.owner { color: var(--gold); border-color: var(--gold-44); }
.inactive-chip { color: var(--red); border-color: var(--red-44); }

/* ============ LOGIN ============ */
.login-wrap { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 26px; padding: 24px; position: relative; z-index: 1; }
.login-logo { display: flex; flex-direction: column; align-items: center; gap: 10px; }
/* On the login and owner screens the full name gets to breathe: it wraps
   instead of truncating, and scales down on a phone. */
.login-logo .wordmark, .owner-head .wordmark { font-size: clamp(24px, 6vw, 42px); letter-spacing: 3px; white-space: normal; overflow: visible; text-align: center; line-height: 1.05; max-width: 12ch; margin-inline: auto; }
.login-logo .tagline { font-size: 11px; letter-spacing: 1px; }
.user-grid { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
.user-card { background: var(--card); border: 1px solid var(--border); border-radius: 2px; padding: 18px 26px; display: flex; flex-direction: column; align-items: center; gap: 8px; cursor: pointer; transition: all 0.15s; min-width: 130px; }
.user-card:hover { border-color: var(--green-55); }
.user-card.active { border-color: var(--green); border-width: 2px; background: var(--green-15); }
.user-card .avatar { width: 44px; height: 44px; font-size: 17px; }
.user-card .nm { font-size: 14px; font-weight: 500; }
.pin-area { display: flex; flex-direction: column; align-items: center; gap: 16px; }
.pin-dots { display: flex; gap: 12px; height: 16px; }
.pin-dot { width: 12px; height: 12px; border-radius: 50%; border: 1px solid var(--muted); }
.pin-dot.on { background: var(--green); border-color: var(--green); }
.pin-pad { display: grid; grid-template-columns: repeat(3, 74px); gap: 10px; }
.pin-key { height: 62px; border-radius: 2px; background: var(--card); border: 1px solid var(--border-strong); color: var(--text); font-size: 22px; font-family: var(--font-mono); cursor: pointer; transition: all 0.1s; }
.pin-key:hover { border-color: var(--green-55); }
.pin-key:active { background: var(--green-22); }
.pin-key.fn { font-size: 15px; color: var(--muted); }
.pin-key.go { background: var(--green-20); color: var(--green); border-color: var(--green-44); }
.shake { animation: shake 0.35s; }
@keyframes shake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-8px); } 75% { transform: translateX(8px); } }
.login-err { color: var(--red); font-size: 12px; min-height: 16px; }

/* ============ TOAST ============ */
#toast-root { position: fixed; top: 70px; right: 20px; z-index: 300; display: flex; flex-direction: column; gap: 8px; }
.toast { background: var(--card-alt); border: 1px solid var(--green-44); border-radius: 2px; padding: 12px 16px; color: var(--text); font-size: 13px; animation: slide-in-right 0.3s ease; max-width: 320px; }
.toast.err { border-color: var(--red-66); }
.toast .t-title { font-size: 12px; font-weight: 600; color: var(--green); margin-bottom: 2px; }
.toast.err .t-title { color: var(--red); }
@keyframes slide-in-right { from { transform: translateX(120%); } to { transform: translateX(0); } }

/* ============ RESPONSIVE ============ */
@media (max-width: 980px) {
  .main-layout { grid-template-columns: 1fr; }
  .sidebar { border-left: none; border-top: 1px solid var(--border); }
  .topbar-center { display: none; }
  .two-col, .settings-grid, .form-grid { grid-template-columns: 1fr; }
  .pay-split { grid-template-columns: 1fr; }
  .tagline { display: none; }
  /* ...but the login and owner screens have room for it, and it's the only
     place the venue's strapline appears on a phone. */
  .login-logo .tagline { display: block; }
}
/* On a phone the topbar cannot fit the venue name, the signed-in staff member
   and three controls. The name wins: who is logged in is already established at
   the PIN pad, and the venue name is the thing staff glance at to confirm they
   are on the right till. */
@media (max-width: 560px) {
  .staff-info { display: none; }
  .topbar { padding: 0 12px; gap: 8px; }
  .topbar-right { gap: 8px; }
}

/* ============ MOBILE ============ */
/* The venue laptop is the primary screen, but the owner works from a phone, so
   every screen has to hold together at 360px — not just avoid a scrollbar.
   Grid and flex children default to min-width:auto, which means they refuse to
   shrink below their content and silently overflow; the body's overflow-x:hidden
   then CLIPS that overflow rather than revealing it. Hence min-width:0 here
   rather than a wider breakpoint. */
.main-layout > *, .floor > *, .floor-col > *, .two-col > *, .settings-grid > *,
.form-grid > *, .acc-cards > *, .summary-cards > * { min-width: 0; }

/* Pool beside Snooker is a floor plan, and a floor plan needs width. The
   previous rule pinned every card to a fixed 272px from 901px upward, so a wide
   monitor got a fixed-width island with a dead strip beside it, and the two
   clusters flipped between side-by-side and stacked purely on whether their
   content happened to fit — which is why the same build looked different on
   different screens.

   Side by side is now earned rather than attempted: it needs room for all five
   cards on one line at a readable width (5 x 240 + gaps + the 280px sidebar),
   which is 1600px. Above that each cluster claims width in proportion to how
   many tables it holds (--n, set in dashboard.js), so the cards come out the
   same width across both clusters and the row ends flush with the page. Below
   it the clusters stack and the base auto-fit rule fills the width instead. */
/* Was 1600px, which meant a 1366x768 laptop — the machine this actually runs on
   — stacked the two clusters and pushed Snooker below the fold. Staff then had
   to scroll to see half the floor, which defeats the point of a floor view.
   1280px covers every real laptop; below that the stacked grid still applies. */
/* Below this the room map stops being readable — three columns on a phone gives
   cards too narrow to press. Fall back to a single column in floor order, which
   still reads top-left to bottom-right like the room does. */
@media (max-width: 860px) {
  .floor { grid-template-columns: 1fr; }
  .floor > .table-card { grid-row: auto !important; grid-column: auto !important; }
}

@media (max-width: 760px) {
  .screen-page, .tables-area { padding: 12px; gap: 10px; }

  /* Tables: drop the desktop floor and let each one scroll inside its own box
     rather than pushing the page sideways. */
  .data-table { min-width: 0; font-size: 12px; }
  .data-table th, .data-table td { padding: 9px 8px; }
  .data-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

  /* The khata list keeps what a phone actually needs — who, how much, how much
     more they may take, and the actions. Phone number and last-entry date are
     available by opening the customer. */
  .khata-table th:nth-child(2), .khata-table td:nth-child(2),
  .khata-table th:nth-child(5), .khata-table td:nth-child(5) { display: none; }

  /* Summary figures read as a stack, not a squeezed row. */
  .summary-cards { flex-direction: column; }
  .summary-card { min-width: 0; padding: 10px 14px; }
  .summary-card .val { font-size: 26px; }

  /* Modals become sheets: full width, less inset, room for the keyboard. */
  .modal-overlay { padding: 0; align-items: flex-end; }
  .modal-box, .modal-box.wide { max-width: 100%; padding: 18px 16px 24px; max-height: 92vh; }
  .modal-title { font-size: 21px; }
  .pay-split { grid-template-columns: 1fr; gap: 8px; }
  .pay-cell { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; }
  .pay-cell label { margin-bottom: 0; }
  .pay-cell input { width: 45%; text-align: right; font-size: 18px; }

  /* The PIN pad was a fixed 3x74px grid — it now scales to the handset. */
  /* .pin-area centres its children, so a percentage width here collapses to
     content — which with minmax(0,1fr) tracks means almost nothing. An explicit
     width sizes the pad regardless of how the parent aligns it. */
  .pin-pad { grid-template-columns: repeat(3, 1fr); width: min(300px, 86vw); gap: 8px; }
  .pin-key { height: 58px; font-size: 20px; }
  .user-grid { width: 100%; }
  .user-card { flex: 1 1 132px; padding: 14px 16px; }

  /* Anything tappable clears a real target, including the icon-only ones and
     the two rows that get hit most on a phone: the screen tabs and the
     day/week/month switch. */
  .icon-btn, .chip-remove { min-width: 40px; min-height: 40px; }
  .btn { min-height: 40px; }
  .filter-row .btn, .quick-row .btn { min-height: 40px; }
  .screen-tab { min-height: 42px; padding: 10px 14px; font-size: 13px; }
  .type-pill { min-height: 40px; padding: 9px 16px; font-size: 13px; }
  .screen-tabs { padding: 6px 10px 0; gap: 4px; }

  /* Footer figures wrap instead of scrolling off. */
  .bottom-bar { padding: 10px 12px; }
  .stat-group { gap: 14px; width: 100%; justify-content: space-between; }
  .stat-divider { display: none; }
  .conn-note { width: 100%; text-align: center; }

  .page-title { font-size: 23px; }

  /* Ledger rows: the note can be long ("Session on Mini Pool · session #104"),
     which was pushing the amount and the send control off the right edge. Let
     the note take the space it can and wrap, and keep the figure and action
     together on the right where the eye expects them. */
  .khata-entry { flex-wrap: wrap; row-gap: 4px; }
  .khata-entry > :first-child { flex: 1 1 100%; min-width: 0; }
  .khata-entry > :last-child { flex: 1 1 100%; display: flex; align-items: center;
    justify-content: space-between; gap: 10px; }
  .entry-note { white-space: normal; word-break: break-word; }
  .outstanding-banner { flex-direction: column; align-items: flex-start; gap: 8px; }
}

@media (max-width: 440px) {
  /* The four screen tabs measured 402px against a 375px handset, so Settings sat
     off-screen behind a scroll nobody can see is there. Tightening the padding
     brings the whole row inside the viewport; .screen-tabs keeps its overflow-x
     as the fallback for a longer tab set. */
  .screen-tabs { gap: 2px; padding: 6px 8px 0; }
  .screen-tab { padding: 10px 9px; }

  /* Smallest handsets: drop the Actions column rather than the credit limit.
     The whole row already opens the customer, where View and Receive both live,
     so Actions was the redundant one — the limit is not. */
  .khata-table th:nth-child(6), .khata-table td:nth-child(6) { display: none; }
  .screen-page, .tables-area { padding: 10px; }
  /* Make it obvious the row itself is the control. */
  .data-table tbody tr { cursor: pointer; -webkit-tap-highlight-color: transparent; }
  .data-table tbody tr:active { background: var(--card-alt); }
}

/* ============ SHORT SCREENS (768px-tall laptops) ============ */
/* Width was only half the problem. At 768px tall, once the topbar, tabs and
   footer are taken out there is ~560px for cards, and a full-size card with a
   5:3 photo is ~300px — so a second row never fits. These rules shrink the
   photo and the padding rather than the information: every card still shows
   name, status, rate, timer and its buttons. */
@media (max-height: 820px) {
  /* A FIXED height, not an aspect ratio. With the room laid out as a 3-wide map
     the cards are ~350px across, and any aspect ratio makes the photo grow with
     them — two rows then run past the bottom of a 768px screen. Pinning the
     height decouples card width from card height, which is what has to happen
     for the whole floor to fit. object-fit: cover already crops cleanly. */
  .table-photo { aspect-ratio: auto; height: 104px; }
  .table-card { padding: 10px; gap: 7px; }
  .table-num { font-size: 30px; }
  .card-actions .btn { padding: 7px 10px; font-size: 12px; }
  .tables-area { padding: 10px; gap: 8px; }
  .section-header { margin-bottom: 0; }
  .floor { gap: 10px 24px; }
  .floor-cards { gap: 10px; }
  .topbar { height: 54px; }
  .clock { font-size: 22px; }
}

/* Really short (e.g. 1366x600 windowed): the photo is the first thing to go.
   A pool table photo is decoration; the status block and the meter are not. */
@media (max-height: 640px) {
  .table-photo { display: none; }
}
