/* site/app/screens/bookings.css — Tickets.
 * Depends on tokens.css + ui.css + shell.css. Loaded after them.
 *
 * The whole screen is one contrast: a live ticket is an object you hold up, a used one is a
 * receipt in a pile. Nothing here is styled to sit between those two sizes, because the
 * moment they read as the same card at different scales the screen stops answering the only
 * question a player has when they open it — "what do I need in the next hour?"
 *
 * ⚠ No hex codes in this file. Every colour is a token, so all of it follows the app into
 *   dark mode; a raw hex would be a light-mode ticket floating on a navy page at 9pm.
 */

/* ── Section furniture ─────────────────────────────────────────────────────
 * shell.css styles `.sec-head button` in the action colour. The count on the right is a
 * SPAN, not a button, and deliberately: orange is the one thing you are meant to press, and
 * on this screen that is "Manage the session". A second orange thing would make both weaker.
 */
.tkts .sec-count{
  font: 500 12px/1 var(--font-ui); letter-spacing: .01em;
  color: var(--ink-tertiary); font-variant-numeric: tabular-nums;
}

/* ── The live ticket ───────────────────────────────────────────────────────
 * Navy ground, cream ink — DESIGN.md's identity surface, and the highest-contrast pair the
 * brand owns. That matters here more than anywhere: this is read at arm's length, outdoors,
 * by someone who is not looking at their own phone.
 */
.tkts .tkt{
  --tkt-ground: var(--navy);
  --tkt-ink: var(--cream);
  --tkt-dim: color-mix(in srgb, var(--cream) 62%, transparent);
  --tkt-hair: color-mix(in srgb, var(--cream) 22%, transparent);

  position: relative; overflow: hidden;
  margin: 0 16px 18px; padding: 20px 18px 18px;
  border-radius: var(--r-xl);
  background: var(--tkt-ground); color: var(--tkt-ink);
  box-shadow: var(--shadow-2);
}

/* At night the page ground is already navy, so a navy ticket would vanish into it. Lift the
   ticket one step and give it a hairline instead of relying on a shadow nobody can see. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .tkts .tkt{
    --tkt-ground: var(--navy-90);
    border: 1px solid var(--tkt-hair);
  }
}
:root[data-theme="dark"] .tkts .tkt{
  --tkt-ground: var(--navy-90);
  border: 1px solid var(--tkt-hair);
}

.tkts .tkt-top{
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 12px;
}
.tkts .tkt-kind{
  font: 600 11px/1 var(--font-ui); letter-spacing: .09em; text-transform: uppercase;
  color: var(--tkt-dim);
}
/* The default .tag from shell.css is a cream chip on a cream page; on navy it disappears. */
.tkts .tkt .tag:not(.live){
  background: color-mix(in srgb, var(--cream) 14%, transparent);
  color: var(--tkt-ink);
}

.tkts .tkt-title{
  font-family: var(--font-display); font-weight: 600;
  font-size: 26px; line-height: 1.1; letter-spacing: -.018em;
  color: var(--tkt-ink); margin: 0;
}
.tkts .tkt-sub{
  margin: 4px 0 0; font: 400 13px/1.4 var(--font-ui); color: var(--tkt-dim);
}

/* ── The code plate ───────────────────────────────────────────────────────
 * Always a light plate, in both themes, because the canvas inside it is always drawn dark on
 * light. A scanner reads contrast, not taste.
 *
 * ⚠ THE QUIET ZONE IS NOW INSIDE THE CANVAS, NOT THIS PADDING. bookings.js draws four clear
 *   modules on every side of the code, because a margin that lives in CSS is a margin that a
 *   crop, a screenshot or the next person restyling this plate can take away — and a QR with
 *   no quiet zone is one a scanner may never lock on to. The padding here is now only the
 *   visual inset of the plate; the code is legal without it.
 * ⚠ --tkt-code-size MIRRORS QR_SIZE IN bookings.js. Change one, change the other. The cap
 *   matters on a narrow phone: without it a 231px canvas plus padding overflows a 320px
 *   screen's card, and the code is clipped rather than shrunk. */
