/* ============================================================================
   JSOOR Gaming · THE SHELL, and the layout vocabulary every surface shares
   ----------------------------------------------------------------------------
   Layout and motion ONLY. Colour, type, radius, elevation and every easing
   curve are the design system's tokens; none is redefined here, because a
   second definition of a token is a second implementation of one fact.

   MOTION, decided before it was written, in this order:
     1. Should it animate at all?  Frequency decides. The launcher is a command
        palette opened by Ctrl+T dozens of times a night, and tab switching is a
        keystroke — so neither animates, ever. An action repeated a hundred times
        must happen at the speed of the key.
     2. What is it for?  An overlay appearing is feedback that the question
        changed; a pressed control descending is feedback that the press landed.
        Nothing here animates because it looks nice.
     3. Which curve?  Entering and exiting: the system's --ease-out, never
        ease-in, which starts slow at the exact moment the eye is watching.
     4. How long?  Presses 120ms, popovers 150ms, overlays 200ms. Nothing over
        300ms. Exits are faster than entrances.
   Only transform and opacity move. Hover is gated to real pointers, because a
   touch screen fires hover on tap and leaves it stuck.
   ========================================================================= */

html, body { block-size: 100%; overflow: hidden; }
body { margin: 0; background: var(--ground); color: var(--ink); font-family: var(--font-sans);
       font-variant-numeric: tabular-nums; -webkit-font-smoothing: antialiased; }
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
h1, h2, h3, p { margin: 0; }

/* ── press feedback, for everything pressable ─────────────────────────────── */
.js-btn, .tab, .lrow, .jg-tile {
  transition: transform var(--dur-press) var(--ease-out);
}
.js-btn:active:not([disabled]), .lrow:active:not([disabled]) { transform: scale(0.97); }
.tab:active { transform: scale(0.98); }

/* ══ THE WINDOW BAR ═══════════════════════════════════════════════════════════
   One strip, two jobs: the window's own controls AND the tab strip. Not a header
   with tabs bolted underneath — that costs a second row on the one screen that
   cannot spare any, and puts a border between a tab and the thing it names. */
.wbar { position: fixed; inset-block-start: 0; inset-inline: 0; block-size: var(--bar-h, 56px);
        display: flex; align-items: stretch; gap: 12px; padding-inline: 14px;
        background: var(--card); border-block-end: 1px solid var(--border); z-index: 500; }
.wbar-mark { display: inline-flex; align-items: center; gap: 10px; flex: none;
             padding-inline-end: 8px; color: var(--ink); }
.wbar-mark b { display: block; font-size: .9rem; font-weight: 600; letter-spacing: .12em; line-height: 1; }
.wbar-mark small { display: block; margin-block-start: 3px; font-size: .5rem; font-weight: 600;
                   letter-spacing: .22em; color: var(--accent-fg); text-transform: uppercase; }

/* Tabs COMPRESS, never scroll. A tab that has scrolled off the strip is a tab
   the operator has forgotten they hold, and the strip exists so they can see it. */
.tabs { display: flex; align-items: stretch; gap: 2px; flex: 1; min-inline-size: 0; overflow: hidden; }
.tab { position: relative; display: inline-flex; align-items: center; gap: 8px;
       min-inline-size: 74px; max-inline-size: 240px; padding-inline: 12px 8px;
       border: 0; border-radius: 0; background: transparent; color: var(--muted);
       font: 500 var(--t-meta)/1 var(--font-sans); white-space: nowrap; cursor: pointer; }
.tab .lbl, .tab .who { overflow: hidden; text-overflow: ellipsis; }
.tab .who { color: var(--faint); font-weight: 400; }
.tab .who::before { content: "· "; }
.tab.cur { color: var(--ink); font-weight: 600; min-inline-size: 136px; }
/* The crown: a rail under the active tab. It reads from two metres away, which
   is the distance an operator actually stands from the screen. */
.tab.cur::after { content: ""; position: absolute; inset-inline: 10px; inset-block-end: 0;
                  block-size: 2.5px; border-radius: 2px 2px 0 0; background: var(--accent); }
.tab .x { display: grid; place-items: center; flex: none; inline-size: 20px; block-size: 20px;
          border-radius: var(--r-xs); color: var(--faint); font-size: 14px; line-height: 1; }
@media (hover: hover) and (pointer: fine) {
  .tab:hover { color: var(--ink); }
  .tab .x:hover { background: var(--sunken); color: var(--ink); }
}
/* UNSAVED IS A DOT BESIDE THE ×, NEVER INSTEAD OF IT. See shell.js. */
.dot--dirty { flex: none; inline-size: 7px; block-size: 7px; border-radius: 50%; background: var(--warn-dot); }

