/* ============================================================================
   JSOOR Gaming — VERTICAL UI LAYER
   Prefix: jg-   ·   Requires the family layer (ui/jsoor-tech-ui.css) and
   the vertical brand (brand/jsoor-gaming.css).

   This file holds ONLY what the family layer has no equivalent for. Buttons,
   chips, cards, fields, dialogs, toasts, tabs, pagers and the empty state all
   come from js- and are not restyled here. A wrapper that adds a style is a bug;
   so is a vertical component that duplicates a family one.

   Every component here satisfies the family's K1-K5 contract, and adds the
   vertical's own two rules:
     G-A  the accent is never a chip and never behind a button. It is the focus
          ring, the spill, and the glow on a tile that is live.
     G-B  normal is silent. A healthy agent wears no marking at all.
   ========================================================================= */

.jg-scope { --jg-tile-min: 104px; }

/* ── PRESS · the vertical descends instead of scaling ─────────────────────────
   --press is already translateY(2px) from the brand file, so js- components pick
   it up for free. These two rules add the rest of the gesture: the surface dims
   because it is further from the light, and its shadow tightens. Nothing changes
   colour, so a press never looks like a state change. */
.jg-scope .js-btn:active:not(:disabled),
.jg-scope .js-tile:active,
.jg-scope .jg-tile:active:not(.is-dead) {
  box-shadow: 0 1px 3px oklch(0 0 0 / .45), var(--refl-1);
  filter: brightness(0.88);
}

/* ── THE NUMBER · the first of two gestures ───────────────────────────────────
   Zain 900, as large as the surface allows, with nothing on it. No card, no rule,
   no ornament — the size is the gesture. If a number can be made bigger by
   removing something, remove it. */
.jg-num {
  font-family: var(--font-display);
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  line-height: 0.82;
  letter-spacing: -0.02em;
  color: var(--ink);
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.jg-num--xl { font-size: clamp(3rem, 6vw, 4.5rem); }
.jg-num--lg { font-size: 2.5rem; }
.jg-num--md { font-size: 2rem; }
.jg-num .u {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--faint);
  text-transform: uppercase;
}
/* A machine that cannot be seated dims its number so the eye skips it. */
.jg-num--dim { color: var(--muted); }

/* ── THE SPILL · the second gesture ───────────────────────────────────────────
   The light a screen throws on the wall behind it. An ellipse, closest-side,
   accent at 30% to transparent, 8px blur. Permitted in exactly three places:
   behind the wordmark, behind the selected record, and as the live-tile glow
   below. Never behind a button, a panel, or a healthy-but-idle tile. */
.jg-spill {
  position: absolute;
  inline-size: 300px;
  block-size: 120px;
  border-radius: 50%;
  background: radial-gradient(closest-side,
    color-mix(in oklab, var(--accent) 30%, transparent), transparent);
  filter: blur(8px);
  pointer-events: none;
  z-index: 0;
}
.jg-spill--sm { inline-size: 190px; block-size: 100px; }

/* ── THE TILE · the atom of the Floor ─────────────────────────────────────────
   Two truths that can disagree, and the whole design is keeping them separable.
     OCCUPANCY — what the business thinks is happening — fills the tile and owns
                 the clock. Carried by the family's state tones.
     AGENT     — what the hardware last reported — draws the frame.
   So a lit tile in a dashed frame reads exactly right: someone is playing, and we
   cannot see the machine. */
.jg-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-block-size: var(--jg-tile-min);
  padding: 11px 12px 0;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--raised);
  box-shadow: var(--sh-2), var(--refl-3);
  color: var(--ink);
  text-align: start;
  font-family: inherit;
  cursor: pointer;
  overflow: hidden;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              filter var(--dur-press) var(--ease-out), transform var(--dur-press) var(--ease-out);
}
.jg-tile:active:not(.is-dead) { transform: var(--press); }
@media (hover: hover) and (pointer: fine) {
  .jg-tile:hover:not(.is-dead) { border-color: var(--border-strong); }
}