.tkts .tkt-plate{
  --tkt-code-size: 231px;
  margin: 18px auto 10px;
  width: 100%; max-width: calc(var(--tkt-code-size) + 20px); padding: 10px;
  background: var(--cream); border-radius: var(--r-md);
}
/* height:auto with no inline height (see drawCode) so a shrunk code stays square. A stretched
   code is not a code. */
/* ⚠ aspect-ratio, NOT AN INLINE HEIGHT. A <canvas> with no width/height attributes set yet
   reports the HTML default 300×150, so between the node being appended and drawCode running in
   the next frame the plate would flash a 2:1 rectangle — and if drawing ever failed it would
   stay one. Squared here, so the plate is the right shape before a single module is painted. */
.tkts .tkt-canvas{
  display: block; margin-inline: auto;
  width: var(--tkt-code-size); max-width: 100%; height: auto; aspect-ratio: 1 / 1;
}

.tkts .tkt-code{
  text-align: center;
  font: 500 12px/1 var(--font-mono); letter-spacing: .12em;
  color: var(--tkt-dim); font-variant-numeric: tabular-nums;
}

/* ── Holder ────────────────────────────────────────────────────────────────
 * Second-largest thing on the ticket after the code. The door check is a person reading this
 * name and looking at a face; DESIGN.md §7 makes that the entire defence against a forwarded
 * screenshot, so it does not get shrunk to make room for anything.
 */
.tkts .tkt-holder{ text-align: center; margin-top: 16px; }
.tkts .tkt-name{
  font-family: var(--font-display); font-weight: 600;
  font-size: 27px; line-height: 1.1; letter-spacing: -.02em; color: var(--tkt-ink);
}
.tkts .tkt-handle{
  margin-top: 3px; font: 500 14px/1 var(--font-ui); color: var(--tkt-dim);
}

/* ── The perforation ──────────────────────────────────────────────────────
 * A dashed rule with a bite taken out of both edges. The bites are circles in the PAGE
 * colour, half outside the card, clipped by the card's own overflow — so they follow the
 * theme for free and never need a second colour of their own.
 */
.tkts .tkt-perf{
  position: relative; height: 0;
  margin: 18px -18px;
  border-top: 1.5px dashed var(--tkt-hair);
}
.tkts .tkt-perf::before, .tkts .tkt-perf::after{
  content: ""; position: absolute; top: 0;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--bg); transform: translateY(-50%);
}
.tkts .tkt-perf::before{ left: -11px; }
.tkts .tkt-perf::after{ right: -11px; }

/* ── The stub ─────────────────────────────────────────────────────────────── */
.tkts .tkt-facts{
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px;
  margin: 0;
}
.tkts .tkt-facts .fact{ min-width: 0; }
.tkts .tkt-facts dt{
  font: 600 10px/1 var(--font-ui); letter-spacing: .08em; text-transform: uppercase;
  color: var(--tkt-dim);
}
.tkts .tkt-facts dd{
  margin: 5px 0 0; font: 500 15px/1.25 var(--font-ui); letter-spacing: -.006em;
  color: var(--tkt-ink); font-variant-numeric: tabular-nums;
}

.tkts .tkt-with{
  margin: 14px 0 0; font: 400 13px/1.45 var(--font-ui); color: var(--tkt-dim);
}

/* ── The one action on this screen ────────────────────────────────────────── */
.tkts .tkt-score{ margin-top: 18px; }

.tkts .soon{
  display: block; margin-top: 10px; padding: 14px;
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--cream) 10%, transparent);
  border: 1px solid var(--tkt-hair);
  opacity: 1; transform: translateY(0);
  transition: opacity var(--t-menu) var(--ease-out), transform var(--t-menu) var(--ease-out);
}
@starting-style{ .tkts .soon{ opacity: 0; transform: translateY(-4px); } }
/* `hidden` loses to the display above unless it is said again. */
.tkts .soon[hidden]{ display: none; }
/* ⚠ NO `.soon p` RULE ANY MORE. The panel used to carry a paragraph explaining what the
   scorekeeper will do and which question about it is still open — the app narrating its own
   roadmap, struck out with the rest of that voice on 2026-09-03. The panel is now one
   state line, so a rule for a paragraph that cannot exist would be a trap for the next
   person who adds one and wonders why it is styled. */