.wbar-lent, .wbar-right { display: inline-flex; align-items: center; gap: 10px; flex: none; }
.bar-chip { block-size: 28px; }
/* + Start never shrinks. It is the only door to new work. */
.start-key { flex: none; align-self: center; }
.wbar-clock { font-family: var(--font-mono); font-size: var(--t-meta); color: var(--muted); }
.wbar-user { display: inline-flex; align-items: center; gap: 9px; }
.wbar-user .av { display: grid; place-items: center; inline-size: 32px; block-size: 32px; border-radius: 50%;
                 background: var(--primary); color: var(--primary-fg); font-size: var(--t-micro); font-weight: 600; }
.wbar-user b { display: block; font-size: var(--t-meta); font-weight: 600; line-height: 1.2; }
.wbar-user span { font-size: var(--t-micro); color: var(--muted); }

/* ══ THE SURFACE, and the vocabulary every surface shares ════════════════════ */
.surface { position: absolute; inset: var(--bar-h, 56px) 0 0 0; display: flex; flex-direction: column;
           gap: 12px; padding: 16px; overflow: hidden; }

.eyebrow { display: block; font-family: var(--font-mono); font-size: var(--t-micro);
           letter-spacing: .08em; text-transform: uppercase; color: var(--faint); }

/* A till is a strip of labelled figures with the actions at its end. The front
   desk uses it for the shift and a sell tab for the ticket — one shape, because
   it is one kind of fact: what this surface is about, at a glance. */
.till { display: flex; align-items: center; gap: 24px; flex: none; padding: 12px 16px;
        border: 1px solid var(--hairline); border-radius: var(--r-md); background: var(--raised); }
.till-cell { display: flex; flex-direction: column; gap: 4px; min-inline-size: 0; }
.till-who { font-size: var(--t-meta); font-weight: 600; color: var(--ink); }
.till-fig { font-family: var(--font-display); font-size: 1.4rem; font-weight: 800; line-height: 1;
            letter-spacing: -.01em; color: var(--ink); }
.till-warn { font-size: var(--t-meta); color: var(--warn-fg); }
.till-acts { display: flex; gap: 8px; margin-inline-start: auto; }

.stage { flex: 1; min-block-size: 0; display: grid; gap: 12px; grid-template-columns: minmax(0, 1fr) 340px; }
.rail { display: flex; flex-direction: column; gap: 12px; min-block-size: 0; }
.panel { display: flex; flex-direction: column; gap: 8px; min-block-size: 0; padding: 16px;
         border: 1px solid var(--hairline); border-radius: var(--r-md); background: var(--raised); }
.panel--grow { flex: 1; }
.panel-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.panel-head h3 { font-size: var(--t-body); font-weight: 600; }
.panel-head .count { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--faint); }
.panel-scroll { min-block-size: 0; overflow-y: auto; margin-inline: -16px; padding-inline: 16px; overscroll-behavior: contain; }
.panel-cta { margin-block-start: 8px; inline-size: 100%; }

.kv { display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
      padding-block: 9px; border-block-end: 1px solid var(--hairline); font-size: var(--t-meta); }
.kv:last-of-type { border-block-end: 0; }
.kv span { color: var(--muted); }
.kv em { font-style: normal; color: var(--faint); }
.kv b { font-family: var(--font-mono); font-weight: 500; color: var(--ink); }
.kv--total span { color: var(--ink); font-weight: 600; }
.kv--total b { font-size: var(--t-body); font-weight: 600; }

.empty-note { padding: 20px; text-align: center; font-size: var(--t-meta); color: var(--muted); }
.empty-state { margin: auto; max-inline-size: 440px; display: grid; gap: 10px; justify-items: center; text-align: center; }
.empty-state h2 { font-size: var(--t-h3); font-weight: 600; }
.empty-state p { font-size: var(--t-meta); line-height: 1.55; color: var(--muted); }
.hint { margin-block-start: 12px; font-size: var(--t-meta); line-height: 1.5; color: var(--muted); }
.field-gap { margin-block-start: 12px; }

/* ══ OVERLAYS, LAUNCHER, GATE ════════════════════════════════════════════════ */
/* THE SCRIM STOPS AT THE CHROME: it begins below the bar, so an overlay can
   never take away the strip that says which tab the operator is on. */
.scrim { position: fixed; inset: var(--bar-h, 56px) 0 0 0; z-index: 700; display: none;
         background: oklch(0 0 0 / .45); }
.scrim.on { display: block; }