.jg-tile-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-2); min-inline-size: 0;
}
.jg-tile-name {
  font-family: var(--font-mono); font-size: 0.75rem; font-weight: 500;
  color: var(--ink-2); white-space: nowrap;
}
.jg-tile-kind {
  font-family: var(--font-mono); font-size: 0.625rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--faint); white-space: nowrap;
}
.jg-tile-sub {
  font-size: var(--t-meta); color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  min-block-size: 1.05rem;
}
/* The state bar sits flush at the bottom edge — the one place a tone appears
   without a word beside it, because the word is already in the tile. */
.jg-tile-bar {
  margin-block-start: auto; margin-inline: -12px; block-size: 3px;
  background: var(--neutral-dot);
}

/* Occupancy — the fill and the clock. Family tones, no new hues. */
.jg-tile.is-running .jg-num { color: var(--info-fg); }
.jg-tile.is-running .jg-tile-bar { background: var(--info-dot); }
.jg-tile.is-ending  .jg-num { color: var(--warn-fg); }
.jg-tile.is-ending  .jg-tile-bar { background: var(--warn-dot); }
.jg-tile.is-ending  { border-color: var(--warn-bd); }
.jg-tile.is-held    .jg-num { color: var(--frozen-fg); }
.jg-tile.is-held    .jg-tile-bar { background: var(--frozen-dot); }
.jg-tile.is-free    .jg-num { color: var(--muted); font-weight: 800; }
.jg-tile.is-free    .jg-tile-bar { background: var(--neutral-dot); }
.jg-tile.is-broken  .jg-num { color: var(--bad-fg); }
.jg-tile.is-broken  .jg-tile-bar { background: var(--bad-dot); }
.jg-tile.is-broken  { border-color: var(--bad-bd); }

/* THE LIVE GLOW — the third and last permitted place for the accent.
   A machine in use is lit from within and the room around it is not. Only a tile
   that is actually running glows; a healthy idle tile does not. */
.jg-tile.is-live { box-shadow: var(--sh-2), var(--refl-3), inset 0 0 26px color-mix(in oklab, var(--accent) 12%, transparent); }

/* Agent health — the frame. An independent axis, encoded differently on purpose:
   occupancy colours the content, the agent axis draws the frame. */
.jg-tile.agent-off { border-color: var(--warn-bd); }
.jg-tile.agent-off::before {           /* the corner rule — agent was seen, now gone */
  content: ""; position: absolute; inset-block-start: -1px; inset-inline-start: -1px;
  inline-size: 16px; block-size: 16px;
  border-block-start: 2px solid var(--warn-dot);
  border-inline-start: 2px solid var(--warn-dot);
  border-start-start-radius: var(--r-sm);
}
.jg-tile.agent-unknown {               /* never reported — claims nothing about hardware */
  border-style: dashed; border-color: var(--border);
  box-shadow: none; background: var(--card);
}
.jg-tile.agent-unknown .jg-num,
.jg-tile.agent-unknown .jg-tile-name { opacity: 0.62; }
.jg-tile.is-dead { cursor: default; }

/* The agent foot — present only when the agent is not healthy. Normal is silent. */
.jg-tile-foot {
  margin-block-start: 2px; padding-block: 5px; margin-inline: -12px; padding-inline: 12px;
  border-block-start: 1px solid var(--hairline);
  font-family: var(--font-mono); font-size: 0.625rem; letter-spacing: 0.04em;
  color: var(--muted);
}
.jg-tile-foot--warn { color: var(--warn-fg); }
.jg-tile.agent-unknown .jg-tile-foot { border-block-start-style: dashed; }

/* ── THE ROOM · a container that holds devices ────────────────────────────────
   A room is not a bookable unit; it groups the floor. A customer is seated at a
   device, and the room is where that device sits. */
.jg-room {
  display: flex; flex-direction: column; gap: var(--s-2); min-inline-size: 0;
  padding: var(--s-3); border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--plate); box-shadow: var(--refl-1);
}
.jg-room-head {
  display: flex; align-items: baseline; gap: var(--s-2);
  min-block-size: 20px;
}
.jg-room-head h3 {
  margin: 0; font-size: var(--t-h3); font-weight: 600; color: var(--ink);
  letter-spacing: -0.01em; white-space: nowrap;
}
.jg-room-head .meta {
  font-family: var(--font-mono); font-size: 0.625rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--faint); white-space: nowrap;
}
.jg-room-head .rule { flex: 1; block-size: 1px; background: var(--hairline); }
.jg-grid {
  display: grid; gap: var(--s-2); min-block-size: 0;
  grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
}