.tkts .soon b{
  display: block; font: 600 14px/1.3 var(--font-ui); letter-spacing: -.006em;
  color: var(--tkt-ink);
}

/* ── The door note ────────────────────────────────────────────────────────── */
.tkts .tkt-note{ margin: 2px 20px 0; }
.tkts .tkt-note p{
  margin: 0; font: 400 13px/1.5 var(--font-ui); color: var(--ink-tertiary);
}

/* ── The pile ─────────────────────────────────────────────────────────────
 * Absolutely-positioned cards inside a container whose height JS sets. The transform on each
 * card belongs to a spring — nothing in CSS may transition transform here, or the two would
 * fight and the loser would be visible as a stutter every frame.
 */
.tkts .pile{ margin: 0 16px; }

.tkts .pile-stack{
  position: relative;
  /* Scaling shrinks each card from its top edge, so the ones behind peek out below. Scaling
     from the centre would pull their bottom edges UP and the stack would look like one card
     with a shadow. */
  transform-origin: top center;
}

.tkts .pcard{
  position: absolute; top: 0; left: 0; right: 0;
  transform-origin: top center;
  will-change: transform, opacity;
  background: var(--bg-raised); border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}

.tkts .pcard-face{
  display: block; width: 100%; text-align: left;
  border: 0; background: transparent; cursor: pointer;
  padding: 14px 16px; color: inherit;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out);
}
.tkts .pcard-head{
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.tkts .pcard-title{
  font: 600 15px/1.25 var(--font-ui); letter-spacing: -.008em; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tkts .pcard-meta{
  display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px;
  font: 400 13px/1.35 var(--font-ui); color: var(--ink-tertiary);
  font-variant-numeric: tabular-nums;
}
.tkts .pcard-dot{ opacity: .5; }

@media (hover: hover) and (pointer: fine){
  .tkts .pile.is-open .pcard-face:hover{ background: var(--bg-sunken); }
}

/* The tap target for the collapsed stack. One control, over the whole pile. */
.tkts .pile-hit{
  position: absolute; inset: 0; z-index: 50;
  border: 0; background: transparent; cursor: pointer; padding: 0;
  /* ⚠ inset:0 MEANS THIS CONTROL IS AS SHORT AS THE PILE, AND THE COLLAPSED PILE IS 42px.
     It looked exempt from the 44px floor because it has no painted box of its own — but it
     is the only way to open the stack, and an invisible target is measured by the thumb like
     any other. It grows downward into the 12px gap above .pile-hint, so nothing is covered. */
  min-height: var(--tap-min);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.tkts .pile-hit[hidden]{ display: none; }

.tkts .pile-hint{
  margin: 12px 0 0; text-align: center;
  font: 500 12px/1 var(--font-ui); letter-spacing: .01em; color: var(--ink-tertiary);
}
.tkts .pile-hint[hidden]{ display: none; }

.tkts .pile-less{
  display: block; width: 100%; margin-top: 12px;
  border: 0; background: transparent; cursor: pointer;
  min-height: var(--tap-min);
  font: 600 13px/1 var(--font-ui); letter-spacing: -.004em; color: var(--ink-tertiary);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out);
}
.tkts .pile-less[hidden]{ display: none; }

/* ── The receipt ──────────────────────────────────────────────────────────
 * Appears instantly, then the cards below spring down around it. The alternative — animating
 * the card's own height — is the one thing the house rules forbid outright, and it would also
 * make every measurement below it wrong for the length of the animation.
 */
.tkts .pcard-receipt{ display: none; padding: 0 16px 16px; }
.tkts .pcard.is-open .pcard-receipt{ display: block; }

.tkts .receipt-stamp{
  display: inline-block;
  font: 700 11px/1 var(--font-ui); letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-tertiary);
  border: 1.5px solid var(--rule); border-radius: var(--r-sm);
  padding: 6px 10px; transform: rotate(-3deg); transform-origin: left center;
  margin-bottom: 12px;
}

.tkts .receipt-scan{
  margin: 0 0 12px; font: 500 13px/1.45 var(--font-ui); color: var(--ink-secondary);
  font-variant-numeric: tabular-nums;
}

.tkts .receipt-facts{
  margin: 0; padding-top: 12px; border-top: 1px solid var(--rule);
  display: grid; gap: 9px;
}
.tkts .receipt-facts .rfact{
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
}
.tkts .receipt-facts dt{
  flex: none; font: 600 11px/1.3 var(--font-ui); letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-tertiary);
}
.tkts .receipt-facts dd{
  margin: 0; text-align: right; min-width: 0;
  font: 400 13px/1.4 var(--font-ui); color: var(--ink);
  font-variant-numeric: tabular-nums; overflow-wrap: anywhere;
}