.launcher, .ov { position: fixed; inset-block-start: calc(var(--bar-h, 56px) + 40px); inset-inline: 0;
                 margin-inline: auto; z-index: 710; display: none; flex-direction: column; overflow: hidden;
                 max-block-size: calc(100vh - var(--bar-h, 56px) - 72px);
                 border: 1px solid var(--border-strong); border-radius: var(--r-md);
                 background: var(--card); box-shadow: var(--sh-3); }
.launcher { inline-size: min(680px, calc(100vw - 32px)); }
.ov { inline-size: min(460px, calc(100vw - 32px)); }
.launcher.on, .ov.on { display: flex; }

/* The overlay is occasional, so it gets a standard entrance: from 97% and
   transparent, never from nothing — nothing in the world appears from zero.
   Centred origin, because a modal is not anchored to a trigger. The LAUNCHER has
   no entrance at all: it is a command palette, opened from the keyboard. */
.ov.on { transition: opacity var(--dur-pop) var(--ease-out), transform var(--dur-pop) var(--ease-out); }
@starting-style { .ov.on { opacity: 0; transform: scale(0.97); } }

.launcher-head, .ov-head { padding: 18px 18px 12px; border-block-end: 1px solid var(--hairline); }
.launcher-head h2, .ov-head h2 { font-size: var(--t-h3); font-weight: 600; }
.launcher-head p, .ov-head p { margin-block-start: 4px; font-size: var(--t-meta); color: var(--muted); }
.ov-head { border-block-end: 0; }
.launcher-body { overflow-y: auto; padding: 12px 18px 18px; overscroll-behavior: contain; }
.ov-body { padding: 0 18px 18px; }
.ov-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 18px; border-block-start: 1px solid var(--hairline); }
.launcher-foot { padding: 10px 18px; border-block-start: 1px solid var(--hairline);
                 font-family: var(--font-mono); font-size: var(--t-micro); letter-spacing: .06em; color: var(--faint); }

.lgroup + .lgroup { margin-block-start: 16px; }
.lgroup > .eyebrow { margin-block-end: 8px; }
.lgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.lrow { display: flex; align-items: center; gap: 12px; inline-size: 100%; margin-block-end: 6px; padding: 11px 13px;
        border: 1px solid var(--hairline); border-radius: var(--r-sm); background: var(--raised);
        color: var(--ink); font-family: inherit; text-align: start; cursor: pointer; }
.lgrid .lrow { margin-block-end: 0; }
.lrow[disabled] { opacity: .5; cursor: not-allowed; }
.lrow-main { display: flex; flex-direction: column; gap: 3px; min-inline-size: 0; }
.lrow-main b { font-size: var(--t-body); font-weight: 600; }
.lrow-main span { font-size: var(--t-meta); color: var(--muted); }
.lrow-side { margin-inline-start: auto; flex: none; font-family: var(--font-mono); font-size: var(--t-micro); color: var(--faint); }
.lrow-side--money { font-family: var(--font-display); font-size: 1rem; font-weight: 700; color: var(--warn-fg); }
@media (hover: hover) and (pointer: fine) {
  .lrow:hover:not([disabled]) { border-color: var(--border-strong); }
}
.lrow:focus-visible, .tab:focus-visible, .js-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The close confirm hangs off the tab it protects. Origin-aware: it grows from
   the top-left corner nearest its tab, because a popover comes from its trigger. */
.gate { position: fixed; z-index: 760; display: none; inline-size: 300px; padding: 16px;
        border: 1px solid var(--warn-bd); border-radius: var(--r-sm); background: var(--card); box-shadow: var(--sh-3);
        transform-origin: top left; }
.gate.on { display: block; transition: opacity 150ms var(--ease-out), transform 150ms var(--ease-out); }
@starting-style { .gate.on { opacity: 0; transform: scale(0.96); } }
.gate p { margin-block-end: 12px; font-size: var(--t-meta); line-height: 1.5; color: var(--ink-2); }
.gate b { color: var(--ink); }
.gate .acts { display: flex; gap: 8px; }
.gate-discard { border-color: var(--bad-bd); color: var(--bad-fg); }

/* ══ REDUCED MOTION ══════════════════════════════════════════════════════════
   Fewer and gentler, not none: opacity still says what changed. Movement goes. */
@media (prefers-reduced-motion: reduce) {
  .js-btn, .tab, .lrow, .jg-tile, .ov.on, .gate.on { transition-property: opacity; }
  .js-btn:active, .lrow:active, .tab:active { transform: none; }
  @starting-style { .ov.on, .gate.on { transform: none; } }
}