/* ── THE QUEUE · a line, not a table ──────────────────────────────────────────
   A single hairline runs down the rail and each party hangs off it as a node, so
   it reads as people standing in an order, which is what it is. */
.jg-queue { position: relative; display: flex; flex-direction: column; gap: var(--s-2); padding-inline-start: 18px; }
.jg-queue::before {
  content: ""; position: absolute; inset-block: 6px 14px; inset-inline-start: 5px;
  inline-size: 1px; background: var(--border);
}
.jg-party { position: relative; display: flex; align-items: baseline; gap: var(--s-2); min-block-size: 28px; }
.jg-party::before {
  content: ""; position: absolute; inset-inline-start: -17px; inset-block-start: 6px;
  inline-size: 9px; block-size: 9px; border-radius: 50%;
  background: var(--card); border: 1.5px solid var(--border-strong);
}
.jg-party.is-next::before { background: var(--accent); border-color: var(--accent); }
.jg-party.is-called::before { background: transparent; border-color: var(--warn-dot); }
.jg-party b { font-size: var(--t-body-lg); font-weight: 600; color: var(--ink); }
.jg-party span { font-size: var(--t-meta); color: var(--muted); }
.jg-party .w { margin-inline-start: auto; font-family: var(--font-mono); font-size: 0.625rem; color: var(--faint); }
.jg-party .w.is-long { color: var(--warn-fg); }
.jg-queue-end {
  font-family: var(--font-mono); font-size: 0.625rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--faint); padding-block-start: 2px;
}

/* ── MONEY · never live, always as-of ─────────────────────────────────────────
   The accent is never on a money figure. Money is paper-toned, tabular, and it
   names its ledger and its as-of time — the family's law 6. */
.jg-money { font-variant-numeric: tabular-nums; color: var(--ink); font-weight: 600; }
.jg-asof {
  font-family: var(--font-mono); font-size: 0.625rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--faint);
}

/* ── MOTION · five things move, and the list is closed ────────────────────────
   A value updating is not a change of state: a clock going 108 to 107 does
   nothing. A clock crossing ten minutes, where the tile becomes a different
   object, animates once. Nothing loops, ever. */