/* ── Empty state ──────────────────────────────────────────────────────────── */
.tkts .tkt-empty{ text-align: left; padding: 22px 20px 20px; }
.tkts .tkt-empty-title{
  font-family: var(--font-display); font-weight: 600;
  font-size: 21px; line-height: 1.15; letter-spacing: -.014em;
  color: var(--ink); margin-bottom: 8px;
}
.tkts .tkt-empty p{ margin: 0 0 10px; text-align: left; }
.tkts .tkt-empty-go{ margin-top: 8px; }

/* ── Prototype control ────────────────────────────────────────────────────
 * Not part of the product. It exists so Syd can see the first-run state without an empty
 * account, and it goes when the mock data goes.
 */
/* 32px tall before the min-height: under the 44px floor even for scaffolding. */
.tkts .demo-toggle{
  display: block; margin: 26px auto 0;
  border: 1px dashed var(--rule); background: transparent; cursor: pointer;
  border-radius: var(--r-full); padding: 10px 16px; min-height: var(--tap-min);
  font: 500 12px/1 var(--font-ui); color: var(--ink-tertiary);
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
  transition: transform var(--t-press) var(--ease-out);
}

/* ── Reduced motion, transparency, contrast ───────────────────────────────
 * Naming this file's own animations, per DESIGN.md §4.8. The pile's springs already collapse
 * to a jump inside motion.js when reduce is set — spring().to() checks the query at call time
 * — so what is left here is the press feedback and the receipt's entrance.
 */
@media (prefers-reduced-motion: reduce){
  .tkts .pcard-face, .tkts .pile-less, .tkts .demo-toggle{ transition-property: background-color; }
  .tkts .soon{ transition-property: opacity; transform: none; }
  @starting-style{ .tkts .soon{ opacity: 0; transform: none; } }
  .tkts .receipt-stamp{ transform: none; }
}

@media (prefers-contrast: more){
  .tkts .tkt{ --tkt-dim: var(--tkt-ink); --tkt-hair: var(--tkt-ink); }
  .tkts .pcard{ border: 1px solid var(--rule); }
  .tkts .receipt-stamp{ border-color: var(--ink); color: var(--ink); }
}

/* ⚠⚠ THE TICKET FOR THE SESSION HAPPENING NOW. Syd, 2026-09-03: "when you are scanned into
   your session, your ticket for that BOOKING should be highlighted / floating."
   Every ticket in this list is paid and valid; exactly one of them is the thing you are
   standing inside, and drawing all of them identically makes you read four dates to find it.
   ⚠ LIFTED AND EDGED, NOT TINTED. A tint on a card that is already a pale plate on a pale
     ground is worth about two shades and disappears in sunlight. A shadow and a coloured edge
     read as depth, which is a difference the eye finds without looking for it — and the
     chartreuse edge is the same "this is happening now" this app uses everywhere else.
   ⚠ NO ANIMATION ON THE LIFT. "Floating" is a resting state, not a loop: a card that pulses
     in a list is the one thing you cannot then read. DESIGN.md §4.1 — anything seen on every
     visit gets its animation removed. */
.tkts .tkt.is-live {
  border-color: color-mix(in srgb, var(--live) 62%, transparent);
  box-shadow: var(--shadow-3), 0 0 0 3px color-mix(in srgb, var(--live) 20%, transparent);
  transform: translateY(-2px);
}
@media (prefers-contrast: more) {
  .tkts .tkt.is-live { border-color: var(--ink); box-shadow: none; }
}