@media (prefers-reduced-motion: no-preference) {
  .jg-arrive { animation: jg-settle var(--dur-arrive) var(--ease) both; }
  .jg-cross  { animation: jg-cross var(--dur-cross) var(--ease-out) 1; }
}
@keyframes jg-settle { from { transform: translateY(-6px); opacity: 0 } to { transform: none; opacity: 1 } }
@keyframes jg-cross {
  0%, 100% { box-shadow: var(--sh-2), var(--refl-3), 0 0 0 0 transparent; }
  22% { box-shadow: var(--sh-2), var(--refl-3), 0 0 22px 3px color-mix(in oklab, var(--warn-dot) 50%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .jg-scope * { animation: none !important; }
  .jg-tile:active { transform: none !important; filter: none !important; }
}

/* ── SHELL · one accent per vertical, so there is no accent picker ────────────
   The family shell offers Voltage and Circuit Gold because JSOOR Tech ships two.
   This vertical ships one, so the two dots and their separator come out and the
   theme control is a light/dark toggle only. The ground switch stays, because
   the ground is a ruled choice here, not a decoration. */
.jshell-theme .tdot,
.jshell-theme .tsep { display: none; }

/* ── MONEY ON A TILE · the cafe exception, stated rather than smuggled ────────
   A cafe table is not billed by time, so its number cannot answer "minutes until
   this needs me". It carries the open order instead, with EGP as its unit so it
   can never be misread as minutes — and it stays paper-toned, because money is
   not live. The state tone still rides the bar at the bottom edge. */
.jg-tile.is-running .jg-num--money,
.jg-tile.is-ending .jg-num--money { color: var(--ink); }

/* ── THE PEEK · press a chip, get five facts, go nowhere ──────────────────────
   The hardest density in the product and the first surface drawn, because every
   other one inherits its decisions about which five facts matter.

   Fixed width. Exactly five fact rows — a sixth is a record pane asking to be
   opened. One row may be big. One action, which opens a sheet over the host
   rather than navigating, because nothing on this card is a link and that is what
   stops a counter losing a half-built order to a stray click.

   Two reconciliations with the vertical's own laws, both deliberate:
     · the lead figure takes its STATE tone, never the accent — the accent is not
       a state here. A live peek gets the spill behind it instead, which is the
       third of the accent's three permitted places.
     · the action is --primary (near-white on this ground), never accent-filled.
       The accent is never behind a button. */
.jg-peek {
  position: relative; overflow: hidden;
  inline-size: 320px; max-inline-size: 100%;
  display: flex; flex-direction: column;
  background: var(--sheet);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-card);
  box-shadow: var(--sh-3), var(--refl-4);
}
.jg-peek > * { position: relative; }

.jg-peek-head {
  display: flex; align-items: flex-start; gap: var(--s-2);
  padding: 14px 16px 10px;
}
.jg-peek-head .id { min-inline-size: 0; flex: 1; }
.jg-peek-head b {
  display: block; font-size: var(--t-h2); font-weight: 600; color: var(--ink);
  letter-spacing: -.015em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.jg-peek-head span {
  display: block; font-size: var(--t-meta); color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* A live dot only when something is actually live. Normal is silent. */
.jg-peek-live {
  inline-size: 7px; block-size: 7px; border-radius: 50%; flex: none;
  margin-block-start: 7px; background: var(--info-dot);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--info-dot) 22%, transparent);
}

/* ── the five facts ── */
.jg-facts { display: flex; flex-direction: column; padding: 0 16px; }
.jg-fact {
  display: flex; align-items: baseline; gap: var(--s-3);
  min-block-size: 30px; padding-block: 5px;
  border-block-start: 1px solid var(--hairline);
}
.jg-fact:first-child { border-block-start: 0; }
.jg-fact > .k {
  font-size: var(--t-meta); color: var(--muted); white-space: nowrap;
}
.jg-fact > .v {
  margin-inline-start: auto; text-align: end; min-inline-size: 0;
  font-size: var(--t-body-lg); color: var(--ink); font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.jg-fact > .v.is-quiet { color: var(--muted); }
/* One row is allowed to be big. On a resource or a visit that is the clock. */
.jg-fact--lead { min-block-size: 52px; align-items: center; }
.jg-fact--lead > .v { font-family: var(--font-display); font-weight: 900; font-size: 2rem; line-height: .9; letter-spacing: -.02em; }

/* SCOPED, NOT BROKEN. A withheld row keeps its position and its label and names
   who can see it. A scoped total with nothing said about it reads as the truth,
   and that is the difference between a scoped view and a broken one. */
.jg-fact.is-withheld > .k { color: var(--faint); }
.jg-fact.is-withheld > .v { margin-inline-start: auto; }
.jg-scope-note {
  margin: 10px 16px 0; padding: 8px 10px;
  background: var(--warn-bg); border: 1px solid var(--warn-bd); border-radius: var(--r-sm);
  font-size: var(--t-meta); color: var(--warn-fg); line-height: var(--lh-snug);
}

/* ── the foot: which ledger, and as of when. Never absent on a money figure. ── */
.jg-peek-foot {
  margin: 12px 16px 0; padding-block-start: 9px;
  border-block-start: 1px solid var(--hairline);
}

/* ── one action, and the reason when it cannot fire ── */
.jg-peek-act { padding: 12px 16px 16px; display: flex; flex-direction: column; gap: 7px; }
.jg-peek-act .js-btn { inline-size: 100%; }
.jg-why {
  font-size: var(--t-meta); color: var(--warn-fg); line-height: var(--lh-snug);
}
.jg-why--quiet { color: var(--muted); }
