/* ==========================================================================
   Learnæway — mobile-first PWA, 9:16 vertical
   Palette: bg #050614 · card #070A18 · cyan #3DDFFF · magenta #FF3D9A
            teal #2FE6C2 · gradient mid #7B5FC0
   ========================================================================== */

:root {
  --bg: #050614;
  --card: #070A18;
  --cyan: #3DDFFF;
  --magenta: #FF3D9A;
  --teal: #2FE6C2;
  --grad-mid: #7B5FC0;
  --text: #EAF6FF;
  --fs: 1;              /* text-size multiplier (settings) */
  --radius-card: 30px;
  --radius-pill: 22px;
  /* iOS safe areas, resolved once. The fallbacks matter: a bare env() with no
     fallback invalidates the whole declaration on anything that doesn't
     support it, so every inset in this file goes through these two. */
  --sat: env(safe-area-inset-top, 0px);
  /* One per cent of the column the app is actually drawn in — which is not
     what vh gives you. In Safari with its toolbars up, 100vh is the LARGE
     viewport, a hundred-odd pixels taller than anything you can see, so a
     screen laid out in vh overflows by exactly the toolbars. --vhpx is the
     figure JS measures from innerHeight/clientHeight/visualViewport, which is
     the visible column, and 100dvh is the fallback until it lands (one frame,
     at boot). Used by anything that has to fit a viewport exactly. */
  --vh1: calc(var(--vhpx, 100dvh) / 100);
  /* a title pill's height, named because the live chart panel takes over the
     header's and both pills' footprint and has to be exactly as tall */
  --bar-h: clamp(40px, 5.3vh, 48px);
  --sab: env(safe-area-inset-bottom, 0px);
  /* What the dock reserves under itself. The inset is the boundary, and this
     sits 14px inside it: the home indicator needs less room than iOS reserves,
     so trimming the reservation moves the dock down and hands the difference
     to the card. At a 34pt inset that leaves 20pt under the pill, 7pt above
     the indicator's top edge. max() floors it at 4px so the flat-bottomed
     devices, where the inset is 0, still get a sliver rather than sitting
     flush on the edge.

     Not padding inside the dock, and not an auto height: either one grows the
     pill, and the 9-slice's 11px middle band stretched four times over reads
     as a different shape. The pill keeps its size; only the space under it
     changes. */
  /* Home-screen iPhone: leave almost none of the safe-area as empty black
     under the dock. The pill sits near the physical bottom; the home
     indicator overlays the thin remaining sliver. Card flex grows into the
     reclaimed space. */
  --gap-bottom: max(0px, calc(var(--sab) - 28px));
  --dock-h: clamp(48px, 6.2vh, 58px);
  /* how far the dock shrinks when the card is scrolled; the card's
     clearance below follows it, so the two cannot drift apart */
  --dock-min-scale: .88;
}

/* Standalone / home-screen: pin even tighter — the reported black “dock gap”. */
@media (display-mode: standalone) {
  :root {
    --gap-bottom: max(0px, calc(var(--sab) - 32px));
  }
}
@supports (-webkit-touch-callout: none) {
  @media (display-mode: standalone) {
    :root {
      --gap-bottom: 0px;
    }
  }
}

* { margin: 0; padding: 0; box-sizing: border-box; }

/* Scrollbars are hidden everywhere, scrolling itself is untouched. The panels
   set scrollbar-width: thin and a themed colour, which Firefox honours but
   which older Chrome ignored entirely — leaving a default grey track down the
   course list and any other scrollable panel. Applied globally rather than
   per-panel so a new scroll container can't reintroduce it. */
* { scrollbar-width: none; -ms-overflow-style: none; }
*::-webkit-scrollbar { width: 0; height: 0; display: none; }

html, body {
  /* Pin the page to the webview edges. A short 100vh/dvh column was leaving
     a black band under the dock on iPhone home-screen installs; fixed inset
     makes the paint box match the visible webview. */
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  overscroll-behavior: none;
}

body {
  font-family: "Bryant Two", "Inter", Arial, sans-serif;
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  display: flex;
  justify-content: center;
  /* ambient glow behind the app column so wide screens don't read as black bars */
  background:
    radial-gradient(60% 45% at 20% 0%, rgba(61,223,255,.07), transparent 70%),
    radial-gradient(60% 45% at 80% 100%, rgba(255,61,154,.07), transparent 70%),
    var(--bg);
}

button {
  font-family: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* a tap is a tap: nothing here is double-tap-to-zoom, and waiting to find
     out is the delay between pressing a button and the button answering */
  touch-action: manipulation;
}

img { user-select: none; -webkit-user-drag: none; }

.app {
  position: absolute;
  inset: 0;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  height: auto;                 /* fill the fixed html/body inset */
  background: var(--bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* Tablet-sized viewports (iPad portrait/landscape, browser or home-screen):
   widen the column fluidly instead of pillarboxing at phone width. Width is
   capped by the viewport height so the 9:16 composition keeps its shape. */
@media (min-width: 700px) {
  .app {
    max-width: min(640px, 72vh);
    max-width: min(640px, 72dvh);
    border-left: 1px solid rgba(61,223,255,.14);
    border-right: 1px solid rgba(255,61,154,.14);
    box-shadow:
      -40px 0 90px -50px rgba(61,223,255,.35),
       40px 0 90px -50px rgba(255,61,154,.35);
  }
}

/* ===================== HEADER ZONE ===================== */

/* wave-only header per the v2 target layout — action icons live in the card footer */
/* Full-bleed: the zone starts at y=0 and grows by the top inset, so the wave
   runs up behind the status bar and dynamic island rather than being pushed
   below them. Nothing interactive lives in here — the action icons moved to
   the card footer — so there is nothing to keep clear of the notch. */
/* The clip is 1080x606, but its candlestick wave sits in the lower part of the
   frame and everything above that is empty — so the box is the frame with its
   top quarter cut off (1080x455) and the video anchored to the bottom. The
   wave still lands exactly on the header's bottom edge, nothing of it is lost,
   and the header gives back around 60pt of dead space to the card below.
   Raising 455 back toward 606 reveals more of the empty top again.
   Height follows the width, so it is right at any phone size. Full-bleed from
   y:0, notch included; the clock inside carries its own safe-area inset.
   Desktop restores a fixed height further down: there the banner covers this
   and row 1's rhythm is set by --dt-head. */
/* The header is a framed card now, not a full-bleed strip: the same 4% side
   inset the bars take, a rounded corner of its own, and the delivered neon
   frame drawn over it. `overflow: hidden` plus the radius is what actually
   clips the video — the frame is a glow painted on top, and a glow cannot
   crop anything, so the corner has to be a real clip.

   Height comes from --head-h, which JS measures from the header's own width.
   The aspect-ratio underneath it is the fallback that holds the shape before
   that runs, and it is what the measurement reproduces — so nothing moves when
   the variable arrives. A definite height is the point: it is the only form of
   this box that can be animated to the collapsed pill. */
/* .auth-wave — the gate's copy of this panel — is on the selector rather than
   in a rule of its own: the inset, the corner and the clip are what make this
   the header panel, and the two boxes have to be able to drift only by the one
   thing that actually differs between them, which is the height. */
.header-zone,
.auth-wave {
  position: relative;
  flex: 0 0 auto;
  /* the notch when there is one, a hairline when there is not — the frame has
     corners now, and a corner flush against the top of the screen reads as a
     rendering fault rather than as a design */
  margin: max(var(--sat), 6px) 4% 0;
  border-radius: 23px;
  overflow: hidden;
}
.header-zone {
  aspect-ratio: 1080 / 455;
  height: var(--head-h);
}
/* the neon rounded rect, over the footage rather than behind it. No `fill`:
   the middle of this frame belongs to the video. */
.header-zone::after,
.auth-wave::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  border: 34px solid transparent;
  border-image: url("../assets/header/frame-expanded.png") 90 / 34px stretch;
}
/* the header is its own card now, so it keeps the same gap from the first bar
   that the two bars keep from each other */
.header-zone + .bar { margin-top: 5px; }

.wave-bg {
  position: absolute;
  inset: 0;
  opacity: 0.95;
  transition: filter .4s ease, opacity .22s ease;
}
.wave-video {
  width: 100%;
  height: 100%;
  /* Cover crops to the box, and the box is shorter than the frame — so the
     crop has to come off the top, where the frame is empty. Anchored to the
     bottom, the wave keeps sitting on the header's bottom edge. */
  object-fit: cover;
  object-position: center bottom;
  background: #050614;   /* shows briefly if the video is still buffering */
}
/* static fallback — hidden by default; shown if the video can't play at all
   (see JS 'video-broken' class) or under prefers-reduced-motion below */
.wave-still {
  display: none;
  background: url("../assets/backgrounds/wave-header@2x.png") center bottom / cover no-repeat;
}
.header-zone.video-broken .wave-video { display: none; }
.header-zone.video-broken .wave-still { display: block; }

/* session · time · date, straight on the video. Plain white by request — no
   scrim, gradient or shadow behind it. Sits below the notch so the status bar
   never lands on top of the time. */
.wave-clock {
  position: absolute;
  left: 0;
  right: 0;
  /* the notch is cleared by the header's own top margin now, so the clock no
     longer carries the inset itself; the bottom keeps clear of the grabber */
  top: 0;
  bottom: 18px;
  transition: opacity .18s ease;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  color: #FFFFFF;
  text-align: center;
  pointer-events: none;
}
.wave-clock.hidden { display: none; }
.wc-session {
  display: flex;
  flex-direction: column;
  line-height: 1.05;
  font-size: calc(12px * var(--fs));
  font-weight: 700;
  letter-spacing: .08em;
}
.wc-session b { font-size: calc(14px * var(--fs)); font-weight: 800; }
.wc-time {
  font-size: calc(34px * var(--fs));
  font-weight: 800;
  letter-spacing: .01em;
  line-height: 1.05;
}
.wc-date {
  font-size: calc(12px * var(--fs));
  font-weight: 700;
  letter-spacing: .1em;
}

/* Narration pulse: subtle rhythmic scale + glow while audio is playing,
   giving the impression Æway is "speaking". Off by default. */
.header-zone.narrating .wave-bg {
  animation: wavePulse 1.8s ease-in-out infinite;
}
@keyframes wavePulse {
  0%, 100% { transform: scale(1);     filter: brightness(1)    saturate(1); }
  50%      { transform: scale(1.035); filter: brightness(1.22) saturate(1.25); }
}

@media (prefers-reduced-motion: reduce) {
  .wave-video { display: none; }
  .wave-still { display: block; }
  .header-zone.narrating .wave-bg { animation: none; filter: brightness(1.15); }
}

/* ===================== TOP BARS (two separate pills) ===================== */

.bar {
  position: relative;
  isolation: isolate;
  flex: 0 0 auto;
  margin: 5px 4% 0;
  padding: 0 14px;
  height: var(--bar-h);
  display: flex;
  align-items: center;
  gap: 12px;
  border-radius: var(--radius-pill);
}
/* The dock's own pill, nine-sliced: the two bars and the bar of five icons at
   the bottom of the screen are the same object now, drawn from the same file.
   Same slices the dock takes (54 60), and the widths it takes scaled to this
   bar's height — 19 of 40 against the dock's 24 of 48 — so the caps keep the
   curve they were drawn with rather than being squashed into a shorter box.

   Nothing here touches layout: this is an absolutely positioned pseudo-element
   with no content, so its border box is the bar's border box and its border
   widths cost the bar's own icons and title nothing. */
.bar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 19px solid transparent;
  border-left-width: 21px;
  border-right-width: 21px;
  border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 19px 21px stretch;
}

.bar-icon {
  flex: 0 0 auto;
  width: 36px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  transition: transform .15s ease, filter .15s ease;
}
.bar-icon:active { transform: scale(.9); filter: brightness(1.4); }
.bar-icon img { width: 24px; height: 24px; object-fit: contain; }
.bar-icon svg { width: 22px; height: 22px; }
.bar-icon .ico { fill: none; stroke: #BFE9FF; stroke-width: 2; filter: drop-shadow(0 0 5px rgba(61,223,255,.6)); }

.bar-title {
  flex: 1 1 auto;
  text-align: center;
  font-weight: 700;
  font-size: calc(14.5px * var(--fs));
  letter-spacing: .02em;
  color: #DDEFFF;
  text-shadow: 0 0 12px rgba(61,223,255,.5);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ===================== PROGRESS ROW ===================== */

.progress-track {
  position: relative;
  flex: 1 1 auto;
  height: 20px;
  border-radius: 11px;
  background: rgba(2,4,14,.85);
  border: 1px solid rgba(61,223,255,.30);
  box-shadow: inset 0 2px 6px rgba(0,0,0,.6);
  overflow: hidden;
}
.progress-fill {
  position: absolute;
  inset: 2px auto 2px 2px;
  border-radius: 10px;
  background: linear-gradient(90deg, #14907e, var(--teal));
  box-shadow: 0 0 10px rgba(47,230,194,.75);
  transition: width .35s ease;
  min-width: 0;
}
.progress-label {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 12.5px;
  font-weight: 700;
  color: #CFE9FF;
  text-shadow: 0 1px 3px rgba(0,0,0,.8);
  letter-spacing: .04em;
}

/* ===================== MAIN CARD ===================== */

.card-outer {
  position: relative;
  isolation: isolate;
  flex: 1 1 auto;
  min-height: 0;
  /* Bottom margin (not padding) clears the dock so the neon border ends
     ABOVE the pill. The dock lives in the black strip under the card. */
  margin: 8px 3.5% calc(var(--dock-h) + var(--gap-bottom) + 18px);
  padding-bottom: 0;
  border-radius: var(--radius-card);
  transition: margin-bottom .28s cubic-bezier(.2,.8,.2,1);
}
/* card backgrounds as 9-slices: glowing corners stay crisp, centers stretch */
.card-outer::before,
.auth-card-outer::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 36px solid transparent;
  border-image: url("../assets/backgrounds/app-background-card-v2@2x.png") 96 fill / 36px stretch;
}
/* content/lesson screens: gridpattern texture (round-3 item 9) */
.card-outer::before {
  border-image-source: url("../assets/backgrounds/background-card-gridpattern@2x.png");
}
/* section-selection (outline) view: plain version (round-3 item 10) */
.card-outer.outline-bg::before {
  border-image-source: url("../assets/backgrounds/background-card-plain@2x.png");
}

.card {
  position: relative;
  height: 100%;
  border-radius: calc(var(--radius-card) - 1.5px);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.card-scroll {
  overflow-anchor: none;   /* app restores scroll itself; no auto-adjust */
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 14px 18px 6px;
  touch-action: pan-y;
}

/* The mark and the way into the contents, on one row. The spacer on the left
   is the same width as the button on the right, which is what keeps the mark
   in the middle of the card rather than nudged off-centre by its new
   neighbour. */
.screen-head {
  display: flex; align-items: center; justify-content: center;
  gap: 10px;
  margin-bottom: 8px;
}
.screen-head-pad,
.lesson-nav { flex: 0 0 34px; }
.card-logo {
  display: block;
  width: 50px;
  margin: 0 auto 8px;
  filter: drop-shadow(0 0 8px rgba(61,223,255,.35));
}
.screen-head .card-logo { margin: 0; }
.lesson-nav {
  height: 34px;
  display: grid; place-items: center;
  padding: 0;
  border: 0; background: none;
  -webkit-tap-highlight-color: transparent;
}
.lesson-nav img {
  /* the mark is 50px across; this sits beside it at a weight that reads as a
     companion rather than a second logo */
  width: 32px; height: auto;
  object-fit: contain;
  filter: drop-shadow(0 0 6px rgba(61,223,255,.35));
}
.lesson-nav:active img { filter: brightness(1.4) drop-shadow(0 0 9px rgba(61,223,255,.6)); transform: scale(.9); }

/* ---- Course Contents ----
   Every page of the course in teaching order, grouped by module and section.
   The rows borrow nothing from the home outline on purpose: that one is a
   place to choose what to study, this one is a place to get somewhere. */
.ct { padding: 0 2px 16px; }
.ct-cap {
  margin: 0 2px 14px;
  font-size: calc(10.5px * var(--fs)); line-height: 1.5;
  color: #6F86A3;
  text-align: center;
}
.ct-mod {
  display: flex; flex-direction: column; gap: 2px;
  margin: 18px 2px 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(61,223,255,.22);
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--cyan);
}
.ct-mod:first-child { margin-top: 2px; }
.ct-mod i {
  font-style: normal; font-size: calc(12px * var(--fs)); font-weight: 800;
  letter-spacing: 0; text-transform: none;
  color: var(--text);
}
.ct-sec {
  display: flex; align-items: center; gap: 8px;
  margin: 14px 2px 6px;
}
.ct-sec-title {
  flex: 1 1 auto; min-width: 0;
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .14em; text-transform: uppercase;
  color: #8FA9C6;
}
.ct-row {
  width: 100%;
  display: flex; align-items: center; gap: 10px;
  padding: 9px 11px;
  margin-bottom: 5px;
  border: 1px solid rgba(120,170,255,.18);
  border-radius: 12px;
  background: rgba(4,7,18,.6);
  text-align: left;
}
.ct-row:active { filter: brightness(1.35); }
.ct-n {
  flex: 0 0 auto;
  min-width: 26px;
  font-size: calc(10px * var(--fs)); font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: #6F86A3;
}
.ct-label {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column;
  font-size: calc(12.5px * var(--fs)); font-weight: 700; line-height: 1.35;
  color: var(--text);
}
.ct-label i {
  font-style: normal; font-size: calc(9.5px * var(--fs)); font-weight: 600;
  color: #7E93AE;
}
.ct-go { flex: 0 0 auto; font-size: calc(13px * var(--fs)); color: #6F86A3; }
/* read already: dimmer, and the number carries the tick */
.ct-row.seen .ct-n { color: #2FE6C2; }
.ct-row.seen .ct-label { color: #C8D8E8; }
/* the page it was opened from */
.ct-row.here {
  border-color: rgba(61,223,255,.6);
  background: rgba(10,34,52,.8);
}
.ct-row.here .ct-label { color: #F2FBFF; }
.ct-row.here .ct-n,
.ct-row.here .ct-go { color: var(--cyan); }

.screen-headline {
  text-align: center;
  font-size: calc(22px * var(--fs));
  font-weight: 800;
  letter-spacing: .01em;
  color: #F2FBFF;
  text-shadow: 0 0 16px rgba(61,223,255,.45);
  margin-bottom: 4px;
}

.screen-subhead {
  text-align: center;
  font-size: calc(17.5px * var(--fs));
  font-weight: 600;
  font-style: italic;
  color: var(--cyan);
  text-shadow: 0 0 14px rgba(61,223,255,.55);
  margin-bottom: 14px;
}

.screen-body p {
  font-size: calc(14.5px * var(--fs));
  line-height: 1.55;
  color: #E6F2FD;
  margin: 0 0 11px;
}
.screen-body p.term { color: #CFF6EC; }
.screen-body p.term strong { color: var(--teal); font-weight: 700; }

/* numbered-list template (itemized screens, e.g. 60/20/20 rule) */
.screen-list {
  list-style: none;
  counter-reset: sl;
  margin: 2px 0 14px;
  padding: 0 4px;
}
.screen-list li {
  counter-increment: sl;
  font-size: calc(14.5px * var(--fs));
  line-height: 1.55;
  color: #E6F2FD;
  padding: 4px 0;
}
.screen-list li::before {
  content: counter(sl) ". ";
  color: var(--teal);
  font-weight: 700;
  text-shadow: 0 0 8px rgba(47,230,194,.5);
}

/* footer stack: wordmark above, then bookmark | mic · volume · play · replay | heart */
.card-footer {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 4px 16px 10px;
}
.card-footer .wordmark {
  height: 20px;
  opacity: .9;
  filter: drop-shadow(0 0 10px rgba(61,223,255,.3));
}
.footer-row {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
}
.action-btn {
  line-height: 0;
  transition: transform .15s ease, filter .15s ease;
  /* The artwork shrank; the thing you press did not. Sized like its .footer-icon
     neighbours so the whole row stays comfortably tappable. */
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
}
.action-btn:active { transform: scale(.9); filter: brightness(1.35); }
/* The same restraint the Trade Journal and Trade Day Check-In icons were cut
   back to: a little under three quarters of what these used to be, so the
   footer row reads as chrome rather than as the loudest thing on the card. */
.action-btn img { width: clamp(27px, 4vh, 34px); height: auto; }
.footer-icon {
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  transition: transform .15s ease;
}
.footer-icon:active { transform: scale(.88); }
.footer-icon svg { width: 27px; height: 27px; }

/* stroke/fill states for bookmark + heart */
.footer-icon .ico { fill: none; stroke: #BFE9FF; stroke-width: 2; filter: drop-shadow(0 0 5px rgba(61,223,255,.6)); transition: all .2s ease; }
.footer-icon.on-cyan .ico    { fill: var(--cyan);    stroke: var(--cyan);    filter: drop-shadow(0 0 9px rgba(61,223,255,.9)); }
.footer-icon.on-magenta .ico { fill: var(--magenta); stroke: var(--magenta); filter: drop-shadow(0 0 9px rgba(255,61,154,.9)); }

/* ===================== BOTTOM NAV ===================== */

/* one continuous dock bar (background-bar-pill@2x.png via 9-slice) with
   plain icon buttons inside — no individual boxed buttons */
/* The pill's own box is fixed — height is --dock-h, no padding, ::before
   untouched. It sits in the bottom strip under the neon card; the card uses
   bottom margin (not padding) so its glow ends above the pill. */
.bottom-nav {
  position: absolute;
  /* the card's own side inset, so the pill ends flush with the frame
     directly above it rather than stopping ~2pt short */
  left: 3.5%;
  right: 3.5%;
  /* Sit in the strip under the neon card (the bottom band), app-wide. */
  bottom: var(--gap-bottom);
  z-index: 40;
  isolation: isolate;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-around;
  margin: 0;
  height: var(--dock-h);
  border-radius: 999px;
  transform-origin: center bottom;
  transition: transform .28s cubic-bezier(.2,.8,.2,1), opacity .28s ease, height .28s ease;
  will-change: transform;
}
/* Scroll-minimized dock: shrinks toward the bottom edge and frees card space.
   Toggled by js/dock-chrome.js via .dock-min on .app */
.app.dock-min .bottom-nav {
  /* transform-origin is center bottom, so scale alone pins the pill's bottom
     edge at --gap-bottom and takes the height off the top. The translateY that
     used to ride along with it pushed the pill 42% of its own height past the
     bottom of the screen — that is what made the minimized dock read as a
     narrow sliver cut off by the edge. */
  transform: scale(var(--dock-min-scale));
  opacity: 0.92;
  pointer-events: auto; /* still tappable when peeking */
}
.app.dock-min .card-outer {
  margin-bottom: calc(var(--dock-h) * var(--dock-min-scale) + var(--gap-bottom) + 14px);
}
.bottom-nav::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 24px solid transparent;
  border-left-width: 27px;
  border-right-width: 27px;
  border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 24px 27px stretch;
}
.dock-btn {
  height: 100%;
  display: grid;
  place-items: center;
  transition: transform .12s ease, filter .2s ease;
}
.dock-btn:active { transform: scale(.9); filter: brightness(1.45); }
.dock-btn { position: relative; }
/* active section is marked on the icon itself — no ring behind it */
.dock-btn.active img { filter: brightness(1.5) drop-shadow(0 0 8px rgba(61,223,255,.85)); }
/* eased down a touch now the pill runs the full width of the card; the
   centre profile ring keeps its own size and stays the anchor */
.dock-btn img { width: 22px; height: 22px; object-fit: contain; }
/* The controller is the one glyph in the row that is wider than it is tall —
   1.61 to 1, where its neighbours run between 0.84 and 1.02. Contained in the
   same square box it can only be 22 by 13.6, which reads as a smaller icon
   even though it fills the box's width. Given a wider box it lands at 28 by
   17.4, level with the play triangle's 18.5 by 22. The height stays 22 so it
   can never push the row taller than the glyphs beside it. */
.dock-btn.dock-battle img { width: 28px; height: 22px; }
.dock-btn.glow-cyan { filter: brightness(1.45) drop-shadow(0 0 10px rgba(61,223,255,.65)); }

/* centre slot: the ring asset is the frame, the photo fills it. Sized past the
   bar height so it reads as the anchor of the dock, the way the mockup has it.
   The gradient ring's opening is ~76% of its canvas against the old ring's 88%,
   so the photo inside came in to keep clear of the stroke. */
.dock-profile {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: url("../assets/buttons-icon/profile-ring@2x.png") center / contain no-repeat;
}
.dock-profile img {
  width: 26px;
  height: 26px;
}
/* an uploaded photo fills the ring; the fallback person icon stays icon-sized */
.dock-profile.has-photo img {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  object-fit: cover;
}
.dock-profile.active { filter: drop-shadow(0 0 8px rgba(61,223,255,.85)); }
.dock-profile.active img { filter: none; }

/* 4th slot: reserved for the Battle artwork. Until it lands the slot holds a
   neutral dashed placeholder — deliberately not the ascending-bars mark, which
   belongs to Match Replay, so the two never read as the same thing. */
/* the slot inherits .dock-btn img sizing; nothing extra needed beyond the
   active-state glow every other dock icon gets */

/* ===================== HOME / OUTLINE ===================== */

.home-head { text-align: center; margin-bottom: 12px; }
.home-head .home-logo { width: 46px; display:block; margin: 0 auto 6px; filter: drop-shadow(0 0 8px rgba(61,223,255,.35)); }
.home-module-title {
  font-size: calc(21px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  text-shadow: 0 0 14px rgba(61,223,255,.4);
}
.home-module-tagline {
  margin-top: 2px;
  font-size: calc(13.5px * var(--fs));
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--cyan);
  text-shadow: 0 0 12px rgba(61,223,255,.6);
}

.home-tabs {
  display: flex;
  gap: 8px;
  justify-content: center;
  margin-bottom: 14px;
}
.home-tab {
  padding: 7px 16px;
  border-radius: 999px;
  font-size: calc(13px * var(--fs));
  font-weight: 700;
  letter-spacing: .03em;
  color: #9FB9D8;
  border: 1px solid rgba(61,223,255,.25);
  background: rgba(7,10,24,.5);
  transition: all .2s ease;
}
.home-tab.active {
  color: #06131f;
  background: linear-gradient(90deg, var(--cyan), var(--teal));
  border-color: transparent;
  box-shadow: 0 0 14px rgba(61,223,255,.5);
}

/* Continue — resumes at the last auto-saved page */
.continue-row {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 14px;
  padding: 12px 18px;
  text-align: left;
  border-radius: 999px;
  border: 2px solid transparent;
  border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 22px 25px stretch;
  background: none;
}
.continue-row:active { filter: brightness(1.35); }
.continue-row .cont-label {
  flex: 0 0 auto;
  font-size: calc(14px * var(--fs));
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--teal);
  text-shadow: 0 0 10px rgba(47,230,194,.6);
}
.continue-row .cont-where {
  flex: 1 1 auto;
  font-size: calc(12.5px * var(--fs));
  color: #B8CFE8;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.continue-row .cont-arrow {
  flex: 0 0 auto;
  font-size: 22px;
  color: var(--cyan);
  text-shadow: 0 0 10px rgba(61,223,255,.6);
}

/* daily trading checklist rows */

/* deck: stacked-card affordance — peeking layers behind each section row */
.deck { position: relative; margin: 0 2px 14px; }
.deck-peek {
  position: absolute;
  left: 10px; right: 10px;
  height: 16px;
  border-radius: 14px;
  background: rgba(20,32,64,.5);
  border: 1px solid rgba(61,223,255,.18);
}
.deck-peek.p1 { top: -5px;  opacity: .55; left: 6px;  right: 6px; }
.deck-peek.p2 { top: -10px; opacity: .32; left: 14px; right: 14px; }
.deck-peek.p3 { top: -14px; opacity: .16; left: 22px; right: 22px; }

.section-row {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px 10px 16px;
  border-radius: 18px;
  text-align: left;
  background: linear-gradient(180deg, rgba(24,38,74,.55), rgba(7,10,24,.8));
  border: 1px solid rgba(61,223,255,.35);
  box-shadow: 0 0 10px rgba(61,223,255,.14), inset 0 1px 0 rgba(255,255,255,.06);
  transition: box-shadow .2s ease, border-color .2s ease;
}
.section-row:active { border-color: rgba(61,223,255,.8); box-shadow: 0 0 16px rgba(61,223,255,.45); }
.section-row .sec-title {
  flex: 1 1 auto;
  font-size: calc(15.5px * var(--fs));
  font-weight: 700;
  color: #EAF6FF;
  text-shadow: 0 0 8px rgba(61,223,255,.3);
}

.pct-badge {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 11.5px;
  font-weight: 700;
  color: #BFE9FF;
  background:
    radial-gradient(circle at 50% 50%, rgba(7,10,24,.95) 58%, transparent 59%),
    conic-gradient(var(--teal) calc(var(--pct) * 1%), rgba(61,223,255,.15) 0);
  border: 1px solid rgba(61,223,255,.35);
  box-shadow: 0 0 10px rgba(61,223,255,.2);
}
.pct-badge.done { color: var(--teal); text-shadow: 0 0 8px rgba(47,230,194,.7); }

/* expanded section — subsection list inside a nested glass card */
.subsection-panel {
  margin: 6px 2px 16px;
  padding: 14px 12px;
  border-radius: 22px;
  background: linear-gradient(160deg, rgba(61,223,255,.06), rgba(7,10,24,.55) 45%, rgba(255,61,154,.07));
  border: 1px solid rgba(123,95,192,.45);
  box-shadow: -4px -4px 16px -6px rgba(61,223,255,.4), 4px 4px 16px -6px rgba(255,61,154,.4);
}
.subsection-panel .panel-logo { width: 44px; display: block; margin: 0 auto 10px; }
.subsection-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 10px 10px 16px;
  margin-bottom: 10px;
  border-radius: 16px;
  text-align: left;
  background: linear-gradient(180deg, rgba(20,32,64,.55), rgba(7,10,24,.8));
  border: 1px solid rgba(61,223,255,.3);
}
.subsection-row:active { border-color: rgba(61,223,255,.8); }
.subsection-row .sub-title {
  flex: 1 1 auto;
  font-size: calc(14.5px * var(--fs));
  font-weight: 600;
  color: #EAF6FF;
}
.subsection-row .pct-badge { width: 40px; height: 40px; font-size: 10.5px; }

.liked-empty {
  text-align: center;
  color: #9FB9D8;
  font-size: calc(14px * var(--fs));
  line-height: 1.6;
  padding: 30px 10px;
}
.liked-group-title {
  font-size: calc(14px * var(--fs));
  font-weight: 700;
  color: var(--cyan);
  margin: 14px 4px 8px;
  text-shadow: 0 0 10px rgba(61,223,255,.5);
}
.liked-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 14px;
  margin-bottom: 8px;
  border-radius: 14px;
  text-align: left;
  background: rgba(12,20,42,.6);
  border: 1px solid rgba(255,61,154,.35);
  box-shadow: 0 0 8px rgba(255,61,154,.12);
}
.liked-row .liked-label { flex: 1; font-size: calc(13.5px * var(--fs)); color: #EAF6FF; }
.liked-row .liked-sub { display:block; font-size: 11.5px; color: #9FB9D8; margin-top: 2px; }
.liked-row svg { width: 20px; height: 20px; flex: 0 0 auto; }

/* ===================== DIAGRAM (candle anatomy) ===================== */

.diagram { margin: 10px 0 16px; }
.diagram svg { width: 100%; height: auto; display: block; }

/* ===================== OVERLAYS / MODALS ===================== */

.overlay {
  position: absolute;
  inset: 0;
  z-index: 50;
  background: rgba(2,3,12,.72);
  backdrop-filter: blur(4px);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  opacity: 1;
  transition: opacity .22s ease;
}
.overlay.hidden { opacity: 0; pointer-events: none; }

.overlay-panel {
  width: 94%;
  max-height: 82%;
  margin-bottom: max(12px, var(--sab));   /* clear of the home indicator */
  border-radius: 26px;
  padding: 1.5px;
  background: linear-gradient(135deg, var(--cyan), var(--grad-mid), var(--magenta));
  box-shadow: -6px -6px 24px -8px rgba(61,223,255,.5), 6px 6px 24px -8px rgba(255,61,154,.5);
  transform: translateY(0);
  transition: transform .22s ease;
}
.overlay.hidden .overlay-panel { transform: translateY(24px); }

.panel-inner {
  border-radius: 24.5px;
  background: linear-gradient(170deg, #0B1226, var(--card) 70%);
  padding: 18px 18px 20px;
  max-height: calc(82vh - 20px);
  max-height: calc(82dvh - 20px);
  overflow-y: auto;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
}
.panel-title {
  font-size: calc(18px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  text-shadow: 0 0 12px rgba(61,223,255,.45);
}
.panel-close {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: none;
  color: #06131f;
  font-size: 17px;
  font-weight: 800;
  background: linear-gradient(135deg, var(--cyan), var(--grad-mid) 55%, var(--magenta));
  box-shadow: 0 0 14px rgba(255,61,154,.55), 0 0 10px rgba(61,223,255,.45), inset 0 1px 0 rgba(255,255,255,.35);
  transition: transform .12s ease, filter .15s ease;
}
.panel-close:active { transform: scale(.9); filter: brightness(1.2); }

.menu-module { margin-bottom: 6px; }
.menu-module-title {
  font-size: calc(13px * var(--fs));
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--cyan);
  margin: 12px 2px 8px;
}
.menu-item {
  width: 100%;
  text-align: left;
  padding: 10px 12px;
  margin-bottom: 6px;
  border-radius: 12px;
  font-size: calc(14.5px * var(--fs));
  font-weight: 600;
  color: #EAF6FF;
  background: rgba(14,22,44,.7);
  border: 1px solid rgba(61,223,255,.22);
  display: flex; align-items: center; gap: 8px;
}
.menu-item .mi-pct { margin-left: auto; font-size: 11.5px; color: #8FB4D8; }
.menu-item.current { border-color: var(--teal); box-shadow: 0 0 10px rgba(47,230,194,.35); }
.menu-sub { margin-left: 14px; }

.screenlist-item.done .mi-pct { color: var(--teal); }

/* settings */
.set-group { margin-bottom: 18px; }
.set-label {
  font-size: calc(13px * var(--fs));
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--cyan);
  margin-bottom: 8px;
}
.set-options { display: flex; gap: 8px; }
.set-opt {
  padding: 8px 16px;
  border-radius: 999px;
  font-size: calc(13.5px * var(--fs));
  font-weight: 700;
  color: #9FB9D8;
  border: 1px solid rgba(61,223,255,.3);
  background: rgba(7,10,24,.5);
}
.set-opt.active {
  color: #06131f;
  background: linear-gradient(90deg, var(--cyan), var(--teal));
  border-color: transparent;
  box-shadow: 0 0 12px rgba(61,223,255,.5);
}
.set-input {
  width: 100%;
  padding: 10px 14px;
  border-radius: 12px;
  border: 1px solid rgba(61,223,255,.35);
  background: rgba(2,4,14,.8);
  color: var(--text);
  font-family: inherit;
  font-size: calc(15px * var(--fs));
  outline: none;
}
.set-input:focus { border-color: var(--cyan); box-shadow: 0 0 10px rgba(61,223,255,.4); }

/* notes */
.notes-area {
  width: 100%;
  min-height: 140px;
  resize: vertical;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid rgba(61,223,255,.35);
  background: rgba(2,4,14,.8);
  color: var(--text);
  font-family: inherit;
  font-size: calc(15px * var(--fs));
  line-height: 1.55;
  outline: none;
}
.notes-area:focus { border-color: var(--cyan); box-shadow: 0 0 12px rgba(61,223,255,.4); }
.notes-hint { font-size: 12px; color: #8FB4D8; margin-top: 8px; }

/* overlay action buttons render background-bar-pill@2x.png via 9-slice */
.btn-primary,
.btn-secondary {
  display: block;
  width: 100%;
  border-radius: 999px;
  border: 2px solid transparent;
  border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 22px 25px stretch;
  background: none;
}
.btn-primary {
  margin-top: 14px;
  padding: 12px;
  font-size: calc(15px * var(--fs));
  font-weight: 800;
  letter-spacing: .06em;
  color: #EAF6FF;
  text-shadow: 0 0 10px rgba(61,223,255,.5);
}
.btn-primary:active { filter: brightness(1.35); }
.btn-secondary {
  margin-top: 10px;
  padding: 11px;
  font-size: calc(14px * var(--fs));
  font-weight: 700;
  color: #F2A9CD;
  text-shadow: 0 0 8px rgba(255,61,154,.4);
}
.btn-secondary:active { filter: brightness(1.35); }

/* profile */
.profile-stat-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 6px; }
.profile-stat {
  padding: 14px 12px;
  border-radius: 16px;
  text-align: center;
  background: rgba(14,22,44,.7);
  border: 1px solid rgba(61,223,255,.25);
}
.profile-stat .num {
  font-size: calc(22px * var(--fs));
  font-weight: 800;
  color: var(--cyan);
  text-shadow: 0 0 12px rgba(61,223,255,.6);
}
.profile-stat .lbl { font-size: 11.5px; letter-spacing: .06em; color: #9FB9D8; margin-top: 3px; text-transform: uppercase; }

/* note list on profile */
.note-item {
  padding: 10px 12px;
  margin-bottom: 8px;
  border-radius: 12px;
  background: rgba(14,22,44,.7);
  border: 1px solid rgba(61,223,255,.22);
  font-size: calc(13.5px * var(--fs));
}
.note-item .note-where { color: var(--cyan); font-size: 11.5px; font-weight: 700; margin-bottom: 4px; }
.note-item .note-text { color: #D9EAFB; line-height: 1.5; white-space: pre-wrap; }

/* ===================== AUTH SCREEN (pre-login entry) ===================== */

.auth-screen {
  position: absolute;
  inset: 0;
  z-index: 90;
  /* The wave is the video band at the top now, the same way the app's own
     header works, so the body behind it is just the app's ground. The old
     full-page still is kept as the band's fallback, not as the page. */
  background: var(--bg);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* like .app: no top padding, so the wave portion of the background bleeds
     behind the status bar. The spacer below carries the inset instead. */
}
.auth-screen.hidden { display: none; }
/* the desktop centre column's top band — see the rule further down */
.auth-topbar { display: none; }
/* While a field is focused, shrink the scroll area to the visible viewport
   (set from visualViewport in JS) so the active input scrolls clear of the
   keyboard and its QuickType/autofill toolbar instead of hiding behind it. */
.auth-screen.kb-open {
  bottom: auto;
  height: var(--kbvh, 100%);
}
/* #gateStep is named as well as the bare class: the gate's own padding rule
   further down is an id, so without this the keyboard clearance would be the
   one thing on this screen that a focused field could not get. */
.auth-screen.kb-open .auth-card,
.auth-screen.kb-open #gateStep .auth-card { padding-bottom: 96px; }

/* The panel the clip plays in. Everything that makes it the header panel is on
   the shared rule above — the 4% inset, the 23px corner, the clip, and the neon
   frame drawn over it. What is left here is the part that differs.

   It used to be a full-bleed band that ran behind the status bar and absorbed
   the top inset for the card below. It does neither now: the panel sits below
   the safe area like the home screen's does, and its own top margin is that
   inset.

   The height is the panel's, not the home header's: the home header takes its
   shape from the clip's aspect, and there is a whole form under this one that
   has to fit the same viewport. A fifth of the column — --vh1, the measured
   one, not vh — floored and capped so it stays a panel on a very short screen
   and does not become a banner on a very tall one.

   isolation + the radial mask are the iOS rounded-clip fallback: a rounded
   overflow:hidden box there sometimes fails to clip a <video> child and the
   corners come back square. Same class of bug as the match-history icons. */
.auth-wave {
  height: clamp(120px, calc(18 * var(--vh1)), 170px);
  background: #000;
  isolation: isolate;
  -webkit-mask-image: -webkit-radial-gradient(white, black);
}
/* Same treatment the app header gives this clip: cropped to the panel rather
   than stretched, anchored to the bottom so the candlestick wave — and the
   magenta wash under it — lands on the panel's bottom edge and only the empty
   top of the frame is lost. */
.auth-wave-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center bottom;
  background: #000;   /* no poster: the element's own ground, not a stale frame */
}
.auth-wave-video.hidden { display: none; }

.auth-card-outer {
  position: relative;
  isolation: isolate;
  flex: 1 0 auto;
  margin: 14px 5% max(18px, var(--sab));
  border-radius: var(--radius-card);
}

.auth-card {
  min-height: 100%;
  padding: 34px 26px 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.auth-logo {
  width: min(58%, 240px);
  margin: 8px auto 2px;
  filter: drop-shadow(0 0 18px rgba(61,223,255,.35));
}
.auth-wordmark {
  width: min(74%, 320px);
  margin: 6px auto 30px;
  filter: drop-shadow(0 0 12px rgba(61,223,255,.3));
}

/* login pill: button-pill-standard@2x.png as a 9-slice (login screen only) */
.g-pill {
  border: 2px solid transparent;
  border-image: url("../assets/buttons-pill/button-pill-standard@2x.png") 78 86 fill / 25px 28px stretch;
  border-radius: 999px;
  background: none;
  color: #C7D9EF;
  font-family: inherit;
}

.auth-card-outer.hidden { display: none; }

/* ---- the gate, fitted to one viewport ----
   No screen in this app scrolls, and the panel above takes room the old
   full-bleed band did not. So the gate's vertical rhythm is measured against
   --vh1 — the column the app is really drawn in, not the large viewport vh
   reports — with a floor under every part of it: a 390x844 phone keeps very
   nearly the spacing it has now, and a 375x667 one gives up the logo and the
   gaps rather than the bottom of the form.

   The order is the one the brief asks for — the logo first, then the gaps,
   then the fields, and the fields only down to 48px, which is the tap target
   and is not negotiable. Everything here is scoped to #gateStep: the
   questionnaire and the way in are taller screens with their own bargains and
   neither is part of this change. */
/* four pixels back off the gap under the panel. Phone only: the desktop
   layout sets this margin from the grid it shares with the side columns, and
   an id would quietly outrank it there. */
/* Four pixels back off the gap under the panel, and the card's own bottom
   margin handed over to the dock: ENTER is the bottom pill now, and the pill's
   zone already carries the clearance the card used to carry for itself. Phone
   only — the desktop layout sets both margins from the grid it shares with the
   side columns, and an id would quietly outrank it there. */
@media (max-width: 1199px) {
  #gateStep { margin-top: 10px; margin-bottom: 0; }
}
#gateStep .auth-card {
  padding: clamp(6px, calc(1.6 * var(--vh1)), 28px) 26px clamp(10px, calc(2.5 * var(--vh1)), 38px);
}
/* width -> height, so the mark is bounded by the axis that is actually short.
   The aspect ratio is the asset's, so nothing distorts. */
#gateStep .auth-logo {
  width: auto;
  height: clamp(40px, calc(12.2 * var(--vh1)), 126px);
  margin: 0 auto clamp(0px, calc(.5 * var(--vh1)), 6px);
}
#gateStep .auth-wordmark {
  width: auto;
  height: clamp(24px, calc(5 * var(--vh1)), 56px);
  margin: 0 auto clamp(6px, calc(2.8 * var(--vh1)), 32px);
}
#gateStep .gate-title {
  font-size: calc(clamp(14px, calc(2.1 * var(--vh1)), 17px) * var(--fs));
  margin: 0 0 clamp(6px, calc(2 * var(--vh1)), 20px);
}
#gateStep .auth-input {
  height: clamp(48px, calc(6.4 * var(--vh1)), 54px);
  min-height: clamp(48px, calc(6.4 * var(--vh1)), 54px);
  max-height: clamp(48px, calc(6.4 * var(--vh1)), 54px);
  flex: 0 0 auto;
}

/* ---------------- the way in ----------------
   The brand loop fills the centre column. Idle, the way in is a single pill
   in a dock under it; tapped, the dock folds away and the fields ride on the
   clip itself, at a fixed point in the composition.

   The clip is letterboxed, not cropped: its composition runs type into all
   four corners, and cover would cut whichever pair the column's aspect does
   not match. contain keeps the whole frame and pays for it in bars, which is
   the right way round here. */
.auth-screen.on-login .auth-wave { display: none; }
/* and nothing on this step scrolls — a focused field must not be able to
   drag the composition up behind the keyboard */
.auth-screen.on-login { overflow: hidden; }
.login-step {
  position: relative;
  isolation: isolate;
  flex: 1 1 auto;
  min-height: 0;
  margin: 0;
  border-radius: 0;
  /* Below the notch, not behind it. The clip used to start at y:0 and the
     Dynamic Island sat on top of the composition's own top edge. The inset is
     padding rather than margin on purpose: it comes out of the media box's
     share of the column, so the panel gets shorter by exactly what the island
     takes and the dock under it does not move a pixel. */
  padding: calc(var(--sat) + 10px) 0 0;
  display: flex;
  flex-direction: column;
  background: #000;
  /* the keyboard slide, above — the step moves as one piece, panel and dock */
  transition: transform .22s cubic-bezier(.2, .8, .2, 1);
}
@media (prefers-reduced-motion: reduce) { .login-step { transition: none; } }
.login-step::before { content: none; }   /* the card frame's glow is not wanted here */
.login-media {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  background: #000;
  /* so the frame below can be measured against this box's own height */
  container-type: size;
}
.login-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: contain;              /* the whole frame, bars and all */
  object-position: center;
}
.login-video.hidden { display: none; }

/* The clip's own frame inside the media box. object-fit: contain fits the
   2160x3840 source to whichever axis runs out first and centres it; this is
   the same arithmetic, so the box lines up with the picture exactly and the
   letterbox bars fall outside it. Percentages within it are therefore
   percentages of the composition, which is what "below the tagline, above
   the globe" has to mean. */
.login-frame {
  position: absolute;
  inset: 0;
  margin: auto;
  width: min(100%, 100cqh * 2160 / 3840);
  aspect-ratio: 2160 / 3840;
  pointer-events: none;             /* the clip's frame catches nothing */
  /* The frame's own height as a length, which is what everything riding on
     the composition has to be measured in: percentages of an auto-height box
     do not resolve, and vh is the column, not the picture. Same arithmetic as
     the width above, the other way round — whichever axis runs out first. */
  --lf-h: min(100cqh, 100cqw * 3840 / 2160);
}
/* Without container units the frame cannot be derived, so it falls back to
   the media box. On a phone column the two are within a few percent. */
@supports not (width: 1cqh) {
  .login-frame { width: 100%; height: 100%; aspect-ratio: auto; --lf-h: calc(70 * var(--vh1)); }
}

/* the dock under the clip. It is a place to stand, not a second shape: the
   pill inside it is the only frame, which is why it paints no bar of its
   own — two nine-slices here read as a pill inside a pill. */
/* One zone at the foot of the screen, the same box the bottom nav takes once
   someone is signed in, and the same one the desktop shell's pill takes. It
   holds a different control in each state and moves in none of them —
   including with the keyboard up, which covers it rather than shifting it. */
/* ---- the bottom pill ----
   One control in one place at the foot of every entry screen: LOGIN / SIGN UP
   on the way in, LOGIN or SIGN UP once the form is open, ENTER on the access
   gate. One box and one pill, so the five screens cannot drift apart.

   The box is the landing screen's, which is the one that was right: the app's
   own dock slot, the same side inset and the same clearance under it. The type
   is the LOGIN pill's, which was the other one that was right: bold, upper
   case, widely tracked, white. Nothing here is per-screen. */
.bottom-dock {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 10px 3.5% var(--gap-bottom);
  min-height: clamp(48px, 6.2vh, 58px);
}
.bottom-dock.hidden { display: none; }

.bottom-pill {
  width: 100%;
  max-width: 320px;
  height: 54px;
  font-size: calc(15px * var(--fs));
  font-weight: 800; letter-spacing: .22em; text-transform: uppercase;
  color: #EAF6FF;
}
.bottom-pill:active { filter: brightness(1.25); transform: scale(.98); }
.bottom-pill.pending { color: var(--teal); filter: brightness(1.3); }
.bottom-pill:disabled { opacity: .75; }
.bottom-pill.hidden { display: none; }

/* The fields, on the clip.

   Anchored by their HEAD, not their foot. They used to hang from a line low in
   the frame and grow upward, which is why sign-up's four fields climbed over
   the logo and the wordmark: two more fields meant two more fields of height
   taken off the top. The head is the fixed thing now. 48% is measured off the
   clip itself — the tagline's last row is at 46.5% of the composition — so the
   stack starts just under LEARN | DISCIPLINE | TRADE and everything a field is
   added grows downward, onto the globe and the floor, which is empty.

   The logo, the wordmark and the tagline are above that line in both states
   and neither state moves them.

   Everything below is measured in --lf-h, the picture's own height, so the
   group keeps its place in the composition at any column shape. */
.login-form {
  position: absolute;
  left: 50%;
  top: var(--lf-head, 48%);
  transform: translateX(-50%);
  width: min(84%, 320px);
  pointer-events: auto;             /* but the fields themselves do */
  /* the gap between the stack and whatever hangs under it */
  --lf-bgap: clamp(6px, calc(.014 * var(--lf-h)), 14px);
}
.login-form.hidden { display: none; }
.login-form #authForm {
  /* The fields give up height and gap before anything else does, and only as
     far as 44px, which is the tap target. A 375x667 column is the one that
     actually spends this: a 390x844 one keeps the full 54. */
  gap: clamp(4px, calc(.010 * var(--lf-h)), 12px);
  --lf-fh: clamp(44px, calc(.067 * var(--lf-h)), 54px);
}
.login-form .field-pill {
  width: 100%;
  height: var(--lf-fh);
  flex: 0 0 auto;
}
/* the field itself is only the text now — the pill around it is the wrapper,
   because an <input> has no ::before to hang a gradient ring on */
.login-form .field-pill .auth-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-height: 0;
  max-height: none;
  border: 0;
  border-radius: 999px;
  background: none;
}
/* The two buttons under the fields in the login state — the inline Login and
   the way across to sign-up — and the way back from sign-up, which is the same
   pill in a different place. Smaller than the dock's so they read as the
   second thing on the screen. */
.auth-switch {
  display: block;
  width: 62%;
  text-align: center;
  height: clamp(34px, calc(.058 * var(--lf-h)), 40px);
  flex: 0 0 auto;
  margin: clamp(2px, calc(.008 * var(--lf-h)), 8px) 0 0;
  padding: 0 14px;
  font-size: calc(11.5px * var(--fs));
  font-weight: 700;
  letter-spacing: .1em;
  color: #C7D9EF;
}
.auth-switch:active { filter: brightness(1.35); transform: scale(.97); }
/* Back to Login, down on the reflective floor rather than tucked under the
   last field. The floor runs from the horizon at 76% of the composition to the
   footer type at 90%, and .305 puts the button at 78.5% — clear of both.

   max(), because on a short column the four fields reach that line by
   themselves: there the button takes the first term and sits just under the
   stack, which is still on the floor and still above the footer. The stack is
   never moved up over the logo to make room. */
.login-form .auth-floor {
  position: absolute;
  left: 50%;
  top: max(calc(100% + var(--lf-bgap)), calc(.305 * var(--lf-h)));
  transform: translateX(-50%);
  margin: 0;
}
.login-form .auth-floor:active { transform: translateX(-50%) scale(.97); }

/* ---- .entry-pill: the pills inside the panel ----
   Every field and inline button on the way in, translucent so the artwork and
   its animation carry on behind them.

   The delivered nine-slice cannot do this. button-pill-standard is opaque
   across its edge slices, and those slices are 25 and 28 pixels deep on a pill
   barely 48 tall — the dark interior IS the border image, not a middle band
   under it, so there is nothing there to make see-through. The pill is drawn
   instead, which is also the shape the mockups ask for: a thin gradient
   outline rather than the heavy plate.

   The ring is a pseudo-element, not a gradient background clipped to the
   border box. That was the first thing tried and it is wrong: a border-box
   gradient covers the middle of the pill too, and a 45% fill over it leaves
   the interior washed cyan-to-pink instead of showing the clip through it.
   ::before paints the gradient, then masks its own middle out — content box
   XOR padding box — so only the two pixels of ring survive. An <input> has no
   ::before, which is why each field is wrapped.

   The fill is 45% of #02040E and the blur is 2px, deliberately light: the
   point of this is to watch the animation move behind the pill, and a heavy
   blur would hide exactly what it is there to show. The ring and its glow are
   untouched by any of it — only the fill gives way. */
.entry-pill {
  position: relative;
  isolation: isolate;
  display: block;
  border: 0;
  border-radius: 999px;
  background: rgba(2, 4, 14, .45);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  box-shadow: 0 0 12px rgba(61, 223, 255, .28), 0 0 12px rgba(255, 61, 154, .24);
  color: #EAF6FF;
  font-family: inherit;
  /* the globe and the candles are the brightest thing this type ever sits on */
  text-shadow: 0 1px 4px rgba(0, 0, 0, .8);
}
.entry-pill::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  padding: 2px;
  background: linear-gradient(95deg, var(--cyan) 0%, #3E6BFF 52%, var(--magenta) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask-composite: exclude;
  pointer-events: none;
}
/* the field is transparent over the wrapper, so the focus ring belongs to the
   pill rather than to the box inside it */
.entry-pill:focus-within {
  box-shadow: 0 0 16px rgba(61, 223, 255, .55), 0 0 16px rgba(255, 61, 154, .3);
}
.login-form .auth-input {
  color: #EAF6FF;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .8);
}
.login-form .auth-input:focus { filter: none; }
.login-form .auth-input::placeholder {
  color: #CBDAEE;
  text-shadow: 0 1px 4px rgba(0, 0, 0, .85);
}
/* autofill insists on painting its own ground; keep it dark and legible
   rather than translucent, which is the one place the fill gives way */
.login-form .auth-input:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px rgba(2, 4, 14, .92) inset;
  border-radius: 999px;
}

.gate-title {
  font-size: calc(17px * var(--fs));
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--cyan);
  text-shadow: 0 0 14px rgba(61,223,255,.6);
  margin: -14px 0 20px;
}
.gate-error {
  width: 100%;
  text-align: center;
  font-size: calc(13.5px * var(--fs));
  font-weight: 700;
  color: #FF7DB4;
  text-shadow: 0 0 10px rgba(255,61,154,.5);
}
.gate-error.hidden { display: none; }

.auth-tabs {
  display: flex;
  gap: 14px;
  width: 100%;
  margin-bottom: 26px;
}
.auth-tab {
  flex: 1 1 0;
  height: 52px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: .22em;
  text-transform: uppercase;
  opacity: .55;
  transition: opacity .2s ease, box-shadow .2s ease;
}
.auth-tab.active {
  opacity: 1;
  color: #EAF6FF;
  filter: brightness(1.25) drop-shadow(0 0 10px rgba(255,61,154,.55));
}

#authForm {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 18px;
  align-items: center;
}
.auth-input {
  position: relative;
  width: 100%;
  /* pinned three ways so neither content, focus, nor a browser-injected
     control (autofill key, password reveal) can change the field's box */
  height: 54px;
  min-height: 54px;
  max-height: 54px;
  flex: 0 0 54px;
  box-sizing: border-box;
  padding: 0 24px;
  font-size: 16px;               /* >=16px prevents iOS focus zoom */
  color: var(--text);
  /* every field on the form reads from the left, password included */
  text-align: left;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
.auth-input::placeholder { color: #8FA3BF; letter-spacing: .06em; }
/* WebKit injects these inside password/email fields. Left inline they take
   part in layout and can widen the field; anchored absolutely they sit within
   the bounds it already has.

   ::-webkit-textfield-decoration-container is deliberately NOT in this list.
   It is not an injected button — it is the shadow container holding the
   field's own editing area, so absolutely positioning it at right:14px pulled
   the text, the caret and the placeholder out of flow and jammed them against
   the right edge. That is why the Access Code field, the only one iOS offers
   password autofill on, sat right-aligned showing a stray dot instead of its
   placeholder while every other field on the form looked fine. */
.auth-input::-webkit-credentials-auto-fill-button,
.auth-input::-webkit-strong-password-auto-fill-button,
.auth-input::-webkit-caps-lock-indicator {
  position: absolute;
  right: 14px;
  top: 50%;
  transform: translateY(-50%);
  margin: 0;
}
.auth-input:focus {
  filter: brightness(1.3) drop-shadow(0 0 10px rgba(61,223,255,.55));
}

/* iOS/Chrome autofill: force white text + caret so autofilled email/password
   stays readable on the dark pill (default renders black-on-dark). The long
   background transition defeats the autofill background flash; the pill's
   border-image already supplies the dark interior. */
.auth-input:-webkit-autofill,
.auth-input:-webkit-autofill:hover,
.auth-input:-webkit-autofill:focus,
.auth-input:-webkit-autofill:active {
  -webkit-text-fill-color: var(--text) !important;
  caret-color: var(--text);
  -webkit-box-shadow: 0 0 0 1000px rgba(9, 13, 30, 0.85) inset;
  transition: background-color 100000s ease-in-out 0s;
}

.auth-submit {
  width: 62%;
  height: 54px;
  margin-top: 10px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: #EAF6FF;
  cursor: pointer;
  transition: box-shadow .2s ease, transform .12s ease;
}
.auth-submit:active { transform: scale(.97); }
.auth-submit.pending {
  color: var(--teal);
  filter: brightness(1.3) drop-shadow(0 0 10px rgba(47,230,194,.5));
}

/* ---- step 1.5: beta intake questionnaire ---- */

#surveyStep .auth-card { padding: 26px 20px 34px; }
#surveyStep .auth-wordmark { width: min(62%, 260px); margin: 2px auto 22px; }

.sv-intro {
  font-size: calc(13.5px * var(--fs));
  line-height: 1.55;
  color: #9FC0E0;
  text-align: center;
}

#surveyForm {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
}
/* deliberately not .gate-title's shouty small-caps treatment — a welcome
   message reads friendlier at a normal case, matching the tone of the intro
   paragraph beneath it rather than "BETA ACCESS" up top */
.sv-intro-title {
  text-align: center;
  font-size: calc(20px * var(--fs));
  font-weight: 800;
  color: var(--cyan);
  text-shadow: 0 0 16px rgba(61,223,255,.5);
}

.sv-q { width: 100%; display: flex; flex-direction: column; align-items: center; gap: 16px; }

.sv-label {
  font-size: calc(19px * var(--fs));
  font-weight: 800;
  line-height: 1.35;
  color: #EAF6FF;
  text-align: center;
  text-shadow: 0 0 12px rgba(61,223,255,.25);
}
.sv-multi {
  display: block;
  margin-top: 6px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: #8FB4D8;
}

.sv-opts { width: 100%; display: flex; flex-wrap: wrap; justify-content: center; gap: 9px; }
.sv-opt {
  padding: 9px 15px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.26);
  background: rgba(10,16,34,.72);
  color: #C7D9EF;
  font-size: calc(12.5px * var(--fs));
  line-height: 1.3;
  text-align: left;
  transition: transform .12s ease, box-shadow .2s ease, background-color .2s ease;
}
.sv-opt:active { transform: scale(.96); }
.sv-opt.on {
  border-color: var(--cyan);
  background: rgba(61,223,255,.15);
  color: #EAF6FF;
  font-weight: 600;
  box-shadow: 0 0 12px rgba(61,223,255,.35);
}

.sv-input { width: 100%; }
/* native date picker renders dark to match the card */
.sv-date { color-scheme: dark; }
.sv-date::-webkit-date-and-time-value { text-align: left; }

.sv-other {
  width: 100%;
  height: 48px;
  margin-top: 10px;
  padding: 0 18px;
  border: 1px solid rgba(61,223,255,.3);
  border-radius: 999px;
  background: rgba(10,16,34,.72);
}
.sv-other.hidden { display: none; }

/* progress: "Question X of 12", the same pill-track-with-label language as
   the course progress bar in the top chrome — duplicated rather than shared,
   since that one is a flex-row item (flex:1 1 auto) and this sits in a flex
   column, where flex:1 1 auto would fight the column's other children for
   height instead of just taking the full width. */
.sv-progress-track {
  position: relative;
  width: 100%;
  height: 20px;
  border-radius: 11px;
  background: rgba(2,4,14,.85);
  border: 1px solid rgba(61,223,255,.30);
  box-shadow: inset 0 2px 6px rgba(0,0,0,.6);
  overflow: hidden;
}
.sv-progress-fill {
  position: absolute;
  inset: 2px auto 2px 2px;
  min-width: 12px;
  border-radius: 10px;
  background: linear-gradient(90deg, #14907e, var(--teal));
  box-shadow: 0 0 10px rgba(47,230,194,.75);
  transition: width .3s ease;
}
.sv-progress-label {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 12px;
  font-weight: 700;
  color: #CFE9FF;
  text-shadow: 0 1px 3px rgba(0,0,0,.8);
  letter-spacing: .03em;
}

/* Back / Next share a row; Next carries .auth-submit for the same bold pill
   look as every other primary action on this screen, so its own width/margin
   are overridden here to sit correctly beside Back instead of centered alone. */
.sv-nav { width: 100%; display: flex; align-items: center; gap: 12px; }
.sv-back {
  flex: 0 0 auto;
  height: 54px;
  padding: 0 20px;
  font-size: calc(13px * var(--fs));
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #9FC0E0;
}
.sv-back:active { filter: brightness(1.3); transform: scale(.97); }
.sv-next {
  flex: 1 1 auto;
  width: auto;
  margin-top: 0;
}
/* same disabled treatment as the Trade Day Check-In submit button */
.sv-next.off { opacity: .4; color: #9FC0E0; cursor: default; }

/* ---- survey welcome: Login-only dock pill (skip questionnaire) ---- */
.survey-dock {
  position: absolute;
  left: 4%;
  right: 4%;
  bottom: max(10px, var(--sab));
  z-index: 45;
  height: clamp(48px, 6.2vh, 58px);
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  isolation: isolate;
}
.survey-dock.hidden { display: none; }
.survey-dock::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 24px solid transparent;
  border-left-width: 27px;
  border-right-width: 27px;
  border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 24px 27px stretch;
}
.survey-dock-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 22px;
  font-size: calc(13px * var(--fs));
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #EAF6FF;
}
.survey-dock-btn img { width: 24px; height: 24px; object-fit: contain; }
.survey-dock-btn:active { filter: brightness(1.35); transform: scale(.97); }
/* leave room above the dock on the welcome card */
#surveyStep.sv-has-dock {
  margin-bottom: calc(clamp(48px, 6.2vh, 58px) + max(14px, var(--sab)));
}


/* Start Day result */
.ci-result { text-align: center; padding: 4px 0 2px; }
.ci-result-title {
  font-size: calc(23px * var(--fs));
  font-weight: 800;
  letter-spacing: .04em;
  margin-bottom: 12px;
}
.ci-result.go .ci-result-title { color: var(--teal); text-shadow: 0 0 20px rgba(47,230,194,.75); }
.ci-result.stop .ci-result-title { color: #FF6B9D; text-shadow: 0 0 20px rgba(255,61,154,.7); }
.ci-result-body {
  font-size: calc(13.5px * var(--fs));
  line-height: 1.55;
  color: #D9EAFB;
  margin-bottom: 6px;
}

/* Submitting swaps the seven rows for the result inside the same card — no
   overlay. The result claims the space the rows left so it reads as centred,
   with the category row still below it. */
.card-scroll.ci-resulting { display: flex; flex-direction: column; }
.ci-result-inline {
  flex: 1 1 auto;
  min-height: 240px;   /* small enough that the category row still fits on a 640px screen */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 10px 4px;
}
.ci-result-inline .ci-result-body { max-width: 300px; }
.ci-result-inline .btn-primary { width: 78%; max-width: 300px; margin-top: 18px; }

/* manual trade entry form */
.mt-label {
  display: block;
  margin-bottom: 12px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: #8FB4D8;
}
.mt-row { display: flex; gap: 10px; }
.mt-row .mt-label { flex: 1 1 0; }
.mt-input {
  display: block;
  width: 100%;
  height: 44px;
  margin-top: 5px;
  padding: 0 14px;
  border-radius: 12px;
  border: 1px solid rgba(61,223,255,.3);
  background: rgba(9,13,30,.75);
  color: var(--text);
  font-family: inherit;
  font-size: 16px;                  /* >=16px keeps iOS from zooming on focus */
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
.mt-input:focus { border-color: var(--cyan); }
.mt-date { color-scheme: dark; }
.mt-result {
  margin: 2px 0 12px;
  padding: 9px;
  border-radius: 10px;
  text-align: center;
  font-size: 12.5px;
  font-weight: 800;
  letter-spacing: .1em;
  color: #8FB4D8;
  border: 1px solid rgba(61,223,255,.2);
}
.mt-result.win  { color: var(--teal);  border-color: rgba(47,230,194,.6);  background: rgba(47,230,194,.1); }
.mt-result.loss { color: #FF6B9D;      border-color: rgba(255,61,154,.6);  background: rgba(255,61,154,.12); }
.mt-result.flat { color: #C7D9EF; }

/* ===================== TRADE JOURNAL (Phase 1: layout) ===================== */

.bar-journal.hidden { display: none; }
.journal-summary {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  white-space: nowrap;
  overflow: hidden;
}
.j-broker {
  font-size: 10px;
  font-weight: 700;
  line-height: 1.15;
  color: #C7D9EF;
  flex: 0 1 auto;
  min-width: 0;
  max-width: 58px;
  white-space: normal;
  text-align: right;
}
.j-balance {
  flex: 0 0 auto;
  font-size: calc(15px * var(--fs));
  font-weight: 800;
  color: #EAF6FF;
  text-shadow: 0 0 12px rgba(61,223,255,.45);
}
.j-change { flex: 0 0 auto; display: flex; flex-direction: column; align-items: flex-start; line-height: 1.2; }
.j-change-label { font-size: 9.5px; font-weight: 600; color: #8FB4D8; }
.j-change .pos, .j-stat-val.pos, .j-pnl.pos { color: #2FE6C2; }
.j-change .neg, .j-stat-val.neg, .j-pnl.neg { color: #FF6B9D; }
.j-change span:last-child { font-size: 10.5px; font-weight: 700; }

/* account toggle — same pill style as the Home tabs */
/* the pills use the shared label-button art; the selected one is brightened
   and glows rather than filled, since the art carries its own colour */
/* Live Account · chevron · Prop Account, all on one line */
.j-selector {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 2px 0 16px;
}
.j-acct-pill {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 46px;
  padding: 0 4px;
  border-radius: 999px;
  border-style: solid;
  border-width: 20px 24px;
  border-image: url("../assets/buttons-icon/label-button@2x.png") 40 48 fill / 20px 24px stretch;
  font-size: calc(11.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: #EAF6FF;
  white-space: nowrap;
}
.j-acct-pill.on {
  filter: brightness(1.28) drop-shadow(0 0 10px rgba(61,223,255,.6));
  color: #FFFFFF;
}
.j-acct-pill:active { filter: brightness(1.4); transform: scale(.98); }
/* same circular treatment as the "+ Add Trade" button */
.j-drop {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: url("../assets/buttons-icon/icon-button-frame@2x.png") center / contain no-repeat;
}
.j-drop img { width: 18px; height: 18px; object-fit: contain; }
.j-drop:active { transform: scale(.93); filter: brightness(1.3); }

.j-cal {
  padding: 12px 10px 14px;
  border-radius: 20px;
  background: rgba(4,7,18,.55);
  border: 1px solid rgba(61,223,255,.22);
}
.j-cal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.j-month { display: flex; align-items: center; gap: 6px; font-size: calc(15px * var(--fs)); font-weight: 700; color: #EAF6FF; }
.j-nav {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(61,223,255,.35);
  color: #C7D9EF;
  font-size: 15px;
  line-height: 1;
}
.j-nav:active { border-color: var(--cyan); filter: brightness(1.3); }
.j-cal-stats { display: flex; gap: 14px; text-align: center; }
.j-cal-stats > span { display: flex; flex-direction: column; gap: 2px; }
.j-stat-label { font-size: 9.5px; font-weight: 600; letter-spacing: .04em; color: #8FB4D8; }
.j-stat-val { font-size: calc(13px * var(--fs)); font-weight: 800; }
.j-stat-val.cyan { color: var(--cyan); }

.j-dow, .j-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.j-dow {
  margin-bottom: 5px;
  padding-bottom: 5px;
  border-bottom: 1px solid rgba(61,223,255,.16);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .04em;
  color: #8FB4D8;
  text-align: center;
}
/* day cells: colour carries the outcome, so no artwork is needed */
.j-day {
  min-height: 42px;
  padding: 3px 2px;
  border-radius: 7px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  border: 1px solid rgba(61,223,255,.14);
  background: rgba(9,13,30,.5);
}
.j-date { font-size: calc(12.5px * var(--fs)); font-weight: 700; color: #EAF6FF; line-height: 1.1; }
.j-pnl { font-size: 8.5px; font-weight: 700; line-height: 1.1; }
.j-day.out { border-color: rgba(61,223,255,.07); background: rgba(9,13,30,.25); }
.j-day.out, .j-day.out .j-date { color: #46567A; }
.j-day.profit { background: rgba(47,230,194,.1);  border-color: rgba(47,230,194,.4); }
.j-day.loss   { background: rgba(255,61,154,.12); border-color: rgba(255,61,154,.45); }
.j-week-label {
  font-size: 7.5px;
  font-weight: 700;
  letter-spacing: .05em;
  color: #9FC0E0;
  line-height: 1;
}

/* manual entry — the dock's "+" treatment at button scale */
.j-add {
  position: relative;
  display: block;
  width: 72px;
  height: 72px;
  margin: 20px auto 4px;
  border: 0;
  border-radius: 50%;
  background: url("../assets/buttons-icon/plus-button@2x.png") center / contain no-repeat;
  box-shadow: 0 0 22px -6px rgba(61,223,255,.7);
}
.j-add::before, .j-add::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  background: #EAF6FF;
  border-radius: 2px;
  box-shadow: 0 0 10px rgba(61,223,255,.85);
}
.j-add::before { width: 28px; height: 3px; }
.j-add::after  { width: 3px;  height: 28px; }
.j-add:active { transform: scale(.94); filter: brightness(1.3); }

.j-file { display: none; }
/* days backed by real data — imported or manually logged — read slightly
   brighter than the Phase-1 sample days */
.j-day.real { box-shadow: inset 0 0 0 1px rgba(61,223,255,.35); }

/* prop firm net P&L — spend vs. payouts, shown under the Prop Firms tab only.
   Separate from account balances by design: a challenge balance is simulated,
   these are real dollars in and out. */
/* PROP FIRM SUMMARY
   One full-width pill under the Live/Prop row carrying the P&L for whatever
   the account dropdown has selected, and nothing else until it is opened. The
   pill borrows the Live/Prop pill's frame; the panel inside borrows the
   account dropdown's, so the two read as the same control. */
.pf-summary { margin: 0 0 16px; }
/* sits directly under the toggle row when the account dropdown is closed */
.j-selector + .pf-summary { margin-top: -8px; }

.pf-pill {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  height: 46px;
  padding: 0 2px;
  border-radius: 999px;
  border-style: solid;
  border-width: 20px 24px;
  border-image: url("../assets/buttons-icon/label-button@2x.png") 40 48 fill / 20px 24px stretch;
  text-align: left;
}
.pf-pill:active { filter: brightness(1.4); transform: scale(.99); }
.pf-pill.open { filter: brightness(1.28) drop-shadow(0 0 10px rgba(61,223,255,.6)); }
.pf-pill-lbl {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: calc(11px * var(--fs));
  font-weight: 800;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: #EAF6FF;
}
.pf-pill-val {
  flex: 0 0 auto;
  font-size: calc(15px * var(--fs));
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.pf-pill-val.pos { color: var(--teal); text-shadow: 0 0 12px rgba(47,230,194,.5); }
.pf-pill-val.neg { color: #FF6B9D; text-shadow: 0 0 12px rgba(255,61,154,.5); }
.pf-pill-caret { flex: 0 0 auto; display: grid; place-items: center; width: 18px; }
.pf-pill-caret img { width: 16px; height: 16px; object-fit: contain; transition: transform .2s ease; }
.pf-pill.open .pf-pill-caret img { transform: rotate(180deg); }

/* the itemised detail, in the account dropdown's frame */
.pf-panel {
  margin: 10px 0 0;
  padding: 10px 6px 8px;
  border-style: solid;
  border-width: 20px 16px;
  border-image: url("../assets/dropdown/panel@2x.png") 150 170 fill / 20px 16px stretch;
}
.pf-panel .mt-label { margin-bottom: 12px; }
.pf-split { display: flex; justify-content: center; gap: 18px; }
.pf-split > span { display: flex; flex-direction: column; gap: 1px; align-items: center; }
.pf-k { font-size: 9.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: #8FB4D8; }
.pf-v { font-size: calc(13px * var(--fs)); font-weight: 800; }
.pf-v.pos { color: var(--teal); }
.pf-v.neg { color: #FF6B9D; }
.pf-empty {
  font-size: calc(12px * var(--fs));
  color: #9FC0E0;
  line-height: 1.45;
  text-align: center;
  padding: 14px 6px 2px;
}

.pf-list { margin-top: 12px; display: flex; flex-direction: column; gap: 7px; }
.pf-item { display: flex; align-items: stretch; gap: 6px; }
.pf-item-main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 11px;
  border-radius: 12px;
  background: rgba(9,13,30,.6);
  border: 1px solid rgba(61,223,255,.2);
  text-align: left;
}
.pf-item-main:active { border-color: var(--cyan); filter: brightness(1.25); }
.pf-item-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pf-item-kind {
  font-size: calc(12px * var(--fs));
  font-weight: 800;
  letter-spacing: .04em;
  color: #EAF6FF;
}
.pf-item-kind.payout { color: var(--teal); }
.pf-item-meta {
  font-size: calc(10px * var(--fs));
  color: #8FB4D8;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pf-item-amt {
  flex: 0 0 auto;
  font-size: calc(12.5px * var(--fs));
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.pf-item-amt.pos { color: var(--teal); }
.pf-item-amt.neg { color: #FF6B9D; }
/* explicit per-entry delete rather than a hidden swipe — the row itself opens
   the entry for editing, so the two actions need to be separately tappable */
.pf-item-del {
  flex: 0 0 auto;
  width: 36px;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: rgba(9,13,30,.6);
  border: 1px solid rgba(61,223,255,.2);
  color: #FF6B9D;
}
.pf-item-del::before { content: "\2715"; font-size: calc(13px * var(--fs)); font-weight: 700; }
.pf-item-del:active { border-color: #FF6B9D; filter: brightness(1.3); transform: scale(.95); }

.pf-form-head {
  font-size: calc(15px * var(--fs));
  font-weight: 800;
  color: #EAF6FF;
  text-shadow: 0 0 12px rgba(61,223,255,.45);
  margin-bottom: 12px;
}
.pf-add {
  display: block;
  width: 100%;
  margin-top: 12px;
  padding: 10px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.4);
  background: rgba(10,16,34,.72);
  font-size: calc(12px * var(--fs));
  font-weight: 700;
  letter-spacing: .04em;
  color: #C7D9EF;
}
.pf-add:active { border-color: var(--cyan); filter: brightness(1.3); }

/* account picker — one row per added account, plus the add button */

/* "Add Trade" label under the + */
.j-add-wrap { display: flex; flex-direction: column; align-items: center; gap: 7px; }
.j-add-label {
  font-size: calc(12px * var(--fs));
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #C7D9EF;
}

.j-cash {
  display: block;
  margin: 14px auto 2px;
  padding: 9px 20px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.4);
  background: rgba(10,16,34,.72);
  font-size: calc(12.5px * var(--fs));
  font-weight: 700;
  letter-spacing: .05em;
  color: #C7D9EF;
}
.j-cash:active { border-color: var(--cyan); filter: brightness(1.3); }
.j-ledger {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  margin-bottom: 6px;
  border-radius: 10px;
  background: rgba(9,13,30,.6);
  border: 1px solid rgba(61,223,255,.18);
  font-size: 12px;
  font-weight: 600;
  color: #C7D9EF;
}
.j-ledger .pos { color: var(--teal); }
.j-ledger .neg { color: #FF6B9D; }

/* selects share the text-input styling */
select.mt-input {
  background-image: linear-gradient(45deg, transparent 50%, #8FB4D8 50%), linear-gradient(135deg, #8FB4D8 50%, transparent 50%);
  background-position: calc(100% - 18px) 20px, calc(100% - 13px) 20px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  color-scheme: dark;
}
.mt-custom.hidden { display: none; }

/* section panels — Total P&L, Net P&L, Recent Trades. Same card treatment as
   the calendar so the three views read as one family. */
.j-panel {
  padding: 14px 12px 12px;
  border-radius: 20px;
  background: rgba(4,7,18,.55);
  border: 1px solid rgba(61,223,255,.22);
}
.j-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.j-panel-title {
  font-size: calc(13.5px * var(--fs));
  font-weight: 700;
  color: #DDEFFF;
}
.j-range {
  height: 30px;
  padding: 0 26px 0 12px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.35);
  background: rgba(9,13,30,.8);
  background-image: linear-gradient(45deg, transparent 50%, #8FB4D8 50%), linear-gradient(135deg, #8FB4D8 50%, transparent 50%);
  background-position: calc(100% - 14px) 13px, calc(100% - 9px) 13px;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  color: #EAF6FF;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  -webkit-appearance: none;
  appearance: none;
  color-scheme: dark;
}
.j-panel-net {
  font-size: calc(26px * var(--fs));
  font-weight: 800;
  text-align: center;
  margin: 8px 0 6px;
}
.j-panel-net.pos { color: var(--teal); text-shadow: 0 0 18px rgba(47,230,194,.55); }
.j-panel-net.neg { color: #FF6B9D; text-shadow: 0 0 18px rgba(255,61,154,.55); }
.j-panel-foot { text-align: center; font-size: 10.5px; color: #8FB4D8; margin-top: 8px; }

.j-chart { display: block; width: 100%; height: 118px; }
.j-chart-zero { stroke: rgba(143,180,216,.35); stroke-width: 1; stroke-dasharray: 3 3; }
.j-chart-empty { text-align: center; font-size: 12px; color: #8FB4D8; padding: 26px 0; }

/* Net P&L: profit left, loss right, trade count centred between them */
.j-net-grid {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 10px 8px;
  align-items: center;
  margin-top: 6px;
}
.j-net-cell { display: flex; flex-direction: column; gap: 2px; }
.j-net-cell.right { text-align: right; }
.j-net-k { font-size: 10px; font-weight: 600; color: #9FC0E0; }
.j-net-v { font-size: calc(15px * var(--fs)); font-weight: 800; }
.j-net-v.pos { color: var(--teal); }
.j-net-v.neg { color: #FF6B9D; }
.j-net-mid {
  grid-row: span 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 12px;
  border-radius: 12px;
  border: 1px solid rgba(61,223,255,.28);
  background: rgba(9,13,30,.6);
}
.j-net-total { font-size: calc(20px * var(--fs)); font-weight: 800; color: #EAF6FF; }

/* Recent Trades table */
.j-viewall {
  font-size: 11.5px;
  font-weight: 700;
  color: var(--cyan);
  text-decoration: underline;
}
.j-tt { margin-top: 10px; }
.j-tt-head, .j-tt-row {
  display: grid;
  grid-template-columns: 40px 1fr 46px 28px 42px 1fr;
  gap: 5px;
  align-items: center;
}
.j-tt-head {
  padding-bottom: 6px;
  margin-bottom: 5px;
  border-bottom: 1px solid rgba(61,223,255,.18);
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: #8FB4D8;
}
.j-tt-row {
  padding: 7px 0;
  border-bottom: 1px solid rgba(61,223,255,.07);
  font-size: 10.5px;
  font-weight: 600;
  color: #D9EAFB;
}
.j-tt-row:last-child { border-bottom: 0; }
.j-tt-row .pos { color: var(--teal); font-weight: 800; }
.j-tt-row .neg { color: #FF6B9D; font-weight: 800; }
.j-tt-sym { font-weight: 700; color: #EAF6FF; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.j-pill {
  display: inline-block;
  padding: 2px 6px;
  border-radius: 999px;
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: .03em;
}
.j-pill.long, .j-pill.win { color: var(--teal); background: rgba(47,230,194,.14); border: 1px solid rgba(47,230,194,.45); }
.j-pill.short, .j-pill.loss { color: #FF6B9D; background: rgba(255,61,154,.14); border: 1px solid rgba(255,61,154,.5); }

/* the four stat circles are the section switcher, now carrying their icons */
.j-stat-btn.on .ci-orb { filter: brightness(1.3) drop-shadow(0 0 10px rgba(61,223,255,.75)); }
.j-stat-btn.on .ci-action-label { color: var(--cyan); }
.ci-orb { display: grid; place-items: center; }
.ci-orb img { width: 56%; height: 56%; object-fit: contain; }
/* half the size they used to render at — the rings were swallowed by them.
   The journal's bottom-bar orbs reuse .ci-orb and now match; their four icons
   were also re-cut to a common mark size, which CSS could not have evened out
   because the difference was internal padding in each file. */
.ci-actions .ci-orb img,
.j-stat-btn .ci-orb img { width: 28%; height: 28%; }

/* four stat placeholders — same frame asset as the check-in category buttons */
.j-stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin: 16px 0 2px; }
.j-stat-btn { display: flex; flex-direction: column; align-items: center; gap: 8px; }

/* ===================== TRADE DAY CHECK-IN ===================== */

/* date/time bar — replaces the progress bar on this screen. Home sits hard
   right with the same padding the other bars give their trailing icon. */
/* the check-in view swaps these in and out, so both bars and both docks
   need a hide rule — this stylesheet has no generic .hidden */
.bar.hidden { display: none; }
.bottom-nav.hidden { display: none; }
.ci-heading {
  text-align: center;
  font-size: calc(19px * var(--fs));
  font-weight: 800;
  color: var(--cyan);
  text-shadow: 0 0 16px rgba(61,223,255,.6);
  margin: 2px 0 18px;
}

/* rows: icon placeholder · title pill · status. One tap target per row so the
   whole thing is hittable; the status circle only ever reports state. */
.ci-list { display: flex; flex-direction: column; gap: 8px; }

/* One component per row, and the bar artwork is the row: a rounded plate
   9-sliced left and right so the corners keep their radius and only the
   middle stretches. The slice is 50 of the artwork's 160px height, so the
   rendered border width has to hold that same ratio against the row height
   or the corners go elliptical.

   The bars arrived with the transparency checkerboard baked into their
   pixels, so they were cut at the neon core; the outer bloom that came off
   with the checker is the shadow below.

   Content does not live in the border box — a 19px inset on each side is a
   lot of a phone's width to give up — so it sits in an absolutely positioned
   layer over the whole row instead.

   Retired but kept in the library: checkin-yes-no-toggle@2x.png (the old
   two-circle row), checkin-row-plate@2x.png and checkin-status-ring@2x.png. */
.ci-row {
  --ci-h: 62px;
  position: relative;
  height: var(--ci-h);
  border-style: solid;
  border-width: 0 calc(var(--ci-h) * 0.3125);   /* 50/160 of the artwork */
  border-image: url("../assets/checkin/row-dim@2x.png") 0 50 fill / 0 calc(var(--ci-h) * 0.3125) stretch;
  filter: drop-shadow(0 0 6px rgba(61,223,255,.16));
}
/* answered: the bar lights up */
.ci-row.on {
  border-image-source: url("../assets/checkin/row-glow@2x.png");
  filter: drop-shadow(0 0 12px rgba(61,223,255,.34));
}
.ci-row-in {
  /* an absolute child is positioned against the padding box, so inset:0 would
     start inside the two 19px borders and hand back a fifth of a phone's
     width. It reaches out over them instead. */
  position: absolute;
  top: 0; bottom: 0;
  left: calc(var(--ci-h) * -0.3125); right: calc(var(--ci-h) * -0.3125);
  display: flex; align-items: center; gap: 6px;
  padding: 0 12px;
}
.ci-num {
  flex: 0 0 auto;
  font-size: calc(11px * var(--fs)); font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
  color: var(--cyan);
  opacity: .85;
}
.ci-ico { flex: 0 0 auto; width: 24px; height: 24px; object-fit: contain; }
.ci-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ci-text b {
  font-size: calc(11.5px * var(--fs)); font-weight: 800;
  line-height: 1.15; color: #EAF6FF;
}
.ci-text small {
  font-size: calc(8.4px * var(--fs)); font-weight: 600;
  line-height: 1.15; color: #8FA9C4;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ci-btns { flex: 0 0 auto; display: flex; gap: 4px; }
.ci-btn {
  width: 28px; height: 28px;
  background: no-repeat 50% 50% / 100% 100%;
  border: 0;
  transition: transform .12s ease;
}
.ci-btn:active { transform: scale(.9); }
.ci-yes { background-image: url("../assets/checkin/btn-yes-off@2x.png"); }
.ci-yes.on { background-image: url("../assets/checkin/btn-yes-on@2x.png"); }
.ci-no { background-image: url("../assets/checkin/btn-no-off@2x.png"); }
.ci-no.on { background-image: url("../assets/checkin/btn-no-on@2x.png"); }
/* Once a row is answered, only the answer stays on screen. Hidden rather
   than faded, so there is nothing invisible left to tap, and the slot is
   kept rather than removed, so the button that stands does not jump
   sideways as its neighbour goes. Tapping it clears the row, which brings
   the other one back — that is how an answer is changed. */
.ci-row.on .ci-btn:not(.on) { visibility: hidden; }

/* the narrowest phones: the row gives the title and its subtext the width
   back out of everything around them */
@media (max-width: 370px) {
  .ci-row-in { gap: 5px; padding: 0 9px; }
  .ci-num { font-size: calc(10px * var(--fs)); }
  .ci-ico { width: 21px; height: 21px; }
  .ci-text b { font-size: calc(10.5px * var(--fs)); }
  .ci-text small { font-size: calc(7.6px * var(--fs)); }
  .ci-btns { gap: 3px; }
  .ci-btn { width: 25px; height: 25px; }
}

/* label-button asset: a plain rounded pill with a gradient border, 9-sliced on
   all four sides so the rounded caps stay crisp and only the middle stretches.
   Shared by Submit and the journal's Personal Account / Prop Firms pills. */
.ci-submit, .j-tabs .home-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 52px;
  padding: 0 6px;
  border-radius: 999px;
  border-style: solid;
  border-width: 22px 26px;
  border-image: url("../assets/buttons-icon/label-button@2x.png") 40 48 fill / 22px 26px stretch;
  background: none;
  box-shadow: none;
  font-size: calc(13.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #EAF6FF;
  opacity: 1;
}
.ci-submit { width: 78%; margin: 16px auto 2px; }
.ci-submit:active, .j-tabs .home-tab:active { filter: brightness(1.3); transform: scale(.98); }

.ci-submit.off { opacity: .4; color: #9FC0E0; cursor: default; }

/* ===================== BEFORE TRADE — STAGE 1 =====================
   Same screen pattern as Start Day: one tap per row, a Submit that stays dead
   until every row is answered, and a summary that replaces the rows in place.
   The rows carry named answers instead of Yes/No, so the title takes the pill
   and the answers sit under it as tap-to-select pills. */
.bt-sub {
  text-align: center;
  font-size: calc(11px * var(--fs));
  font-weight: 800;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: #8FA9C6;
  margin: -12px 0 18px;
}
.bt-list { display: flex; flex-direction: column; gap: 16px; }
.bt-row { display: flex; flex-direction: column; gap: 8px; }

/* the title pill: the same label-button 9-slice Submit and the journal's
   Live/Prop pills use, so the row reads as part of the same family */
.bt-q {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 0 4px;
  border-radius: 999px;
  border-style: solid;
  border-width: 20px 24px;
  border-image: url("../assets/buttons-icon/label-button@2x.png") 40 48 fill / 20px 24px stretch;
  font-size: calc(12.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .04em;
  line-height: 1.15;
  text-align: center;
  color: #EAF6FF;
}

.bt-opts { display: grid; gap: 8px; }
.bt-opts-1 { grid-template-columns: 1fr; }
.bt-opts-2 { grid-template-columns: 1fr 1fr; }
.bt-opts-3 { grid-template-columns: repeat(3, 1fr); }
.bt-opt {
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 7px 8px;
  border-radius: 999px;
  border: 1.5px solid rgba(120,150,180,.32);
  background: rgba(5,9,22,.5);
  font-size: calc(12px * var(--fs));
  font-weight: 700;
  line-height: 1.15;
  text-align: center;
  color: #7D93AC;
}
.bt-opt.on {
  border-color: var(--cyan);
  color: var(--cyan);
  box-shadow: 0 0 14px -3px rgba(61,223,255,.7), inset 0 0 12px -6px rgba(61,223,255,.9);
}
.bt-opt:active { filter: brightness(1.3); transform: scale(.97); }
/* the single-option confirm rows read as ticked once tapped */
.bt-opts-1 .bt-opt.on::before { content: "\2713"; margin-right: 7px; font-weight: 800; }

/* Stage 2's nine strategies. Two columns rather than Stage 1's three: the
   longest of them is "Continuation Pattern", which will not sit on one line at
   a third of a phone's width, and a pill that wraps mid-word reads worse than
   a slightly taller grid. The odd one out spans both columns so the row does
   not end with a gap. */
.bt-opts-2 .bt-opt:nth-child(odd):last-child { grid-column: 1 / -1; }
.bt-row .bt-opts-2 .bt-opt { padding: 7px 6px; }
/* Stage 2's Back sits under the Continue, so it needs the same width and a
   little air rather than the full-bleed margin btn-secondary carries. */
.bt-list ~ .btn-secondary { width: 78%; margin: 10px auto 2px; }

/* the summary that replaces the rows on submit */
.bt-summary {
  width: 100%;
  max-width: 300px;
  margin: 14px 0 2px;
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.bt-sum-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 12px;
  border-radius: 12px;
  background: rgba(9,13,30,.6);
  border: 1px solid rgba(61,223,255,.2);
  text-align: left;
}
.bt-sum-k { font-size: calc(11px * var(--fs)); color: #8FB4D8; }
.bt-sum-v {
  font-size: calc(12px * var(--fs));
  font-weight: 800;
  color: var(--teal);
  text-align: right;
}
.ci-result-title.soon { color: var(--cyan); text-shadow: 0 0 20px rgba(61,223,255,.6); }
/* the secondary shares the primary's pill frame, as every secondary in the
   app does, so it is dimmed here to keep the eye on the forward action */
.ci-result-inline .btn-secondary {
  width: 78%; max-width: 300px; margin-top: 10px;
  filter: brightness(.72) saturate(.85);
}
.ci-result-inline .btn-secondary:active { filter: brightness(1); }

/* four round action placeholders — laid out but inert until specified */
.ci-actions {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin: 18px 0 2px;
}
.ci-action { display: flex; flex-direction: column; align-items: center; gap: 8px; }
/* wraps the orb so it can be tapped; sized exactly like the span it replaces
   so the row's layout is untouched */
.ci-orb-btn { display: block; width: 100%; max-width: 62px; }
.ci-orb-btn:active { transform: scale(.94); filter: brightness(1.3); }
.ci-orb {
  width: 100%;
  max-width: 62px;
  aspect-ratio: 1;
  background: url("../assets/buttons-icon/icon-button-frame@2x.png") center / contain no-repeat;
}
.ci-action-label {
  font-size: calc(10.5px * var(--fs));
  font-weight: 600;
  line-height: 1.2;
  color: #C7D9EF;
  text-align: center;
}

/* dock: even spacing like the main dock, with a prominent centre "+" */
/* compact icons sitting directly in the bar, no circular backgrounds */
.dock-btn { width: 52px; }

/* ===================== WORD-GRID SCREENS ===================== */
/* Individual Financial Markets / Participants: tappable names down the
   centre, each opening a centred detail view with its own narration. */

.grid-list { display: flex; flex-direction: column; gap: 8px; }
/* Height stays at the 44px tap minimum. The reference render fits all 11
   without scrolling, which would need ~26px pills — too small to hit
   reliably — so the list scrolls instead. */
.grid-pill {
  margin-top: 0;
  min-height: 44px;
  padding: 11px 16px;
  font-size: calc(14px * var(--fs));
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: none;
  color: #EAF6FF;
  transition: filter .15s ease, transform .12s ease;
}
.grid-pill:active { filter: brightness(1.35); transform: scale(.98); }

.grid-back {
  display: inline-block;
  margin: 0 0 16px;
  padding: 7px 15px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.35);
  background: rgba(10,16,34,.7);
  color: #C7D9EF;
  font-size: calc(12.5px * var(--fs));
  font-weight: 600;
}
.grid-back:active { border-color: var(--cyan); }

.grid-title {
  text-align: center;
  font-size: calc(21px * var(--fs));
  font-weight: 800;
  line-height: 1.25;
  color: var(--cyan);
  text-shadow: 0 0 16px rgba(61,223,255,.55);
  margin-bottom: 16px;
}
.grid-body { text-align: center; }
.grid-body p {
  font-size: calc(14.5px * var(--fs));
  line-height: 1.62;
  color: #D9EAFB;
}
/* the name is already the title here, so no bold term lead-in */
.grid-body .term strong { font-weight: inherit; color: inherit; }

.grid-play {
  display: block;
  margin: 24px auto 4px;
  width: 66px;
  height: 66px;
  transition: transform .12s ease, filter .15s ease;
}
.grid-play img { width: 100%; height: 100%; object-fit: contain; }
.grid-play:active { transform: scale(.93); filter: brightness(1.3); }

.grid-soon {
  margin: 22px auto 4px;
  text-align: center;
  font-size: calc(12.5px * var(--fs));
  font-weight: 600;
  letter-spacing: .04em;
  color: #8FB4D8;
}

/* ===================== VIDEO LIBRARY ===================== */
/* Every video in the library is vertical (9:16), so thumbnails and the
   player are both portrait. Categories reuse the .deck / .section-row
   pattern from Home; the expanded panel holds video cards. */

.video-panel { padding: 12px 10px; }

.video-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 13px;
  padding: 9px 12px 9px 9px;
  margin-bottom: 10px;
  border-radius: 16px;
  text-align: left;
  background: linear-gradient(180deg, rgba(20,32,64,.55), rgba(7,10,24,.8));
  border: 1px solid rgba(61,223,255,.3);
  transition: border-color .18s ease, transform .12s ease;
}
.video-row:last-child { margin-bottom: 0; }
.video-row:active { border-color: rgba(61,223,255,.85); transform: scale(.985); }
.video-row.watched { opacity: .72; }

/* 9:16 thumbnail. YouTube serves a 16:9 still with the vertical frame
   pillarboxed dead centre, so object-fit:cover on a 9:16 box crops the bars
   off and leaves exactly the portrait frame. The play badge stays visible if
   the image fails (offline), so a card never renders as an empty box. */
.v-thumb {
  position: relative;
  display: block;              /* aspect-ratio is ignored on inline elements */
  flex: 0 0 auto;
  width: 60px;
  aspect-ratio: 9 / 16;
  border-radius: 11px;
  overflow: hidden;
  background: linear-gradient(150deg, rgba(61,223,255,.16), rgba(9,13,30,.9) 60%, rgba(255,61,154,.16));
  border: 1px solid rgba(61,223,255,.28);
}
.v-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.v-play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(5,9,22,.62);
  border: 1.5px solid rgba(61,223,255,.85);
  box-shadow: 0 0 12px rgba(61,223,255,.5);
}
.v-play::after {
  content: "";
  position: absolute;
  inset: 0;
  margin: auto;
  width: 0;
  height: 0;
  border-left: 9px solid #EAF6FF;
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
  transform: translateX(2px);
}

.v-meta { flex: 1 1 auto; min-width: 0; }
.v-title {
  display: block;
  font-size: calc(13.5px * var(--fs));
  font-weight: 600;
  line-height: 1.35;
  color: #EAF6FF;
}
.v-tag {
  display: block;
  margin-top: 4px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--cyan);
}

/* ---- full-screen vertical player ---- */

.vplayer {
  position: absolute;
  inset: 0;
  z-index: 80;                 /* over the bars and dock, under the auth screen */
  display: flex;
  flex-direction: column;
  background: radial-gradient(130% 75% at 50% 0%, #0c1533 0%, #05070f 62%);
  /* the layer fills .app edge to edge, so it reaches under the notch — the
     close/expand bar at the top has to clear it itself */
  padding-top: var(--sat);
  padding-bottom: max(4px, var(--sab));
}
.vplayer.hidden { display: none; }

.vp-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 14px 10px 8px;      /* sits clear of the status bar / dynamic island */
}
/* 52x52 touch target with a 40px visible ring drawn inside it, so the button
   is comfortably hittable without the circle looking oversized */
.vp-close {
  position: relative;
  flex: 0 0 auto;
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
  color: #EAF6FF;
  font-size: 25px;
  line-height: 1;
}
.vp-close::before {
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: 50%;
  border: 1px solid rgba(61,223,255,.4);
  background: rgba(10,16,34,.75);
  transition: border-color .15s ease, transform .12s ease;
}
.vp-close:active::before { border-color: var(--cyan); transform: scale(.92); }
.vp-close span { position: relative; padding-bottom: 3px; }

/* expand-to-fullscreen — only rendered where the Fullscreen API exists */
.vp-expand {
  position: relative;
  flex: 0 0 auto;
  margin-left: auto;
  width: 52px;
  height: 52px;
  display: grid;
  place-items: center;
}
.vp-expand::before {
  content: "";
  position: absolute;
  inset: 6px;
  border-radius: 50%;
  border: 1px solid rgba(61,223,255,.4);
  background: rgba(10,16,34,.75);
  transition: border-color .15s ease, transform .12s ease;
}
.vp-expand:active::before { border-color: var(--cyan); transform: scale(.92); }
/* four corner brackets = the usual "expand" glyph */
.vp-expand span {
  position: relative;
  width: 15px;
  height: 15px;
  border: 2px solid #EAF6FF;
  border-radius: 3px;
  -webkit-mask:
    linear-gradient(#000 0 0) left top / 5px 5px no-repeat,
    linear-gradient(#000 0 0) right top / 5px 5px no-repeat,
    linear-gradient(#000 0 0) left bottom / 5px 5px no-repeat,
    linear-gradient(#000 0 0) right bottom / 5px 5px no-repeat;
  mask:
    linear-gradient(#000 0 0) left top / 5px 5px no-repeat,
    linear-gradient(#000 0 0) right top / 5px 5px no-repeat,
    linear-gradient(#000 0 0) left bottom / 5px 5px no-repeat,
    linear-gradient(#000 0 0) right bottom / 5px 5px no-repeat;
}
.vp-heading { min-width: 0; display: flex; flex-direction: column; }
.vp-cat {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--cyan);
}
.vp-name {
  font-size: calc(14px * var(--fs));
  font-weight: 600;
  color: #EAF6FF;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* the stage gives the video every pixel left over, and the 9:16 ratio is
   held by deriving width from the available height */
.vp-stage {
  flex: 1 1 auto;
  min-height: 0;
  /* flex (not grid) so the frame's height:100% resolves against a definite
     height — in a grid the auto row makes it indefinite and the frame sizes
     off its width instead, overflowing the shelf */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 12px;
}
/* sizing lives on the wrapper; the iframe and the gesture layer fill it */
.vp-video {
  position: relative;
  height: 100%;
  width: auto;
  max-width: 100%;
  aspect-ratio: 9 / 16;
  border-radius: 18px;
  background: #000;
  border: 1px solid rgba(61,223,255,.35);
  box-shadow: 0 0 26px -6px rgba(61,223,255,.5);
}
.vp-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: 18px;
}
/* transparent swipe-capture layer. Cross-origin iframes swallow touch events,
   so this is the only way to read a gesture over the video. It stops 64px
   short of the bottom so YouTube's control bar and scrubber stay directly
   touchable and a swipe can never become a seek. */
.vp-swipe {
  position: absolute;
  inset: 0 0 64px 0;
  z-index: 2;
  background: transparent;
  touch-action: pan-y;
}
/* stood down after a tap, so the next touch reaches YouTube's own controls */
.vp-swipe.yielded { pointer-events: none; }

/* in fullscreen the player owns the whole screen: drop our framing and get
   the capture layer out of the way entirely */
.vp-video:fullscreen,
.vp-video:-webkit-full-screen {
  width: 100%;
  height: 100%;
  max-width: none;
  aspect-ratio: auto;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.vp-video:fullscreen .vp-frame,
.vp-video:-webkit-full-screen .vp-frame { border-radius: 0; }
.vp-video:fullscreen .vp-swipe,
.vp-video:-webkit-full-screen .vp-swipe { display: none; }

/* The fullscreen element is .vp-video, so the bar (and its expand button)
   sit behind it in the top layer and can't be reached — fullscreen needs its
   own way out, inside the element. Kept top-right, clear of YouTube's
   controls along the bottom. */
.vp-fsexit { display: none; }
.vp-video:fullscreen .vp-fsexit,
.vp-video:-webkit-full-screen .vp-fsexit {
  display: grid;
  place-items: center;
  position: absolute;
  top: calc(14px + var(--sat));
  right: 14px;
  z-index: 3;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: 1px solid rgba(61,223,255,.45);
  background: rgba(5,9,22,.72);
  color: #EAF6FF;
  font-size: 17px;
}
.vp-video:fullscreen .vp-fsexit:active,
.vp-video:-webkit-full-screen .vp-fsexit:active { border-color: var(--cyan); transform: scale(.93); }

/* "More in {category}" — a horizontal shelf of smaller 9:16 cards */
.vp-more { flex: 0 0 auto; padding-top: 12px; }
.vp-more-title {
  padding: 0 16px;
  margin-bottom: 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--cyan);
}
.vp-shelf {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
  padding: 0 16px 4px;
  scrollbar-width: none;
}
.vp-shelf::-webkit-scrollbar { display: none; }
.vp-card {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  width: 72px;
  text-align: left;
  scroll-snap-align: start;
}
.vp-card.watched { opacity: .6; }
.vp-card:active { transform: scale(.96); }
.vp-card .v-thumb { width: 100%; }
.vp-card .v-play { width: 22px; height: 22px; }
.vp-card .v-play::after { border-left-width: 7px; border-top-width: 4.5px; border-bottom-width: 4.5px; }
.vp-card .v-title {
  margin-top: 6px;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* short viewports: give the video back the space the shelf would take */
@media (max-height: 720px) {
  .vp-more { padding-top: 8px; }
  .vp-card { width: 58px; }
  .vp-card .v-title { -webkit-line-clamp: 1; font-size: 10px; }
}

/* ===================== TRANSITIONS ===================== */

.slide-in-left  { animation: slideInLeft .28s ease both; }
.slide-in-right { animation: slideInRight .28s ease both; }
@keyframes slideInLeft  { from { opacity: 0; transform: translateX(36px); }  to { opacity: 1; transform: none; } }
@keyframes slideInRight { from { opacity: 0; transform: translateX(-36px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ===================== PICKÆWAY (Reward Battle) ===================== */

/* Four section dots. Lives in the Trade Day Check-In bar, the one bar that
   shows this instead of the date/time. Completed sections use the delivered
   disc; the rest use the same thin outline ring as the profile frame, left to
   right, bracketed by Start and End. */
.streak-row {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
}
/* same weight and colour as the unfilled dot's ring, so the row reads as one
   piece rather than text bolted onto circles */
.streak-cap {
  font-size: calc(10px * var(--fs));
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: rgba(199,236,244,.7);
  white-space: nowrap;
}
/* Pickæway's second bar carries the game name where the streak used to sit */
.pick-name {
  flex: 1 1 auto;
  min-width: 0;
  text-align: center;
  font-size: calc(15px * var(--fs));
  font-weight: 700;
  color: #F2FBFF;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.streak-dot {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1.5px solid rgba(199,236,244,.55);
}
.streak-dot.on {
  border: none;
  background: url("../assets/buttons-icon/streak-filled@2x.png") center / contain no-repeat;
  filter: drop-shadow(0 0 6px rgba(0, 209, 178, .6));
}

/* stat cards: thin gradient-bordered plates, same family as the journal's */
.pk-reward, .pk-stat {
  border-radius: 18px;
  border: 1px solid rgba(61,223,255,.32);
  background: linear-gradient(170deg, rgba(11,18,38,.85), rgba(7,10,24,.85));
  text-align: center;
  padding: 14px 10px;
}
.pk-cap {
  font-size: calc(10.5px * var(--fs));
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #9FC0E0;
  margin-bottom: 6px;
}
.pk-big {
  font-size: calc(40px * var(--fs));
  font-weight: 800;
  color: var(--teal);
  text-shadow: 0 0 20px rgba(47,230,194,.55);
  line-height: 1.05;
}
.pk-note {
  margin-top: 6px;
  font-size: calc(12px * var(--fs));
  color: #C7D9EF;
}
.pk-val {
  font-size: calc(24px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  line-height: 1.1;
}
.pk-val.teal { color: var(--teal); text-shadow: 0 0 16px rgba(47,230,194,.5); }

.pk-row { display: grid; gap: 10px; margin-top: 10px; }
.pk-row-2 { grid-template-columns: 1fr 1fr; }
.pk-row-3 { grid-template-columns: 1fr 1fr 1fr; }
.pk-row-3 .pk-val { font-size: calc(19px * var(--fs)); }
/* the middle card carries the magenta side of the gradient, per the mockup */
.pk-mid { border-color: rgba(255,61,154,.4); }

.pk-actions { text-align: center; margin: 26px 0 4px; }
.pk-replay {
  width: 96px;
  height: 96px;
  margin: 0 auto;              /* a grid button is block-level — text-align won't centre it */
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: url("../assets/buttons-icon/icon-button-frame@2x.png") center / contain no-repeat;
}
/* the artwork carries its own glow, so no drop-shadow on top of it */
.pk-replay img { width: 31px; height: 31px; object-fit: contain; }
.pk-replay:active { transform: scale(.94); filter: brightness(1.3); }
.pk-replay-label {
  margin-top: 8px;
  font-size: calc(17px * var(--fs));
  font-weight: 700;
  color: #F2FBFF;
}
.pk-build {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 16px;
  min-width: 74%;
  height: 52px;
  padding: 0 6px;
  border-radius: 999px;
  border-style: solid;
  border-width: 22px 26px;
  border-image: url("../assets/buttons-icon/label-button@2x.png") 40 48 fill / 22px 26px stretch;
  font-size: calc(15px * var(--fs));
  font-weight: 700;
  color: #EAF6FF;
}
.pk-build:active { filter: brightness(1.3); transform: scale(.98); }
.pk-plus { font-size: calc(20px * var(--fs)); font-weight: 800; }

/* settings: profile photo row */
.set-photo { display: flex; align-items: center; gap: 14px; }
.set-photo-ring {
  flex: 0 0 auto;
  width: 62px;
  height: 62px;
  display: grid;
  place-items: center;
  background: url("../assets/buttons-icon/profile-ring@2x.png") center / contain no-repeat;
}
.set-photo-ring img { width: 28px; height: 28px; object-fit: contain; }
.set-photo-ring img.shot { width: 50px; height: 50px; border-radius: 50%; object-fit: cover; }
.set-photo-btns { display: flex; flex-wrap: wrap; gap: 8px; }

/* ---------------- circular photo crop ---------------- */

.crop-wrap { display: flex; justify-content: center; margin-bottom: 10px; }
.crop-stage {
  position: relative;
  width: 260px;
  height: 260px;
  max-width: 100%;
  overflow: hidden;
  border-radius: 50%;
  background: #05070F;
  touch-action: none;          /* the stage handles its own pan/pinch */
  cursor: grab;
}
.crop-stage:active { cursor: grabbing; }
.crop-stage img {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  max-width: none;             /* the transform sizes it, not the container */
  user-select: none;
  -webkit-user-drag: none;
}
/* the ring frame drawn over the image, matching the profile frame in use */
.crop-mask {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  border: 2px solid rgba(199,236,244,.85);
  box-shadow: 0 0 18px rgba(61,223,255,.45), inset 0 0 22px rgba(5,7,15,.55);
}
.crop-hint {
  text-align: center;
  font-size: calc(12px * var(--fs));
  color: #9FC0E0;
  margin-bottom: 10px;
}
.crop-zoom {
  display: block;
  width: 78%;
  margin: 0 auto 16px;
  accent-color: var(--cyan);
}

/* ---------------- Select Account: inline dropdown ----------------
   Expands between the Live/Prop pills and the calendar, pushing the page
   below it down. Not an overlay: nothing here is fixed, nothing dims or
   blurs what is behind it. */

.ad-panel {
  margin: 0 0 16px;
  padding: 10px 6px 8px;
  border-style: solid;
  /* kept narrow on purpose: the frame is decorative, and every px it takes is
     a px the account rows inside don't get on a 390px phone */
  border-width: 20px 16px;
  border-image: url("../assets/dropdown/panel@2x.png") 150 170 fill / 20px 16px stretch;
}

.ad-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.ad-title {
  font-size: calc(17px * var(--fs));
  font-weight: 800;
  color: #EAF6FF;
  text-shadow: 0 0 12px rgba(61,223,255,.45);
}
.ad-linkall {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: calc(14px * var(--fs));
  font-weight: 700;
  color: #C7D9EF;
}
.ad-linkall:disabled { opacity: .4; }
.ad-linkall:active { filter: brightness(1.3); }
/* the two delivered circle assets are the toggle's two states */
.ad-linkicon {
  width: 30px;
  height: 30px;
  background: url("../assets/dropdown/link-all@2x.png") center / contain no-repeat;
}
.ad-linkall.on .ad-linkicon { background-image: url("../assets/dropdown/unlink-all@2x.png"); }

/* the list scrolls on its own once there are more accounts than fit, so the
   action row underneath stays reachable without scrolling the whole page */
.ad-list {
  display: flex;
  flex-direction: column;
  gap: 9px;
  max-height: 264px;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin-bottom: 12px;
  padding-right: 2px;
}

.ad-row {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 8px;
  border-radius: 16px;
  text-align: left;
  /* gradient ring, drawn in CSS so it stays crisp at any row height */
  border: 1.5px solid transparent;
  background:
    linear-gradient(rgba(8,12,28,.92), rgba(8,12,28,.92)) padding-box,
    linear-gradient(115deg, var(--cyan), var(--grad-mid), var(--magenta)) border-box;
  /* unselected rows sit back at 50%, per the reference */
  opacity: .5;
  transition: opacity .18s ease, box-shadow .2s ease;
}
.ad-row.on {
  opacity: 1;
  box-shadow: 0 0 18px -4px rgba(61,223,255,.7), 0 0 18px -4px rgba(255,61,154,.5);
}
.ad-row:active { filter: brightness(1.25); }

/* logo frame is the delivered asset; the brand mark is a separate layer on
   top of it, never baked in */
.ad-logo {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  background: url("../assets/dropdown/logo-box@2x.png") center / contain no-repeat;
}
.ad-logo img {
  /* The delivered logos run from 0.61 to 2.03 aspect, so anything that fills
     the square would visibly squash the wide ones. Bounding both axes and
     leaving width/height auto lets each mark keep its own proportions and
     sit centred with even padding, whatever shape it is. */
  /* px, not %: a percentage max-height resolves against an indefinite grid
     row here and gets dropped, which let the tall marks overshoot the box */
  max-width: 28px;
  max-height: 28px;
  width: auto;
  height: auto;
  object-fit: contain;
}
.ad-logo-txt { font-size: calc(15px * var(--fs)); font-weight: 800; color: var(--cyan); }

.ad-id { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ad-name {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-size: calc(13.5px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
}
.ad-nametext { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ad-current {
  flex: 0 0 auto;
  padding: 2px 6px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.55);
  background: rgba(61,223,255,.14);
  font-size: 8.5px;
  font-weight: 700;
  color: var(--cyan);
}
.ad-kind { font-size: calc(11px * var(--fs)); color: #9FC0E0; white-space: nowrap; }
.ad-bal {
  flex: 0 0 auto;
  font-size: calc(14px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  white-space: nowrap;
}
/* the two delivered indicator assets */
.ad-check {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  background: url("../assets/dropdown/check-off@2x.png") center / contain no-repeat;
}
.ad-row.on .ad-check { background-image: url("../assets/dropdown/check-on@2x.png"); }

.ad-go { flex: 0 0 auto; font-size: calc(12px * var(--fs)); font-weight: 800; color: var(--cyan); }
.ad-go.danger { color: #FF6B9D; }
.ad-row[data-jeditacct], .ad-row[data-jdelacct] { opacity: 1; }

/* four icon-only buttons, each its own delivered asset — no text labels */
.ad-actions { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.ad-act {
  height: 46px;
  border-radius: 12px;
  background: center / contain no-repeat;
}
.ad-act-add    { background-image: url("../assets/dropdown/btn-add@2x.png"); }
.ad-act-edit   { background-image: url("../assets/dropdown/btn-edit@2x.png"); }
.ad-act-del    { background-image: url("../assets/dropdown/btn-delete@2x.png"); }
.ad-act-close  { background-image: url("../assets/dropdown/btn-close@2x.png"); }
.ad-act.off { opacity: .35; }
.ad-act:active { filter: brightness(1.3); transform: scale(.96); }

.ad-note {
  font-size: calc(12px * var(--fs));
  line-height: 1.5;
  color: #8FB4D8;
  margin-bottom: 12px;
}
.ad-empty {
  padding: 16px 8px;
  text-align: center;
  font-size: calc(13px * var(--fs));
  color: #9FC0E0;
}
.ad-confirm {
  font-size: calc(13.5px * var(--fs));
  line-height: 1.55;
  color: #D9EAFB;
  margin-bottom: 14px;
}
.ad-panel .mt-label { margin-bottom: 12px; }
.ad-save, .ad-back, .ad-danger {
  display: block;
  width: 100%;
  margin-top: 10px;
  padding: 12px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.4);
  background: rgba(10,16,34,.7);
  font-size: calc(14px * var(--fs));
  font-weight: 800;
  letter-spacing: .05em;
  color: #EAF6FF;
}
.ad-back { border-color: rgba(120,150,180,.35); color: #9FC0E0; font-weight: 700; }
.ad-danger { border-color: rgba(255,61,154,.5); color: #FF6B9D; }
.ad-save:active, .ad-back:active, .ad-danger:active { filter: brightness(1.3); transform: scale(.98); }

/* the chevron flips when its panel is open */
.j-drop.open img { transform: rotate(180deg); }
.j-drop img { transition: transform .2s ease; }

@media (max-width: 370px) {
  /* claw back frame and padding rather than adding to it — every px here is
     name width, and three names ellipsed at 360px without this */
  .ad-panel { padding: 8px 2px 6px; border-width: 18px 12px; border-image-width: 18px 12px; }
  .pf-panel { padding: 8px 2px 6px; border-width: 18px 12px; border-image-width: 18px 12px; }
  .pf-split { gap: 12px; }
  .pf-item-main { padding: 7px 8px; }
  .pf-item-del { width: 32px; }
  .ad-row { gap: 7px; padding: 7px 6px; }
  .ad-logo { width: 36px; height: 36px; }
  .ad-logo img { max-width: 24px; max-height: 24px; }
  .ad-name { font-size: calc(13px * var(--fs)); }
  .ad-bal { font-size: calc(13px * var(--fs)); }
  .ad-check { width: 23px; height: 23px; }
  .ad-current { padding: 2px 5px; font-size: 8px; }
  .ad-actions { gap: 6px; }
}

/* ===================== BUILD MATCH ===================== */

/* the two stat cards: duration reads warm, bank roll cyan, per the mockup */
.bm-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px; }
.bm-stat {
  padding: 10px 8px 12px;
  border-radius: 16px;
  border: 1px solid rgba(61,223,255,.4);
  background: rgba(5,9,22,.55);
  text-align: center;
}
.bm-stat-dur { border-color: rgba(255,110,60,.55); }
.bm-cap {
  font-size: calc(10px * var(--fs));
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--cyan);
  margin-bottom: 5px;
}
.bm-stat-dur .bm-cap { color: #FF8A4C; }
.bm-val {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: calc(21px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  font-variant-numeric: tabular-nums;
}
.bm-bankicon { display: inline-flex; width: 24px; color: var(--cyan); }
.bm-bankicon svg { width: 100%; height: auto; }

.bm-reward { display: flex; justify-content: center; margin-bottom: 16px; }
.bm-reward-tag {
  padding: 6px 20px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.55);
  background: rgba(61,223,255,.08);
  font-size: calc(11px * var(--fs));
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--cyan);
}

.bm-label {
  font-size: calc(10.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #8FA9C6;
  margin: 0 0 8px 2px;
}

.bm-row { display: grid; gap: 8px; margin-bottom: 16px; }
.bm-row-4 { grid-template-columns: repeat(4, 1fr); }
.bm-row-5 { grid-template-columns: repeat(5, 1fr); }

/* instruments stay circular; everything else is the rounded-rect system */
.bm-circle {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1.5px solid rgba(120,150,180,.35);
  background: rgba(5,9,22,.5);
  font-size: calc(15px * var(--fs));
  font-weight: 700;
  color: #7D93AC;
}
.bm-circle.on {
  border-color: var(--cyan);
  color: var(--cyan);
  box-shadow: 0 0 14px -2px rgba(61,223,255,.7), inset 0 0 12px -6px rgba(61,223,255,.9);
}
.bm-circle:active, .bm-rect:active { filter: brightness(1.3); transform: scale(.96); }

.bm-rect {
  min-height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 4px;
  border-radius: 12px;
  border: 1.5px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  font-size: calc(13px * var(--fs));
  font-weight: 700;
  color: #7D93AC;
  white-space: nowrap;
}
.bm-rect.on {
  border-color: var(--cyan);
  color: var(--cyan);
  box-shadow: 0 0 14px -3px rgba(61,223,255,.65);
}

/* difficulty: two buttons with the shared "to react" label between them */
.bm-diff { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; margin-bottom: 14px; }
.bm-diff-btn { min-height: 54px; justify-content: space-between; padding: 8px 14px; }
.bm-diff-name { font-size: calc(15px * var(--fs)); font-weight: 800; }
.bm-diff-secs { font-size: calc(14px * var(--fs)); font-weight: 700; }
.bm-diff-mid {
  font-size: calc(10px * var(--fs));
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #7D93AC;
  text-align: center;
}
/* hard reads warm when chosen, matching the duration card */
.bm-diff-btn.hard.on { border-color: #FF6B3D; color: #FF8A4C; box-shadow: 0 0 14px -3px rgba(255,107,61,.6); }

.bm-rule { height: 1px; background: rgba(120,150,180,.22); margin: 4px 0 16px; }

/* MATCH OVERVIEW — rounded rectangles, not circles, using the delivered neon
   frame as a 9-slice so the corners stay crisp while the middle stretches */
.bm-overview { display: grid; grid-template-columns: repeat(6, 1fr); gap: 5px; margin-bottom: 20px; }
.bm-badge { display: flex; flex-direction: column; align-items: center; gap: 5px; min-width: 0; }
/* circular, using the round button frame already used app-wide for the
   Start Day orbs and Match Replay — the glowing blue-to-pink ring */
.bm-badge-box {
  width: 100%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  background: url("../assets/buttons-icon/icon-button-frame@2x.png") center / contain no-repeat;
}
.bm-badge-val {
  font-size: calc(12px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  text-align: center;
  line-height: 1.05;
}
.bm-badge-lbl {
  font-size: calc(8.5px * var(--fs));
  font-weight: 600;
  line-height: 1.15;
  color: #9FC0E0;
  text-align: center;
}

/* full-width CTA using the delivered pill asset */
.bm-start {
  /* A 9-slice of a 420x124 pill sliced "53 60", so the frame only renders
     undistorted while the border-width keeps the source's own proportions:
     each cap is 53/124 = .427 of the rendered height, and each corner is
     60/53 = 1.13x as wide as it is tall. Both follow --pill-h, so a shorter
     button stays the same shape — a fixed 26px cap in a 46px button overflows
     the box, the browser squashes the frame to fit, and the two rounded ends
     meet with no straight midsection between them. */
  --pill-h: 62px;
  --pill-cap: calc(var(--pill-h) * .427);
  --pill-side: calc(var(--pill-h) * .484);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: var(--pill-h);
  margin-bottom: 10px;
  border-style: solid;
  border-width: var(--pill-cap) var(--pill-side);
  border-image: url("../assets/buttons-pill/button-start-match@2x.png") 53 60 fill / var(--pill-cap) var(--pill-side) stretch;
  font-size: calc(17px * var(--fs));
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #FFFFFF;
}
.bm-start:active { filter: brightness(1.3); transform: scale(.985); }
.bm-note {
  text-align: center;
  font-size: calc(11.5px * var(--fs));
  color: #8FA9C6;
  margin-bottom: 4px;
}

/* narrow phones: six badges across is the tightest row on the screen */
@media (max-width: 370px) {
  .bm-overview { gap: 4px; }
  .bm-badge-box { /* stays circular; aspect-ratio handles the narrow case */ }
  .bm-badge-val { font-size: calc(11px * var(--fs)); }
  .bm-badge-lbl { font-size: calc(8px * var(--fs)); }
  .bm-rect { font-size: calc(12px * var(--fs)); }
}

/* ===================== PROFILE SCREEN =====================
   View mode renders what another trader would see; edit mode swaps the same
   sections for their fields. Reuses the app's form and pill vocabulary rather
   than introducing a third one. */
.pr-head { text-align: center; margin-bottom: 20px; }
.pr-photo {
  position: relative;
  display: block;
  width: 104px;
  height: 104px;
  margin: 2px auto 20px;
  border-radius: 50%;
  background: url("../assets/buttons-icon/profile-ring@2x.png") center / contain no-repeat;
}
.pr-photo img {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 70%;
  height: 70%;
  transform: translate(-50%, -50%);
  object-fit: contain;
}
.pr-photo img.shot { border-radius: 50%; object-fit: cover; }
/* clears the gradient ring's lower stroke, which is thicker than the plain
   ring this badge was first placed against */
.pr-photo-edit {
  position: absolute;
  left: 50%;
  bottom: -9px;
  transform: translateX(-50%);
  padding: 2px 12px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.5);
  background: rgba(5,9,22,.9);
  font-size: calc(9px * var(--fs));
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--cyan);
}
.pr-photo:active { transform: scale(.97); filter: brightness(1.2); }
.pr-name {
  font-size: calc(21px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  line-height: 1.2;
}
.pr-user {
  font-size: calc(13px * var(--fs));
  font-weight: 700;
  color: var(--cyan);
  margin-top: 2px;
}
.pr-loc {
  font-size: calc(11.5px * var(--fs));
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: #8FA9C6;
  margin-top: 4px;
}
.pr-bio {
  font-size: calc(13px * var(--fs));
  line-height: 1.5;
  color: #D9EAFB;
  margin: 10px auto 0;
  max-width: 300px;
}

.pr-sec { margin-bottom: 22px; }
.pr-sec-head {
  font-size: calc(10.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #8FA9C6;
  margin: 0 0 10px 2px;
}
.pr-sec-note {
  font-size: calc(11px * var(--fs));
  line-height: 1.45;
  color: #8FB4D8;
  margin: -4px 0 10px 2px;
}
.pr-empty {
  font-size: calc(12px * var(--fs));
  color: #7D93AC;
  padding: 4px 2px;
}
.pr-opt {
  font-size: calc(9.5px * var(--fs));
  font-weight: 600;
  letter-spacing: .06em;
  color: #6E86A0;
  text-transform: none;
}

/* picked markets, as tags */
.pr-tags { display: flex; flex-wrap: wrap; gap: 7px; }
.pr-tag {
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.5);
  background: rgba(61,223,255,.08);
  font-size: calc(11.5px * var(--fs));
  font-weight: 700;
  color: var(--cyan);
}
.pr-checks { display: flex; flex-wrap: wrap; gap: 8px; }
.pr-checks .bt-opt { flex: 1 1 auto; min-width: 30%; min-height: 42px; padding: 8px 12px; }

.pr-facts { display: flex; flex-direction: column; gap: 7px; }
.pr-fact {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 13px;
  border-radius: 12px;
  background: rgba(9,13,30,.6);
  border: 1px solid rgba(61,223,255,.2);
}
.pr-fact span { font-size: calc(11.5px * var(--fs)); color: #8FB4D8; }
.pr-fact b {
  font-size: calc(14px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  font-variant-numeric: tabular-nums;
}

.pr-links { display: flex; flex-direction: column; gap: 7px; }
.pr-link {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 13px;
  border-radius: 12px;
  background: rgba(9,13,30,.6);
  border: 1px solid rgba(61,223,255,.2);
  text-decoration: none;
}
a.pr-link:active { border-color: var(--cyan); filter: brightness(1.25); }
.pr-link-k {
  flex: 0 0 auto;
  font-size: calc(11px * var(--fs));
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #8FB4D8;
}
.pr-link-v {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: calc(12.5px * var(--fs));
  font-weight: 700;
  color: var(--cyan);
  text-align: right;
}

/* the two blocks nobody else would see */
.pr-owner { border-top: 1px solid rgba(120,150,180,.22); padding-top: 16px; }
.pr-owner-note {
  font-size: calc(10px * var(--fs));
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #6E86A0;
  text-align: center;
  margin-bottom: 12px;
}

.pr-connect { margin-top: 22px; text-align: center; }
.pr-connect .pr-sec-head { text-align: left; }
.pr-code-cap {
  font-size: calc(10px * var(--fs));
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #8FB4D8;
}
.pr-code {
  font-size: calc(30px * var(--fs));
  font-weight: 800;
  letter-spacing: .1em;
  color: var(--teal);
  text-shadow: 0 0 20px rgba(47,230,194,.6);
  font-variant-numeric: tabular-nums;
  margin: 4px 0 12px;
  user-select: all;
  -webkit-user-select: all;
}
.pr-code-btn {
  display: block;
  width: 78%;
  max-width: 300px;
  margin: 0 auto 20px;
  padding: 11px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.45);
  background: rgba(10,16,34,.72);
  font-size: calc(12.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #C7D9EF;
}
.pr-code-btn:active { border-color: var(--cyan); filter: brightness(1.3); transform: scale(.98); }
.pr-code-sub {
  font-size: calc(12px * var(--fs));
  line-height: 1.45;
  color: #9FC0E0;
  margin-bottom: 10px;
}
.pr-code-input { text-align: center; letter-spacing: .16em; text-transform: uppercase; }
.pr-notice {
  margin-top: 12px;
  padding: 9px 12px;
  border-radius: 10px;
  font-size: calc(11.5px * var(--fs));
  line-height: 1.4;
  border: 1px solid;
}
.pr-notice.ok { color: var(--teal); border-color: rgba(47,230,194,.45); background: rgba(47,230,194,.07); }
.pr-notice.warn { color: #FFC46B; border-color: rgba(255,196,107,.4); background: rgba(255,196,107,.07); }
.pr-notice.err { color: #FF6B9D; border-color: rgba(255,61,154,.45); background: rgba(255,61,154,.07); }

.pr-sent-head {
  margin: 18px 0 8px;
  font-size: calc(10px * var(--fs));
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #8FA9C6;
  text-align: left;
}
.pr-sent {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 13px;
  margin-bottom: 6px;
  border-radius: 12px;
  background: rgba(9,13,30,.6);
  border: 1px solid rgba(61,223,255,.2);
  font-size: calc(12px * var(--fs));
  font-weight: 700;
  color: #EAF6FF;
  letter-spacing: .06em;
}
.pr-sent-state {
  font-size: calc(10px * var(--fs));
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #FFC46B;
}
/* says plainly that this half of the screen is scaffolding */
.pr-stub {
  margin-top: 14px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px dashed rgba(120,150,180,.4);
  font-size: calc(10.5px * var(--fs));
  line-height: 1.45;
  color: #7D93AC;
  text-align: left;
}

/* bio: a textarea in the app's input skin, with the count under its corner */
.pr-bio-input {
  height: auto;
  min-height: 82px;
  padding: 11px 14px;
  line-height: 1.45;
  resize: none;
}
.pr-count {
  display: block;
  margin-top: 5px;
  text-align: right;
  font-size: calc(10.5px * var(--fs));
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: none;
  color: #6E86A0;
}
.pr-count.low { color: #FFC46B; }

@media (max-width: 370px) {
  .pr-code { font-size: calc(26px * var(--fs)); }
  .pr-checks .bt-opt { min-width: 46%; }
}

/* ===================== JOURNAL DAY VIEW =====================
   Opens in place of the calendar when a day is tapped. Reuses the prop-firm
   list's item plate so a trade row reads the same wherever it appears. */
.jd { margin-bottom: 16px; }
.jd-head { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.jd-back {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(61,223,255,.35);
  background: rgba(10,16,34,.72);
  font-size: calc(20px * var(--fs));
  line-height: 1;
  color: #C7D9EF;
}
.jd-back:active { border-color: var(--cyan); filter: brightness(1.3); transform: scale(.94); }
.jd-title { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.jd-date {
  font-size: calc(13.5px * var(--fs));
  font-weight: 800;
  color: #EAF6FF;
}
.jd-total {
  font-size: calc(16px * var(--fs));
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.jd-total.pos { color: var(--teal); }
.jd-total.neg { color: #FF6B9D; }

.jd-sec { margin-bottom: 16px; }
.jd-sec-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 7px;
  font-size: calc(11px * var(--fs));
  font-weight: 800;
  letter-spacing: .08em;
  color: #C7D9EF;
}
/* says at a glance where a row came from, which is why one is editable and
   the other is not */
.jd-tag {
  flex: 0 0 auto;
  padding: 3px 9px;
  border-radius: 999px;
  font-size: calc(9px * var(--fs));
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.jd-tag.manual { color: var(--teal); border: 1px solid rgba(47,230,194,.5); background: rgba(47,230,194,.08); }
.jd-tag.imported { color: var(--cyan); border: 1px solid rgba(61,223,255,.5); background: rgba(61,223,255,.08); }
.jd-batch-meta {
  font-size: calc(10px * var(--fs));
  line-height: 1.45;
  color: #8FB4D8;
  margin-bottom: 8px;
}
/* imported rows are plates, not buttons — nothing to tap into */
.pf-item-main.jd-static { cursor: default; }
.jd-sec .pf-item { margin-bottom: 7px; }
.jd-batch-acts { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px; }
.jd-act {
  min-height: 40px;
  padding: 8px 6px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.4);
  background: rgba(10,16,34,.72);
  font-size: calc(11px * var(--fs));
  font-weight: 700;
  line-height: 1.2;
  color: #C7D9EF;
}
.jd-act.danger { border-color: rgba(255,61,154,.45); color: #FF6B9D; }
.jd-act:active { filter: brightness(1.3); transform: scale(.97); }

/* the calendar's day cells are buttons now, so the button reset has to not
   flatten them */
.j-day { font-family: inherit; text-align: inherit; }

/* ===================== MATCH ENGINE =====================
   Live battle, match result and match replay. Same panel/chip/pill vocabulary
   as Build Match — nothing here opens over the top of anything else. */

.mk-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}
.mk-round {
  font-size: calc(15px * var(--fs));
  font-weight: 800;
  letter-spacing: .06em;
  color: #F2FBFF;
}
.mk-meta {
  font-size: calc(10.5px * var(--fs));
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #8FA9C6;
}

/* the two bankrolls, split by a VS */
.mk-score {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
}
.mk-side {
  padding: 9px 8px 10px;
  border-radius: 16px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.55);
  text-align: center;
}
.mk-side.you { border-color: rgba(47,230,194,.5); }
.mk-side.opp { border-color: rgba(255,107,61,.45); }
.mk-side-cap {
  font-size: calc(9.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #8FA9C6;
}
.mk-side.you .mk-side-cap { color: var(--teal); }
.mk-side.opp .mk-side-cap { color: #FF8A4C; }
.mk-side-pts {
  font-size: calc(22px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}
.mk-side-bank {
  font-size: calc(11px * var(--fs));
  font-weight: 700;
  color: #9FC0E0;
  font-variant-numeric: tabular-nums;
}
.mk-vs {
  font-size: calc(11px * var(--fs));
  font-weight: 800;
  letter-spacing: .1em;
  color: #6E86A0;
}

.mk-chart-wrap {
  border-radius: 14px;
  border: 1px solid rgba(120,150,180,.28);
  background: rgba(5,9,22,.6);
  overflow: hidden;
  margin-bottom: 10px;
}
.mk-chart { display: block; width: 100%; height: 200px; }

.mk-clock-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 6px;
}
.mk-phase {
  font-size: calc(10.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #8FA9C6;
}
.mk-phase.reacting { color: var(--teal); }
.mk-phase.closing { color: var(--cyan); }
.mk-phase.resolved { color: #FF8A4C; }
.mk-clock {
  font-size: calc(19px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  font-variant-numeric: tabular-nums;
}
.mk-clock-bar {
  height: 4px;
  border-radius: 999px;
  background: rgba(120,150,180,.2);
  overflow: hidden;
  margin-bottom: 16px;
}
.mk-clock-bar > span {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--teal), var(--cyan));
}

/* green / red call buttons */
.mk-calls { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 16px; }
.mk-call {
  min-height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border-radius: 16px;
  border: 1.5px solid;
  font-size: calc(16px * var(--fs));
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  background: rgba(5,9,22,.5);
}
.mk-call span { font-size: calc(18px * var(--fs)); }
.mk-call.green { border-color: rgba(47,230,194,.6); color: var(--teal); }
.mk-call.red { border-color: rgba(255,107,61,.6); color: #FF8A4C; }
.mk-call.green:active { background: rgba(47,230,194,.16); filter: brightness(1.25); }
.mk-call.red:active { background: rgba(255,107,61,.16); filter: brightness(1.25); }

.mk-row { display: grid; gap: 6px; margin-bottom: 16px; }
.mk-row-4 { grid-template-columns: repeat(4, 1fr); }
.mk-row-6 { grid-template-columns: repeat(6, 1fr); }
.mk-chip {
  min-height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px 2px;
  border-radius: 10px;
  border: 1.5px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  font-size: calc(12px * var(--fs));
  font-weight: 700;
  color: #7D93AC;
  white-space: nowrap;
}
.mk-chip.on {
  border-color: var(--cyan);
  color: var(--cyan);
  box-shadow: 0 0 14px -3px rgba(61,223,255,.65);
}
.mk-chip:active { filter: brightness(1.3); transform: scale(.96); }

/* what replaces the controls once you've committed, or the round is over */
.mk-waiting, .mk-resolved {
  border-radius: 16px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.55);
  padding: 14px 14px 15px;
  text-align: center;
  margin-bottom: 4px;
}
.mk-waiting.locked { border-color: rgba(61,223,255,.5); }
.mk-resolved.win { border-color: rgba(47,230,194,.6); }
.mk-resolved.loss { border-color: rgba(255,107,61,.6); }
.mk-waiting-head, .mk-resolved-head {
  font-size: calc(16px * var(--fs));
  font-weight: 800;
  letter-spacing: .06em;
  color: #F2FBFF;
  margin-bottom: 4px;
}
.mk-resolved.win .mk-resolved-head { color: var(--teal); }
.mk-resolved.loss .mk-resolved-head { color: #FF8A4C; }
.mk-resolved.miss .mk-resolved-head { color: #8FA9C6; }
.mk-waiting-sub, .mk-resolved-sub {
  font-size: calc(11.5px * var(--fs));
  color: #9FC0E0;
  line-height: 1.4;
}

/* result banner */
.mk-result {
  border-radius: 18px;
  border: 1px solid rgba(120,150,180,.35);
  background: rgba(5,9,22,.6);
  padding: 16px 14px 18px;
  text-align: center;
  margin-bottom: 12px;
}
.mk-result.player { border-color: rgba(47,230,194,.6); box-shadow: 0 0 26px -12px rgba(47,230,194,.8); }
.mk-result.opponent { border-color: rgba(255,107,61,.55); }
.mk-result-cap {
  font-size: calc(10px * var(--fs));
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #8FA9C6;
}
.mk-result-head {
  font-size: calc(26px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  margin: 2px 0 6px;
}
.mk-result.player .mk-result-head { color: var(--teal); }
.mk-result.opponent .mk-result-head { color: #FF8A4C; }
.mk-result-score {
  font-size: calc(30px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.mk-result-score em { color: #6E86A0; font-style: normal; margin: 0 6px; }
.mk-result-sub {
  font-size: calc(10px * var(--fs));
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #8FA9C6;
}

.mk-secondary {
  display: block;
  width: 100%;
  min-height: 48px;
  margin-bottom: 10px;
  border-radius: 14px;
  border: 1.5px solid rgba(120,150,180,.35);
  background: rgba(5,9,22,.5);
  font-size: calc(14px * var(--fs));
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #C7DCF0;
}
.mk-secondary:active { filter: brightness(1.3); transform: scale(.985); }

/* ---- round history ---- */
.rt { margin-top: 16px; margin-bottom: 16px; }
.rt-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 10px;
  margin-bottom: 7px;
  background: none;
  text-align: left;
}
.rt-title {
  font-size: calc(10px * var(--fs));
  font-weight: 800;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #8FA9C6;
}
.rt-title em { color: var(--teal); font-style: normal; }
.rt-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  border-radius: 8px;
  border: 1px solid rgba(120,150,180,.3);
  font-size: calc(10px * var(--fs));
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--teal);
  white-space: nowrap;
}
.rt-caret { display: inline-block; transition: transform .2s ease; }
.rt-caret.up { transform: rotate(180deg); }
.rt-body {
  border-radius: 12px;
  border: 1px solid rgba(120,150,180,.28);
  background: rgba(5,9,22,.55);
  overflow: hidden;
}
.rt-cols {
  display: grid;
  grid-template-columns: 1fr 1.4fr 1fr;
  border-bottom: 1px solid rgba(120,150,180,.2);
  font-size: calc(9.5px * var(--fs));
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-align: center;
}
.rt-cols span { padding: 6px 2px; }
.rt-you { color: var(--teal); }
.rt-opp { color: #FF8A4C; }
.rt-mid { color: #8FA9C6; }
.rt-row + .rt-row { border-top: 1px solid rgba(120,150,180,.14); }
.rt-grid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1.4fr 1.4fr 1.4fr 1fr 1fr 1fr;
  align-items: center;
  padding: 8px 2px 2px;
}
.rt-cell {
  text-align: center;
  font-size: calc(10px * var(--fs));
  font-weight: 700;
  color: #8FA9C6;
  font-variant-numeric: tabular-nums;
}
.rt-cell.g { color: var(--teal); }
.rt-cell.r { color: #FF8A4C; }
.rt-cell.n { color: #6E86A0; }
.rt-cell.fast { color: var(--cyan); }
.rt-up { color: var(--teal); }
.rt-dn { color: #FF6B3D; }
.rt-miss { color: #6E86A0; font-size: calc(9px * var(--fs)); font-weight: 800; }
.rt-pts {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 2px 10px 7px;
  font-size: calc(9px * var(--fs));
  font-weight: 700;
  color: #6E86A0;
}
.rt-pts .on { color: var(--cyan); }
.rt-no { color: #6E86A0; font-weight: 600; }
.rt-tot {
  display: grid;
  grid-template-columns: 1fr 1.4fr 1fr;
  align-items: center;
  text-align: center;
  border-top: 1px solid rgba(120,150,180,.2);
  background: rgba(0,0,0,.28);
  font-size: calc(10px * var(--fs));
  font-weight: 800;
  color: #8FA9C6;
  font-variant-numeric: tabular-nums;
}
.rt-tot span { padding: 6px 3px; }
.rt-tot .on { color: var(--cyan); }
.rt-tot.big { font-size: calc(11.5px * var(--fs)); }
.rt-tot .rt-no {
  font-size: calc(9px * var(--fs));
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* ---- match replay ---- */
.rv-tfs { margin-bottom: 12px; }
.rv-stage { display: flex; gap: 8px; align-items: stretch; margin-bottom: 6px; }
.rv-scroll {
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-radius: 12px;
  border: 1px solid rgba(120,150,180,.28);
  background: rgba(5,9,22,.6);
}
.rv-chart { display: block; height: 220px; }
.rv-zoom {
  position: relative;
  flex: 0 0 12px;
  width: 12px;
  border-radius: 999px;
  background: rgba(120,150,180,.18);
  touch-action: none;
  cursor: grab;
}
.rv-thumb {
  position: absolute;
  left: 0;
  width: 12px;
  height: 44px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--teal), var(--cyan));
  transition: top .18s ease;
}
.rv-zoom-lbl {
  text-align: right;
  font-size: calc(9.5px * var(--fs));
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: #6E86A0;
  margin-bottom: 10px;
}
.rv-hint {
  font-size: calc(11px * var(--fs));
  color: #8FA9C6;
  text-align: center;
  padding: 10px 6px;
  line-height: 1.45;
}
.rv-detail {
  border-radius: 14px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.55);
  padding: 12px 13px 13px;
}
.rv-detail.g { border-color: rgba(47,230,194,.55); }
.rv-detail.r { border-color: rgba(255,107,61,.5); }
.rv-detail-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  font-size: calc(12px * var(--fs));
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #C7DCF0;
  margin-bottom: 9px;
}
.rv-detail.g .rv-detail-res { color: var(--teal); }
.rv-detail.r .rv-detail-res { color: #FF8A4C; }
.rv-detail.n .rv-detail-res { color: #8FA9C6; }
.rv-detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 5px 14px; }
.rv-detail-grid > div { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.rv-detail-grid span { font-size: calc(10.5px * var(--fs)); color: #8FA9C6; }
.rv-detail-grid b {
  font-size: calc(11.5px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  font-variant-numeric: tabular-nums;
}
.rv-detail-grid b.g { color: var(--teal); }
.rv-detail-grid b.r { color: #FF8A4C; }

@media (max-width: 370px) {
  .streak-row { gap: 7px; }
  .streak-cap { font-size: calc(9px * var(--fs)); letter-spacing: .06em; }
  .streak-dot { width: 16px; height: 16px; }
  .bt-opts { gap: 6px; }
  .bt-opt { font-size: calc(11px * var(--fs)); padding: 6px 4px; }
  .bt-q { font-size: calc(11.5px * var(--fs)); }
  .mk-chip { font-size: calc(11px * var(--fs)); }
  .rt-cell { font-size: calc(9px * var(--fs)); }
}

/* ===================== DESKTOP WEB LAYOUT (phase 1) =====================
   Everything below is scoped to >=1200px. Nothing here applies to the mobile
   PWA, which keeps its single-column, single-video-header layout untouched. */

.dt-shell { display: none; }

/* Sound toggle for the hero video: directly above the gear, sharing its column
   — the bar insets its own icons by margin 4% plus padding 14px, so the two
   line up at any width. Anchored to the BOTTOM of the header rather than the
   top: up by the status bar it needed a strip of its own, which is exactly the
   dead space the cropped header just gave back. Held at half opacity so it
   reads as a control on the footage rather than a button over it. The
   delivered assets are bare glyphs, so the element carries no frame. */
.hdr-mute {
  position: absolute;
  /* the header carries the 4% itself now that it is an inset card, so the
     glyph takes the bar's own 14px padding and lands in the same column as
     the gear in the bar below it */
  right: 14px;
  bottom: 6px;
  z-index: 3;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  opacity: .5;
}
/* Same cut as the card's action icons: the glyph comes down to the scale the
   Journal and Check-In screens use, while the 34px box — and so the tap target
   — stays where it was. Opacity is untouched. */
.hdr-mute img { width: 24px; height: 24px; object-fit: contain; display: block; }
.hdr-mute:active { opacity: .85; transform: scale(.92); }
/* The hamburger, mirrored across the header from the speaker: the same box,
   the same inset, the same weight. It reads as the pair's other half rather
   than as something dropped into the corner. */
.hdr-menu {
  position: absolute;
  left: 14px;
  bottom: 6px;
  z-index: 3;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  opacity: .5;
}
.hdr-menu img { width: 24px; height: 24px; object-fit: contain; display: block; }
.hdr-menu:active { opacity: .85; transform: scale(.92); }
/* folded away, it stays lit so the way back is obvious */
.hdr-menu.on { opacity: .95; }

/* ---- the grabber ----
   The third control on the header, between the other two and centred on the
   header rather than on a corner. Drawn rather than delivered: it is a bar
   five pixels tall, and a picture of one would be a picture of nothing. The
   button's box is much larger than the mark so the tap target clears the 44
   the platform asks for without the mark growing to match. */
.hdr-fold {
  position: absolute;
  left: 50%;
  bottom: 4px;
  transform: translateX(-50%);
  z-index: 4;
  width: 56px;
  height: 26px;
  display: grid;
  place-items: center;
  background: none;
}
.hdr-fold::before {
  content: "";
  width: 36px;
  height: 5px;
  border-radius: 999px;
  background: rgba(233,245,255,.82);
  box-shadow: 0 0 9px rgba(61,223,255,.55);
  transition: width .2s ease, background .2s ease;
}
.hdr-fold:active::before { background: #FFFFFF; width: 30px; }

/* ---- the header, folded to a pill ----
   Same bargain the title bars strike: a definite height either side of the
   toggle, so the shrink is a thing that animates and the card below takes the
   room back frame by frame. The video is not display:none — it is faded and
   cropped away by the shrinking box, and JS pauses it, which is what "not
   playing" has to mean for a <video>.

   Mobile only, and scoped so it cannot survive a widened window: past the
   breakpoint every control in this header is hidden, and a header folded away
   with no button to unfold it would be a trap. */
@media (max-width: 1199px) {
  .header-zone {
    transition: height .34s cubic-bezier(.2,.8,.2,1),
                border-radius .34s cubic-bezier(.2,.8,.2,1);
  }
  .app.head-collapsed .header-zone {
    height: 54px;
    border-radius: 999px;
  }
  /* the pill's own frame, nine-sliced at half its height so the caps keep the
     radius they were drawn with however wide the column is. `fill` here
     because this frame has an inside and nothing behind it to show. */
  .app.head-collapsed .header-zone::after {
    border-width: 26px 28px;
    border-image: url("../assets/header/frame-collapsed.png") 76 80 fill / 26px 28px stretch;
  }
  .app.head-collapsed .wave-bg { opacity: 0; }
  .app.head-collapsed .wave-clock { opacity: 0; pointer-events: none; }
  /* the three that stay come to the middle of the pill */
  .app.head-collapsed .hdr-menu,
  .app.head-collapsed .hdr-mute {
    top: 50%;
    bottom: auto;
    transform: translateY(-50%);
    opacity: .9;
  }
  .app.head-collapsed .hdr-fold {
    top: 50%;
    bottom: auto;
    transform: translate(-50%, -50%);
  }
  /* the press states have to carry the centring transform too, or a tap on a
     pill icon would fling it back down to where it sits when expanded */
  .app.head-collapsed .hdr-menu:active,
  .app.head-collapsed .hdr-mute:active { transform: translateY(-50%) scale(.92); }
  .app.head-collapsed .hdr-fold:active { transform: translate(-50%, -50%); }
}
@media (prefers-reduced-motion: reduce) {
  .header-zone, .wave-bg, .wave-clock, .hdr-fold::before { transition: none; }
}

/* ---- the title bars, folded away ----
   Both bars have a definite height, so height is a thing that can be animated
   — no measuring, no max-height guess. The card below is the column's one
   growing child and takes the room back frame by frame as they give it up,
   which is what makes the two read as a single motion rather than as a panel
   leaving and a panel jumping. */
@media (max-width: 1199px) {
  .bar,
  .card-outer {
    transition: height .34s cubic-bezier(.2,.8,.2,1),
                margin-top .34s cubic-bezier(.2,.8,.2,1),
                opacity .2s ease,
                transform .34s cubic-bezier(.2,.8,.2,1);
  }
}
/* Mobile only, and scoped so it cannot survive a widened window: past the
   breakpoint the hamburger is hidden with the rest of the header's controls,
   and a layout folded away with no button to unfold it would be a trap. */
@media (max-width: 1199px) {
  .app.bars-hidden .bar {
    height: 0;
    margin-top: 0;
    opacity: 0;
    transform: translateY(-10px);
    overflow: hidden;
    pointer-events: none;
  }
  /* and the card comes up to meet the video */
  .app.bars-hidden .card-outer { margin-top: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .bar, .card-outer { transition: none; }
}

/* nothing to toggle if the video can't play at all */
.header-zone.video-broken .hdr-mute { display: none; }

@media (min-width: 1200px) {
  /* Solid black behind everything — the mobile build's ambient corner glows
     would fight the header strip and the panel glows on a wide screen. */
  html, body { background: #000; }

  /* One 8-column grid drives both bands. Row 1 is now a single full-width
     banner rather than five aligned segments, so only the lower band splits:
        cols   1   2   3   4   5   6   7   8
        row 1  |            banner            |
        below  |   left   | app   |  right   |                              */
  body {
    /* Row 1's height, and so the banner's. Everything in the banner scales off
       it — at 128px the centre clip lands ~132px wide, which is the whole
       composition's size dial: raise this one value to make the scene bigger. */
    --dt-head: clamp(76px, 12vh, 128px);
    --dt-barh: clamp(40px, 5.3vh, 48px);   /* == .bar height */
    --dt-dock: clamp(48px, 6.2vh, 58px);   /* == .bottom-nav height */
    /* transparent glow inside the bar asset's box: border-width 19px x 40/131 */
    --dt-bar-glow: 6px;
    /* How far the centre column's content sits inside its own grid column:
       .card-outer's 3.5% of an app column that is two of eight, i.e. 25vw.
       The side columns read it too — it is what they have to reach across to
       leave an even gap either side of the centre. */
    --dt-centre-inset: 0.875vw;
    --dt-gap: 8px;                          /* between the three columns */
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    /* the same expression .header-zone uses, so row 1 is exactly as tall as
       the app's own header video sitting inside it */
    grid-template-rows: var(--dt-head) 1fr;
    height: 100vh;
    gap: 0;
    padding: 0;
  }
  .dt-shell { display: contents; }

  /* the app shell is the centre column, spanning both bands: its own header
     video is segment 3 of the strip */
  .app {
    grid-column: 4 / 6;
    grid-row: 1 / 3;
    max-width: none;
    width: 100%;
    height: 100%;
    border: 0;
    box-shadow: none;
    /* the mobile shell paints itself --bg (#050614); against the black desktop
       page that reads as a lighter panel behind the centre column, which is
       the seam. Everything sits on the one black surface here. */
    background: transparent;
    /* clip, not hidden: an overflow:hidden box is still a scroll container and
       can be scrolled programmatically, which is how focusing a login field
       used to drag the header video up. clip creates no scroll container. */
    overflow: clip;
  }
  .auth-screen, .auth-card-outer { overflow: clip; }

  /* the phone sizes this header to the clip it plays; here the banner behind
     is what shows, and row 1's height is the rhythm everything else follows */
  /* the phone's framed card goes back to being a flat full-width strip here:
     the banner below is what shows, and a rounded neon box around a black
     plane would be a frame around nothing */
  .header-zone {
    aspect-ratio: auto;
    height: var(--dt-head);
    background: #000;
    margin: 0;
    border-radius: 0;
  }
  .header-zone::after { display: none; }
  /* Row 1 is one flat black plane until the art for it arrives. There was
     never a clip playing up here — the source is only ever attached below the
     breakpoint — but the empty <video> still painted its own #050614 ground,
     a 479px navy block sitting in the middle of an otherwise black strip. It
     and the static wave behind it both go, and with no hero left on this
     layout the speaker has nothing to switch. */
  .header-zone .wave-bg,
  .header-zone .hdr-mute,
  .header-zone .hdr-menu,
  .header-zone .hdr-fold { display: none; }
  .header-zone + .bar { margin-top: 5px; }

  /* ---- header banner ----
     One video across the full width of row 1, painted behind all three columns:
     left edge of the left panel to the right edge of the right panel, one
     continuous strip. It is the same clip the phone plays in its own header.

     Replaces a four-layer composition — a tiled floor with two flanking
     overlays and a centre clip standing on it — that only ever covered the
     middle of the row. object-fit keeps the frame's proportions and crops to
     the strip rather than stretching; object-position is the one value to
     change if a different band of the frame should show. */
  .dt-banner {
    grid-row: 1;
    grid-column: 1 / 9;
    position: relative;
    overflow: hidden;
    background: #000;
    z-index: 0;
  }
  /* the app column sits over the strip and plays its own header clip there —
     the banner carries no second copy of it any more, so the strip is the
     black ground either side of the column and nothing else */
  .app { position: relative; z-index: 1; }

  /* ---- the chart's controls, in this column's info bar ----
     The bar at the top of the right column, level with the centre column's
     two stacked bars, holds everything that steers the chart: the toggle,
     what it is showing, the drawings and the timeframe. The card below is
     then the plot and its two buttons and nothing else.

     The bar's own frame is a 9-slice with 19px borders, so its content box is
     already inset from the lit stroke — the rows sit inside that. */
  .dt-bar-chart {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    min-width: 0;
    padding: 0 4px;
  }
  .dt-bar-chart:empty { display: block; }
  .dt-ht-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; min-width: 0;
  }
  /* the bar is between 400 and 700px wide across the desktop range, and nine
     timeframes and five tools have to share a line inside it at all of them,
     so these run small everywhere rather than at a breakpoint */
  .dt-ht-row .tp-mode { flex: 0 0 auto; margin-bottom: 0; width: 152px; gap: 4px; }
  .dt-ht-row .tp-mode-btn { padding: 3px 4px; font-size: calc(8.5px * var(--fs)); letter-spacing: .02em; }
  .dt-ht-row .dc-quote { flex: 1 1 auto; justify-content: flex-end; }
  .dt-ht-row .dc-tf { flex: 1 1 auto; margin-bottom: 0; max-width: 210px; gap: 3px; }
  .dt-ht-row .dc-tf-btn { font-size: calc(8.5px * var(--fs)); }
  .dt-ht-row .dc-tools { flex: 0 0 auto; gap: 3px; }
  .dt-ht-row .dc-tool { padding: 3px 6px; font-size: calc(9px * var(--fs)); letter-spacing: .02em; }
  .dt-ht-note {
    font-size: calc(10px * var(--fs)); font-weight: 700;
    letter-spacing: .06em; color: #8FA9C4;
  }


  /* ---- columns ----
     The side columns mirror the centre column's own vertical rhythm exactly,
     expressed with the same values .bar / .card-outer / .bottom-nav use, so
     the bars and panels line up with the app shell instead of approximately
     matching it:
       .bar        margin-top 5px, height clamp(40px, 5.3vh, 48px)  x2
       .card-outer margin 8px top / 0 bottom
       .bottom-nav margin 0 top / --gap-bottom bottom, height clamp(48px, 6.2vh, 58px)
     so a side bar spans both centre bars (2 x height + the 5px between them),
     and the panels below start where the card starts and end where it ends.
     --gap-bottom is 4px here: desktop has no safe-area inset, so its max()
     floor is what applies. If that floor ever changes, this padding follows. */
  .dt-col {
    grid-row: 2;
    /* Above the centre column's own header. The bars start six pixels into
       row 1 to sit flush under the banner, and now that these columns reach
       in toward the centre their inner top corners land inside the header's
       box — which is positioned, so without this it paints over them and
       clips the corner off each one. */
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;                                   /* == .card-outer's top margin */
    min-height: 0;
    /* the same bottom margin the centre dock has, read from the variable
       rather than written out: the two lines have to agree, and --gap-bottom
       is not the same number on every build of this app */
    padding: 0 14px var(--gap-bottom);
  }
  /* Each reaches across its own grid line to within --dt-gap of the centre
     column's content, which is --dt-centre-inset inside the line. The centre
     does not move; the two beside it grow toward it. */
  .dt-left {
    grid-column: 1 / 4;
    padding-right: 0;
    margin-right: calc(var(--dt-gap) - var(--dt-centre-inset));
  }
  .dt-right {
    grid-column: 6 / 9;
    padding-left: 0;
    margin-left: calc(var(--dt-gap) - var(--dt-centre-inset));
  }

  /* One bar, as tall as the centre column's two stacked bars together.
     The border width is not arbitrary. A 9-slice scales the corner arc
     independently on each axis, so a circular corner needs the horizontal and
     vertical slice-to-border ratios to match — which is why all three desktop
     bar assets were re-cut with an identical 40px margin on every side. Each
     then has one square slice, and the rendered radius is simply
     arc x border/slice: 91 x 16/131 = 11px here, 70 x 17/110 and 74 x 17/114
     on the lower bars. The centre .bar renders 24 x 24/53 = 11px from its own
     asset. The exact border widths were then tuned against a pixel measurement
     of the rendered corners rather than the arithmetic alone, because what
     reads as the radius is where the drawn stroke settles, not the geometric
     arc — all six desktop bars and both centre bars land within a pixel of
     each other. */
  .dt-bar {
    flex: 0 0 auto;
    /* The asset carries a transparent glow band inside its own box, so the lit
       stroke starts --dt-bar-glow in from each edge. To sit flush under the
       wave the element has to start that far above the strip's bottom edge and
       grow by the same amount at each end. The extra 10px is the 5px the centre
       column leaves above its first bar plus the 5px between the two, so the
       stroke runs from the video's bottom edge down to exactly where the
       centre column's second bar ends. */
    margin-top: calc(-1 * var(--dt-bar-glow));
    height: calc(2 * var(--dt-barh) + 10px + 2 * var(--dt-bar-glow));
    border-style: solid;
    border-width: 19px;
    border-image: url("../assets/desktop/bar@2x.png") 131 fill / 19px stretch;
  }

  /* placeholder bars under each column, holding a row of icons later. They
     take the dock's slot, so the panels above still end level with the card
     and these sit level with the centre dock. Present in both the logged-out
     and logged-in states, since the desktop shell is not tied to auth. */
  /* Same bar as the centre dock's Log In pill — background-bar-pill 9-sliced
     at the same height and the same border widths, so all three read as one
     component. Drawn straight on the element rather than through a ::before
     the way .intro-dock and .bottom-nav do; those need the pseudo-element to
     sit behind their icons, and these are empty. Deliberately empty: they are
     placeholder containers, content lands in a later step.

     Width comes for free — they are flex children of .dt-col alongside the
     panels, so each spans exactly the panel above it. */
  .dt-lower {
    flex: 0 0 auto;
    height: var(--dt-dock);
    border-radius: 999px;
    border-style: solid;
    border-width: 24px;
    border-left-width: 27px;
    border-right-width: 27px;
    border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 24px 27px stretch;
  }

  .dt-panel {
    min-height: 0;
    border-style: solid;
    border-width: 26px;
  }
  /* left: one large panel filling everything under the bar */
  .dt-panel-square {
    flex: 1 1 0;
    border-image: url("../assets/desktop/square@2x.png") 185 fill / 26px stretch;
  }
  /* right: two stacked, split ~1.8 : 1 as in the reference, so the pair spans
     exactly what the single left panel does */
  .dt-panel-chart {
    flex: 1.8 1 0;
    border-image: url("../assets/desktop/chart@2x.png") 181 fill / 26px stretch;
  }
  .dt-panel-wide {
    flex: 1 1 0;
    border-image: url("../assets/desktop/wide@2x.png") 152 fill / 26px stretch;
  }

  /* ---- the landing art, while nobody is signed in ----
     One picture per panel, filling everything inside the panel's lit rim.
     The rim is the 26px border the 9-slice paints; the picture takes the box
     within it, corner to corner, cropped rather than squashed — so the frame
     the three panels share stays the frame, and the art sits in it.

     The moment someone signs in, renderDesktopTools() writes the live chart
     and watchlist over the two on the right and empties the one on the left,
     and all three of these go with them. */
  .dt-still {
    position: absolute;
    inset: 0;
    background-position: center;
    background-size: cover;               /* crop to the box, never stretch */
    background-repeat: no-repeat;
    /* the rendered rim's inner curve, near enough that no corner of the
       picture shows outside the lit stroke */
    border-radius: 6px;
  }
  .dt-panel { position: relative; }
  .dt-still-journey    { background-image: url("../assets/landing/left-journey.jpg"); }
  .dt-still-portal     { background-image: url("../assets/landing/right-portal.jpg"); }
  .dt-still-discipline { background-image: url("../assets/landing/right-discipline.jpg"); }

  /* ---- the two right panels once a signed-in visitor fills them ----
     The 9-slice frame stays exactly as it is; the content lives inside the
     26px border, which is why the panels get a flex column rather than any
     padding of their own. */
  .dt-panel.dt-live {
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
  }
  .dc-head {
    flex: 0 0 auto;
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap;
    margin-bottom: 6px;
  }
  .dc-quote { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
  .dc-quote b { font-size: calc(15px * var(--fs)); font-weight: 800; color: #F2FBFF; }
  .dc-quote .up { color: var(--teal); font-weight: 800; font-size: calc(12px * var(--fs)); }
  .dc-quote .down { color: var(--magenta); font-weight: 800; font-size: calc(12px * var(--fs)); }
  .dc-name {
    font-size: calc(11px * var(--fs)); color: #8FA9C4;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .dc-tools { display: flex; gap: 5px; }
  .dc-tf { flex: 0 0 auto; display: flex; gap: 4px; margin-bottom: 6px; }
  .dc-tf-btn {
    flex: 1 1 0;
    padding: 3px 0;
    border-radius: 7px;
    border: 1px solid rgba(120,150,180,.28);
    background: rgba(5,9,22,.45);
    font-size: calc(10px * var(--fs)); font-weight: 700; color: #8FA9C4;
  }
  .dc-tf-btn.on { border-color: var(--cyan); color: var(--cyan); }

  /* the chart box: the bars, the drawings and the crosshair all share it, so
     everything inside is positioned in percent off the same corner */
  .dc-box {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    border-radius: 10px;
    border: 1px solid rgba(61,223,255,.16);
    background: rgba(4,7,18,.55);
    overflow: hidden;
    cursor: grab;
    touch-action: none;
  }
  .dc-box.drawing { cursor: crosshair; }
  .dc-box .tp-track { position: absolute; inset: 0; }
  /* ---- the bottom panel: the watchlist as a strip ---- */
  .dc-wl-head {
    flex: 0 0 auto;
    display: flex; align-items: center; gap: 10px;
    margin-bottom: 7px;
  }
  .dc-wl-cap {
    font-size: calc(10.5px * var(--fs)); font-weight: 800;
    letter-spacing: .16em; text-transform: uppercase; color: #8FA9C4;
  }
  .dc-wl-search {
    flex: 1 1 auto; min-width: 0;
    padding: 5px 10px;
    border-radius: 999px;
    border: 1px solid rgba(120,150,180,.3);
    background: rgba(5,9,22,.6);
    color: var(--text);
    font-family: inherit; font-size: calc(11.5px * var(--fs));
  }
  .dc-wl-hits { flex: 0 0 auto; display: flex; gap: 6px; margin-bottom: 7px; overflow-x: auto; }
  .dc-wl-hit {
    display: flex; align-items: baseline; gap: 6px;
    padding: 4px 9px;
    border-radius: 8px;
    border: 1px solid rgba(61,223,255,.28);
    background: rgba(5,9,22,.6);
    white-space: nowrap;
  }
  .dc-wl-hit b { font-size: calc(11px * var(--fs)); color: #F2FBFF; }
  .dc-wl-hit span { font-size: calc(10px * var(--fs)); color: #8FA9C4; }
  .dc-wl-hit i { font-style: normal; font-weight: 800; color: var(--cyan); }
  .dc-wl-hit[disabled] { opacity: .45; }
  /* the rows run across the strip rather than down it — that is the whole
     difference from the hamburger's copy of this list */
  .dc-wl-rows {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-wrap: wrap; align-content: flex-start;
    gap: 6px;
    overflow-y: auto;
  }
  .dc-wl-row {
    display: flex; align-items: center;
    border-radius: 9px;
    border: 1px solid rgba(120,150,180,.26);
    background: rgba(5,9,22,.5);
  }
  .dc-wl-row.on { border-color: var(--cyan); box-shadow: 0 0 12px -4px rgba(61,223,255,.7); }
  .dc-wl-pick { display: flex; align-items: baseline; gap: 7px; padding: 5px 4px 5px 10px; }
  .dc-wl-pick b { font-size: calc(11.5px * var(--fs)); font-weight: 800; color: #F2FBFF; }
  .dc-wl-name {
    font-size: calc(10px * var(--fs)); color: #8FA9C4;
    max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .dc-wl-last { font-size: calc(10.5px * var(--fs)); color: #C9DDF2; font-variant-numeric: tabular-nums; }
  .dc-wl-chg { font-size: calc(10.5px * var(--fs)); font-weight: 800; font-variant-numeric: tabular-nums; }
  .dc-wl-chg.up { color: var(--teal); }
  .dc-wl-chg.down { color: var(--magenta); }
  .dc-wl-del {
    padding: 4px 9px 5px;
    font-size: calc(14px * var(--fs)); line-height: 1; color: #6E86A6;
  }
  .dc-wl-del:active { color: var(--magenta); }

  /* the login screen must not cover the header strip: at desktop it starts
     below it, so all five segments stay visible and playing while logged out.
     Its own wave spacer is redundant here — the strip above is the header. */
  .auth-screen {
    top: var(--dt-head);
    /* Opaque black, not transparent: its own full-page wave image belongs to
       the mobile layout (here the strip above is the header, so it would show
       as a second static wave under a live one), but going fully transparent
       let the app's own bars and card peek out around the login panel's
       edges. Black hides them and matches the page. */
    background: #000;
  }
  .auth-wave { display: none; }

  /* The centre column gets the same three parts as the two beside it: a band
     where the bars go, the panel, then the dock pill. This is the band —
     the same nine-sliced bar asset and the same box as .dt-bar, so its top
     and bottom edges land on the side bars' exactly. Once someone signs in
     the auth screen goes and the app's own two bars stand here instead. */
  /* Only on the login step. It is the band above the phone mockup — the gate
     and the questionnaire are taller than their slot on a 1280x800 screen and
     would start scrolling to pay for it. */
  .auth-screen.on-login .auth-topbar {
    display: block;
    flex: 0 0 auto;
    margin: calc(-1 * var(--dt-bar-glow)) var(--dt-centre-inset) 0;
    height: calc(2 * var(--dt-barh) + 10px + 2 * var(--dt-bar-glow));
    border-style: solid;
    border-width: 19px;
    border-image: url("../assets/desktop/bar@2x.png") 131 fill / 19px stretch;
  }

  /* The panel's slot, exactly: it starts where the side panels start — one
     gap below the band — and stops one gap above the dock pill, so all three
     columns run panel-then-pill on the same two lines.

     The clearance is the pill, the space under the pill, and the 8px gap
     above it — all three read from the variables rather than added up into
     one number. --gap-bottom is not the same on every build of this app, and
     a literal here landed the centre panel four pixels shy of the two beside
     it on the build where it is zero. */
  .auth-card-outer {
    margin: 8px var(--dt-centre-inset)
            calc(var(--dt-dock) + var(--gap-bottom) + 8px);
  }
  /* and the signed-in card takes the same slot, so the panel band does not
     move under someone as they log in. The dock is flex: 0 0 auto at the end
     of the column, so the card giving back these pixels cannot shift it. */
  .card-outer { margin-top: 14px; margin-bottom: 8px; }

  /* ---- the dock stands still here ----
     The phone shrinks its dock as the card scrolls and walks the card's
     bottom margin down after it. That is worth having on a phone, where the
     dock is a fifth of what you can see. Here it is one of three pills on a
     row that runs the whole window, and a centre one that changed size as the
     middle column scrolled took the row with it — the panel's bottom edge
     breathing up and down against two that did not move.

     The minimised state is neutralised rather than removed, so the phone
     keeps every bit of it. */
  .app.dock-min .bottom-nav { transform: none; opacity: 1; }
  .card-outer,
  .app.dock-min .card-outer { margin-bottom: 8px; transition: none; }
  /* and the pill sits in the column rather than over it. Lifted out of flow
     it was drawn on top of the card, which is why the panel had no bottom
     edge of its own down here — it ran on underneath the pill and stopped
     wherever the column did. Back in flow it ends where the two beside it
     end, and the pill follows it. */
  .bottom-nav {
    position: relative;
    z-index: auto;
    /* The deployed build lifts this pill out of flow on a phone with
       left/right: 3.5%, and putting it back in flow here did not take those
       offsets back. On a relatively positioned box `left` is a nudge and
       `right` is ignored, so the pill was shifted right by its own inset —
       measured at 11.2px on a 1280 window and 16.8px on a 1920 one, which is
       exactly 3.5% of the centre column — while its margins kept it the right
       width. Sitting on top of that nudge it was the one thing on the page not
       centred on the column it belongs to. */
    left: auto;
    right: auto;
    margin: 0 3.5% var(--gap-bottom);
    height: var(--dt-dock);
  }

  /* One way in, not two. The pill in the dock below is the control now; the
     form it opens still rides on the clip, so nothing else moves. Scoped to
     the way in: the gate's dock is the centre ENTER here and stays. */
  .login-step .bottom-dock { display: none; }

  /* The way in is this column's panel, so it carries the frame the signed-in
     card carries and fills the slot exactly as the two beside it do.

     The clip inside it is 9:16 and this slot is not — on a 1920x950 window it
     is nearer 7:10 — so one of the two has to give. It used to be the clip:
     drawn as large as it would go without losing an edge, which left a band
     of the panel's own ground down each side. That band is what read as a
     black-blue border around the video, and it is the only thing on the
     desktop page that was not flat black. The panel wins now — the clip is
     cropped to fill it, top and bottom, and the type the composition runs
     into those two edges is the price. Rounded to the panel's own radius, so
     its four corners are the same curve as the two panels beside it. */
  .login-step {
    background: none;
    border-radius: var(--radius-card);
  }
  .login-step::before { content: ""; }
  /* The picture stands where the clip stood — same box, same crop, same
     radius. Declared as a background inside this query on purpose: a phone
     never matches the rule, so it never fetches the file, and the clip it
     does play is attached by JS and skipped past this breakpoint. Neither
     layout pays for the other's hero. */
  .login-media {
    background: url("../assets/landing/centre-globe.jpg") center / cover no-repeat;
    border-radius: var(--radius-card);
    overflow: hidden;
  }
  .login-video { display: none; }
  /* Cropping leaves no letterbox, so the composition has no frame of its own
     to hang the fields on any more: what is visible is the media box. Its
     height is what the fields are anchored against and that has not changed,
     so they stay on the same line — only the width they may use grows. */
  .login-frame { width: 100%; height: 100%; aspect-ratio: auto; }
}

/* ---- desktop pre-login: intro video, CTA, and the Log In dock ----
   All of it is desktop-only; on mobile #introStep and #introDock stay hidden
   and the login form remains the default step, exactly as before. */
.intro-dock { display: none; }

@media (min-width: 1200px) {
  .intro-card {
    position: relative;
    justify-content: center;
    padding: 0;
    overflow: clip;
  }
  .intro-video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: calc(var(--radius-card) - 2px);
  }
  .intro-video.hidden { display: none; }

  .intro-cta {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    width: 100%;
    padding: 34px 26px;
  }
  .intro-cta.hidden { display: none; }
  .intro-cta .auth-wordmark { margin: 0 auto 14px; }
  /* same pill treatment as the login screen's own Log In / Sign Up tabs */
  .intro-btn {
    /* .auth-tab is flex:1 1 0 for its side-by-side row on the login screen;
       stacked in this column that basis of 0 applies to the height and
       collapses the button, so the basis is restated here */
    flex: 0 0 54px;
    width: 78%;
    height: 54px;
    opacity: 1;
  }

  /* sits in the centre column's dock slot, matching the real dock's pill and
     placement so the swap reads as the same object.

     #gateDock is on the same rule for the same reason: on a phone the gate's
     ENTER is the shared bottom pill, but here the row it has to join is the
     desktop one — the two .dt-lower bars either side of it — and that row's
     shape is this dock's, not the pill's. Same box, same bar, same line, so
     the three bottom pills sit level and read as one component. */
  .intro-dock,
  #gateDock {
    display: flex;
    position: absolute;
    /* the same box the app's own dock has, so the three bottom pills across
       the row sit on one line whichever state the centre column is in */
    left: 3.5%;
    right: 3.5%;
    bottom: var(--gap-bottom);
    height: var(--dt-dock);
    min-height: 0;
    margin: 0;
    align-items: center;
    justify-content: center;
    border-radius: 999px;
    isolation: isolate;
  }
  #gateDock.hidden { display: none; }
  /* the pill's own nine-slice would be a pill inside a pill here: the dock is
     the shape at this width, so ENTER is the type on it and nothing else */
  #gateDock .bottom-pill {
    width: auto;
    max-width: none;
    height: auto;
    border: 0;
    border-image: none;
    padding: 8px 22px;
    font-size: calc(13px * var(--fs));
    letter-spacing: .14em;
  }
  .intro-dock::before,
  #gateDock::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border: 24px solid transparent;
    border-left-width: 27px;
    border-right-width: 27px;
    border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 24px 27px stretch;
  }
  .intro-dock.hidden { display: none; }
  /* The dock holds two controls in the same place — the way in, then the way
     through — and shows one at a time. Nothing was hiding the other: there is
     no blanket .hidden rule in this sheet, every one of them is scoped to the
     thing it hides, and this pair had none. So both painted, and the pill read
     "LOG IN  LOGIN". */
  .intro-dock-btn.hidden { display: none; }
  .intro-dock-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 22px;
    font-size: calc(13px * var(--fs));
    font-weight: 800;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: #EAF6FF;
  }
  .intro-dock-btn img { width: 24px; height: 24px; object-fit: contain; }
  .intro-dock-btn:active { filter: brightness(1.35); transform: scale(.97); }

}

/* ===================== GAMEÆWAY SELECTOR ===================== */

.gs-head {
  text-align: center;
  font-size: calc(15px * var(--fs));
  font-weight: 800;
  letter-spacing: .04em;
  color: var(--cyan);
  margin: 4px 0 12px;
}
/* three entries, one view: the heading and the gaps between them are the only
   places left to find the last few pixels once the scene has its width */
.gs-list { display: flex; flex-direction: column; gap: 11px; }
.gs-card {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-align: left;
  /* the three entries share one view on a phone and in the desktop centre
     column, which is narrower still and wraps the blurbs harder — these few
     pixels are what keep the last entry on screen there */
  padding: 12px 14px;
  border-radius: 18px;
  border: 1px solid rgba(61,223,255,.32);
  background: linear-gradient(170deg, rgba(11,18,38,.85), rgba(7,10,24,.85));
  transition: transform .14s ease, filter .14s ease;
}
.gs-card:active { transform: scale(.985); filter: brightness(1.25); }
/* the chevron sits at the right of every entry, vertically centred on the
   row it belongs to rather than on the whole card */
.gs-chev {
  flex: 0 0 auto;
  align-self: center;
  font-size: calc(22px * var(--fs));
  font-weight: 400;
  line-height: 1;
  color: #7FA8CC;
}

/* ---- the entries with a scene ----
   Each game's art carries the game, so it stands in for the icon rather than
   sitting next to one. The picture fills the top of the card edge to edge and
   takes the card's own corner radius up there; the line underneath sits on the
   card's ground. */
.gs-card-art {
  position: relative;
  display: block;
  padding: 0;
  overflow: hidden;
  border-color: rgba(61,223,255,.55);
  box-shadow: 0 0 18px rgba(61,223,255,.16), inset 0 0 22px rgba(255,61,154,.08);
}
.gs-scene {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 2px;
  /* The banner is 3:1 and this band is a little squarer, so it crops rather
     than letterboxes — the two animals sit at the ends and survive the crop.
     The band is kept wide on purpose: it is one of three entries that have to
     share a single view, and every row this picture gains the list loses. */
  aspect-ratio: 2.35 / 1;
  position: relative;
  background-size: cover;
  background-position: center;
  padding: 12px 44px 0;
  text-align: center;
  /* the names have to hold against whatever the picture does behind them */
  text-shadow: 0 2px 10px rgba(0,0,0,.85), 0 0 22px rgba(0,0,0,.7);
}
/* The scrim is part of the treatment, not decoration on top of it: with one
   scene the type happened to sit over the empty middle between two animals and
   a shadow was enough. With three, it lands on a face and on a countdown clock
   as well, so the band it sits in gets a ground of its own that fades out
   before the picture's subject starts.

   A pseudo-element rather than a second background layer: the picture arrives
   inline, from the entry's own record, and a relative url() handed through a
   custom property would be resolved against the stylesheet rather than against
   the page — which is a 404 and a blank card. */
.gs-scene::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(180deg,
    rgba(3,6,18,.88) 0%, rgba(3,6,18,.72) 30%,
    rgba(3,6,18,.34) 52%, rgba(3,6,18,0) 76%);
}
.gs-scene > * { position: relative; z-index: 1; }
.gs-card-art .gs-name { font-size: calc(19px * var(--fs)); }
/* The icon rides at the head of the description line, in the same left column
   the other two entries use — this entry's title row is the scene, so there is
   nowhere up there to put it. It is taken out of the flow so the line it sits
   beside stays centred in the card rather than being pushed off by its width. */
.gs-card-art .gs-foot {
  position: relative;
  display: block;
  /* the same on both sides so the line stays centred in the card, and wide
     enough that it clears the icon rather than running into it */
  padding: 9px 42px 13px;
}
.gs-card-art .gs-icon.sm {
  position: absolute;
  /* the left edge the other two entries start their icons on */
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  width: 34px; height: 34px;
}
.gs-card-art .gs-blurb {
  display: block;
  text-align: center;
}
.gs-card-art .gs-chev {
  position: absolute;
  top: 14px; right: 14px;
  color: #EAF6FF;
  text-shadow: 0 2px 8px rgba(0,0,0,.9);
}
.gs-icon {
  flex: 0 0 auto;
  width: 54px; height: 54px;
  display: grid; place-items: center;
}
.gs-icon img { width: 100%; height: 100%; object-fit: contain; }
.gs-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.gs-name { font-size: calc(16px * var(--fs)); font-weight: 800; color: var(--text); }
.gs-tag {
  font-size: calc(10px * var(--fs));
  font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--magenta);
}
.gs-blurb { font-size: calc(12.5px * var(--fs)); line-height: 1.45; color: #9FC0E0; }

/* ===================== POINTÆWAY ===================== */
/* Its own palette, carried over from the reference prototype: bull teal, bear
   red, wild gold. Kept as local tokens rather than folded into the app's cyan
   and magenta, because in this game the two colours mean sides, not brand.

   The live print panel is named here too because it is the one piece of this
   game that lives OUTSIDE the content card — it stands where the video header
   stands — and a candle whose fill is var(--pw-bull) draws in nothing at all
   when that token does not reach it. */
#cardScroll,
#chartPanel {
  --pw-bull: #1FCBA0;
  --pw-bull-dim: #12493D;
  --pw-bear: #E5484D;
  --pw-bear-dim: #4A1E20;
  --pw-wild: #E8B23A;
  --pw-wild-dim: #4A3A14;
  --pw-panel: rgba(11,18,38,.85);
  --pw-line: rgba(61,223,255,.24);
  --pw-muted: #8FA9C4;
}
.pw-c-bull { color: var(--pw-bull); }
.pw-c-bear { color: var(--pw-bear); }
.pw-c-wild { color: var(--pw-wild); }

/* ---- setup ---- */
/* ---- the way in ----
   Wordmark, tagline, the two side cards, what the game is, and the two ways
   past it. The side cards are finished pictures — art, name, target and their
   own button baked in — so each picture is the button and nothing is drawn
   over it. The two were exported at slightly different proportions (the
   bull's frame is 0.85 to the bear's 0.88), so they are matched on HEIGHT:
   their own buttons then sit on one line, which is what the eye checks. */
/* One view, no scrolling: the scroller becomes a fixed-height column and the
   two cards take whatever the rows above and below leave, exactly as the
   match screen does. Everything else is its own height. */
.card-scroll.pw-introing { display: flex; flex-direction: column; overflow: hidden; }
.pw-intro {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  text-align: center;
  padding: 6px 4px 4px;
}
.pw-intro > * { flex: 0 0 auto; }
.pw-wordmark {
  display: block;
  width: min(82%, 300px);
  height: auto;
  margin: 2px auto 0;
}
.pw-subtitle {
  display: block;
  width: min(66%, 232px);
  height: auto;
  margin: 3px auto 0;
}
.pw-tagline {
  margin: 6px auto 0;
  max-width: 34em;
  font-size: calc(12px * var(--fs));
  line-height: 1.5;
  color: var(--pw-muted);
}
/* the label with a rule running out of it either side */
.pw-rule {
  display: flex; align-items: center; gap: 10px;
  margin: 8px 2px 7px;
}
.pw-rule::before, .pw-rule::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
}
.pw-rule::before { background: linear-gradient(90deg, transparent, var(--pw-bull)); }
.pw-rule::after  { background: linear-gradient(90deg, var(--pw-bear), transparent); }
.pw-rule span {
  flex: 0 0 auto;
  font-size: calc(11px * var(--fs));
  font-weight: 800; letter-spacing: .26em; text-transform: uppercase;
  color: #9FD9FF;
}

.pw-picks {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  justify-items: center;
  gap: 10px;
  flex: 1 1 auto;
  min-height: 0;
}
.pw-pick {
  display: block;
  width: 100%; height: 100%;
  padding: 0; border: 0; background: none;
  -webkit-tap-highlight-color: transparent;
  /* measured on both axes: the row's height is what it has to fit into */
  container-type: size;
}
.pw-pick img {
  display: block;
  /* Height, not width, so the pair matches and their buttons land on one
     line — bounded three ways: by the row's own height, by the column's
     width, and by a floor so a short screen cannot squeeze them to nothing.
     1.1189 is the wider card's height per unit width, so sizing both to it
     keeps the wider one exactly inside its column. */
  height: min(100cqh, calc(100cqw * 1.1189));
  min-height: 96px;
  width: auto;
  margin: 0 auto;
}
@supports not (width: 1cqw) {
  .pw-pick img { height: auto; width: 100%; min-height: 0; }
}
/* the randomiser's flicker, and the card it lands on */
.pw-pick.lit img   { filter: brightness(1.5) saturate(1.15); transform: scale(1.035); }
.pw-pick.won img   { filter: brightness(1.55) saturate(1.2); transform: scale(1.06); }
.pw-picks:has(.lit) .pw-pick:not(.lit) img,
.pw-picks:has(.won) .pw-pick:not(.won) img { filter: brightness(.45) saturate(.5); }
.pw-pick img { transition: filter .07s linear, transform .07s linear; }
.pw-pick.won img { transition: filter .18s ease, transform .18s ease; }
@media (prefers-reduced-motion: reduce) {
  .pw-pick img, .pw-pick.won img { transition: none; }
}
.pw-pick:active { transform: translateY(-3px) scale(1.03); filter: brightness(1.12); }

/* what the game is, four at a time. Two across on a phone column and four on
   the desktop one — four across a 366px column leaves 91px a box, which is
   not enough for "Learn While You Play" and a line of subtext under it. */
/* One row of four, phone included: a second row costs the two cards above it
   more height than this screen has to give. About 86px a box on a 393 phone,
   so the type is small and every word is allowed to break. */
.pw-feats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 5px;
  margin: 9px 0 3px;
}
.pw-feat {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 7px 3px;
  border: 1px solid rgba(90,170,255,.3);
  border-radius: 10px;
  background: rgba(6,14,34,.5);
  overflow-wrap: anywhere;
}
.pw-feat-ico { display: block; height: 22px; line-height: 0; color: #35BFFF; }
.pw-feat-ico img { height: 100%; width: auto; display: block; }
.pw-feat-svg {
  height: 100%; width: auto; display: block;
  filter: drop-shadow(0 0 5px rgba(53,191,255,.65));
}
.pw-feat-title {
  margin-top: 2px;
  font-size: calc(8.5px * var(--fs));
  font-weight: 800;
  line-height: 1.2;
  color: var(--text);
}
.pw-feat-sub {
  font-size: calc(7.5px * var(--fs));
  line-height: 1.28;
  color: var(--pw-muted);
  /* the deck's two counts run to two lines; balanced they break between the
     counts rather than leaving "Cards" on a line by itself */
  text-wrap: balance;
}

.pw-random-btn {
  display: flex; align-items: center; justify-content: center; gap: 11px;
  width: min(86%, 320px);
  height: 54px;
  margin: 9px auto 0;
  font-size: calc(12.5px * var(--fs));
  font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: #EAF6FF;
}
.pw-random-btn img { height: 22px; width: auto; display: block; }
.pw-random-btn:active { transform: scale(.97); filter: brightness(1.25); }

.pw-wilds-btn {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: min(70%, 260px);
  margin: 7px auto 0;
  padding: 8px 14px;
  border: 1px solid rgba(90,170,255,.45);
  border-radius: 999px;
  background: rgba(6,14,34,.5);
  font-size: calc(11.5px * var(--fs));
  font-weight: 700;
  color: #C7D9EF;
}
.pw-wilds-btn img { height: 17px; width: auto; display: block; }
.pw-wilds-btn:active { filter: brightness(1.4); }

.pw-setup { text-align: center; padding: 8px 4px 4px; }
.pw-lede {
  font-size: calc(13px * var(--fs));
  line-height: 1.55; color: #C9DDF2;
  margin: 0 auto 20px; max-width: 30em;
}
.pw-sides { display: flex; gap: 12px; justify-content: center; margin-bottom: 16px; }
.pw-side {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 16px 10px;
  border-radius: 14px;
  font-size: calc(13px * var(--fs)); font-weight: 700; color: var(--text);
  transition: transform .14s ease, filter .14s ease;
}
.pw-side:active { transform: scale(.97); filter: brightness(1.25); }
.pw-side.bull { border: 1.5px solid var(--pw-bull); background: linear-gradient(160deg, var(--pw-bull-dim), var(--pw-panel)); }
.pw-side.bear { border: 1.5px solid var(--pw-bear); background: linear-gradient(160deg, var(--pw-bear-dim), var(--pw-panel)); }

.pw-ghost {
  display: block; margin: 4px auto;
  padding: 7px 16px;
  border: 1px solid var(--pw-line);
  border-radius: 999px;
  font-size: calc(11px * var(--fs)); letter-spacing: .06em;
  color: var(--pw-muted);
}
.pw-ghost:active { filter: brightness(1.4); }

/* ===================== POINTÆWAY — CARD LIBRARY =====================
   Its own screen, reached from the picker and returning to it. Unlike every
   other Pointæway screen this one is allowed to run past a view: it is read,
   not played, and ten wild faces with their effects will not fit one.

   The three tiles are the delivered side-select art used whole. Their baked
   buttons say the wrong thing here, so they are not what anyone reads — the
   live caption under each is the label, and it is the button's accessible
   name too. */
.pw-lib { padding: 0 2px 12px; text-align: left; }
.pw-lib-head {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  min-height: 34px;
  margin-bottom: 9px;
}
.pw-lib-title {
  font-size: calc(14px * var(--fs));
  font-weight: 800; letter-spacing: .22em; text-transform: uppercase;
  color: #9FD9FF;
  /* the back arrow is absolute at the head's left edge, so the title has to
     keep a 38px gutter on BOTH sides or a long one slides under it on a 320px
     phone — and the gutter has to be symmetric, or the title stops being
     centred. Past that width it wraps instead of overlapping. */
  padding: 0 38px; text-align: center;
}
.pw-lib-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.pw-lib-tile {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 0; border: 0; background: none;
  -webkit-tap-highlight-color: transparent;
  text-align: center;
  /* the three files are three different shapes (1.12, 1.13 and 1.22 tall per
     unit wide), so matching them on WIDTH would leave their captions on three
     different lines. Matched on height instead — the tallest file's own ratio,
     measured against the tile's width — the captions share a baseline and the
     narrow one simply sits narrower in its column. */
  container-type: inline-size;
}
.pw-lib-tile img {
  display: block; width: auto; height: 113cqw; max-width: 100%;
  object-fit: contain;
  transition: filter .16s ease, transform .16s ease;
}
@supports not (width: 1cqw) {
  .pw-lib-tile img { width: 100%; height: auto; }
}
.pw-lib-tiles:has(.on) .pw-lib-tile:not(.on) img { filter: brightness(.48) saturate(.55); }
.pw-lib-tile.on img { filter: brightness(1.14) saturate(1.08); }
.pw-lib-tile:active img { transform: scale(.96); }
@media (prefers-reduced-motion: reduce) { .pw-lib-tile img { transition: none; } }
.pw-lib-cap { display: flex; flex-direction: column; gap: 1px; }
.pw-lib-cap b { font-size: calc(10px * var(--fs)); font-weight: 800; color: var(--text); }
.pw-lib-cap i {
  font-style: normal;
  font-size: calc(8px * var(--fs)); line-height: 1.3;
  color: var(--pw-muted);
}

.pw-lib-list { display: grid; gap: 8px; }
.pw-lib-row {
  display: flex; align-items: center; gap: 11px;
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--pw-line);
  border-radius: 12px;
  background: rgba(7,10,24,.7);
  text-align: left;
  -webkit-tap-highlight-color: transparent;
  /* the gap closes as the picture takes the row, so the picture can reach the
     far edge rather than stopping 11px short of it */
  transition: gap .34s cubic-bezier(.2,.7,.2,1);
}
.pw-lib-row.wild { border-color: rgba(232,178,58,.38); }
/* ---- a card grown in place ----
   The face is sized on WIDTH here, not on the height the rest of the game
   sizes a card by, and that is the whole trick: one length animates, the
   picture's own ratio gives the height, and the row's height follows it — so
   every row after this one slides down as it grows and back up as it
   shrinks, without a single number being measured in script.

   Nothing opens over anything: the row is where it always was, in the list,
   at the scroll position the reader left it at. */
.pw-lib-face {
  flex: 0 0 auto;
  display: flex;
  width: calc(clamp(58px, 19vw, 82px) * 304 / 460);
  transition: width .34s cubic-bezier(.2,.7,.2,1);
}
.pw-lib-face .pw-card { width: 100%; height: auto; }
.pw-lib-face .pw-card-art { width: 100%; height: auto; }
.pw-lib-row.big { gap: 0; }
.pw-lib-row.big .pw-lib-face { width: 100%; }
/* the words step aside for the picture that already carries them */
.pw-lib-text {
  display: flex; flex-direction: column; gap: 3px;
  flex: 1 1 auto; min-width: 0;
  overflow: hidden;
  transition: flex-grow .34s cubic-bezier(.2,.7,.2,1),
              flex-basis .34s cubic-bezier(.2,.7,.2,1),
              opacity .18s ease;
}
.pw-lib-row.big .pw-lib-text {
  flex: 0 0 0;
  opacity: 0;
  pointer-events: none;
}
.pw-lib-row:active { filter: brightness(1.2); }
@media (prefers-reduced-motion: reduce) {
  .pw-lib-row, .pw-lib-face, .pw-lib-text { transition: none; }
}
.pw-lib-name {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: calc(11.5px * var(--fs)); font-weight: 800; color: var(--text);
}
.pw-lib-pts {
  flex: 0 0 auto;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: calc(8.5px * var(--fs)); font-weight: 800; letter-spacing: .07em;
}
.pw-lib-pts.bull { color: #7CF3C8; background: rgba(0,200,150,.14); border: 1px solid rgba(0,220,160,.4); }
.pw-lib-pts.bear { color: #FF9CA8; background: rgba(255,60,90,.14); border: 1px solid rgba(255,80,110,.4); }
.pw-lib-desc { font-size: calc(10.5px * var(--fs)); line-height: 1.45; color: var(--pw-muted); }

/* the picker's own header: the wordmark keeps the middle, the way back to the
   record sits in the corner it leaves free */
.pw-intro-head {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  /* the arrow's own width kept clear on BOTH sides, so the wordmark stays
     centred on the header rather than on what is left of it, and cannot run
     under the arrow on a narrow phone — the wordmark file has no transparent
     margin to give, so the clearance has to be real */
  padding: 0 38px;
}
.pw-intro-head .pw-wordmark { width: min(100%, 300px); margin-top: 0; }

/* ---- random side picker ----
   One card turning on its Y axis with Bull on one face and Bear on the other,
   so the side that is up is the rotation itself and not a separate decision.
   The angle comes from JS every frame; nothing here animates on its own. */

/* ---- the game-over meter ----
   The match screen has its own upright gauge below; this is the one the
   final print is held on, kept as it was. */
.pw-track-panel {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
}
.pw-track-val { font-size: calc(24px * var(--fs)); font-weight: 800; line-height: 1; }
.pw-track-val.flat { color: var(--pw-muted); }
.pw-track-val.bull { color: var(--pw-bull); }
.pw-track-val.bear { color: var(--pw-bear); }
.pw-track-row {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
}
.pw-track-end {
  font-size: calc(9px * var(--fs));
  font-weight: 700; letter-spacing: .08em;
  color: var(--pw-muted);
}
.pw-track {
  position: relative;
  width: 44px; height: 132px;
  border-radius: 10px;
  background: rgba(4,7,18,.9);
  border: 1px solid var(--pw-line);
  overflow: hidden;
  /* Dotted tick guides. A gradient only varies along one axis, so a dashed row
     tiled with repeat-y comes out as unbroken vertical stripes. A dot grid
     needs a shape that varies on both axes, which is what the radial does. */
  background-image: radial-gradient(circle, rgba(143,169,196,.34) 0.5px, transparent 1px);
  background-size: 8px 13px;
  background-position: center;
}
/* the midline the fill grows from, carrying its own ground so it stays
   readable with the bar sitting on it */
.pw-track-mid {
  position: absolute; left: 0; right: 0;
  top: 50%; transform: translateY(-50%);
  text-align: center;
  font-size: calc(7px * var(--fs));
  font-weight: 700; letter-spacing: .08em;
  color: #93A9C0;
  background: rgba(4,7,18,.9);
  padding: 1px 0;
  z-index: 2;
  pointer-events: none;
}
.pw-track-fill {
  position: absolute;
  left: 4px; right: 4px;
  height: var(--pw-fill, 0%);
  border-radius: 4px;
  transition: height .38s ease, width .38s ease;
  z-index: 1;
}
.pw-track-fill.up { bottom: 50%; }
.pw-track-fill.down { top: 50%; }
.pw-track-fill.bull { background: var(--pw-bull); }
.pw-track-fill.bear { background: var(--pw-bear); }
.pw-track-fill.flat { background: transparent; }

/* ---- the table ----
   Top to bottom: what is left to draw from, their side, the meter both sides
   pull on, your side, then your hand. The two animals are behind all of it
   rather than in it — they are the room, not a row, which is why they sit on
   their own layer and catch nothing.

   Card faces are finished artwork: frame, name and strength are all in the
   pixels. Nothing here paints a card, so every card rule is about how big the
   picture is and what may be done to it. */
/* While a match is up the scroller is a fixed-height flex column: the counter
   row and the hand are whatever they need, and the arena takes the rest. That
   is what puts the whole match in one view, and it is also what lets the card
   art be as large as the phone can afford rather than a fixed size chosen for
   the smallest one. */
.card-scroll.pw-playing {
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.pw-field {
  position: relative;
  isolation: isolate;
  /* kept from the flanks it used to hold: nothing in here bleeds past the
     edges now, but a stray wide child still must not slide the screen */
  overflow: hidden;
  padding: 2px 2px 6px;
  display: flex;
  flex-direction: column;
  /* the one part of the column that gives: when the specials sheet is open it
     yields most of its height, but never all of it */
  flex: 1 1 auto;
  min-height: 84px;
}
/* .pw-flank — the two animals behind the table — is gone with them. */

/* ---- what is left, and the two controls that belong with it ---- */
.pw-counts {
  display: flex; align-items: center; gap: 6px;
  flex: 0 0 auto;
  padding: 2px 2px 6px;
}
.pw-count {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 52px;
  padding: 3px 8px;
  border: 1px solid var(--pw-line);
  border-radius: 11px;
  background: rgba(4,7,18,.7);
  line-height: 1.1;
}
.pw-count b { font-size: calc(15px * var(--fs)); font-weight: 800; color: var(--text); }
.pw-count i {
  font-style: normal;
  font-size: calc(8px * var(--fs));
  font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--pw-muted);
}
.pw-count.wild b { color: var(--pw-wild); }
.pw-counts-gap { flex: 1 1 auto; }
.pw-count-btn {
  white-space: nowrap;
  padding: 7px 10px;
  border: 1px solid var(--pw-line);
  border-radius: 11px;
  background: rgba(4,7,18,.7);
  font-size: calc(9.5px * var(--fs));
  font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--pw-muted);
}
.pw-count-btn.on { border-color: var(--pw-wild); color: var(--pw-wild); }
/* the live chart's button: a glyph rather than a word, because the row it
   joins already carries two words and a 320px phone has no room for a third */
.pw-chart-btn { padding: 6px 9px; display: grid; place-items: center; }
.pw-chart-ico { width: 20px; height: 15px; display: block; color: currentColor; }

/* ---- the live print, in a panel of its own ----
   Two containers stacked, not one: this panel wears the same 9-slice frame
   the content card wears, and the board's own panel starts fresh below it.

   ITS SIZE IS FIXED, AND IT IS NOT ITS OWN. The panel takes over the exact
   footprint of the looping video header and the two title pills — one region,
   two uses that cannot both be open — so its box is their box: the same side
   margins, and a height that adds up to the three of them plus the gaps
   between. That is why .app.chart-open hides all three: they are not merely
   out of the way, the panel is standing where they stood.

   Because the height is computed from the header and the pills rather than
   from the chart, it is the same box at one candle and at thirty-four. The
   chart inside compresses to fit, exactly as the replay does for a long
   match. */
.chart-outer {
  position: relative;
  isolation: isolate;
  flex: 0 0 auto;
  /* the header's own top margin, then its height, then each pill's gap and
     height — the three boxes this one replaces, added up */
  margin: max(var(--sat), 6px) 4% 0;
  height: calc(var(--head-h, 152px) + 10px + 2 * var(--bar-h));
  border-radius: var(--radius-card);
}
.chart-outer[hidden] { display: none; }
.chart-outer::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 36px solid transparent;
  border-image: url("../assets/backgrounds/app-background-card-v2@2x.png") 96 fill / 36px stretch;
}
/* the panel is open, so the region it borrows is not */
.app.chart-open .header-zone,
.app.chart-open .bar { display: none; }

.chart-panel {
  position: relative;
  height: 100%;
  border-radius: calc(var(--radius-card) - 1.5px);
  overflow: hidden;
  /* the same inset the content card gives its own scroller, so the two
     stacked panels hold their content at the same distance from the frame */
  padding: 16px 16px 12px;
}
.pw-live { display: flex; height: 100%; }
.pw-live .pw-chart {
  flex: 1 1 auto; min-width: 0; min-height: 0;
  margin: 0;
}
/* the chart fills the panel rather than asking for a height of its own: the
   box is fixed, so the plot is whatever is left after the head, the chip row
   and a reveal if one is open */
.pw-live .pw-chart-body {
  flex: 1 1 auto;
  min-height: 0;
  --pw-row-h: 30px;
  --pw-plot-min: 54px;
}
.pw-live .pw-chart-head { margin-bottom: 4px; font-size: calc(8.5px * var(--fs)); }
.pw-live .pw-chart-rowcap { font-size: calc(6.5px * var(--fs)); }
.pw-live .pw-chart-empty {
  display: flex; align-items: center; justify-content: center;
  flex: 1 1 auto;
  padding: 0 6px;
  font-size: calc(10.5px * var(--fs));
  text-align: center;
}
/* tapping a candle opens that round the way the replay does. The panel may
   not grow for it, so the plot yields the room instead. */
.pw-live .pw-reveal { flex: 0 0 auto; margin-top: 6px; }
.pw-count-btn:active { filter: brightness(1.5); }

/* ---- the arena: your card, the meter, theirs ----
   One row where there were three. The seat on the left is also the drop
   target, so a dragged card goes to the place it will sit. */
.pw-arena {
  --pw-gauge-w: clamp(62px, 17vw, 88px);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  justify-items: center;
  gap: 6px;
  padding: 4px 0 6px;
  flex: 1 1 auto;
  min-height: 0;
  /* so the seats below can be measured against this box on both axes */
  container-type: size;
}
/* A card is bounded twice over: by the height the arena has left, and by the
   width of its own column once the gauge and the gaps are paid for. Whichever
   runs out first is the card. Height alone is not enough — on a phone it is
   the width that binds, and sizing on height alone grows the cards straight
   through the meter between them. */
.pw-seat {
  /* A floor under both bounds: whichever runs out first decides the card, but
     neither may decide there is no card. Above the floor this is a no-op, so
     the board at any ordinary height is unchanged; it is here because a short
     arena once sized the height bound to zero and emptied the table. */
  --pw-card-h: max(64px, min(
    100cqh - 36px,
    (100cqw - var(--pw-gauge-w) - 18px) / 2 * 334 / 249
  ));
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  min-width: 0;
  height: 100%;
}
@supports not (height: 1cqh) {
  .pw-seat { --pw-card-h: clamp(88px, 12.5vh, 124px); }
}
.pw-seat-tag, .pw-seat-cap, .pw-seat-slot { flex: 0 0 auto; }
.pw-seat-tag {
  font-size: calc(9px * var(--fs));
  font-weight: 800; letter-spacing: .18em; text-transform: uppercase;
  color: var(--pw-muted);
}
.pw-seat-tag.you { color: var(--pw-bull); }
.pw-seat-tag.opp { color: var(--pw-bear); }
/* The seat is a place, not a frame: whatever stands in it — a card back or a
   played card — is finished artwork carrying its own border, and a second one
   drawn around it only doubles up. So the seat paints nothing and takes its
   width from whatever it holds. */
.pw-seat-slot {
  display: flex; align-items: center; justify-content: center;
  height: var(--pw-card-h);
  width: auto;
  border: 0;
  background: none;
  border-radius: 12px;
  transition: box-shadow .15s ease, transform .15s ease;
}
/* the back fits the seat's height and keeps its own proportions — the art is
   a different shape from a played card, and neither is stretched to the other */
.pw-back {
  display: block;
  height: 100%;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  user-select: none;
  -webkit-user-drag: none;
}
/* a card is being dragged onto your seat */
.pw-seat-slot.over {
  box-shadow: 0 0 0 2px rgba(47,230,194,.3), 0 0 26px rgba(47,230,194,.45);
  transform: scale(1.04);
}
.pw-seat-cap {
  max-width: 100%;
  font-size: calc(8px * var(--fs));
  font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  text-align: center;
  color: var(--pw-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}




/* ---- the meter, upright ----
   +25 at the top, −25 at the bottom, the print itself in the middle. The fill
   grows from the midline and arrives as one percentage, the same number the
   game-over meter spends. */
.pw-print { display: flex; align-items: center; justify-content: center;
  height: 100%; max-height: 260px; padding: 14px 0; }
.pw-print-end {
  position: absolute;
  left: 0; right: 0;
  z-index: 1;
  font-size: calc(10px * var(--fs));
  font-weight: 800; letter-spacing: .04em; text-align: center;
  color: var(--text);
}
.pw-print-end.top { top: 3px; }
.pw-print-end.bot { bottom: 3px; }
.pw-print-gauge {
  position: relative;
  width: var(--pw-gauge-w, clamp(62px, 17vw, 88px));
  height: min(100%, 210px);
  /* the read-out sits in the middle and the two ends ride inside the gauge,
     so below this the figure lands on top of +25 and −25. The arena gives the
     meter its height, and with the live print panel open there is less of it
     to give — see the floor on .pw-field below. */
  min-height: 74px;
  border: 1.5px solid rgba(120,200,255,.4);
  border-radius: 14px;
  background: linear-gradient(180deg, rgba(255,60,90,.07), rgba(4,7,18,.85) 46%, rgba(4,7,18,.85) 54%, rgba(47,230,194,.07));
  overflow: hidden;
}
.pw-print-fill {
  position: absolute;
  left: 0; right: 0;
  height: var(--pw-fill, 0%);
  opacity: .3;
}
.pw-print-fill.up   { bottom: 50%; }
.pw-print-fill.down { top: 50%; }
.pw-print-fill.bull { background: linear-gradient(0deg, transparent, var(--pw-bull)); }
.pw-print-fill.bear { background: linear-gradient(180deg, transparent, var(--pw-bear)); }
.pw-print-fill.flat { background: transparent; }
.pw-print-read {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px;
}
.pw-print-val {
  font-size: calc(26px * var(--fs));
  font-weight: 800; line-height: 1;
  color: var(--text);
}
.pw-print-val.bull { color: var(--pw-bull); }
.pw-print-val.bear { color: var(--pw-bear); }
.pw-print-cap {
  font-size: calc(8px * var(--fs));
  font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  color: var(--pw-muted);
}

/* ---- the hand's header: the count, and the way into the ten wilds ---- */
.pw-handhead {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px;
  padding: 4px 2px 5px;
}
.pw-specials-btn {
  display: flex; align-items: center; gap: 7px;
  padding: 6px 11px;
  border: 1px solid rgba(120,200,255,.4);
  border-radius: 999px;
  background: rgba(4,7,18,.7);
  font-size: calc(9px * var(--fs));
  font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: #C7D9EF;
}
.pw-specials-btn.on { border-color: var(--pw-wild); color: var(--pw-wild); }
.pw-specials-btn:active { filter: brightness(1.4); }
.pw-specials-ico {
  position: relative;
  flex: 0 0 auto;
  width: 11px; height: 15px;
  border: 1.5px solid currentColor;
  border-radius: 3px;
}
.pw-specials-ico::before {
  content: "";
  position: absolute; left: 2px; top: -3px;
  width: 11px; height: 15px;
  border: 1.5px solid currentColor;
  border-radius: 3px;
  opacity: .5;
}

/* ---- the ten wilds, expanded in place ---- */
.pw-sheet {
  margin-top: 8px;
  border: 1px solid var(--pw-wild);
  border-radius: 14px;
  background: rgba(7,10,24,.9);
  /* ten rows will not fit beside the table on a phone. The sheet takes what
     is left of the column and scrolls its own rows — the screen behind it
     still does not move, which is the whole point of this layout. */
  flex: 1 1 auto;
  min-height: 0;
  max-height: 62%;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.pw-sheet-cap {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex; align-items: center; justify-content: space-between;
  padding: 9px 12px;
  background: rgba(7,10,24,.97);
  border-bottom: 1px solid var(--pw-line);
  font-size: calc(10px * var(--fs));
  font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: var(--pw-wild);
}
.pw-sheet-x {
  padding: 3px 9px;
  border: 1px solid var(--pw-line);
  border-radius: 999px;
  background: none;
  font-size: calc(9px * var(--fs));
  font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--pw-muted);
}
.pw-sheet-rows { display: flex; flex-direction: column; }
.pw-sheet-row {
  display: grid;
  grid-template-columns: 44px 1fr;
  align-items: center;
  gap: 11px;
  padding: 9px 12px;
  border-top: 1px solid rgba(255,255,255,.05);
}
.pw-sheet-row:first-child { border-top: 0; }
.pw-sheet-art { width: 44px; height: auto; display: block; border-radius: 4px; }
.pw-sheet-text { display: flex; flex-direction: column; gap: 2px; }
.pw-sheet-name {
  font-size: calc(11px * var(--fs));
  font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--pw-wild);
}
.pw-sheet-desc { font-size: calc(11px * var(--fs)); line-height: 1.4; color: var(--pw-muted); }

/* ---- cards ----
   The face is the artwork. These rules set how tall the picture is, and what
   may happen to it — nothing draws one. */
.pw-card {
  position: relative;
  display: inline-flex;
  flex: 0 0 auto;
  height: var(--pw-card-h, 118px);
  margin: 0; padding: 0;
  border: 0;
  border-radius: 11px;
  background: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform .14s ease, filter .14s ease, opacity .14s ease;
}
.pw-card-art {
  display: block;
  height: 100%;
  width: auto;
  border-radius: 10px;
  -webkit-user-drag: none;
  user-select: none;
}
/* ---- .pw-cardfit: one card, the right shape, everywhere off the table ----
   A card face is 2:3, and the only thing that was ever wrong with the pages
   that show one was that they sized it from one axis. `height: 100%` on a
   panel that grows — because the video header folded away, or the title bars
   did — makes the card grow with it, and since its width follows its height
   it leaves the panel sideways. The Library did the same thing the other way
   round and stretched the picture to the cell.

   So the shape is stated, not inferred, and the box is allowed to be smaller
   than the space it is given in either direction: max-width and max-height
   together mean the card takes the smaller of the two, which is the whole of
   "fits inside its container, never clipped, never off-screen". object-fit
   keeps the picture honest inside that box whatever the file's own pixels
   are, and the aspect-ratio holds the space before the picture has loaded,
   so nothing jumps when it does.

   Used by: How to Play (the card pairs and the strength ladder), the Card
   Library grid, the open card in Card Detail. Gameplay is not on this rule
   and does not need to be — a hand is sized from --pw-card-h, a number, which
   is why it was never the thing that stretched. */
.pw-cardfit {
  min-width: 0; min-height: 0;
  display: flex; align-items: center; justify-content: center;
  container-type: size;
}
/* First the floor, for an engine with no container units: the picture does
   its own fitting and cannot leave the box, whatever shape the box took. */
.pw-cardfit .pw-card {
  flex: 0 1 auto;
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
}
/* .pw-back is the face-down card, which is a picture rather than a frame with
   a picture in it — so it is both the box and the art, and it takes both
   halves of this rule. */
.pw-cardfit .pw-card-art,
.pw-cardfit > .pw-back {
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
  aspect-ratio: 2 / 3;
  object-fit: contain;
}
/* Then the rule itself. A width that is the smaller of the room across and
   the room down turned back into a width is the whole idea in one line, and
   it needs the container's height, which is what the unit is for. The card
   and its picture are then the same 2:3 rectangle rather than a picture
   centred in a box of some other shape. */
@supports (width: 1cqh) {
  .pw-cardfit .pw-card,
  .pw-cardfit > .pw-back {
    width: min(100%, calc(100cqh * 2 / 3));
    height: auto;
    aspect-ratio: 2 / 3;
  }
  .pw-cardfit .pw-card-art { width: 100%; height: 100%; }
}
/* and the stand-in, when a picture will not load, is the same shape */
.pw-cardfit .pw-card-alt { width: auto; height: auto; aspect-ratio: 2 / 3; max-height: 100%; }
/* A face that has not arrived yet is an empty rectangle the right size, with
   the frame drawn on it, rather than a hole where a card should be. It takes
   no space of its own and nothing moves when the picture lands — the box is
   already the box. */
.pw-cardfit .pw-card-art:not(.ready),
.pw-cardfit > .pw-back:not(.ready) {
  border-radius: 10px;
  background: rgba(8,14,32,.55);
  box-shadow: inset 0 0 0 1px rgba(61,223,255,.22);
}

/* a name for the card if its picture will not load */
.pw-card-alt {
  display: flex; align-items: center; justify-content: center;
  width: 84px; height: 100%;
  padding: 6px;
  border: 1px solid var(--pw-line);
  border-radius: 10px;
  font-size: calc(10px * var(--fs));
  font-weight: 700; text-align: center;
  color: var(--pw-muted);
}
.pw-card[data-pw-play]:active,
.pw-card[data-pw-answer]:active { transform: translateY(-5px) scale(1.04); }
.pw-card.dim { opacity: .34; filter: grayscale(.65); }
.pw-card.dragging { opacity: .25; }
/* the clone that follows the finger */
.pw-card.pw-ghost {
  position: fixed; left: 0; top: 0;
  z-index: 90;
  pointer-events: none;
  filter: drop-shadow(0 12px 24px rgba(0,0,0,.75));
}
/* How many of this candle are still in your own deck. It cannot go near the
   foot of the card: the art prints STRENGTH there, and a second number beside
   that one reads as part of it. Top-right, opposite the art's own badge, and
   written as a count so it cannot be mistaken for a value. */
.pw-card-left {
  position: absolute;
  right: 4px; top: 4px;
  min-width: 17px;
  padding: 1px 4px;
  border: 1px solid var(--pw-line);
  border-radius: 999px;
  background: rgba(3,5,14,.9);
  font-size: calc(9px * var(--fs));
  font-weight: 800; line-height: 1.5; text-align: center;
  color: var(--pw-muted);
}
/* their card turns over as it arrives */
.pw-card.flipping { animation: pw-turn .3s ease; }
@keyframes pw-turn {
  from { transform: rotateY(84deg); }
  to   { transform: rotateY(0); }
}

/* ---- your hand: one row, scrolled sideways ----
   The table no longer scrolls under it — the whole screen fits — so the hand
   is back in the flow with nothing pinned over anything. */
.pw-hand-cap {
  font-size: calc(10px * var(--fs));
  font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--pw-muted);
}
.pw-hand-cap b { color: var(--text); font-weight: 800; }
.pw-hand {
  flex: 0 0 auto;
  --pw-card-h: clamp(94px, 13.5vh, 122px);
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 2px 10px 6px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* the drag reads vertical movement, so the row may only take the other axis */
  touch-action: pan-x;
}
.pw-hand::-webkit-scrollbar { display: none; }
.pw-hand .pw-card { scroll-snap-align: center; }
.pw-hand-empty {
  width: 100%;
  padding: 22px 0;
  font-size: calc(11px * var(--fs));
  text-align: center;
  color: var(--pw-muted);
}

/* ---- draw choice: stands where the hand would be ---- */
.pw-choice {
  margin-top: 10px;
  padding: 12px;
  border: 1px solid var(--pw-wild);
  border-radius: 14px;
  background: rgba(7,10,24,.8);
  text-align: center;
}
.pw-choice-cap { font-size: calc(12px * var(--fs)); color: var(--text); margin-bottom: 10px; }
.pw-choice-btns { display: flex; gap: 10px; justify-content: center; }
.pw-choice-btn {
  flex: 1 1 0;
  padding: 10px 8px;
  border-radius: 10px;
  font-size: calc(12px * var(--fs)); font-weight: 700; color: var(--text);
  border: 1.5px solid var(--pw-line);
}
.pw-choice-btn.bull { border-color: var(--pw-bull); background: linear-gradient(160deg, var(--pw-bull-dim), var(--pw-panel)); }
.pw-choice-btn.bear { border-color: var(--pw-bear); background: linear-gradient(160deg, var(--pw-bear-dim), var(--pw-panel)); }
.pw-choice-btn.wild { border-color: var(--pw-wild); background: linear-gradient(160deg, var(--pw-wild-dim), var(--pw-panel)); }
.pw-choice-btn:disabled { opacity: .4; }

/* ---- what the opponent has shown ----
   Stands where the hand does, like the draw choice: it is a thing to read, and
   the screen must not start scrolling to read it. */
.pw-seen {
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px solid var(--pw-line);
  border-radius: 14px;
  background: rgba(4,7,18,.72);
}
.pw-seen-cap {
  font-size: calc(9px * var(--fs));
  font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--pw-muted);
  margin-bottom: 6px;
}
.pw-seen-row {
  display: flex; justify-content: space-between; gap: 8px;
  padding: 2px 0;
  font-size: calc(11px * var(--fs));
  color: #5B6E85;
}
.pw-seen-row.on { color: var(--text); }
.pw-seen-n { font-weight: 700; }
.pw-seen-row.on .pw-seen-n.bull { color: var(--pw-bull); }
.pw-seen-row.on .pw-seen-n.bear { color: var(--pw-bear); }
.pw-seen .pw-ghost { margin-top: 8px; }

/* ---- game over ---- */
/* The result screen carries the meter now, so the padding it used to spend on
   empty space goes to the meter instead — the whole thing still has to land
   inside one screenful on a short phone without scrolling. */
/* ===================== POINTÆWAY — MATCH HUB =====================
   The game's front door: the record, the recent matches, and the two ways in.

   Every frame here is a delivered picture used as a nine-slice rather than as
   a stretched background. The tiles are square files standing in portrait
   boxes and the history row is a file six times wider than it is tall sitting
   in a box thirteen times wider — stretched, the corner radius and the lit
   stroke would go with them. Sliced, only the flat middle moves, and the ends
   the artwork put things in (the row's icon well, the row's chevron, the
   pills' glyph) keep their shape. */
/* The hub is a column of a fixed height, not a page that grows. Everything on
   it has a job and a size except the match history, which is the one part that
   can give — so it takes what is left and its own list scrolls inside its own
   frame when there is less of it than there are matches. The screen itself
   never scrolls, which is the rule, and on a short phone the history is a
   shorter list rather than the reason the buttons are off the bottom.

   (It did not fit a 375x667 screen before this: 127px over, with the overflow
   landing on the bottom nav. The two reference buttons made that worse, and
   this is what makes both sizes right.) */
.pw-hub {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 0 2px 6px;
}
.pw-hub > * { flex: 0 0 auto; }
/* and everything on it is measured against the column it is really drawn in,
   the same --vh1 the entry screens use: a 390x844 phone keeps the sizes it
   has, a 375x667 one gives a few pixels back everywhere rather than losing
   the buttons off the bottom */
.pw-hub .pw-hub-stats { margin-bottom: clamp(3px, calc(.55 * var(--vh1)), 8px); }
/* the tile's own height, not a floor under it: the nine-slice's 13px border
   and the caption underneath are what make it 96 tall, and both come down */
.pw-hub .pw-hub-stats { align-items: stretch; }
.pw-hub .pw-stat {
  height: clamp(56px, calc(10.2 * var(--vh1)), 96px);
  padding: clamp(2px, calc(.6 * var(--vh1)), 5px) 1px;
  border-width: clamp(9px, calc(1.6 * var(--vh1)), 13px);
  border-image-width: clamp(9px, calc(1.6 * var(--vh1)), 13px);
}
.pw-hub .pw-stat-ico {
  width: clamp(12px, calc(1.9 * var(--vh1)), 16px);
  height: clamp(12px, calc(1.9 * var(--vh1)), 16px);
}
.pw-hub .pw-stat-n { font-size: calc(clamp(13px, calc(1.9 * var(--vh1)), 16px) * var(--fs)); }
.pw-hub .pw-hub-banner { max-width: clamp(128px, calc(23 * var(--vh1)), 208px); }
.pw-hub .pw-hub-link { padding: clamp(4px, calc(.83 * var(--vh1)), 7px) 4px; }
.pw-hub .pw-hist {
  flex: 1 1 auto;
  min-height: clamp(30px, calc(4.5 * var(--vh1)), 72px);
  margin-bottom: clamp(3px, calc(.55 * var(--vh1)), 8px);
  display: flex;
  flex-direction: column;
}
.pw-hub .pw-hub-pill { height: clamp(44px, calc(6.4 * var(--vh1)), 54px); }
.pw-hub .pw-hub-pill.chal { margin-top: clamp(3px, calc(.55 * var(--vh1)), 8px); }
.pw-hub .pw-hub-pill.mini { height: clamp(31px, calc(4.5 * var(--vh1)), 38px); }
.pw-hub .pw-hub-acts.second { margin-top: clamp(3px, calc(.55 * var(--vh1)), 8px); }
.pw-hub .pw-hub-link {
  min-height: clamp(20px, calc(3.1 * var(--vh1)), 26px);
  margin-top: clamp(3px, calc(.55 * var(--vh1)), 8px);
}
.pw-hub .pw-hub-head { margin-bottom: clamp(3px, calc(.7 * var(--vh1)), 6px); }
.pw-hub .pw-hist-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
/* The history box is the one that gives, so it is also the one that has to
   clip: squeezed to its floor it would otherwise spill its empty-state line
   out from behind the buttons below it. */
.pw-hub .pw-hist {
  overflow: hidden;
  padding: clamp(4px, calc(1.1 * var(--vh1)), 8px) 7px;
}
.pw-hub .pw-hist-head { margin-bottom: clamp(2px, calc(.7 * var(--vh1)), 6px); }
/* On a column this short (an iPhone SE), the decoration is what pays for the
   history rows, and the pill subtitles do not fit a 44px pill once the title
   wraps. The titles alone say what the buttons do. */
.short-vh .pw-hub .pw-hub-banner { max-width: 104px; }
.short-vh .pw-hub .pw-hub-pill-s { display: none; }
/* and with one line left in the pill, it should be one line: "Create Match"
   wrapping while "Start Match" did not is what reads as broken */
.short-vh .pw-hub .pw-hub-pill-t {
  font-size: calc(11.5px * var(--fs));
  white-space: nowrap;
}
/* the empty history still has to say what it is in the room it has left */
.short-vh .pw-hub .pw-hist-none { padding: 2px 6px; font-size: calc(10.5px * var(--fs)); }
/* Losing the subtitle must not take the pill under a thumb's worth of height.
   It needs the flex too: .pw-hub-pill sets flex: 1 1 0 for the side-by-side
   rows, and as a child of the hub column that makes this one stretchy. */
.short-vh .pw-hub .pw-hub-pill.chal { flex: 0 0 auto; height: 44px; }

.pw-hub-head {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  margin-bottom: 6px;
}
/* out of the flow so the banner centres on the header rather than on what is
   left of it once the arrow has had its share */
.pw-hub-back {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 34px; height: 34px;
  display: grid; place-items: center;
  background: none;
  z-index: 1;
}
.pw-hub-back img { width: 20px; height: 20px; object-fit: contain; }
.pw-hub-back:active { filter: brightness(1.4); transform: translateY(-50%) scale(.9); }
.pw-hub-banner {
  /* wide enough to be the header and no wider: every row it gains, the
     history list below it loses, and the five entries have to share one view */
  width: 57%;
  max-width: 208px;
  height: auto;
  pointer-events: none;
}

/* ---- the five ---- */
.pw-hub-stats {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  margin-bottom: 8px;
}
.pw-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: 2px;
  min-width: 0;
  padding: 5px 1px 5px;
  border-style: solid;
  border-width: 13px;
  /* one square file per tile, sliced so the portrait box keeps its corners */
  border-image-slice: 55 fill;
  border-image-width: 13px;
  border-image-repeat: stretch;
}
.pw-stat.t1 { border-image-source: url("../assets/pointaeway/hub/tile-1.png"); }
.pw-stat.t2 { border-image-source: url("../assets/pointaeway/hub/tile-2.png"); }
.pw-stat.t3 { border-image-source: url("../assets/pointaeway/hub/tile-3.png"); }
.pw-stat.t4 { border-image-source: url("../assets/pointaeway/hub/tile-4.png"); }
.pw-stat.t5 { border-image-source: url("../assets/pointaeway/hub/tile-5.png"); }
.pw-stat-ico { width: 16px; height: 16px; object-fit: contain; flex: 0 0 auto; }
.pw-stat-cap {
  flex: 1 1 auto;
  font-size: calc(7px * var(--fs));
  font-weight: 600;
  line-height: 1.15;
  text-align: center;
  color: #CFE4F7;
}
.pw-stat-n {
  font-size: calc(16px * var(--fs));
  font-weight: 800;
  line-height: 1;
  color: #F2FBFF;
}
.pw-stat-n.win  { color: var(--pw-bull); }
.pw-stat-n.loss { color: #FF5C93; }
.pw-stat-n.bull { color: #3DDFFF; }
.pw-stat-n.bear { color: #FF5C93; }

/* ---- the record ---- */
.pw-hist {
  border-radius: 16px;
  border: 1px solid rgba(61,223,255,.22);
  background: rgba(6,10,24,.6);
  padding: 8px 7px;
  margin-bottom: 8px;
}
/* ==================== the performance chart ====================
   It lives inside the Match History box, which becomes the whole of the hub's
   middle while it is up — the header video and the two title bars having
   stepped aside the way they do for the live chart in a match.

   The plot is a plain box with absolutely positioned candles in it. Not a
   canvas and not an SVG: a pan writes left and width on sixty elements, which
   the compositor handles without a repaint of anything else, and the candles
   stay ordinary buttons that a finger and a screen reader can both find. */
.pw-hist.charted {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column;
}
.pw-perf {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column;
  gap: clamp(4px, calc(.8 * var(--vh1)), 8px);
}
/* The two filters, in the plot's top-left, wearing the chart menus the day
   chart already has — .tp-menu-btn and .tp-menu, reused rather than copied,
   so there is one dropdown in this app and not two that look alike. They cost
   the chart nothing: they stand over it rather than above it, where the two
   rows of pills they replace were taking a fifth of its height. */
.pw-perf-menus {
  position: absolute; top: 7px; left: 7px;
  display: flex; gap: 5px;
  z-index: 3;
}
.pw-perf-menus .tp-menu-btn { min-width: 52px; }

.pw-perf-total {
  display: flex; align-items: baseline; gap: 8px;
  padding: 0 2px;
}
.pw-perf-total b { font-size: calc(19px * var(--fs)); font-weight: 800; color: var(--text); }
.pw-perf-total b.up { color: var(--pw-bull); }
.pw-perf-total b.down { color: var(--pw-bear); }
.pw-perf-total i { font-style: normal; font-size: calc(10px * var(--fs)); color: var(--pw-muted); }
.pw-perf-total span { margin-left: auto; font-size: calc(11.5px * var(--fs)); font-weight: 700; color: var(--pw-muted); }
.pw-perf-total span.up { color: var(--pw-bull); }
.pw-perf-total span.down { color: var(--pw-bear); }
.pw-perf-total em { font-style: normal; font-weight: 600; color: var(--pw-muted); }

.pw-perf-plot {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  border-radius: 12px;
  border: 1px solid var(--pw-line);
  background: rgba(4,7,18,.9);
  background-image: radial-gradient(circle, rgba(143,169,196,.22) 0.5px, transparent 1px);
  background-size: 13px 13px;
  padding: 8px 40px 8px 8px;      /* the right gutter is the axis's */
  overflow: hidden;
  /* the chart takes the gesture: no page swipe, no pull-to-refresh, no
     double-tap zoom under a finger that is reading it */
  touch-action: none;
}
.pw-perf-cands { position: relative; height: 100%; width: 100%; }
.pw-cand {
  position: absolute; top: 0; bottom: 0;
  padding: 0; border: 0; background: none;
  -webkit-tap-highlight-color: transparent;
}
.pw-cand-wick, .pw-cand-body {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  border-radius: 1px;
}
.pw-cand-wick { width: 1.5px; background: currentColor; opacity: .75; }
.pw-cand-body { width: 62%; min-width: 3px; background: currentColor; border-radius: 2px; }
.pw-cand.win { color: #26a69a; }
.pw-cand.loss { color: #ef5350; }
.pw-cand.flat { color: #8FA9C4; }
/* a match recorded before replays were kept: the body, and no wick to tell a
   story the record does not have */
.pw-cand.bodyonly .pw-cand-wick { display: none; }
.pw-cand.on .pw-cand-body { box-shadow: 0 0 0 1.5px #EAF6FF, 0 0 10px rgba(234,246,255,.5); }
.pw-cand.on .pw-cand-wick { opacity: 1; }

.pw-perf-y {
  position: absolute; top: 8px; right: 6px; bottom: 8px; width: 34px;
  pointer-events: none;
}
.pw-perf-y i {
  position: absolute; right: 0;
  transform: translateY(-50%);
  font-style: normal;
  font-size: calc(9px * var(--fs)); font-weight: 700;
  color: var(--pw-muted);
}
.pw-perf-x {
  position: absolute; left: 8px; right: 40px; bottom: 1px; height: 11px;
  pointer-events: none;
}
.pw-perf-x i {
  position: absolute;
  transform: translateX(-50%);
  font-style: normal;
  font-size: calc(8.5px * var(--fs)); font-weight: 700;
  color: rgba(143,169,196,.75);
}
.pw-perf-zero {
  position: absolute; left: 8px; right: 40px;
  border-top: 1px dashed rgba(143,169,196,.4);
  pointer-events: none;
}
/* The scrub label has three corners to choose from — the fourth is the
   filters', which have to stay reachable. It takes the top-right one, and
   drops to a bottom corner when the candle it is describing is standing in
   that one; pwPerfTip measures which rather than guessing from which half the
   finger is in, because a tall candle near the middle reaches the top-right
   box while still being on the left. */
.pw-perf-tip {
  position: absolute; right: 44px; top: 8px;
  display: flex; flex-direction: column; gap: 1px;
  /* kept to its corner: a label wide enough to cross the plot would reach
     the candle it is describing however it is anchored */
  max-width: min(60%, 215px);
  padding: 5px 8px;
  border: 1px solid var(--pw-line); border-radius: 9px;
  background: rgba(5,9,22,.94);
  pointer-events: none;
}
.pw-perf-tip.low { top: auto; right: auto; left: 8px; bottom: 16px; }
.pw-perf-tip.lowright { top: auto; bottom: 16px; }
.pw-perf-tip[hidden] { display: none; }
.pw-perf-tip b { font-size: calc(11px * var(--fs)); font-weight: 800; }
.pw-perf-tip b.win { color: var(--pw-bull); }
.pw-perf-tip b.loss { color: var(--pw-bear); }
.pw-perf-tip b.flat { color: var(--pw-muted); }
.pw-perf-tip span { font-size: calc(9.5px * var(--fs)); color: #C7D9EF; }
.pw-perf-tip i { font-style: normal; font-size: calc(9.5px * var(--fs)); font-weight: 700; color: var(--pw-muted); }

.pw-perf.empty { justify-content: center; }
.pw-perf-none {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px;
  text-align: center;
  padding: 12px;
  font-size: calc(11.5px * var(--fs)); color: var(--pw-muted);
}
.pw-perf-none .pw-hub-pill.wide { flex: 0 0 auto; width: min(100%, 230px); }

/* the toggle: the same candle glyph the live chart has, at the size of the
   row it sits in */
.pw-perf-btn {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 30px; height: 26px;
  border: 1px solid var(--pw-line); border-radius: 8px;
  background: rgba(5,9,22,.7);
  color: #9FD9FF;
}
.pw-perf-btn .pw-chart-ico { width: 18px; height: 13px; }
.pw-perf-btn.on { border-color: rgba(61,223,255,.7); background: rgba(10,30,56,.95); color: #EAF6FF; }
.pw-perf-btn:active { filter: brightness(1.35); transform: scale(.94); }

.pw-hist-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
  padding: 0 2px;
}
.pw-hist-title {
  font-size: calc(13.5px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
}
.pw-hist-all {
  display: flex; align-items: center; gap: 5px;
  background: none;
  font-size: calc(10.5px * var(--fs));
  font-weight: 700;
  color: #7FE3F5;
}
.pw-hist-all img { width: 9px; height: 13px; object-fit: contain; }
.pw-hist-all:active { filter: brightness(1.35); transform: scale(.97); }
.pw-hist-list { display: flex; flex-direction: column; gap: 4px; }
.pw-hist-none {
  padding: 16px 6px;
  text-align: center;
  font-size: calc(11.5px * var(--fs));
  color: var(--pw-muted);
}
/* The row frame. Its left end holds a drawn icon well and its right end a
   drawn chevron, so both ends are kept out of the stretch: only the flat
   middle between them moves as the row gets wider. */
.pw-hrow {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 42px;
  padding: 0 2px;
  border-style: solid;
  /* the ends are held out of the stretch at the same scale the row is drawn
     at — 42/135 of each slice — so the well and the chevron keep their shape */
  border-width: 9px 31px 9px 44px;
  border-image: url("../assets/pointaeway/hub/row.png") 30 100 30 140 fill / 9px 31px 9px 44px stretch;
  font-size: calc(9.5px * var(--fs));
  font-weight: 700;
}
/* the well the frame draws is in the left border, so the icon is placed over
   it rather than laid out in the row */
/* In flow, not out of it. It used to be position:absolute, and the nearest
   positioned ancestor is .card — which sits OUTSIDE #cardScroll, the box that
   actually scrolls. An absolutely positioned element inside a momentum
   scroller whose containing block is an ancestor outside that scroller is
   what lets an icon detach from its row and paint over the list on iOS; it
   renders correctly on desktop, which is why it stood this long.

   Staying in flow costs three numbers instead of one: the negative left
   margin still pulls it over the well drawn in the row's left border, and the
   right margin gives back exactly what the item's own width and the row's
   4px gap would otherwise take from everything after it. Measured at 320,
   375 and 393: every other child of the row is where it was. */
.pw-hrow-ico {
  position: static;
  flex: 0 0 auto;
  width: 23px; height: 23px;
  margin: 0 5px 0 -32px;
  display: grid; place-items: center;
}
.pw-hrow-ico img { width: 100%; height: 100%; object-fit: contain; }
.pw-hrow-mid  { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.pw-hrow-opp  { color: #DCEBFA; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* what the match was set to, under who it was against */
.pw-hrow-set  {
  font-size: calc(8.5px * var(--fs)); font-weight: 600; color: #7E9CBB;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pw-hrow-side { flex: 0 0 auto; color: #9FC0E0; }
.pw-hrow-res  { flex: 0 0 auto; }
.pw-hrow-pts  { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.pw-hrow-when { flex: 0 0 auto; color: #8FA9C4; font-weight: 600; white-space: nowrap; }
.pw-hrow-res.win,  .pw-hrow-pts.win  { color: var(--pw-bull); }
.pw-hrow-res.loss, .pw-hrow-pts.loss { color: #FF5C93; }
.pw-hrow-res.flat, .pw-hrow-pts.flat { color: var(--pw-muted); }
/* a row with a match behind it is a button; the frame already ends in a
   chevron, so the only thing it needs is to answer a press */
.pw-hrow.open {
  width: 100%;
  text-align: left;
  transition: filter .13s ease, transform .13s ease;
  -webkit-tap-highlight-color: transparent;
}
.pw-hrow.open:active { filter: brightness(1.32); transform: scale(.99); }

/* ===================== POINTÆWAY — ONLINE =====================
   The live 1v1, the queue in front of it and the record behind it. Built from
   the hub's and the library's parts — the same back arrow, the same title,
   the same pills — so it reads as more of the same game rather than as a
   second app inside the first. */
.pw-hub-link {
  display: block;
  width: 100%;
  margin-top: 8px;
  padding: 7px 4px;
  text-align: center;
  font-size: calc(11px * var(--fs));
  font-weight: 700;
  letter-spacing: .04em;
  color: #9FC0E0;
}
.pw-hub-link span { color: #7FA8CC; }
.pw-hub-link:active { color: #EAF6FF; }

.pw-on { padding: 0 2px 12px; }

/* one spinner for every wait on these screens */
.pw-spinner {
  width: 44px; height: 44px;
  border-radius: 50%;
  border: 3px solid rgba(61,223,255,.18);
  border-top-color: var(--cyan);
  animation: pw-spin .9s linear infinite;
}
.pw-spinner.sm { width: 22px; height: 22px; border-width: 2.5px; display: inline-block; vertical-align: middle; }
@keyframes pw-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .pw-spinner { animation: none; border-top-color: rgba(61,223,255,.18); border-right-color: var(--cyan); }
}

.pw-on-ava {
  display: inline-grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: url("../assets/buttons-icon/profile-ring@2x.png") center / contain no-repeat;
  flex: 0 0 auto;
}
.pw-on-ava img { width: 22px; height: 22px; object-fit: contain; }
.pw-on-ava img.shot { width: 34px; height: 34px; border-radius: 50%; object-fit: cover; }
.pw-on-ava.lg { width: 96px; height: 96px; }
.pw-on-ava.lg img { width: 44px; height: 44px; }
.pw-on-ava.lg img.shot { width: 76px; height: 76px; }

/* ---- the queue ---- */
.pw-finding-body {
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  padding: 22px 0 18px;
  text-align: center;
}
.pw-finding-name { font-size: calc(16px * var(--fs)); font-weight: 800; color: var(--text); }
.pw-finding-cap {
  font-size: calc(12.5px * var(--fs)); font-weight: 700; letter-spacing: .06em;
  color: #DDEFFF;
}
.pw-finding-sub { font-size: calc(11px * var(--fs)); color: var(--pw-muted); }
.pw-finding-cancel { margin: 6px auto 0; display: flex; }

.pw-on-msg {
  display: flex; flex-direction: column; gap: 6px;
  margin: 18px 2px 14px;
  padding: 14px;
  border: 1px solid var(--pw-line);
  border-radius: 12px;
  background: rgba(7,10,24,.7);
  text-align: center;
}
.pw-on-msg b { font-size: calc(14px * var(--fs)); font-weight: 800; color: var(--text); }
.pw-on-msg span { font-size: calc(11.5px * var(--fs)); line-height: 1.5; color: var(--pw-muted); }
.pw-on-err {
  margin: 6px 2px 0;
  font-size: calc(11px * var(--fs)); line-height: 1.4;
  color: #FF9CA8;
  text-align: center;
}

/* ---- the room ---- */
.pw-on-head {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  padding: 4px 2px 8px;
}
.pw-on-player {
  flex: 1 1 0; min-width: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 8px;
  align-items: center;
}
.pw-on-player .pw-on-ava { grid-row: 1 / span 2; }
.pw-on-player.opp { direction: rtl; text-align: right; }
.pw-on-player.opp > * { direction: ltr; }
.pw-on-pname {
  font-size: calc(12px * var(--fs)); font-weight: 800; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pw-on-ptag {
  font-size: calc(9px * var(--fs)); font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
}
.pw-on-player.me .pw-on-ptag { color: var(--pw-bull); }
.pw-on-player.opp .pw-on-ptag { color: var(--pw-bear); }
.pw-on-score {
  grid-column: 1 / -1;
  font-size: calc(22px * var(--fs)); font-weight: 800; line-height: 1;
  color: var(--text); font-variant-numeric: tabular-nums;
  margin-top: 4px;
}
.pw-on-player.opp .pw-on-score { text-align: right; }
.pw-on-vs {
  flex: 0 0 auto;
  font-size: calc(11px * var(--fs)); font-weight: 800; letter-spacing: .14em;
  color: #6E86A6;
}

.pw-on-chart {
  border: 1px solid var(--pw-line);
  border-radius: 12px;
  background: rgba(7,10,24,.7);
  padding: 6px 6px 4px;
}
.pw-on-svg { display: block; width: 100%; height: 120px; }
.pw-on-open { stroke: rgba(159,192,224,.35); stroke-width: 1; stroke-dasharray: 3 4; }
.pw-on-wick { stroke-width: 1.2; }
.pw-on-wick.bull { stroke: var(--pw-bull); }
.pw-on-wick.bear { stroke: var(--pw-bear); }
.pw-on-wick.flat { stroke: #6E86A6; }
.pw-on-body.bull { fill: var(--pw-bull); }
.pw-on-body.bear { fill: var(--pw-bear); }
.pw-on-body.flat { fill: #6E86A6; }
.pw-on-chartcap {
  display: flex; justify-content: space-between;
  padding: 4px 4px 0;
  font-size: calc(9px * var(--fs)); font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: #6E86A6;
}

/* ---- the live board ----
   An online match is played on the same table a single-player one is, so it
   reuses .pw-counts, .pw-field/.pw-arena, .pw-handhead and .pw-hand whole.
   What is added here is only the wrapper: the scroller becomes a fixed-height
   flex column for a local match, and the online board sits one level inside
   it, so the column has to be handed down. */
.card-scroll.pw-playing > .pw-on-board {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  padding-bottom: 2px;
}
/* The board's one header row: the way back, then both players with their
   round-win scores beside them. Off the board this row stacks the score under
   the name and there is a title line above it; here neither fits, so the
   player collapses to a single line and the title is gone entirely. */
.pw-on-head.tight { padding: 2px 2px 4px; gap: 4px; flex: 0 0 auto; }
.pw-on-back {
  flex: 0 0 auto;
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border: 0; background: none;
  -webkit-tap-highlight-color: transparent;
}
.pw-on-back img { width: 18px; height: 18px; object-fit: contain; }
.pw-on-back:active { filter: brightness(1.4); transform: scale(.9); }
.pw-on-head.tight .pw-on-player {
  grid-template-columns: auto 1fr auto;
  grid-template-rows: auto;
  column-gap: 6px;
}
.pw-on-head.tight .pw-on-player .pw-on-ava { grid-row: 1; width: 30px; height: 30px; }
.pw-on-head.tight .pw-on-ava img { width: 16px; height: 16px; }
.pw-on-head.tight .pw-on-ava img.shot { width: 23px; height: 23px; }
/* YOU / OPP is already written under both seats on the table below */
.pw-on-head.tight .pw-on-ptag { display: none; }
.pw-on-split {
  flex: 0 0 auto;
  width: 1px; height: 22px;
  margin: 0 5px;
  background: rgba(255,255,255,.18);
}
.pw-on-head.tight .pw-on-score {
  grid-column: 3; grid-row: 1;
  margin-top: 0;
  font-size: calc(17px * var(--fs));
}
.pw-on-board .pw-counts,
.pw-on-board .pw-handhead,
.pw-on-board .pw-hand,
.pw-on-board .pw-seen,
.pw-on-board .pw-choice,
.pw-on-board .pw-on-err { flex: 0 0 auto; }
.pw-on-board .pw-sheet { flex: 1 1 auto; min-height: 0; }
/* a card in the online hand is a button; the local hand's are too, so the
   only thing to say is that a disabled one still reads as a card */
.pw-on-board .pw-hand .pw-card[disabled] { opacity: .55; }


.pw-on-banner {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  margin: 14px 2px 12px;
  padding: 16px 12px;
  border-radius: 14px;
  border: 1px solid var(--pw-line);
  background: rgba(7,10,24,.7);
  text-align: center;
}
.pw-on-banner b { font-size: calc(22px * var(--fs)); font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
.pw-on-banner span { font-size: calc(12px * var(--fs)); font-weight: 700; color: var(--pw-muted); }
.pw-on-banner.win { border-color: rgba(0,220,160,.5); }
.pw-on-banner.win b { color: var(--pw-bull); }
.pw-on-banner.loss { border-color: rgba(255,92,147,.5); }
.pw-on-banner.loss b { color: #FF5C93; }
.pw-on-banner.draw b { color: #C9DDF2; }

/* ---- the record ---- */
.pw-oh-list { display: flex; flex-direction: column; gap: 7px; }
.pw-oh-row {
  border: 1px solid var(--pw-line);
  border-radius: 12px;
  background: rgba(7,10,24,.7);
  overflow: hidden;
}
.pw-oh-row.open { border-color: rgba(61,223,255,.5); }
.pw-oh-btn {
  display: flex; align-items: center; gap: 8px;
  width: 100%;
  padding: 7px 10px 7px 8px;
  text-align: left;
  font-size: calc(11px * var(--fs)); font-weight: 700;
  -webkit-tap-highlight-color: transparent;
}
.pw-oh-btn:active { filter: brightness(1.3); }
.pw-oh-btn .pw-on-ava { width: 34px; height: 34px; }
.pw-oh-btn .pw-on-ava img { width: 18px; height: 18px; }
.pw-oh-btn .pw-on-ava img.shot { width: 26px; height: 26px; }
.pw-oh-opp { flex: 1 1 auto; min-width: 0; color: #DCEBFA; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pw-oh-res, .pw-oh-score { flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.pw-oh-when { flex: 0 0 auto; color: #8FA9C4; font-weight: 600; white-space: nowrap; font-size: calc(9.5px * var(--fs)); }
.pw-oh-res.win,  .pw-oh-score.win  { color: var(--pw-bull); }
.pw-oh-res.loss, .pw-oh-score.loss { color: #FF5C93; }
.pw-oh-res.draw, .pw-oh-score.draw { color: var(--pw-muted); }
.pw-oh-res.live, .pw-oh-score.live { color: var(--cyan); }
.pw-oh-chart { padding: 0 8px 8px; }
.pw-oh-chart .pw-on-svg { height: 110px; }

/* ---- the challenge bar (invites.js) ----
   A challenge can land while its recipient is anywhere in the app, so the
   newest one draws itself in a strip at the top of the card, above whatever
   screen is up. It is a row of the card's own flex column, not a layer over
   it — nothing in this app opens on a dimmed background. */
.chal-bar {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 12px;
  border-bottom: 1px solid rgba(255,92,147,.3);
  background: linear-gradient(180deg, rgba(58,10,32,.92), rgba(24,6,18,.92));
}
.chal-bar[hidden] { display: none; }
.chal-bar-dot {
  flex: 0 0 auto;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--pink, #FF5C93);
  box-shadow: 0 0 8px rgba(255,92,147,.9);
  animation: chal-pulse 1.6s ease-in-out infinite;
}
@keyframes chal-pulse { 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .chal-bar-dot { animation: none; } }
.chal-bar-text {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column;
  font-size: calc(11.5px * var(--fs)); color: var(--text);
}
.chal-bar-text b,
.chal-bar-text i {
  display: block; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chal-bar-text b { font-weight: 800; }
.chal-bar-text i {
  font-style: normal; font-size: calc(9.5px * var(--fs)); font-weight: 600;
  color: #E7A8BF;
}
.chal-bar-btn {
  flex: 0 0 auto;
  padding: 5px 10px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.05);
  font-size: calc(10px * var(--fs)); font-weight: 800;
  color: var(--text);
  white-space: nowrap;
}
.chal-bar-btn.yes { border-color: rgba(61,223,255,.55); color: var(--cyan); }
.chal-bar-btn:active { filter: brightness(1.4); }
.chal-bar-x {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  border: 0; background: none;
  font-size: calc(15px * var(--fs)); line-height: 1;
  color: #B487A0;
}

/* ---- the two sessions have drifted (see onlineAuthState) ---- */
.on-reconnect {
  display: flex; flex-direction: column; gap: 8px;
  margin: 10px 2px;
  padding: 12px 13px;
  border: 1px solid rgba(61,223,255,.32);
  border-radius: 14px;
  background: rgba(6,16,30,.72);
}
.on-reconnect b { font-size: calc(13px * var(--fs)); font-weight: 800; color: var(--text); }
.on-reconnect span { font-size: calc(11px * var(--fs)); line-height: 1.5; color: var(--pw-muted, #8FA9C6); }
.on-reconnect-mail {
  font-size: calc(11px * var(--fs)); font-weight: 700;
  color: var(--cyan);
  word-break: break-all;
}

/* ---- Connections (connections.js + messages.js) ---- */
.conn { padding: 0 2px 14px; }
.conn-me {
  width: 100%;
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  align-items: center; gap: 10px;
  margin-bottom: 14px;
  padding: 10px 12px;
  border: 1px solid var(--pw-line, rgba(120,170,255,.22));
  border-radius: 16px;
  background: rgba(4,7,18,.7);
  text-align: left;
}
.conn-me-n { font-size: calc(22px * var(--fs)); font-weight: 800; color: var(--cyan); }
.conn-me-cap {
  font-size: calc(10px * var(--fs)); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--pw-muted, #8FA9C6);
}
.conn-me-go { font-size: calc(10px * var(--fs)); color: var(--pw-muted, #8FA9C6); }
.conn-me:active { filter: brightness(1.25); }

.conn-list { margin: -6px 2px 16px; }
.conn-sec { margin-bottom: 18px; }
.conn-sec-head {
  display: flex; align-items: center; gap: 7px;
  margin: 0 2px 8px;
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .18em; text-transform: uppercase;
  color: #8FA9C6;
}
.conn-sec-n {
  min-width: 18px; height: 18px;
  display: grid; place-items: center;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--pink, #FF5C93);
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
  letter-spacing: 0;
  color: #fff;
}
.conn-row {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 2px;
}
.conn-row + .conn-row { border-top: 1px solid rgba(255,255,255,.07); }
.conn-row .pw-on-ava { width: 34px; height: 34px; }
.conn-row .pw-on-ava img { width: 18px; height: 18px; }
.conn-row .pw-on-ava img.shot { width: 26px; height: 26px; }
.conn-row.result .pw-on-ava { width: 42px; height: 42px; }
.conn-row.result .pw-on-ava img { width: 22px; height: 22px; }
.conn-row.result .pw-on-ava img.shot { width: 32px; height: 32px; }
.conn-row-name {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column;
  font-size: calc(12px * var(--fs)); font-weight: 800; color: var(--text);
}
/* a display name runs to 40 characters and the narrowest phone is 320px, so
   both lines ellipsize rather than run under the buttons */
.conn-row-name i {
  display: block; max-width: 100%;
  font-style: normal; font-size: calc(9.5px * var(--fs)); font-weight: 600;
  color: #9FB4CC;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.conn-row-name { overflow: hidden; }
.conn-row-name > :first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.conn-btn {
  flex: 0 0 auto;
  padding: 6px 11px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.05);
  font-size: calc(10px * var(--fs)); font-weight: 800;
  color: var(--text);
  white-space: nowrap;
}
.conn-btn.yes { border-color: rgba(61,223,255,.55); color: var(--cyan); }
.conn-btn.sent { border-color: rgba(255,196,94,.5); color: #FFC45E; }
.conn-btn.done { border-color: rgba(120,255,190,.4); color: #6FE9B0; }
.conn-btn.msg { border-color: rgba(190,140,255,.5); color: #C9A0FF; }
.conn-btn:active { filter: brightness(1.4); }
.conn-empty {
  padding: 10px 2px;
  font-size: calc(11px * var(--fs)); color: var(--pw-muted, #8FA9C6);
}
.conn-find-cap {
  margin: 0 2px 7px;
  font-size: calc(10.5px * var(--fs)); line-height: 1.5;
  color: var(--pw-muted, #8FA9C6);
}
.conn-find { text-transform: none; }
.conn-go { width: 100%; margin-top: 8px; }
.conn-foot {
  margin: 4px 2px 0;
  font-size: calc(10px * var(--fs)); line-height: 1.5;
  color: #6F86A3;
  text-align: center;
}
.pr-conn-entry {
  width: 100%;
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: 10px;
  margin-top: 10px;
  padding: 11px 14px;
  border: 1px solid var(--pw-line, rgba(120,170,255,.22));
  border-radius: 14px;
  background: rgba(4,7,18,.7);
  text-align: left;
}
.pr-conn-entry-n { font-size: calc(18px * var(--fs)); font-weight: 800; color: var(--cyan); }
.pr-conn-entry-cap {
  font-size: calc(11px * var(--fs)); font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--pw-muted, #8FA9C6);
}
.pr-conn-entry-go { font-size: calc(15px * var(--fs)); color: var(--pw-muted, #8FA9C6); }
.pr-conn-entry:active { filter: brightness(1.25); }

/* ---- one thread, text only (messages.js) ---- */
.conn-thread { display: flex; flex-direction: column; }
.conn-thread-head {
  display: flex; align-items: center; gap: 9px;
  padding: 2px 2px 10px;
  border-bottom: 1px solid rgba(255,255,255,.08);
}
.conn-thread-back {
  width: 28px; height: 28px;
  border: 0; background: none;
  font-size: calc(22px * var(--fs)); line-height: 1;
  color: var(--cyan);
}
.conn-thread-head .pw-on-ava { width: 32px; height: 32px; }
.conn-thread-head .pw-on-ava img { width: 17px; height: 17px; }
.conn-thread-head .pw-on-ava img.shot { width: 24px; height: 24px; }
.conn-thread-name {
  flex: 1 1 auto; min-width: 0;
  font-size: calc(13px * var(--fs)); font-weight: 800; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.conn-msgs {
  display: flex; flex-direction: column; gap: 6px;
  min-height: 180px;
  max-height: 46vh;
  padding: 10px 2px;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.conn-msg {
  max-width: 78%;
  padding: 7px 11px;
  border-radius: 14px;
  font-size: calc(12px * var(--fs)); line-height: 1.45;
  color: var(--text);
  word-wrap: break-word; overflow-wrap: anywhere;
}
.conn-msg.mine {
  align-self: flex-end;
  border: 1px solid rgba(61,223,255,.35);
  background: rgba(10,40,58,.75);
}
.conn-msg.theirs {
  align-self: flex-start;
  border: 1px solid rgba(255,255,255,.14);
  background: rgba(16,20,34,.8);
}
.conn-compose { display: flex; align-items: center; gap: 8px; padding-top: 8px; }
.conn-msg-input { flex: 1 1 auto; min-width: 0; text-transform: none; }
.conn-send {
  flex: 0 0 auto;
  padding: 10px 16px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.55);
  background: rgba(10,40,58,.6);
  font-size: calc(11px * var(--fs)); font-weight: 800;
  color: var(--cyan);
}
.conn-send:active { filter: brightness(1.4); }
.conn-send[disabled] { opacity: .5; }

/* ---- challenges: the inbox, the lookup, the wait (invites.js) ---- */
/* the count on the dock's Gameæway slot — the one place the app already
   points at the games, so it is where a waiting challenge announces itself */
.dock-badge {
  position: absolute;
  top: 4px; right: 8px;
  min-width: 16px; height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--magenta, #FF3D9A);
  box-shadow: 0 0 8px rgba(255,61,154,.8);
  color: #fff;
  font-size: 10px; font-weight: 800; line-height: 16px;
  text-align: center;
  pointer-events: none;
}

.pw-inbox {
  margin: 0 0 10px;
  padding: 9px 10px 10px;
  border: 1px solid rgba(255,61,154,.45);
  border-radius: 12px;
  background: linear-gradient(160deg, rgba(60,10,34,.6), rgba(7,10,24,.85));
}
.pw-inbox-head { display: flex; align-items: center; gap: 7px; margin-bottom: 7px; }
.pw-inbox-title {
  flex: 1 1 auto;
  font-size: calc(10.5px * var(--fs)); font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: #FFC4D2;
}
.pw-inbox-n {
  min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 999px; background: var(--magenta, #FF3D9A);
  color: #fff; font-size: 10px; font-weight: 800; line-height: 18px; text-align: center;
}
.pw-inbox-err { font-size: calc(11px * var(--fs)); color: #FFC4D2; }
.pw-inv { display: flex; align-items: center; gap: 8px; padding: 5px 0; }
.pw-inv + .pw-inv { border-top: 1px solid rgba(255,255,255,.07); }
.pw-inv .pw-on-ava { width: 34px; height: 34px; }
.pw-inv .pw-on-ava img { width: 18px; height: 18px; }
.pw-inv .pw-on-ava img.shot { width: 26px; height: 26px; }
.pw-inv-name {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column;
  font-size: calc(12px * var(--fs)); font-weight: 800; color: var(--text);
}
/* a display name is up to 40 characters and the narrowest phone is 320px, so
   both lines ellipsize rather than run under the two buttons. The ellipsis
   has to sit on the children: the column itself is a flex box, and a flex
   box never ellipsizes its own content. */
.pw-inv-name b,
.pw-inv-name i {
  display: block; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pw-inv-name b { font-weight: 800; }
.pw-inv-name i {
  font-style: normal; font-size: calc(9.5px * var(--fs)); font-weight: 600;
  color: #C9A0B4;
}
.pw-inv-act {
  flex: 0 0 auto;
  padding: 6px 11px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.22);
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  color: #DDEFFF;
}
.pw-inv-act.yes { border-color: rgba(0,220,160,.55); color: var(--pw-bull); background: rgba(0,200,150,.14); }
.pw-inv-act:active { filter: brightness(1.35); transform: scale(.96); }
.pw-inv-busy { flex: 0 0 auto; display: grid; place-items: center; width: 60px; }

/* the hub's third pill — the same frame as the other two, since it is the
   same kind of thing: another way into a match */
.pw-hub-pill.chal {
  width: 100%;
  margin-top: 8px;
  border-image-source: url("../assets/pointaeway/hub/pill-find.png");
}
/* the whole of Play Local for now: one line under the pill that asked for it */
.pw-local-note { margin: 10px 2px 2px; }

/* ---- Create Match ----
   Two questions and a button. Each question is a caption, a line of why it
   matters, and the answers as pressable tiles — the point targets four across
   because they are numbers, the specialty settings stacked because they are
   sentences. Nothing here opens over anything: the screen changes to the join
   form and back, as every other flow in this app does. */
.pw-create { padding: 0 2px 14px; }
.pw-cm-group {
  margin: 0 2px 16px;
  padding: 12px 12px 14px;
  border: 1px solid var(--pw-line);
  border-radius: 14px;
  background: rgba(7,10,24,.62);
}
.pw-cm-cap {
  font-size: calc(10px * var(--fs)); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase;
  color: #9FD9FF;
}
.pw-cm-sub {
  margin: 5px 0 11px;
  font-size: calc(10.5px * var(--fs)); line-height: 1.5;
  color: var(--pw-muted);
}
.pw-cm-opts { display: grid; gap: 7px; }
.pw-cm-opts.pts { grid-template-columns: repeat(4, 1fr); }
.pw-cm-opts.spec { grid-template-columns: 1fr; }
.pw-cm-opt {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  min-height: 56px;
  padding: 8px 6px;
  border: 1px solid var(--pw-line);
  border-radius: 11px;
  background: rgba(4,8,20,.72);
  text-align: center;
  transition: border-color .16s ease, background .16s ease;
}
.pw-cm-opt.wide { flex-direction: column; align-items: flex-start; text-align: left; min-height: 0; }
.pw-cm-opt-t {
  font-size: calc(14px * var(--fs)); font-weight: 800; color: var(--text);
  line-height: 1.1;
}
.pw-cm-opt.wide .pw-cm-opt-t { font-size: calc(12.5px * var(--fs)); }
.pw-cm-opt-s {
  font-size: calc(9px * var(--fs)); line-height: 1.35; color: var(--pw-muted);
}
.pw-cm-opt.on {
  border-color: rgba(61,223,255,.7);
  background: rgba(10,34,60,.85);
  box-shadow: 0 0 12px rgba(61,223,255,.22) inset;
}
.pw-cm-opt.on .pw-cm-opt-t { color: var(--cyan); }
.pw-cm-opt:active { filter: brightness(1.3); transform: scale(.985); }
.pw-cm-note {
  margin: 10px 0 0;
  font-size: calc(10px * var(--fs)); line-height: 1.5;
  color: #7FA8CC;
}
.pw-cm-go { width: calc(100% - 4px); margin: 2px 2px 4px; justify-content: center; }

/* the code, once it exists: the biggest thing on the screen, because reading
   it out to somebody is the only job it has */
.pw-cm-code-wrap { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.pw-cm-code {
  padding: 10px 18px;
  border: 1px solid rgba(61,223,255,.5);
  border-radius: 14px;
  background: rgba(6,16,34,.8);
  font-size: calc(30px * var(--fs)); font-weight: 800;
  letter-spacing: .22em; text-indent: .22em;
  color: var(--cyan);
  text-shadow: 0 0 16px rgba(61,223,255,.5);
}
.pw-cm-code-acts { display: flex; gap: 8px; }

/* what the joiner is shown before committing to it */
.pw-cm-preview { margin: 14px 2px 0; }
.pw-cm-sum {
  display: flex; flex-direction: column;
  border: 1px solid var(--pw-line);
  border-radius: 12px;
  background: rgba(7,10,24,.7);
  overflow: hidden;
}
.pw-cm-sum-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 12px;
  font-size: calc(11.5px * var(--fs));
  color: var(--pw-muted);
}
.pw-cm-sum-row + .pw-cm-sum-row { border-top: 1px solid var(--pw-line); }
.pw-cm-sum-row b { font-weight: 800; color: var(--text); text-align: right; }
.pw-cm-lock {
  margin: 9px 2px 11px;
  font-size: calc(10px * var(--fs)); line-height: 1.5;
  color: #6E86A6;
  text-align: center;
}
.pw-cm-preview .pw-over-pill { width: 100%; justify-content: center; }
/* ---- a YOLO's two cards in one slot ----
   Fanned rather than stacked: both have to be readable, and the total they
   come to is the thing that actually fought, so it sits over the join where
   neither card can hide it. The slot's own height is the card's, so the two
   are scaled to fit it rather than overflowing the arena. */
.pw-yolo-fan {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  /* one card's width, not two: the slot is a seat in a three-column arena and
     a pair at full size runs out of it and over the print meter. The two are
     scaled to share the one slot instead. */
  width: calc(var(--pw-card-h) * 303 / 460);
}
.pw-yolo-card {
  display: block;
  height: 66%;
}
.pw-yolo-card .pw-card { height: 100%; width: auto; }
.pw-yolo-card .pw-card-art { height: 100%; width: auto; }
.pw-yolo-card.i0 { transform: rotate(-11deg) translateX(26%); transform-origin: bottom center; z-index: 1; }
.pw-yolo-card.i1 { transform: rotate(11deg) translateX(-26%); transform-origin: bottom center; z-index: 2; }
.pw-yolo-total {
  position: absolute;
  left: 50%; bottom: 2%;
  transform: translateX(-50%);
  z-index: 3;
  padding: 2px 10px;
  border: 1px solid rgba(214,232,255,.6);
  border-radius: 999px;
  background: rgba(3,6,16,.92);
  font-size: calc(15px * var(--fs)); font-weight: 800;
  letter-spacing: .04em;
  color: #EAF6FF;
  white-space: nowrap;
}
.pw-yolo-total.bull { border-color: rgba(0,220,160,.7); color: var(--pw-bull); }
.pw-yolo-total.bear { border-color: rgba(255,77,109,.7); color: var(--pw-bear); }
@media (prefers-reduced-motion: no-preference) {
  .pw-seat-slot.sub .pw-yolo-card.i0 { animation: pwFanL .5s cubic-bezier(.2,.8,.2,1); }
  .pw-seat-slot.sub .pw-yolo-card.i1 { animation: pwFanR .5s cubic-bezier(.2,.8,.2,1) .08s backwards; }
}
@keyframes pwFanL {
  from { transform: rotate(0deg) translateX(0) scale(.86); opacity: .2; }
  to   { transform: rotate(-11deg) translateX(26%); opacity: 1; }
}
@keyframes pwFanR {
  from { transform: rotate(0deg) translateX(0) scale(.86); opacity: .2; }
  to   { transform: rotate(11deg) translateX(-26%); opacity: 1; }
}

/* ---- the slot's substitution badge ----
   YOLO and Diamond Hands put a different card in the slot than the one that
   was tapped, so the slot has to say so: the card that stepped aside, and what
   it put there. It sits over the foot of the card rather than under the seat,
   because the caption under the seat already has a job. */
.pw-sub-badge {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  max-width: 100%;
  margin-top: 2px;
  padding: 2px 7px;
  border: 1px solid rgba(214,232,255,.4);
  border-radius: 8px;
  background: rgba(3,6,16,.8);
  text-align: center;
  pointer-events: none;
}
.pw-sub-badge b {
  font-size: calc(8px * var(--fs)); font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase;
  color: #E6F2FF;
  white-space: nowrap;
}
.pw-sub-badge i {
  font-size: calc(7.5px * var(--fs)); font-style: normal; line-height: 1.2;
  color: #9FD9FF;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
/* the flipped card arrives with a short turn of its own — under the 600ms the
   brief asks for, and the same curve the opponent's reveal uses */
.pw-sub-badge.yolo { border-color: rgba(61,223,255,.5); }
.pw-sub-badge.dh { border-color: rgba(255,61,154,.45); }
.pw-seat-slot.sub .pw-card { animation: pwSubIn .42s cubic-bezier(.2,.8,.2,1); }
@keyframes pwSubIn {
  from { transform: rotateY(84deg) scale(.94); opacity: .25; }
  to   { transform: none; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .pw-seat-slot.sub .pw-card { animation: none; }
}

.pw-sheet-none {
  padding: 16px 12px;
  text-align: center;
  font-size: calc(11.5px * var(--fs));
  color: var(--pw-muted);
}

/* ---- the challenge screen ---- */
.pw-chal { padding: 0 2px 14px; }
.pw-chal-intro {
  margin: 2px 2px 12px;
  font-size: calc(11.5px * var(--fs)); line-height: 1.5;
  color: var(--pw-muted);
  text-align: center;
}
.pw-chal-input {
  text-transform: uppercase;
  letter-spacing: .08em;
  font-weight: 700;
}
.pw-chal-go { margin-top: 10px; }
.pw-chal-go[disabled] { opacity: .6; }
.pw-chal-cap {
  margin: 14px 2px 8px;
  text-align: center;
  font-size: calc(10px * var(--fs)); font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: #9FD9FF;
}
.pw-chal-results { display: flex; flex-direction: column; gap: 8px; }
.pw-chal-card {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 10px;
  border: 1px solid var(--pw-line);
  border-radius: 12px;
  background: rgba(7,10,24,.7);
}
.pw-chal-name {
  flex: 1 1 auto; min-width: 0;
  font-size: calc(13px * var(--fs)); font-weight: 800; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pw-chal-card .pw-over-pill { flex: 0 0 auto; }
.pw-on-ava.md { width: 52px; height: 52px; }
.pw-on-ava.md img { width: 26px; height: 26px; }
.pw-on-ava.md img.shot { width: 42px; height: 42px; }
.pw-chal-foot {
  margin: 16px 2px 0;
  text-align: center;
  font-size: calc(10.5px * var(--fs)); line-height: 1.5;
  color: #6E86A6;
}

/* ---- rematch, on a past opponent ---- */
.pw-oh-foot { display: flex; justify-content: flex-end; padding: 0 8px 8px; }
.pw-oh-rematch {
  padding: 5px 11px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.4);
  background: rgba(6,14,34,.6);
  font-size: calc(10.5px * var(--fs)); font-weight: 800; letter-spacing: .04em;
  color: #9FD9FF;
}
.pw-oh-rematch:active { filter: brightness(1.4); transform: scale(.96); }

/* ---- the invite code, on the profile ---- */
.pr-invite {
  margin: 0 0 14px;
  padding: 11px 12px 12px;
  border: 1px solid rgba(61,223,255,.3);
  border-radius: 12px;
  background: rgba(2,4,14,.6);
  text-align: center;
}
.pr-invite-cap {
  font-size: calc(9.5px * var(--fs)); font-weight: 800; letter-spacing: .18em; text-transform: uppercase;
  color: #8FA9C4;
  margin-bottom: 6px;
}
.pr-invite-code {
  font-size: calc(26px * var(--fs)); font-weight: 800; letter-spacing: .18em;
  color: var(--cyan);
  text-shadow: 0 0 14px rgba(61,223,255,.5);
  user-select: all; -webkit-user-select: all;
}
.pr-invite-row { display: flex; gap: 8px; margin-top: 10px; }
.pr-invite-row .ad-save, .pr-invite-row .ad-back { flex: 1 1 0; min-width: 0; margin: 0; }
.pr-invite-note {
  margin-top: 8px;
  font-size: calc(10px * var(--fs)); line-height: 1.45;
  color: #6E86A6;
}

/* ---- trade notes, under the journal's ledger (journal.js) ---- */
.jn {
  margin: 16px 0 4px;
  padding: 12px 12px 14px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  border-radius: 14px;
  background: rgba(7,10,24,.55);
}
.jn-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; }
.jn-title {
  font-size: calc(12px * var(--fs)); font-weight: 800; letter-spacing: .14em; text-transform: uppercase;
  color: #9FD9FF;
}
.jn-sub { flex: 1 1 auto; font-size: calc(10px * var(--fs)); color: #6E86A6; font-weight: 600; }
.jn-add {
  flex: 0 0 auto;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid rgba(61,223,255,.45);
  background: rgba(6,14,34,.6);
  font-size: calc(11px * var(--fs)); font-weight: 800; letter-spacing: .04em;
  color: #DDEFFF;
}
.jn-add:active { filter: brightness(1.35); transform: scale(.97); }
.jn-line {
  display: flex; align-items: center; gap: 8px;
  font-size: calc(12px * var(--fs)); line-height: 1.5;
  color: #9FC0E0;
  margin-bottom: 10px;
}
.jn-line.small { font-size: calc(10.5px * var(--fs)); color: #8FA9C4; }

.jn-composer { display: flex; flex-direction: column; gap: 8px; margin-bottom: 12px; }
.jn-text { min-height: 78px; resize: vertical; }
.jn-pic { position: relative; }
.jn-pic img {
  display: block; width: 100%; max-height: 260px; object-fit: contain;
  border-radius: 10px; border: 1px solid rgba(61,223,255,.3); background: #050614;
}
.jn-pic-x {
  position: absolute; top: 6px; right: 6px;
  width: 30px; height: 30px; border-radius: 50%;
  background: rgba(5,6,20,.8); border: 1px solid rgba(255,255,255,.25);
  color: #fff; font-size: 18px; line-height: 1;
}
.jn-row { display: flex; gap: 8px; }
.jn-row .btn-secondary, .jn-row .btn-primary { flex: 1 1 0; min-width: 0; margin: 0; }
.jn-save[disabled] { opacity: .6; }
.jn-cancel {
  align-self: center;
  padding: 6px 14px;
  font-size: calc(11px * var(--fs)); font-weight: 700;
  color: #8FA9C4;
}

.jn-list { display: flex; flex-direction: column; gap: 8px; }
.jn-note {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 9px 10px;
  border: 1px solid rgba(61,223,255,.2);
  border-radius: 12px;
  background: rgba(2,4,14,.55);
}
.jn-note.open { flex-direction: column; }
.jn-thumb {
  flex: 0 0 auto;
  width: 64px; height: 64px;
  padding: 0; border-radius: 8px; overflow: hidden;
  border: 1px solid rgba(61,223,255,.3); background: #050614;
  -webkit-tap-highlight-color: transparent;
}
.jn-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.jn-note.open .jn-thumb { width: 100%; height: auto; }
.jn-note.open .jn-thumb img { height: auto; max-height: 420px; object-fit: contain; }
.jn-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.jn-note-text {
  font-size: calc(12.5px * var(--fs)); line-height: 1.5;
  color: #DCEBFA;
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.jn-note-text.muted { color: #6E86A6; font-style: italic; }
.jn-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; }
.jn-when { flex: 1 1 auto; font-size: calc(10px * var(--fs)); color: #8FA9C4; font-weight: 600; }
.jn-ask { font-size: calc(10.5px * var(--fs)); color: #FFC4D2; font-weight: 700; }
.jn-act {
  padding: 4px 8px;
  font-size: calc(10.5px * var(--fs)); font-weight: 700; letter-spacing: .04em;
  color: #9FD9FF;
}
.jn-act.danger { color: #FF5C93; }
.jn-act:active { filter: brightness(1.4); }

/* ---- the account, on the profile screen ---- */
.pr-online { border: 1px solid var(--pw-line); border-radius: 14px; padding: 12px 12px 14px; background: rgba(7,10,24,.55); }
.pr-online .pr-sec-head { margin-top: 0; }
.pr-online-line {
  display: flex; align-items: center; gap: 8px;
  font-size: calc(12px * var(--fs)); line-height: 1.5;
  color: #9FC0E0;
  margin-bottom: 10px;
}
.pr-online-stats { display: flex; gap: 6px; margin-bottom: 12px; }
.pr-online-stat {
  flex: 1 1 0; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 8px 4px;
  border-radius: 10px;
  border: 1px solid rgba(61,223,255,.22);
  background: rgba(2,4,14,.6);
}
.pr-online-stat b { font-size: calc(18px * var(--fs)); font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; }
.pr-online-stat b.win { color: var(--pw-bull); }
.pr-online-stat b.loss { color: #FF5C93; }
.pr-online-stat b.xp { color: var(--cyan); }
.pr-online-stat span { font-size: calc(9.5px * var(--fs)); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #8FA9C4; }
.pr-online-levels { margin: 6px 0 12px; }
.pr-online .pr-notice { margin-top: 8px; }
.pr-notice.pending { color: #9FC0E0; }

/* ---- a match read back off the record ----
   A fixed-height column, not a list that stops where its content does. The two
   header lines take what they need; everything under them is the chart and the
   round it opens, and those two split the rest in half. With no round open the
   chart simply takes all of it — either way the screen ends where the card
   does, at any round count. */
.card-scroll.pw-savedscreen { display: flex; flex-direction: column; overflow: hidden; }
/* One page, by rule. The screen is a column of a fixed height and whatever is
   inside it shares that height out — nothing here scrolls, on any phone. */
.card-scroll.pw-fixed { display: flex; flex-direction: column; overflow: hidden; }
.card-scroll.pw-fixed > * { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }

/* ---- the Card Library ----
   Three tabs over a grid that is sized BY its box rather than sizing the box:
   the rows share what is left and the faces scale into them, so twelve
   specials fit a 375x667 screen the same way six candles fit a 390x844 one.
   That is why there is no paging — the grid cannot outgrow the page it is on. */
.pw-lib-tabs {
  flex: 0 0 auto;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
  margin: 0 2px 10px;
}
.pw-lib-tab {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 7px 4px;
  border: 1px solid var(--pw-line);
  border-radius: 11px;
  background: rgba(5,9,22,.72);
  transition: border-color .16s ease, background .16s ease;
}
.pw-lib-tab b {
  font-size: calc(12px * var(--fs)); font-weight: 800; color: var(--text);
  letter-spacing: .04em;
}
.pw-lib-tab i {
  font-size: calc(8.5px * var(--fs)); font-style: normal; color: var(--pw-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.pw-lib-tab.on { background: rgba(10,30,56,.9); }
.pw-lib-tab.on.bull { border-color: rgba(0,220,160,.7); }
.pw-lib-tab.on.bull b { color: var(--pw-bull); }
.pw-lib-tab.on.bear { border-color: rgba(255,77,109,.7); }
.pw-lib-tab.on.bear b { color: var(--pw-bear); }
.pw-lib-tab.on.special { border-color: rgba(214,232,255,.65); }
.pw-lib-tab:active { filter: brightness(1.3); }

/* The grid takes the room it is given and hands each cell an equal share of
   it; the card inside takes the smaller of that cell's two dimensions and
   keeps its shape. A taller panel therefore means more space around the
   cards, not taller cards — which is the whole of the stretching bug. */
.pw-lib-grid {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(var(--pw-lg-cols, 3), 1fr);
  grid-auto-rows: 1fr;
  gap: 7px;
  padding: 0 2px;
  align-content: center;
  justify-content: center;
}
/* The specials are a colour per column, so the grid fills downwards and the
   cells are in the order the cards are read in — which is the order the open
   card steps through and the order its dots count in. One order, one array,
   three places reading it. */
.pw-lib-grid.special {
  grid-auto-flow: column;
  grid-template-rows: repeat(var(--pw-lg-rows, 3), 1fr);
  grid-auto-columns: 1fr;
}
/* and the surplus goes around the grid rather than between its rows: the
   cards are as tall as their own width allows, the grid is no taller than
   its cards, and whatever height is left over is margin above and below.
   The height a row wants is the column's width in 2:3, which is what the
   container unit is here to say. */
@supports (height: 1cqw) {
  .pw-lib { container-type: inline-size; }
  .pw-lib-grid {
    --pw-lg-cell: calc((100cqw - 4px - (var(--pw-lg-cols, 3) - 1) * 7px) / var(--pw-lg-cols, 3));
    max-height: calc(var(--pw-lg-cell) * 1.5 * var(--pw-lg-rows, 2)
                     + (var(--pw-lg-rows, 2) - 1) * 7px);
    margin-block: auto;
  }
}
.pw-lib-cell {
  min-height: 0;
  padding: 0;
  background: none;
  border: 0;
}
.pw-lib-cell:active { filter: brightness(1.3); transform: scale(.96); }
.pw-lib-foot {
  flex: 0 0 auto;
  margin: 9px 2px 0;
  text-align: center;
  font-size: calc(10px * var(--fs)); color: var(--pw-muted);
}

/* ---- one card, full size ---- */
.pw-lib-big {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 2px;
}
/* The open card is centred in the panel, not in whatever is left over after
   the two arrows: the arrows take a fixed column each side and the card has
   the middle, so it sits on the panel's centre line at every size and in
   every panel state. */
.pw-lib-bigcard { flex: 1 1 auto; min-width: 0; height: 100%; }
.pw-lib-step {
  flex: 0 0 auto;
  width: 34px; height: 54px;
  display: grid; place-items: center;
  border: 1px solid var(--pw-line);
  border-radius: 10px;
  background: rgba(5,9,22,.7);
  font-size: calc(22px * var(--fs)); line-height: 1;
  color: #9FD9FF;
}
.pw-lib-step[disabled] { opacity: .28; }
.pw-lib-step:active:not([disabled]) { filter: brightness(1.4); transform: scale(.94); }
.pw-lib-info {
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  margin: 10px 4px 0;
  text-align: center;
}
.pw-lib-meta {
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase;
  color: #9FD9FF;
}
.pw-lib-meta.bull { color: var(--pw-bull); }
.pw-lib-meta.bear { color: var(--pw-bear); }
.pw-lib-detail-name {
  font-size: calc(16px * var(--fs)); font-weight: 800; color: var(--text);
}
.pw-lib-detail-text {
  font-size: calc(11.5px * var(--fs)); line-height: 1.5; color: var(--pw-muted);
  max-width: 34ch;
}
.pw-lib-dots {
  flex: 0 0 auto;
  display: flex; justify-content: center; gap: 5px; flex-wrap: wrap;
  margin: 10px 0 2px;
}
.pw-lib-dots i {
  width: 5px; height: 5px; border-radius: 999px;
  background: rgba(159,217,255,.3);
}
.pw-lib-dots i.on { background: var(--cyan); box-shadow: 0 0 7px rgba(61,223,255,.7); }

/* ---- How to Play ----
   Eight pages, one rule each, and the page is a column that shares its height
   between the picture and the words rather than running past the bottom. */
.pw-ht { padding: 0 2px 10px; text-align: left; }
.pw-ht-page {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
}
.pw-ht-step {
  flex: 0 0 auto;
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
  letter-spacing: .18em; text-transform: uppercase;
  color: #7FA8CC;
}
/* The title and the copy are measured against the column they are drawn in,
   the same --vh1 the hub and the entry screens use: on a tall phone they are
   what they were, and on a short one they give their pixels to the cards
   rather than squeezing them to thumbnails. */
.pw-ht-title {
  flex: 0 0 auto;
  margin: 4px 0 clamp(4px, calc(1.2 * var(--vh1)), 10px);
  font-size: calc(clamp(15px, calc(2.25 * var(--vh1)), 19px) * var(--fs));
  font-weight: 800;
  letter-spacing: .02em;
  color: var(--text);
}
.pw-ht-art {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px;
}
.pw-ht-text {
  flex: 0 0 auto;
  margin: clamp(6px, calc(1.4 * var(--vh1)), 12px) 6px 0;
  font-size: calc(clamp(10.5px, calc(1.5 * var(--vh1)), 12.5px) * var(--fs));
  line-height: 1.5;
  color: #C7D9EF;
  max-width: 38ch;
}
/* The Card Library link on page 8. .pw-over-pill is flex: 1 1 0 because the
   row it was written for lays two of them out side by side; as a child of
   this column that meant it grew to fill whatever height was left, which is
   how an ordinary pill became a tall black box and the two specials above it
   became thumbnails. It is a pill of a pill's height here, and the height it
   is not taking goes to the pair. */
/* Two classes, same specificity, and .pw-over-pill is written later in this
   file — so it has to be beaten on its own terms rather than by coming
   after it. */
.pw-over-pill.pw-ht-link {
  flex: 0 0 auto;
  align-self: center;
  width: auto;
  height: clamp(34px, calc(4.6 * var(--vh1)), 40px);
  padding: 0 16px;
  margin-top: clamp(6px, calc(1.4 * var(--vh1)), 12px);
  justify-content: center;
}

/* ---- .pw-ht-cards: the pair, and the only pair ----
   Five of the eight pages show two cards side by side — the two face-down
   backs on Lock In, the three fought rounds, and the two specials on the last
   page — and they are all this one layout. Each side is half the width and
   all of the height, each card takes the smaller of the two through
   .pw-cardfit, and the gap between them is one number written once. The
   backs on page 2 went through none of this before and ran off both edges of
   the panel, which is what happens when the one shared rule has an exception
   in it. */
.pw-ht-cards {
  display: flex; align-items: center; justify-content: center;
  gap: var(--ht-pair-gap, 12px);
  width: 100%; height: 100%;
  min-height: 0;
}
.pw-ht-cards > * { flex: 1 1 0; min-width: 0; height: 100%; }
/* Half the width each is right only while the cards are as wide as their
   half; on a short panel they are sized by height instead, and two cards
   centred in two half-width columns stand apart with a hole between them —
   which is what "spaced far apart" on page 8 was. So each side is only as
   wide as the card it holds, and the gap between them is the gap. */
@supports (width: 1cqh) {
  .pw-ht-cards { container-type: size; }
  .pw-ht-cards > * {
    flex: 0 1 auto;
    width: min(calc(50% - var(--ht-pair-gap, 12px) / 2), calc(100cqh * 2 / 3));
  }
}
.pw-ht-cards.win .pw-cardfit:first-child .pw-card { filter: drop-shadow(0 0 14px rgba(0,220,160,.6)); }
/* The line under the pair — BULL / BEAR, "+5 → the Print", "The Print does
   not move" — and on the two pages that have nothing to say there, the space
   it would have taken. Reserved on all five, so the cards above it are the
   same size whether the page has a caption or not. */
.pw-ht-cap {
  flex: 0 0 auto;
  min-height: clamp(13px, calc(1.9 * var(--vh1)), 17px);
  display: flex; align-items: center; justify-content: center;
}
.pw-ht-tags { display: flex; gap: 58px; font-size: calc(10px * var(--fs)); font-weight: 800; letter-spacing: .14em; }
.pw-ht-tags .bull { color: var(--pw-bull); }
.pw-ht-tags .bear { color: var(--pw-bear); }
.pw-ht-delta {
  font-size: calc(12px * var(--fs)); font-weight: 800; letter-spacing: .06em;
  color: var(--pw-bull);
}
.pw-ht-delta.flat { color: var(--pw-muted); font-weight: 700; }

/* The two pages that draw a diagram rather than a card — the Print on page 1
   and the two decks on page 6 — were fixed pixel sizes sitting in the middle
   of whatever space the panel had, which on a folded header is most of the
   screen. They scale with the box now, the way the cards do. */
.pw-ht-art { container-type: size; }
.pw-ht-goal {
  display: flex; align-items: center; justify-content: center;
  gap: clamp(12px, 5cqw, 30px);
}
.pw-ht-arrow { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.pw-ht-arrow b { font-size: calc(clamp(15px, 4cqh, 28px) * var(--fs)); font-weight: 800; }
.pw-ht-arrow span { font-size: calc(9.5px * var(--fs)); font-weight: 800; letter-spacing: .16em; }
.pw-ht-arrow.bull, .pw-ht-arrow.bull b, .pw-ht-arrow.bull span { color: var(--pw-bull); }
.pw-ht-arrow.bear, .pw-ht-arrow.bear b, .pw-ht-arrow.bear span { color: var(--pw-bear); }
.pw-ht-print {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: clamp(10px, 3cqh, 26px) clamp(14px, 5cqw, 34px);
  border: 1px solid var(--pw-line); border-radius: 13px;
  background: rgba(5,9,22,.75);
}
.pw-ht-print i {
  font-style: normal;
  font-size: calc(clamp(26px, 7cqh, 54px) * var(--fs));
  font-weight: 800; color: var(--text);
}
.pw-ht-print span { font-size: calc(8.5px * var(--fs)); font-weight: 800; letter-spacing: .16em; color: var(--pw-muted); }

.pw-ht-piles { display: flex; gap: clamp(16px, 7cqw, 44px); align-items: flex-end; }
.pw-ht-pile { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.pw-ht-pile i { font-style: normal; font-size: calc(10px * var(--fs)); color: var(--pw-muted); }
.pw-ht-stack {
  height: clamp(80px, 52cqh, 300px);
  width: auto;
  aspect-ratio: 2 / 3;
  border-radius: 9px;
  border: 1px solid rgba(214,232,255,.4);
  background: rgba(8,14,32,.9);
  box-shadow: 3px 3px 0 -1px rgba(8,14,32,.9), 3px 3px 0 0 rgba(214,232,255,.3),
              6px 6px 0 -1px rgba(8,14,32,.9), 6px 6px 0 0 rgba(214,232,255,.22);
}
.pw-ht-stack.bull { border-color: rgba(0,220,160,.6); }
.pw-ht-stack.bear { border-color: rgba(255,77,109,.6); }

/* the strength ladder: three across, two down, strongest first */
.pw-ht-ladder {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: 4px 6px;
  width: 100%; height: 100%; min-height: 0;
  padding: 0 2px;
}
/* the card takes the room the row has and the name sits directly under it,
   not at the far bottom of the cell */
.pw-ht-tier {
  min-height: 0; min-width: 0;
  display: grid; grid-template-rows: 1fr auto;
  gap: 3px;
}
.pw-ht-tier .pw-cardfit { min-height: 0; width: 100%; align-items: flex-end; }
/* the names are written out: "Mar…" on a page about which card beats which
   is the one abbreviation that cannot be made */
.pw-ht-tname {
  display: block;
  text-align: center;
  font-size: calc(9.5px * var(--fs)); line-height: 1.2;
}
.pw-ht-tname b { font-weight: 700; color: #C7D9EF; }
.pw-ht-tname i {
  font-style: normal;
  font-size: calc(11px * var(--fs)); font-weight: 800; color: var(--pw-bull);
}

.pw-ht-nav {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 10px;
}
.pw-ht-arrowbtn {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border: 1px solid var(--pw-line); border-radius: 11px;
  background: rgba(5,9,22,.7);
  font-size: calc(21px * var(--fs)); line-height: 1; color: #9FD9FF;
}
.pw-ht-arrowbtn[disabled] { opacity: .28; }
.pw-ht-arrowbtn:active:not([disabled]) { filter: brightness(1.4); transform: scale(.94); }
.pw-ht-dots { display: flex; gap: 7px; }
.pw-ht-dots button {
  width: 7px; height: 7px; padding: 0;
  border: 0; border-radius: 999px;
  background: rgba(159,217,255,.3);
}
.pw-ht-dots button.on { background: var(--cyan); box-shadow: 0 0 8px rgba(61,223,255,.75); }

/* ---- the hub's second row ----
   The same pill, shorter: these are the way to read the rules, not the way to
   start a game, and they should not read as equals of the row above them. */
.pw-hub-acts.second { margin-top: 8px; }
.pw-hub-pill.mini {
  /* about seventy per cent of the row above, which is what makes them read as
     the second thing on the screen rather than two more ways to start a game.
     The nine-slice's end caps come down with it or the glyph would be taller
     than the pill it is drawn in. */
  height: 38px;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 0 4px;
  /* the app's plain neon pill rather than the match row's nine-slice. The
     match row's art carries a multiplayer glyph baked into its left end, and
     a 9-slice cannot leave one slice out — so matching that pill exactly would
     have put "two people" on How to Play and on Card Library. Same family,
     same glow, no glyph. */
  border-width: 2px;
  border-image: url("../assets/buttons-pill/button-pill-standard@2x.png") 78 86 fill / 13px 18px stretch;
}
.pw-hub-pill.mini .pw-hub-pill-t { font-size: calc(12px * var(--fs)); }
.pw-saved {
  padding: 0 2px 6px;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* read by both halves below, so they can price the strip that sits between
     them: the chart is half the area, and the strip plus the round it opens is
     the other half */
  --pw-row-h: 44px;
}
.pw-saved > .pw-lib-head,
.pw-saved > .pw-saved-head { flex: 0 0 auto; }
.pw-saved .pw-chart {
  flex: 1 1 auto;
  /* the opposite of the live result screen's chart, which may not shrink past
     its content because that screen is allowed to scroll. This one is not, so
     it is the thing that gives. */
  min-height: 0;
  margin: 0;
}
/* the two halves. The chip row rides inside the top one, with the plot, because
   the two are one scroller — column n of the chart has to stay column n of the
   row, and that only holds while they share a parent. */
.pw-saved .pw-chart-body {
  /* half the area, plus the strip that rides inside it — so the plot alone is
     the half, not the plot and the strip together */
  flex: 1 1 calc(50% + var(--pw-row-h));
  /* the parent floor goes: on a short phone the whole area can be less than
     twice this body's natural minimum, and a floor that cannot be met is an
     overflow rather than a protection. The plot keeps a smaller one of its
     own. */
  min-height: 0;
  --pw-plot-min: 56px;
}
.pw-saved .pw-reveal {
  flex: 1 1 calc(50% - var(--pw-row-h));
  min-height: 0;
  margin: 8px 0 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
/* the pair of cards takes the middle of its half rather than hugging the top */
.pw-saved .pw-reveal-row { flex: 1 1 auto; min-height: 0; }
.pw-saved .pw-reveal-card { --pw-card-h: clamp(62px, 26vw, 128px); }
.pw-saved-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 9px;
  margin: 2px 2px 10px;
  font-size: calc(11px * var(--fs));
  font-weight: 700;
}
.pw-saved-res {
  font-size: calc(15px * var(--fs));
  font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
}
.pw-saved-meta { flex: 1 1 auto; min-width: 0; color: #9FC0E0; font-weight: 600; }
.pw-saved-pts { font-variant-numeric: tabular-nums; font-size: calc(14px * var(--fs)); }
.pw-saved-when {
  flex: 0 0 100%;
  color: #8FA9C4; font-weight: 600;
  font-size: calc(10px * var(--fs));
}
/* the chart carries its own "Match Replay · N rounds" caption, which is what
   the screen above it is called and what the line under that already counts —
   on this screen it is the same thing said three times, so it goes */
.pw-saved .pw-chart-head { display: none; }
.pw-saved-res.win,  .pw-saved-pts.win  { color: var(--pw-bull); }
.pw-saved-res.loss, .pw-saved-pts.loss { color: #FF5C93; }
.pw-saved-res.flat, .pw-saved-pts.flat { color: var(--pw-muted); }

/* ---- the two ways in ---- */
.pw-hub-acts { display: flex; gap: 8px; }
.pw-hub-pill {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 1px;
  height: 54px;
  padding: 0 4px 0 2px;
  text-align: left;
  /* ==> What a pill looks like when its picture does not arrive.
     These are nine-slices: border-style: solid plus a border-image. If the
     image fails — one flaky fetch is enough, and /assets/ is cache-first with
     nothing to retry it — the border falls back to a solid one in the
     inherited colour, which is the text's near-white. That is a 43px white
     frame around a dark label, which is exactly what Create Match turned into
     on the phone and is reproduced here by serving that one file a 503.

     So the border has no colour of its own to fall back to, and underneath
     the art sits a painted pill of the same shape in the same hue. With the
     picture there it is covered by it; without one, the button is still a
     button in the right colour. */
  border-radius: 999px;
  /* and no colour of its own to fall back to */
  border-color: transparent;
  border-style: solid;
  /* the left end carries the glyph the artwork drew, the right end the
     rounded cap and its own chevron */
  border-width: 12px 24px 12px 43px;
  border-image-slice: 40 95 40 165 fill;
  border-image-width: 12px 24px 12px 43px;
  border-image-repeat: stretch;
}
.pw-hub-pill.start { border-image-source: url("../assets/pointaeway/hub/pill-start.png"); }
.pw-hub-pill.find  { border-image-source: url("../assets/pointaeway/hub/pill-find.png"); }

/* The painted pill, for a session where the art did not arrive. app.js asks
   for the two files itself at boot and sets this class if either refuses, so
   nothing here is paid for by the normal case: with the pictures present not
   one of these declarations exists. The four buttons then read as one family
   — same shape, same glow, the row above in its own colour and the row below
   in the quieter one. */
.no-pill-art .pw-hub-pill {
  border-width: 2px;
  border-image: none;
  border-color: rgba(61,223,255,.45);
  background: linear-gradient(100deg, rgba(61,223,255,.22), rgba(7,13,30,.94) 46%);
  padding: 0 14px;
  box-shadow: 0 0 14px rgba(61,223,255,.22);
}
.no-pill-art .pw-hub-pill.find,
.no-pill-art .pw-hub-pill.chal {
  border-color: rgba(255,61,154,.5);
  background: linear-gradient(100deg, rgba(255,61,154,.24), rgba(7,13,30,.94) 46%);
  box-shadow: 0 0 14px rgba(255,61,154,.22);
}
.no-pill-art .pw-hub-pill.mini {
  background: linear-gradient(100deg, rgba(61,223,255,.12), rgba(7,13,30,.94) 55%);
}
.pw-hub-pill:active { filter: brightness(1.3); transform: scale(.985); }
.pw-hub-pill-t {
  font-size: calc(12.5px * var(--fs));
  font-weight: 800;
  color: #F2FBFF;
  line-height: 1.1;
}
.pw-hub-pill-s {
  /* one line, both pills: the longer of the two labels is what sets this, and
     a pill that wrapped where its twin did not read as the taller of the two */
  font-size: calc(7.5px * var(--fs));
  font-weight: 600;
  color: #BCD6EE;
  line-height: 1.2;
  white-space: nowrap;
  letter-spacing: -.01em;
}
.pw-hub-note {
  margin-top: 8px;
  padding: 7px 10px;
  border-radius: 10px;
  border: 1px solid rgba(255,92,147,.3);
  background: rgba(255,92,147,.08);
  font-size: calc(10.5px * var(--fs));
  font-weight: 600;
  text-align: center;
  color: #FFAECB;
}
.pw-hub-note.hidden { display: none; }

/* ---- the result screen ----
   Top to bottom: what round it ended on, who won, the line under it, then the
   scene — the winner on the left, the print they won it on at the right — and
   the three ways out. Everything is centred on the column except the scene,
   which is the one row with two things in it. */
.card-scroll.pw-overing { display: flex; flex-direction: column; overflow: hidden; }
.pw-over {
  --pw-over-tone: var(--pw-muted);
  text-align: center;
  padding: 10px 6px 4px;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}
.pw-over.bull { --pw-over-tone: var(--pw-bull); }
.pw-over.bear { --pw-over-tone: var(--pw-bear); }
.pw-over-kicker {
  font-size: calc(10.5px * var(--fs));
  font-weight: 700; letter-spacing: .22em; text-transform: uppercase;
  color: #8FA9C4;
  margin-bottom: 4px;
}
/* The stage is the room between the round line and the buttons; the art is
   drawn as large as that room allows without losing an edge. Both axes are
   bounded through container units — sizing on one alone is the trap every
   picture in this game has fallen into once. */
.pw-over-stage {
  flex: 1 1 auto;
  min-height: 0;
  container-type: size;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pw-over-art {
  position: relative;
  aspect-ratio: var(--ar);
  width: min(100cqw, 100cqh * var(--ar));
  max-width: 100%;
  max-height: 100%;
  /* the overlay measures itself against this box, so it must be the art's
     box exactly — which it is, since the image fills it edge to edge */
  container-type: size;
}
.pw-over-art > img { display: block; width: 100%; height: 100%; }
/* The hole the art leaves under its FINAL PRINT label, and what goes in it:
   the figure at the top, the meter filling the rest, the two branches beside
   it. Every size in here is a fraction of the art's width, so the whole
   thing scales with the picture rather than with the screen. */
.pw-over-slot {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
}
.pw-over-slot .pw-track-panel {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  gap: 0.6cqw;
}
.pw-over-slot .pw-track-val {
  font-size: 8.2cqw;
  font-weight: 900;
  line-height: 1;
  text-shadow: 0 0 14px color-mix(in srgb, currentColor 70%, transparent);
}
.pw-over-slot .pw-track-row {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  gap: 0.5cqw;
}
.pw-over-slot .pw-track-end { font-size: 2.2cqw; letter-spacing: .06em; color: #C9DDF2; }
.pw-over-slot .pw-track {
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
  width: 9.5cqw;
  border-radius: 2.4cqw;
  background-size: 1.8cqw 2.6cqw;
  border-color: rgba(143,169,196,.55);
}
.pw-over-slot .pw-track-mid { font-size: 1.7cqw; }
.pw-over-slot .pw-track-fill { left: 0.9cqw; right: 0.9cqw; border-radius: 1cqw; }
.pw-laurel {
  position: absolute;
  top: 40%;
  width: 6.4cqw;
  height: 21cqw;
  color: var(--pw-over-tone);
  opacity: .85;
  filter: drop-shadow(0 0 4px color-mix(in srgb, var(--pw-over-tone) 60%, transparent));
}
.pw-laurel svg { width: 100%; height: 100%; display: block; }
.pw-laurel.l { left: 6%; }
.pw-laurel.r { right: 6%; transform: scaleX(-1); }

/* Play Again is the one thing this screen wants you to do, so it carries the
   wide pill; the two below it share the row and the smaller one. Both are the
   pill the app already draws everywhere — no new art for this screen. */
.pw-over-again {
  display: block;
  width: 100%;
  margin-top: auto;
  padding: 13px;
  border-radius: 999px;
  border: 2px solid transparent;
  border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 22px 25px stretch;
  background: none;
  font-size: calc(16px * var(--fs));
  font-weight: 800; letter-spacing: .04em;
  color: #EAF6FF;
  text-shadow: 0 0 10px rgba(61,223,255,.5);
}
.pw-over-again:active { filter: brightness(1.35); transform: scale(.99); }
.pw-over-row { display: flex; gap: 8px; margin-top: 8px; }
.pw-over-pill {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 10px 6px;
  border-radius: 999px;
  border: 2px solid transparent;
  border-image: url("../assets/bars/background-bar-pill@2x.png") 54 60 fill / 20px 23px stretch;
  background: none;
  font-size: calc(12.5px * var(--fs));
  font-weight: 800; letter-spacing: .03em;
  color: #DCEBFA;
}
.pw-over-pill img { width: 17px; height: 17px; object-fit: contain; }
.pw-over-pill.on { color: var(--cyan); }
.pw-over-pill:active { filter: brightness(1.35); transform: scale(.98); }
.pw-over-foot {
  font-size: calc(8.5px * var(--fs));
  font-weight: 700; letter-spacing: .18em; text-transform: uppercase;
  color: #55708C;
  margin: 10px 0 2px;
}

/* ---- the match as a chart ----
   Takes the scene's slot when View Match is on. One candle per round on the
   same −25..+25 scale the track uses, so a body's height is the ground that
   round took — and one chip per round underneath it, in the same order and
   the same colour. */
.pw-chart {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  /* deliberately NOT min-height:0. The chart may shrink as far as its own
     content allows — plot floor, a whole chip row, and the reveal if one is
     open — and no further. Past that the screen scrolls (.pw-revealing)
     rather than the buttons being slid under the panel. */
  margin: 2px 0 6px;
}
.pw-chart-head {
  display: flex; align-items: baseline; justify-content: space-between;
  font-size: calc(9.5px * var(--fs));
  font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: #9FC0E0;
  margin-bottom: 6px;
}
.pw-chart-n { color: #6E86A6; letter-spacing: .1em; }

/* The scale and the row's caption sit outside the scroller so they hold their
   place; everything that is per-round sits inside it.

   What flexes is the plot. The chart has to fit between the round line and the
   buttons whether or not a reveal is open below it, and when one opens the
   room has to come from somewhere — so the plot gives it up and the chip row,
   which is the thing being pointed at, keeps its height. The axis column is
   split the same way, ends against plot and caption against row, which is what
   keeps the labels on their lines as the plot changes height. */
.pw-chart-body {
  --pw-row-h: 44px;
  --pw-plot-min: 90px;
  flex: 1 1 auto;
  /* the floor, stated: plot at its smallest plus a whole chip row. A scroll
     container contributes nothing to its parent's automatic minimum, so
     without this the body shrinks under its own content and the row lands on
     top of the reveal. */
  min-height: calc(var(--pw-plot-min) + var(--pw-row-h));
  display: flex;
  align-items: stretch;
  gap: 6px;
}
.pw-chart-axis {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  font-size: calc(7.5px * var(--fs));
  font-weight: 700; letter-spacing: .06em;
  color: var(--pw-muted);
}
.pw-chart-ends {
  flex: 1 1 auto;
  min-height: 0;
  display: flex; flex-direction: column; justify-content: space-between;
  padding: 5px 0;
  text-align: right;
}
.pw-chart-rowcap {
  flex: 0 0 var(--pw-row-h);
  display: flex; align-items: center; justify-content: flex-end;
  text-align: right;
  line-height: 1.25;
  text-transform: uppercase;
}
/* One scroller, two rows. Both use the same per-column basis, so column n of
   the chart is column n of the row however many rounds there are — and when a
   long match outruns the width they slide together rather than apart. */
.pw-chart-track {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  overflow-x: auto;
  overflow-y: hidden;
  min-height: calc(var(--pw-plot-min) + var(--pw-row-h));
  scrollbar-width: none;
}
.pw-chart-track::-webkit-scrollbar { display: none; }
.pw-chart-plot {
  position: relative;
  /* the chart area is scrubbed, so a finger travelling across it belongs to
     the chart: no panning, no page swipe, no double-tap zoom under it */
  touch-action: none;
  /* no preferred height of its own: the plot is whatever the chart has left
     after the chip row, and the floor below is how far it may give when a
     reveal opens underneath */
  flex: 1 1 auto;
  min-height: var(--pw-plot-min);
  min-width: 0;
  border-radius: 12px;
  border: 1px solid var(--pw-line);
  background: rgba(4,7,18,.9);
  background-image: radial-gradient(circle, rgba(143,169,196,.26) 0.5px, transparent 1px);
  background-size: 13px 13px;
  padding: 8px;
  overflow: hidden;
}
/* the zero line the candles are read against */
.pw-chart-plot::after {
  content: "";
  position: absolute;
  left: 8px; right: 8px; top: 50%;
  border-top: 1px dashed rgba(143,169,196,.3);
  pointer-events: none;
}
.pw-chart-bars,
.pw-chip-row {
  display: flex;
  align-items: stretch;
  gap: 2px;
  width: 100%;
}
.pw-chart-bars { position: relative; height: 100%; }
.pw-chip-row { flex: 0 0 var(--pw-row-h); padding: 6px 8px 0; align-items: stretch; touch-action: none; }
/* The one number both rows are laid out on. They compress rather than scroll:
   the whole point of the chart is the whole match at a glance, and a long one
   pushed half of itself off the edge. The columns get thin instead, and the
   row's numbers thin out with them — see .pw-chip-row.sparse. */
/* A column may shrink to a hairline for a long match, and it may NOT stretch
   to fill the box for a short one: four rounds spread across the whole plot
   read as four wide smears rather than as four candles. The cap is a little
   above what a full 34-round match gets, so a finished match is untouched and
   a match in progress grows into the box from the left. */
.pw-cndl,
.pw-chip { flex: 1 1 0; min-width: 4px; max-width: 26px; }

.pw-cndl {
  position: relative;
  background: none;
  border: 0;
  padding: 0;
}
/* the body: placed by percentage of the plot, which is the same scale end to
   end, so every candle in the run is directly comparable */
.pw-cndl::before {
  content: "";
  position: absolute;
  left: 2px; right: 2px;
  top: var(--t); height: var(--h);
  min-height: 1.5px;
  border-radius: 1px;
}
/* the leader down to this round's chip. It stops at the plot's floor — the
   box clips — but the chip sits directly under it, so the eye carries it. */
.pw-cndl::after {
  content: "";
  position: absolute;
  left: 50%;
  top: calc(var(--t) + var(--h));
  bottom: 0;
  border-left: 1px dashed rgba(143,169,196,.2);
  pointer-events: none;
}
.pw-cndl.bull::before { background: var(--pw-bull); }
.pw-cndl.bear::before { background: var(--pw-bear); }
.pw-cndl.flat::before { background: #6E86A6; }
.pw-cndl.on::before { box-shadow: 0 0 0 1.5px #EAF6FF, 0 0 10px rgba(234,246,255,.6); }
.pw-cndl.on::after { border-left-color: rgba(234,246,255,.75); }
.pw-cndl:active::before { filter: brightness(1.4); }

/* ---- the cards played ----
   One chip a round, carrying that round's colour and its number. A wild on
   the table is the thing that happened that round, so it takes the wild
   colour whichever way the print then moved. */
.pw-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  background: none;
  border: 0;
  padding: 0;
}
/* a fixed height, not an aspect: a long match makes the columns narrow, and a
   chip that kept its proportions there turned into a bead */
.pw-chip-face {
  position: relative;
  width: 100%;
  min-width: 0;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 3px;
  border: 1px solid currentColor;
  background: color-mix(in srgb, currentColor 16%, rgba(4,7,18,.92));
  box-shadow: 0 0 6px color-mix(in srgb, currentColor 30%, transparent);
}
/* a candle, drawn: a wick the height of the face and a body across it */
.pw-chip-candle {
  position: relative;
  width: min(3px, 40%);
  height: 58%;
  border-radius: 1px;
  background: currentColor;
}
.pw-chip-candle::before {
  content: "";
  position: absolute;
  left: 50%; top: -22%;
  width: 1px; height: 144%;
  transform: translateX(-50%);
  background: currentColor;
}
/* a wild reads as a different kind of thing, not a bigger candle */
.pw-chip-wild {
  width: min(9px, 62%);
  aspect-ratio: 1;
  background: currentColor;
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}
.pw-chip-n {
  font-size: calc(8px * var(--fs));
  font-weight: 700;
  line-height: 1;
  height: calc(9px * var(--fs));
  color: var(--pw-muted);
  font-variant-numeric: tabular-nums;
  /* a number wider than its column must not stretch the column */
  overflow: visible;
  white-space: nowrap;
}
.pw-chip.bull { color: var(--pw-bull); }
.pw-chip.bear { color: var(--pw-bear); }
.pw-chip.wild { color: var(--pw-wild); }
.pw-chip.flat { color: #6E86A6; }
.pw-chip.on .pw-chip-face {
  border-color: #EAF6FF;
  box-shadow: 0 0 0 1px #EAF6FF, 0 0 12px color-mix(in srgb, currentColor 60%, transparent);
}
.pw-chip.on .pw-chip-n { color: #EAF6FF; }
.pw-chip:active .pw-chip-face { filter: brightness(1.35); transform: scale(.94); }

/* ---- the round, opened up ----
   Inline under the row, never over it: this app opens nothing on a dimmed
   screen. The two cards are the same component the table deals. It is kept
   deliberately short — it shares the screen with the chart it was opened
   from, and every line it takes is a line the plot gives up. */
.pw-reveal {
  flex: 0 0 auto;
  margin-top: 6px;
  padding: 5px 9px 7px;
  border-radius: 13px;
  border: 1px solid var(--pw-line);
  background: rgba(7,11,26,.92);
}
.pw-reveal-head {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 3px;
}
.pw-reveal-title {
  flex: 1 1 auto;
  font-size: calc(9.5px * var(--fs));
  font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: #C9DDF2;
}
.pw-reveal-delta {
  flex: 0 0 auto;
  font-size: calc(11px * var(--fs));
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.pw-reveal-delta.bull { color: var(--pw-bull); }
.pw-reveal-delta.bear { color: var(--pw-bear); }
.pw-reveal-delta.flat { color: var(--pw-muted); }
.pw-reveal-x {
  flex: 0 0 auto;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 50%;
  font-size: calc(15px * var(--fs));
  line-height: 1;
  color: #9FC0E0;
  background: none;
}
.pw-reveal-x:active { color: #EAF6FF; transform: scale(.9); }
.pw-reveal-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
}
.pw-reveal-side {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}
.pw-reveal-tag {
  flex: 0 0 auto;
  font-size: calc(8.5px * var(--fs));
  font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
}
.pw-reveal-tag.you { color: var(--pw-bull); }
.pw-reveal-tag.opp { color: var(--pw-bear); }
/* the card component is sized by its height — its width follows the face's
   own proportions — so this sets that rather than fighting it with a width */
.pw-reveal-card { --pw-card-h: clamp(62px, 21vw, 88px); display: flex; }
.pw-reveal-name {
  max-width: clamp(58px, 20vw, 82px);
  font-size: calc(8px * var(--fs));
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  color: #9FC0E0;
}
.pw-reveal-vs {
  flex: 0 0 auto;
  font-size: calc(11px * var(--fs));
  font-weight: 900; letter-spacing: .06em;
  color: #EAF6FF;
  text-shadow: 0 0 10px rgba(61,223,255,.6);
}
.pw-reveal-cap {
  margin-top: 4px;
  text-align: center;
  font-size: calc(8.5px * var(--fs));
  font-weight: 600; letter-spacing: .03em;
  color: #7FA8CC;
}
/* The safety valve. On a tall phone the whole result still sits in one view
   with a reveal open; on a short one it cannot, and the reveal must not be
   the thing that gets cut off. Only this state scrolls — the screen without
   a reveal open is unchanged. */
.card-scroll.pw-overing.pw-revealing { overflow-y: auto; }
.pw-chart-empty {
  text-align: center;
  font-size: calc(12px * var(--fs));
  color: var(--pw-muted);
  padding: 30px 0;
}
/* the winning side's colour is set once, on .pw-over, and everything on the
   screen that carries it reads it from there */

/* The shortest phones. The way in has to stay in one view like everywhere
   else, and at 568pt there is not enough of it to keep both the cards' floor
   and the type at full size — so both give a little. */
@media (max-height: 620px) {
  .pw-intro { padding: 2px 4px 2px; }
  .pw-wordmark { width: min(70%, 236px); }
  .pw-subtitle { width: min(56%, 190px); margin-top: 2px; }
  .pw-tagline { margin-top: 4px; font-size: calc(10.5px * var(--fs)); line-height: 1.4; }
  .pw-rule { margin: 5px 2px 5px; }
  .pw-rule span { font-size: calc(9.5px * var(--fs)); letter-spacing: .2em; }
  .pw-pick img { min-height: 74px; }
  .pw-feats { gap: 4px; margin: 6px 0 2px; }
  .pw-feat { padding: 5px 2px; }
  .pw-feat-ico { height: 17px; }
  .pw-feat-title { font-size: calc(7.5px * var(--fs)); }
  .pw-feat-sub { font-size: calc(6.5px * var(--fs)); }
  .pw-random-btn { height: 44px; margin-top: 6px; font-size: calc(11px * var(--fs)); }
  .pw-random-btn img { height: 18px; }
  .pw-wilds-btn { margin-top: 5px; padding: 5px 12px; font-size: calc(10px * var(--fs)); }
  .pw-wilds-btn img { height: 14px; }
}

/* Short screens. The app's own chrome takes a fixed share of the height
   whatever the phone, so on a shorter one the table has to give — and this
   screen has to stay inside one view, which is the whole point of it. Steps
   rather than fluid sizing, so the card art lands on whole pixels and the
   strength numbers printed on it stay legible; that is what breaks first. */
@media (max-height: 800px) {
  .pw-seat { --pw-card-h: clamp(82px, 11.5vh, 106px); }
  .pw-hand { --pw-card-h: clamp(84px, 12vh, 108px); }
  .pw-print-gauge { width: clamp(62px, 17vw, 78px); height: clamp(88px, 12vh, 108px); }
  .pw-print-val { font-size: calc(23px * var(--fs)); }
  .pw-arena { padding: 2px 0 4px; }
}
@media (max-height: 710px) {
  .pw-seat { --pw-card-h: clamp(72px, 10.5vh, 90px); }
  .pw-hand { --pw-card-h: clamp(74px, 11vh, 92px); padding: 2px 8px 4px; }
  .pw-print-gauge { width: clamp(56px, 16vw, 68px); height: clamp(74px, 10.5vh, 90px); }
  .pw-print-val { font-size: calc(20px * var(--fs)); }
  .pw-counts { padding: 0 2px 4px; }
  .pw-count { padding: 2px 6px; min-width: 42px; }
  .pw-count b { font-size: calc(13px * var(--fs)); }
  .pw-handhead { padding: 2px 2px 3px; }
  .pw-choice { margin-top: 7px; padding: 8px 10px; }
  .pw-choice-cap { font-size: calc(10.5px * var(--fs)); margin-bottom: 7px; }
  .pw-choice-btn { padding: 8px 6px; font-size: calc(11px * var(--fs)); }
  .pw-seen { margin-top: 7px; padding: 8px 10px; }
  .pw-seen-row { padding: 1px 0; font-size: calc(10px * var(--fs)); }
  .pw-seen .pw-ghost { margin-top: 5px; padding: 5px 14px; }
}

/* the desktop centre column is about a phone's width however wide the
   window is, so the viewport query below never reaches it */
@media (min-width: 1200px) {
.pw-counts { gap: 4px; }
  .pw-count { min-width: 38px; padding: 2px 5px; }
  .pw-count b { font-size: calc(13px * var(--fs)); }
  .pw-count i { font-size: calc(7px * var(--fs)); letter-spacing: .08em; }
  .pw-count-btn { padding: 6px 7px; font-size: calc(8.5px * var(--fs)); letter-spacing: .06em; }
  .pw-count-btn span { display: none; }
  .pw-specials-btn { padding: 5px 9px; font-size: calc(8.5px * var(--fs)); }
}

/* Phones: the counter row is the tightest thing on this screen, and it may not
   wrap — a second line costs the arena its height. The restart glyph goes
   first, then the padding.
   This used to start at 365px, when the row held five things. The live chart's
   button makes six, which is about 40px more than the roomy sizing has room
   for on a 375–430px phone, so the tight sizing now covers every phone width
   and the roomy one is left to the desktop layout, which has its own rule
   above and the width to spend. */
@media (max-width: 440px) {
  .pw-counts { gap: 4px; }
  .pw-count { min-width: 38px; padding: 2px 5px; }
  .pw-count b { font-size: calc(13px * var(--fs)); }
  .pw-count i { font-size: calc(7px * var(--fs)); letter-spacing: .08em; }
  .pw-count-btn { padding: 6px 7px; font-size: calc(8.5px * var(--fs)); letter-spacing: .06em; }
  .pw-count-btn span { display: none; }
  .pw-specials-btn { padding: 5px 9px; font-size: calc(8.5px * var(--fs)); }
}

/* Very narrow phones. The match screen's own meter stays upright — it is the
   spine of that layout — but the game-over meter lies on its side, where a
   tall track would push the result off the bottom. */
@media (max-width: 335px) {
  /* Laid on its side. Reversed so the ends match the direction the fill grows:
     -25 on the left, +25 on the right, bull filling rightward. */
  .pw-track-row { flex-direction: row-reverse; gap: 8px; width: 100%; }
  .pw-track { width: 100%; height: 30px; }
  /* the same figure spent on width instead of height; the vertical anchors have
     to be reset on the direction classes too, since .pw-track-fill.up outranks
     a bare .pw-track-fill whatever the order */
  .pw-track-fill { height: auto; width: var(--pw-fill, 0%); }
  .pw-track-fill.up,
  .pw-track-fill.down { top: 4px; bottom: 4px; }
  .pw-track-fill.up { left: 50%; right: auto; }
  .pw-track-fill.down { right: 50%; left: auto; }
  .pw-track-mid { display: none; }
  .pw-arena { gap: 3px; }
  .pw-seat-cap { font-size: calc(7px * var(--fs)); }
}

/* ===================== VIEWPORT READOUT =====================
   Five taps on the clock. Not styled to belong — it is a measuring tool that
   should look like one, and it has to stay legible over anything. The two
   stripes are the point of it: fixed to the viewport's own edges, so where
   they land is where the browser believes the screen ends. */
#vhDiag {
  position: fixed;
  left: 8px; right: 8px; bottom: 28px;
  z-index: 100000;
  margin: 0;
  padding: 10px 12px;
  border: 1px solid #FF3D9A;
  border-radius: 8px;
  background: rgba(0,0,0,.92);
  color: #EAF6FF;
  font: 600 12px/1.5 ui-monospace, Menlo, Consolas, monospace;
  white-space: pre-wrap;
  word-break: break-word;
}
.vh-diag-stripe {
  position: fixed;
  left: 0; right: 0;
  height: 8px;
  z-index: 100001;
  background: #FF3D9A;
  color: #000;
  font: 700 7px/8px ui-monospace, Menlo, Consolas, monospace;
  text-align: center;
  pointer-events: none;
}
.vh-diag-stripe.top { top: 0; background: #3DDFFF; }
.vh-diag-stripe.bottom { bottom: 0; }

/* ===================== PLACEÆWAY =====================
   The app's glass language over the reference build's layout. Two things here
   are load-bearing rather than decorative:
   - .pa-playing turns the scroller into a fixed-height flex column with
     overflow hidden, and .pa-chart takes flex: 1 1 auto inside it. That is
     what makes the round fit whatever is left after the rows above and below,
     and what stops the page scrolling.
   - the candles inside .pa-track are positioned in percent by JS. Nothing in
     here may give .pa-track or .pa-col a fixed height; they are 100% of the
     chart box, and the chart box is whatever the flex left them. */

.card-scroll.pa-playing {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  touch-action: manipulation;
}
.pa-game {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* ---- setup ---- */
.pa-setup { padding: 4px 2px 8px; }
.pa-lede {
  font-size: calc(13px * var(--fs));
  line-height: 1.55; color: #C9DDF2;
  text-align: center;
  margin: 0 auto 18px; max-width: 30em;
}
.pa-seed-row { display: flex; gap: 8px; margin-bottom: 8px; }
.pa-seed {
  flex: 1 1 auto; min-width: 0;
  min-height: 46px;
  padding: 8px 14px;
  border-radius: 12px;
  border: 1.5px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: var(--text);
  font-family: inherit;
  font-size: calc(14px * var(--fs));
  font-weight: 700; letter-spacing: .1em;
}
.pa-seed:focus { outline: none; border-color: var(--cyan); box-shadow: 0 0 14px -4px rgba(61,223,255,.7); }
.pa-dice {
  flex: 0 0 auto;
  width: 46px; min-height: 46px;
  border-radius: 12px;
  border: 1.5px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: var(--cyan);
  font-size: calc(19px * var(--fs));
  line-height: 1;
}
.pa-dice:active { filter: brightness(1.3); transform: scale(.96); }
.pa-hint {
  font-size: calc(11px * var(--fs));
  line-height: 1.45; color: #8FA9C4;
  text-align: center;
}
.pa-warn { color: var(--pw-bear, #E5484D); margin-top: 6px; }

.pa-links { display: flex; gap: 8px; justify-content: center; margin-top: 14px; }
.pa-ghost {
  padding: 8px 16px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  border-radius: 999px;
  background: rgba(4,7,18,.5);
  font-size: calc(11.5px * var(--fs)); font-weight: 700; letter-spacing: .06em;
  color: #8FA9C4;
}
.pa-ghost:active { filter: brightness(1.4); }
.pa-ghost.on { border-color: var(--cyan); color: var(--cyan); }
.pa-ghost.done { border-color: var(--pw-bull, #1FCBA0); color: var(--pw-bull, #1FCBA0); }
.pa-ghost.danger { border-color: var(--pw-bear, #E5484D); color: var(--pw-bear, #E5484D); }
.pa-ghost[disabled] { opacity: .75; }

.pa-howto {
  margin: 12px 0 0;
  padding: 4px 12px 4px 30px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  border-radius: 12px;
  background: rgba(7,10,24,.7);
}
.pa-howto li {
  font-size: calc(12px * var(--fs));
  line-height: 1.5; color: #C9DDF2;
  padding: 9px 0;
  border-bottom: 1px solid rgba(61,223,255,.14);
}
.pa-howto li:last-child { border-bottom: none; }
.pa-howto li::marker { color: var(--cyan); font-weight: 800; }
.pa-c-up { color: var(--pw-bull, #1FCBA0); }
.pa-c-down { color: var(--pw-bear, #E5484D); }

/* ---- ready ---- */
.pa-ready { text-align: center; padding: 34px 8px; }
.pa-kicker {
  font-size: calc(10.5px * var(--fs));
  font-weight: 700; letter-spacing: .18em; text-transform: uppercase;
  color: #8FA9C4;
}
.pa-ready-head {
  font-size: calc(21px * var(--fs));
  font-weight: 800;
  margin: 10px 0 4px;
}
.pa-ready .btn-primary { max-width: 300px; margin: 18px auto 10px; }

/* ---- the round ---- */
/* Reaction's own setup and round furniture. The three-across pace row, the
   computed window, the running deviation, and the candles that have not
   printed yet — which keep their box so the chart never reflows as the tape
   advances, and only stop being drawn. */
.bm-row-3 { grid-template-columns: repeat(3, 1fr); }
.bm-rect .pa-diff-ms {
  display: block;
  font-size: calc(10px * var(--fs)); font-weight: 700;
  opacity: .75; margin-top: 1px;
}
.bm-rect { flex-direction: column; gap: 0; }
.pa-window {
  margin: 2px 0 4px;
  padding: 10px 12px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  border-radius: 12px;
  background: rgba(7,10,24,.7);
  text-align: center;
}
.pa-window-row { font-size: calc(12px * var(--fs)); line-height: 1.5; color: #C9DDF2; }
.pa-window-row b { color: var(--cyan); font-variant-numeric: tabular-nums; }
.pa-window-row.sub { font-size: calc(11px * var(--fs)); color: #8FA9C4; }
.pa-window-row.sub b { color: var(--magenta); }
.pa-col.pending { visibility: hidden; }
.pa-stat.mid { text-align: center; }
.pa-stat-val.on { color: var(--pw-bull, #1FCBA0); }
.pa-stat-val.off { color: var(--pw-wild, #E8B23A); }
.pa-time.on { color: var(--pw-bull, #1FCBA0); }
.pa-time.off { color: var(--pw-wild, #E8B23A); }

.pa-stats { display: flex; justify-content: space-between; align-items: flex-end; gap: 8px; flex: 0 0 auto; }
.pa-stat { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.pa-stat.right { text-align: right; }
.pa-stat-cap {
  font-size: calc(10px * var(--fs));
  letter-spacing: .06em; color: #8FA9C4;
}
.pa-stat-val {
  font-size: calc(19px * var(--fs));
  font-weight: 800; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.pa-bar {
  flex: 0 0 auto;
  height: 5px; margin: 7px 0 9px;
  border-radius: 3px;
  background: rgba(5,9,22,.8);
  border: 1px solid rgba(120,150,180,.22);
  overflow: hidden;
}
.pa-bar-fill {
  height: 100%; width: 0;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--cyan), var(--magenta));
  transition: width .16s ease;
}

.pa-chart {
  flex: 1 1 auto;
  min-height: 64px;
  position: relative;
  padding: 18px 10px 12px;
  margin-bottom: 10px;
  border-radius: 14px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  background: rgba(7,10,24,.72);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
}
.pa-chart::-webkit-scrollbar { display: none; }
/* a fixed height only where the chart is a thumbnail rather than the round */
.pa-chart-sm { flex: 0 0 auto; height: 150px; margin: 8px 0; }

.pa-track { display: flex; align-items: stretch; gap: 3px; height: 100%; position: relative; }
.pa-col { position: relative; width: 14px; height: 100%; flex: 0 0 auto; }
.pa-col.grid::before {
  content: ""; position: absolute;
  left: -3px; top: -14px; bottom: 0; width: 1px;
  background: rgba(255,255,255,.05);
}
.pa-col.up { color: var(--pw-bull, #1FCBA0); }
.pa-col.down { color: var(--pw-bear, #E5484D); }
.pa-col.done { opacity: .45; }
.pa-wick { position: absolute; left: 50%; width: 1.5px; transform: translateX(-50%); background: currentColor; }
.pa-body { position: absolute; left: 0; width: 100%; border-radius: 1px; background: currentColor; }
.pa-mark { position: absolute; top: -14px; left: 50%; transform: translateX(-50%); font-size: calc(10px * var(--fs)); font-weight: 800; }
.pa-mark.done::after { content: "✓"; color: var(--cyan); }
.pa-band {
  position: absolute;
  top: -14px; bottom: 0; left: 0;
  width: 17px;
  border-radius: 3px;
  background: rgba(61,223,255,.12);
  border-left: 1px solid rgba(61,223,255,.45);
  border-right: 1px solid rgba(61,223,255,.45);
  transition: transform .12s ease;
  pointer-events: none;
}

.pa-taps { flex: 0 0 auto; display: flex; gap: 10px; }
.pa-tap {
  flex: 1 1 0; min-width: 0;
  height: clamp(56px, 8.5vh, 70px);
  border-radius: 14px;
  border: 1.5px solid;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
  font-size: calc(15px * var(--fs));
  font-weight: 800; letter-spacing: .08em;
}
.pa-tap-arrow { font-size: calc(18px * var(--fs)); line-height: 1; }
.pa-tap.up {
  color: var(--pw-bull, #1FCBA0);
  border-color: var(--pw-bull, #1FCBA0);
  background: linear-gradient(160deg, var(--pw-bull-dim, #12493D), rgba(7,10,24,.92));
  box-shadow: 0 0 18px -8px var(--pw-bull, #1FCBA0);
}
.pa-tap.down {
  color: var(--pw-bear, #E5484D);
  border-color: var(--pw-bear, #E5484D);
  background: linear-gradient(160deg, var(--pw-bear-dim, #4A1E20), rgba(7,10,24,.92));
  box-shadow: 0 0 18px -8px var(--pw-bear, #E5484D);
}
/* no double-tap-zoom detection delay on the one control that is timed */
.pa-tap { touch-action: manipulation; -webkit-tap-highlight-color: transparent; }
.pa-tap:active { transform: scale(.96); filter: brightness(1.3); }
@keyframes pa-shake {
  0%,100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-4px); }
  80% { transform: translateX(3px); }
}
.pa-tap.shake { animation: pa-shake .28s ease; }

/* ---- results, in the tap row's place ---- */
.pa-result { flex: 0 0 auto; text-align: center; }
.pa-time {
  font-size: calc(30px * var(--fs));
  font-weight: 800; line-height: 1.05;
  color: var(--cyan);
  font-variant-numeric: tabular-nums;
  margin: 3px 0 2px;
}
.pa-result .btn-primary { max-width: 300px; margin: 10px auto 0; }
.pa-head { font-size: calc(16px * var(--fs)); font-weight: 800; margin-bottom: 7px; }
.pa-head.up { color: var(--pw-bull, #1FCBA0); }
.pa-head.mid { color: var(--cyan); }
.pa-head.flat { color: var(--text); }

.pa-tabs { display: flex; gap: 6px; margin-bottom: 7px; }
.pa-tab {
  flex: 1 1 0; min-width: 0;
  padding: 5px 3px;
  border-radius: 9px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: #8FA9C4;
  display: flex; flex-direction: column; align-items: center; line-height: 1.25;
}
.pa-tab-n { font-size: calc(10px * var(--fs)); }
.pa-tab-t { font-size: calc(12px * var(--fs)); font-weight: 800; font-variant-numeric: tabular-nums; }
.pa-tab.on { border-color: var(--cyan); color: var(--cyan); box-shadow: 0 0 12px -4px rgba(61,223,255,.7); }
.pa-tab:active { filter: brightness(1.3); }

.pa-mini { display: flex; gap: 6px; margin-bottom: 7px; }
.pa-mini-cell {
  flex: 1 1 0; min-width: 0;
  padding: 6px 3px;
  border-radius: 10px;
  border: 1px solid rgba(120,150,180,.26);
  background: rgba(7,10,24,.72);
}
.pa-mini-cell b { display: block; font-size: calc(14px * var(--fs)); font-weight: 800; font-variant-numeric: tabular-nums; }
.pa-mini-cell span { display: block; font-size: calc(9.5px * var(--fs)); color: #8FA9C4; margin-top: 1px; }

.pa-seedline {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 6px 8px;
  font-size: calc(11.5px * var(--fs)); color: #8FA9C4; margin-bottom: 8px;
}
.pa-seedline b { color: var(--pw-wild, #E8B23A); letter-spacing: .08em; }
.pa-copy {
  flex: 0 0 auto;
  padding: 5px 12px;
  border: 1px solid var(--pw-wild, #E8B23A);
  border-radius: 999px;
  background: rgba(4,7,18,.6);
  color: var(--pw-wild, #E8B23A);
  font-size: calc(10.5px * var(--fs)); font-weight: 800; letter-spacing: .06em;
  white-space: nowrap;
  touch-action: manipulation;
}
.pa-copy:active { filter: brightness(1.4); transform: scale(.96); }
.pa-copy.done { border-color: var(--pw-bull, #1FCBA0); color: var(--pw-bull, #1FCBA0); }
/* the row expands, the copy button does not — so they are siblings */
.pa-hhead { display: flex; align-items: center; gap: 8px; padding-right: 11px; }
.pa-hhead .pa-hrow { flex: 1 1 auto; min-width: 0; }
.pa-hd .pa-seedline { margin: 8px 0 0; }
.pa-btn-row { display: flex; gap: 8px; }
.pa-btn-row .pa-ghost { flex: 1 1 0; min-width: 0; padding: 11px 6px; }

/* ---- history, expanded inline on the setup screen ---- */
.pa-hlist { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.pa-hitem {
  border: 1px solid rgba(120,150,180,.26);
  border-radius: 12px;
  background: rgba(7,10,24,.72);
  overflow: hidden;
}
.pa-hitem.open { border-color: var(--cyan); }
.pa-hrow {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 10px;
  padding: 11px 13px;
  background: none; border: 0;
  text-align: left;
}
.pa-hrow:active { filter: brightness(1.3); }
.pa-hseed { font-size: calc(13px * var(--fs)); font-weight: 800; letter-spacing: .06em; color: var(--pw-wild, #E8B23A); }
.pa-htime { font-size: calc(13px * var(--fs)); font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.pa-hmeta { grid-column: 1 / -1; font-size: calc(11px * var(--fs)); color: #8FA9C4; }
.pa-hd { padding: 0 11px 11px; }
.pa-empty {
  margin-top: 12px;
  padding: 20px 12px;
  border: 1px dashed rgba(120,150,180,.3);
  border-radius: 12px;
  text-align: center;
  font-size: calc(12px * var(--fs)); line-height: 1.6; color: #8FA9C4;
}
.pa-confirm {
  margin-top: 10px;
  padding: 11px 13px;
  border: 1px solid var(--pw-bear, #E5484D);
  border-radius: 12px;
  background: rgba(7,10,24,.8);
  font-size: calc(11.5px * var(--fs)); line-height: 1.45; color: #C9DDF2;
  text-align: center;
}
.pa-confirm-btns { display: flex; gap: 8px; margin-top: 9px; }
.pa-confirm-btns .pa-ghost { flex: 1 1 0; }
.pa-setup > .pa-ghost { margin: 10px auto 0; display: block; }
/* the mode cards carry no icon; without one the text should fill the card */
.gs-card:not(:has(.gs-icon)) .gs-text { width: 100%; }

/* Short screens: the round still has to fit, so the fixed rows give first. */
@media (max-height: 740px) {
  .pa-tap { height: clamp(48px, 7.5vh, 60px); }
  .pa-stat-val { font-size: calc(17px * var(--fs)); }
  .pa-time { font-size: calc(25px * var(--fs)); }
  .pa-chart { padding: 16px 8px 10px; margin-bottom: 8px; }
  .pa-ready { padding: 20px 8px; }
}

/* Shorter screens, in two more steps. The round already fits everywhere by
   the time it gets here; what does not is the setup form on a 568pt phone and
   the final results panel, which is the tallest thing the game ever draws. */
@media (max-height: 700px) {
  .pa-lede { margin-bottom: 12px; font-size: calc(12px * var(--fs)); }
  .pa-setup .bm-row { margin-bottom: 11px; }
  .pa-setup .bm-label { margin-bottom: 6px; }
  .pa-setup .bm-rect, .pa-seed, .pa-dice { min-height: 42px; }
  .pa-setup .btn-primary { margin-top: 11px; }
  .pa-links { margin-top: 10px; }
  .pa-mini-cell b { font-size: calc(13px * var(--fs)); }
  .pa-seedline { margin-bottom: 6px; }
  .pa-window { padding: 7px 10px; margin: 0 0 2px; }
  .pa-window-row { font-size: calc(11px * var(--fs)); line-height: 1.4; }
  .pa-window-row.sub { font-size: calc(10px * var(--fs)); }
  .pa-setup .pa-links { margin-top: 8px; }
  .pa-setup .btn-primary { padding: 10px; }
}
@media (max-height: 620px) {
  /* the blurb is the one thing here that is only ever read once */
  .pa-lede { display: none; }
  .pa-setup .bm-row { margin-bottom: 8px; }
  .pa-setup .bm-rect, .pa-seed, .pa-dice { min-height: 38px; }
  .pa-hint { font-size: calc(10px * var(--fs)); }
  .pa-chart { min-height: 54px; padding: 14px 8px 8px; margin-bottom: 6px; }
  .pa-bar { margin: 5px 0 6px; }
  .pa-head { margin-bottom: 5px; }
  .pa-tabs, .pa-mini { margin-bottom: 5px; }
  .pa-tab { padding: 3px 3px; }
  .pa-mini-cell { padding: 4px 3px; }
  .pa-seedline { margin-bottom: 5px; }
  .pa-btn-row .pa-ghost { padding: 9px 6px; }
  /* the button says Copy code; the sentence explaining it is what gives on a
     screen this short, where it would only wrap the line and cost a row */
  .pa-seed-tail { display: none; }
  .pa-time { font-size: calc(22px * var(--fs)); }
  .pa-ready { padding: 14px 8px; }
  /* the two window figures both matter, so they stay — the room comes out of
     the space around them and out of the pace buttons' second line */
  .pa-window { padding: 5px 8px; }
  .pa-window-row { font-size: calc(10.5px * var(--fs)); line-height: 1.35; }
  .bm-rect .pa-diff-ms { font-size: calc(9px * var(--fs)); }
  .pa-setup .bm-label { margin-bottom: 4px; }
  .pa-setup .btn-primary { margin-top: 8px; padding: 9px; }
  .pa-setup .pa-links { margin-top: 7px; }
  .pa-setup .pa-ghost { padding: 6px 13px; }
}

/* ===================== INLINE CENTER PANELS =====================
   The hamburger and the gear render here instead of in an overlay. There is
   no scrim and no dimming: the panel simply is the middle of the screen for
   as long as it is open, which is the whole point of the change. */
.ip-panel { padding: 2px 0 8px; }
.ip-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 12px;
}
.ip-title {
  font-size: calc(11px * var(--fs));
  font-weight: 800; letter-spacing: .18em; text-transform: uppercase;
  color: #8FA9C4;
}
.ip-close {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  background: rgba(4,7,18,.6);
  color: #C9DDF2;
  font-size: calc(13px * var(--fs));
}
.ip-close:active { filter: brightness(1.4); }
/* the icon that opened it reads as held down while it is open */
.bar-icon.on img { filter: brightness(1.6) drop-shadow(0 0 9px rgba(61,223,255,.9)); }

/* ---- the hamburger's four sections ---- */
.tp-tabs { display: flex; gap: 6px; margin-bottom: 12px; }
.tp-tab {
  flex: 1 1 0; min-width: 0;
  padding: 8px 4px;
  border-radius: 10px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: #8FA9C4;
  font-size: calc(11.5px * var(--fs)); font-weight: 700;
}
.tp-tab.on { border-color: var(--cyan); color: var(--cyan); box-shadow: 0 0 12px -4px rgba(61,223,255,.7); }
.tp-tab:active { filter: brightness(1.3); }
.tp-note {
  margin-top: 10px;
  font-size: calc(10.5px * var(--fs)); line-height: 1.5; color: #8FA9C4;
  text-align: center;
}

/* practice chart */
.tp-chart-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 7px; }
.tp-sym-name { font-size: calc(10.5px * var(--fs)); color: #8FA9C4; min-width: 0; text-align: right; }
/* eight timeframes have to fit a phone, so they wrap rather than shrink */
.tp-tf { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 8px; }
.tp-tf-btn { flex: 1 1 auto; }
.tp-quote { font-size: calc(11px * var(--fs)); letter-spacing: .1em; color: #8FA9C4; }
.tp-quote b { color: var(--text); font-weight: 800; margin-right: 6px; }
.tp-quote .up { color: var(--pw-bull, #1FCBA0); font-weight: 800; }
.tp-quote .down { color: var(--pw-bear, #E5484D); font-weight: 800; }
.tp-tf-btn {
  padding: 4px 9px;
  border-radius: 999px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: #8FA9C4;
  font-size: calc(10px * var(--fs)); font-weight: 800;
}
.tp-tf-btn.on { border-color: var(--cyan); color: var(--cyan); }
.tp-chart {
  position: relative;
  height: 210px;
  /* the gesture handler owns this surface: without it the browser pans and
     pinch-zooms the page before a pointermove is ever seen */
  touch-action: none;
  cursor: grab;
  padding: 10px 8px;
  border-radius: 14px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  background: rgba(7,10,24,.72);
  overflow: hidden;
  background-image: radial-gradient(circle, rgba(143,169,196,.22) 0.5px, transparent 1px);
  background-size: 22px 26px;
}
.tp-chart:active { cursor: grabbing; }
.tp-track { display: flex; align-items: stretch; gap: 1px; height: 100%; }
.tp-col { position: relative; flex: 1 1 0; min-width: 0; height: 100%; }
.tp-col.up { color: var(--pw-bull, #1FCBA0); }
.tp-col.down { color: var(--pw-bear, #E5484D); }


/* market watch */
.tp-rows { display: flex; flex-direction: column; gap: 6px; }
.tp-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 10px;
  padding: 9px 12px;
  border-radius: 11px;
  border: 1px solid rgba(120,150,180,.26);
  background: rgba(7,10,24,.72);
}
.tp-sym { font-size: calc(13px * var(--fs)); font-weight: 800; color: var(--text); min-width: 0; }
.tp-sym small { display: block; font-size: calc(10px * var(--fs)); font-weight: 600; color: #8FA9C4; }
.tp-last { font-size: calc(13px * var(--fs)); font-weight: 700; font-variant-numeric: tabular-nums; }
.tp-chg { font-size: calc(12px * var(--fs)); font-weight: 800; font-variant-numeric: tabular-nums; min-width: 62px; text-align: right; }
.tp-chg.up { color: var(--pw-bull, #1FCBA0); }
.tp-chg.down { color: var(--pw-bear, #E5484D); }

/* plan */
.tp-plans { display: flex; flex-direction: column; gap: 9px; }
.tp-plan {
  padding: 12px 14px;
  border-radius: 13px;
  border: 1px solid rgba(120,150,180,.26);
  background: rgba(7,10,24,.72);
}
.tp-plan.on { border-color: var(--cyan); box-shadow: 0 0 16px -8px rgba(61,223,255,.8); }
.tp-plan-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.tp-plan-name { font-size: calc(15px * var(--fs)); font-weight: 800; color: var(--text); }
.tp-plan-price { font-size: calc(13px * var(--fs)); font-weight: 800; color: var(--cyan); }
.tp-plan-list { margin: 8px 0 10px; padding-left: 18px; }
.tp-plan-list li { font-size: calc(11.5px * var(--fs)); line-height: 1.55; color: #C9DDF2; }
.tp-plan-list li::marker { color: var(--cyan); }
.tp-plan-cur {
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .14em; text-transform: uppercase; color: var(--pw-bull, #1FCBA0);
}
.tp-plan .pa-ghost { width: 100%; }

/* economic calendar */
.tp-cal { display: flex; flex-direction: column; gap: 10px; }
.tp-cal-day {
  padding: 10px 12px;
  border-radius: 12px;
  border: 1px solid rgba(120,150,180,.26);
  background: rgba(7,10,24,.72);
}
.tp-cal-day.today { border-color: var(--cyan); }
.tp-cal-head {
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .12em; text-transform: uppercase; color: #8FA9C4;
  margin-bottom: 7px;
}
.tp-cal-day.today .tp-cal-head { color: var(--cyan); }
.tp-ev {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  align-items: center; gap: 8px;
  padding: 5px 0;
  border-top: 1px solid rgba(61,223,255,.12);
  font-size: calc(11px * var(--fs));
}
.tp-ev:first-of-type { border-top: 0; }
.tp-ev-t { color: #8FA9C4; font-variant-numeric: tabular-nums; }
.tp-ev-c { font-weight: 800; color: var(--text); }
.tp-ev-n { color: #C9DDF2; min-width: 0; }
.tp-ev-i {
  padding: 1px 7px; border-radius: 999px;
  font-size: calc(9px * var(--fs)); font-weight: 800;
  border: 1px solid currentColor;
}
.tp-ev-i.i3 { color: var(--pw-bear, #E5484D); }
.tp-ev-i.i2 { color: var(--pw-wild, #E8B23A); }
.tp-ev-i.i1 { color: #8FA9C4; }


/* ===================== ÆWAY HOME ===================== */
.ae-home { padding: 2px 0 10px; }
.ae-cap {
  font-size: calc(10.5px * var(--fs));
  font-weight: 800; letter-spacing: .18em; text-transform: uppercase;
  color: #8FA9C4;
  margin: 16px 0 8px 2px;
}
/* the Featured Connection panel that stood at the top of this screen is
   gone; nothing draws .ae-feature any more. */

.ae-snap { display: flex; gap: 7px; }
.ae-snap-cell {
  flex: 1 1 0; min-width: 0;
  padding: 10px 4px;
  border-radius: 12px;
  border: 1px solid rgba(120,150,180,.26);
  background: rgba(7,10,24,.72);
  text-align: center;
}
.ae-snap-cell b {
  display: block;
  font-size: calc(18px * var(--fs)); font-weight: 800;
  font-variant-numeric: tabular-nums; color: var(--text);
}
.ae-snap-cell b.on { color: var(--cyan); }
.ae-snap-cell b.up { color: var(--pw-bull, #1FCBA0); }
.ae-snap-cell b.down { color: var(--pw-bear, #E5484D); }
.ae-snap-cell span { display: block; font-size: calc(9.5px * var(--fs)); color: #8FA9C4; margin-top: 2px; }

.ae-line {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 7px;
  padding: 9px 13px;
  border-radius: 11px;
  border: 1px solid rgba(120,150,180,.22);
  background: rgba(7,10,24,.6);
  font-size: calc(11.5px * var(--fs));
  color: #8FA9C4;
}
.ae-line b { color: var(--text); font-weight: 700; text-align: right; }

.ae-resume {
  display: block; width: 100%;
  margin-top: 12px;
  padding: 13px 15px;
  border-radius: 14px;
  border: 1px solid var(--cyan);
  background: linear-gradient(160deg, rgba(10,40,58,.7), rgba(7,10,24,.92));
  text-align: left;
  box-shadow: 0 0 18px -10px rgba(61,223,255,.9);
}
.ae-resume:active { filter: brightness(1.25); transform: scale(.99); }
.ae-resume-cap {
  display: block;
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: var(--cyan);
}
.ae-resume-name { display: block; font-size: calc(14.5px * var(--fs)); font-weight: 800; color: var(--text); margin-top: 4px; }
.ae-resume-sub { display: block; font-size: calc(10.5px * var(--fs)); color: #8FA9C4; margin-top: 2px; }

.ae-tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.ae-tile {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 7px;
  min-height: 84px;
  padding: 12px 8px;
  border-radius: 14px;
  border: 1px solid rgba(120,150,180,.26);
  background: rgba(7,10,24,.72);
}
.ae-tile img { width: 26px; height: 26px; object-fit: contain; }
/* the same wide glyph in the same square box — see the note on .dock-battle */
.ae-tile[data-ae-go="games"] img { width: 33px; height: 26px; }
.ae-tile span { font-size: calc(11.5px * var(--fs)); font-weight: 700; color: #C9DDF2; text-align: center; }
.ae-tile:active { filter: brightness(1.3); transform: scale(.97); }

/* ---- watchlist strip on the chart, search, and the calendar's date bar ---- */
.tp-strip {
  display: flex; gap: 6px;
  margin-top: 9px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.tp-strip::-webkit-scrollbar { display: none; }
.tp-chip {
  flex: 0 0 auto;
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 6px 11px;
  border-radius: 10px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
}
.tp-chip.on { border-color: var(--cyan); box-shadow: 0 0 12px -5px rgba(61,223,255,.8); }
.tp-chip:active { filter: brightness(1.3); }
.tp-chip-sym { font-size: calc(11.5px * var(--fs)); font-weight: 800; color: var(--text); }
.tp-chip.on .tp-chip-sym { color: var(--cyan); }
.tp-chip-chg { font-size: calc(9.5px * var(--fs)); font-weight: 700; font-variant-numeric: tabular-nums; }
.tp-chip-chg.up { color: var(--pw-bull, #1FCBA0); }
.tp-chip-chg.down { color: var(--pw-bear, #E5484D); }

.tp-search { position: relative; margin-bottom: 10px; }
.tp-search-in {
  width: 100%;
  min-height: 42px;
  padding: 8px 38px 8px 14px;
  border-radius: 12px;
  border: 1.5px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: var(--text);
  font-family: inherit;
  font-size: calc(13px * var(--fs));
}
.tp-search-in::placeholder { color: #6C82A0; }
.tp-search-in:focus { outline: none; border-color: var(--cyan); box-shadow: 0 0 14px -4px rgba(61,223,255,.7); }
.tp-search-x {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 28px; height: 28px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: none; border: 0;
  color: #8FA9C4; font-size: calc(12px * var(--fs));
}
.tp-hits { display: flex; flex-direction: column; gap: 5px; margin-bottom: 12px; }
.tp-hit {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 12px;
  border-radius: 11px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  background: rgba(7,10,24,.8);
  text-align: left;
}
.tp-hit:active { filter: brightness(1.3); }
.tp-hit[disabled] { opacity: .55; }
.tp-hit-add {
  flex: 0 0 auto;
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; color: var(--cyan);
}
.tp-hit[disabled] .tp-hit-add { color: #8FA9C4; }

/* the watchlist row grew a symbol button and a remove button */
.tp-row { grid-template-columns: 1fr auto auto auto; }
.tp-sym-go { background: none; border: 0; padding: 0; text-align: left; }
.tp-sym-go:active { filter: brightness(1.35); }
.tp-del {
  width: 26px; height: 26px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: #8FA9C4; font-size: calc(10px * var(--fs));
}
.tp-del:active { filter: brightness(1.4); border-color: var(--pw-bear, #E5484D); }

.tp-datebar { display: flex; align-items: center; gap: 8px; margin-bottom: 9px; }
.tp-step {
  flex: 0 0 auto;
  width: 40px; min-height: 40px;
  border-radius: 11px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: var(--cyan);
  font-size: calc(18px * var(--fs)); line-height: 1;
}
.tp-step:active { filter: brightness(1.35); }
.tp-date {
  flex: 1 1 auto; min-width: 0;
  min-height: 40px;
  padding: 8px 12px;
  border-radius: 11px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: var(--text);
  font-family: inherit;
  font-size: calc(12.5px * var(--fs));
}
.tp-date:focus { outline: none; border-color: var(--cyan); }
.tp-date::-webkit-calendar-picker-indicator { filter: invert(1) brightness(1.4); }
.tp-datehead {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  font-size: calc(11.5px * var(--fs)); font-weight: 700; color: #C9DDF2;
  margin-bottom: 10px;
}
.tp-today {
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid var(--cyan);
  background: rgba(4,7,18,.6);
  color: var(--cyan);
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
}
/* the calendar is one day now, so the day wrapper is gone with it */
.tp-cal .tp-ev:first-child { border-top: 0; }

/* ===================== PICKÆWAY LOBBY + STAKE =====================
   The lobby and the stake screen in the app's own glass language: the same
   .bm-rect pill the other selectors use, gradient-bordered summary panels, and
   the established green/red for a correct and a wrong call. */
/* Both screens have to land in one view, so the lobby and the stake screen
   run tighter than the rest of the app: smaller labels, less air between
   sections, and no explanatory paragraphs. */
.bm-lobby { padding-bottom: 2px; }
/* the label carries the instrument's full name on its own right-hand end, so
   the name costs a line of its own nothing */
.bm-lobby .bm-label {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  margin: 0 4px 4px 2px;
}
.bm-lobby .bm-row { gap: 6px; margin-bottom: 8px; }
.bm-lobby .bm-rect { min-height: 36px; font-size: calc(12px * var(--fs)); }
.bm-ins-name {
  color: var(--cyan); font-weight: 700;
  font-size: calc(10.5px * var(--fs));
  letter-spacing: .02em; text-transform: none;
}
.bm-row-3 { grid-template-columns: repeat(3, 1fr); }
.bm-row-6 { grid-template-columns: repeat(6, 1fr); }
.bm-row-8 { grid-template-columns: repeat(8, 1fr); }
/* eight candle counts and six risk amounts each want one line, so they run
   narrower than the four- and five-across rows above them */
.bm-lobby .bm-row-6, .bm-lobby .bm-row-8 { gap: 4px; }
.bm-lobby .bm-row-8 .bm-rect { font-size: calc(11px * var(--fs)); padding: 0 1px; }

/* difficulty gets cards rather than pills — it carries a line of explanation */
/* One column of small boxes rather than three cards across: narrow enough
   that none of them reaches the edge, which is what keeps the screen from
   reading as three big slabs. */
.bm-diffs {
  display: flex; flex-direction: column; align-items: center;
  gap: 4px; margin-bottom: 8px;
}
.bm-diff-card {
  width: 74%;
  display: flex; flex-direction: column; align-items: center; gap: 0;
  padding: 4px 12px;
  border-radius: 12px;
  border: 1.5px solid rgba(120,150,180,.3);
  background: linear-gradient(160deg, rgba(11,18,38,.85), rgba(7,10,24,.9));
  text-align: center;
}
.bm-diff-card.on {
  border-color: var(--cyan);
  box-shadow: 0 0 18px -6px rgba(61,223,255,.75), inset 0 0 14px -8px rgba(61,223,255,.9);
}
.bm-diff-card:active { filter: brightness(1.25); transform: scale(.99); }
.bm-diff-t { font-size: calc(12.5px * var(--fs)); font-weight: 800; color: #7D93AC; }
.bm-diff-card.on .bm-diff-t { color: var(--cyan); }
.bm-diff-s { font-size: calc(9.5px * var(--fs)); line-height: 1.25; color: #8FA9C4; }

/* the two summary panels: match type, and the stake split */
.bm-sum, .bm-split, .bm-bank {
  margin: 0 0 8px;
  padding: 8px 14px;
  border-radius: 14px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  background: linear-gradient(160deg, rgba(11,18,38,.9), rgba(7,10,24,.92));
}
.bm-sum-line {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 3px 0;
  font-size: calc(11.5px * var(--fs)); color: #8FA9C4;
}
.bm-sum-line + .bm-sum-line { border-top: 1px solid rgba(61,223,255,.12); }
.bm-sum-line b {
  font-size: calc(14px * var(--fs)); font-weight: 800;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.bm-sum-head { display: flex; align-items: center; gap: 9px; margin-bottom: 11px; }
.bm-sum-badge {
  padding: 3px 11px;
  border-radius: 999px;
  border: 1px solid currentColor;
  font-size: calc(10px * var(--fs)); font-weight: 800;
  letter-spacing: .1em; text-transform: uppercase;
}
.bm-sum-badge.easy { color: var(--pw-bull, #1FCBA0); }
.bm-sum-badge.medium { color: var(--cyan); }
.bm-sum-badge.hard { color: var(--pw-bear, #E5484D); }
.bm-sum-title {
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: #8FA9C4;
}
.bm-sum-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 7px; }
.bm-sum-cell {
  padding: 8px 4px;
  border-radius: 11px;
  border: 1px solid rgba(120,150,180,.24);
  background: rgba(4,7,18,.6);
  text-align: center;
}
.bm-sum-cell b {
  display: block;
  font-size: calc(15px * var(--fs)); font-weight: 800;
  font-variant-numeric: tabular-nums; color: var(--text);
}
.bm-sum-cell b.up { color: var(--pw-bull, #1FCBA0); }
.bm-sum-cell b.down { color: var(--pw-bear, #E5484D); }
.bm-sum-cell span { display: block; font-size: calc(9.5px * var(--fs)); color: #8FA9C4; margin-top: 2px; }
.bm-sum-say {
  margin-top: 11px;
  font-size: calc(11.5px * var(--fs)); line-height: 1.55; color: #C9DDF2;
}

/* stake screen */
.bm-bank { text-align: center; }
.bm-bank-cap {
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: #8FA9C4;
}
.bm-bank-val {
  display: block; margin-top: 2px;
  font-size: calc(24px * var(--fs)); font-weight: 800;
  color: var(--cyan); font-variant-numeric: tabular-nums;
}
.bm-recap {
  display: flex; flex-direction: column; gap: 3px;
  margin-top: 9px; padding-top: 9px;
  border-top: 1px solid rgba(61,223,255,.16);
  font-size: calc(11px * var(--fs)); color: #9FC0E0;
}
.bm-split-math {
  display: flex; align-items: baseline; justify-content: center; gap: 9px;
  flex-wrap: wrap;
  margin-bottom: 8px;
  font-size: calc(11px * var(--fs)); color: #8FA9C4;
}
.bm-split-math b {
  font-size: calc(19px * var(--fs)); font-weight: 800;
  color: var(--cyan); font-variant-numeric: tabular-nums;
}
/* the CTA is the last thing on either screen, so its bottom margin is dead
   height that pushes the button off the view */
.bm-lobby .bm-start { margin: 2px 0 0; --pill-h: 58px; }
.bm-start ~ .btn-secondary { width: 78%; margin: 6px auto 0; padding: 8px; }
.bm-lobby .bm-sum-cell { padding: 6px 3px; }
.bm-lobby .bm-sum-cell b { font-size: calc(14px * var(--fs)); }

/* Short screens: the two setup screens still have to land in one view, so
   below these heights the sections lose their air, the difficulty boxes lose
   their subtitles, and the type steps down — the same tiering Placeæway's
   setup uses. Nothing is removed; it only gets tighter. */
@media (max-height: 900px) {
  .bm-lobby { padding-bottom: 0; }
  .bm-lobby .bm-label { margin-bottom: 3px; }
  .bm-lobby .bm-row { margin-bottom: 6px; }
  .bm-diffs { gap: 3px; margin-bottom: 6px; }
  .bm-diff-card { padding: 3px 12px; }
  .bm-diff-s { line-height: 1.2; }
  .bm-sum, .bm-split, .bm-bank { margin-bottom: 6px; padding: 6px 14px; }
  .bm-sum-line { padding: 2px 0; }
  .bm-split-math { margin-bottom: 6px; }
  .bm-lobby .bm-start { --pill-h: 54px; }
  .bm-start ~ .btn-secondary { margin-top: 5px; padding: 6px; }
}
@media (max-height: 740px) {
  .bm-lobby { padding-bottom: 0; }
  .bm-lobby .bm-label {
    font-size: calc(9.5px * var(--fs)); margin-bottom: 2px;
    letter-spacing: .13em; line-height: 1.1;
  }
  .bm-lobby .bm-row { gap: 5px; margin-bottom: 4px; }
  .bm-lobby .bm-rect { min-height: 27px; padding: 2px 3px; font-size: calc(11.5px * var(--fs)); }
  .bm-lobby .bm-row-8 .bm-rect { font-size: calc(10.5px * var(--fs)); }
  .bm-ins-name { font-size: calc(9.5px * var(--fs)); }
  .bm-diffs { gap: 2px; margin-bottom: 4px; }
  .bm-diff-card { min-height: 19px; padding: 0 10px; border-radius: 10px; justify-content: center; }
  .bm-diff-s { display: none; }
  .bm-diff-t { font-size: calc(11.5px * var(--fs)); line-height: 1.15; }
  .bm-sum, .bm-split, .bm-bank { margin-bottom: 4px; padding: 2px 12px; }
  .bm-sum-line { padding: 0; font-size: calc(10px * var(--fs)); line-height: 1.15; }
  .bm-sum-line b { font-size: calc(12.5px * var(--fs)); }
  .bm-bank-val { font-size: calc(19px * var(--fs)); }
  .bm-split-math { margin-bottom: 5px; }
  .bm-split-math b { font-size: calc(16px * var(--fs)); }
  /* the four stake figures go to one row rather than two — a short screen
     cannot spare the second */
  .bm-lobby .bm-sum-grid { grid-template-columns: repeat(4, 1fr); gap: 4px; }
  .bm-lobby .bm-sum-cell { padding: 3px 1px; }
  .bm-lobby .bm-sum-cell b { font-size: calc(11.5px * var(--fs)); }
  .bm-lobby .bm-sum-cell span { font-size: calc(8px * var(--fs)); margin-top: 1px; }
  /* the CTA is a 9-slice with 26px caps top and bottom, so 54px is as short as
     it goes before the frame starts squashing; its bottom margin is the last
     thing on the screen and buys nothing */
  .bm-lobby .bm-start { margin: 0; --pill-h: 46px; font-size: calc(14px * var(--fs)); }
  .bm-start ~ .btn-secondary { margin: 4px auto 0; padding: 5px; }
}
/* Below this the card is under 320px tall and five labelled sections plus a
   CTA no longer fit however tight the type gets, so the difficulty boxes give
   up the single column and run three across — still small boxes, still short
   of the edges, and the screen lands in one view. The cut-off is 660 rather
   than 620 because a 640-tall phone's card is smaller than a 568-tall one's
   was: the chrome above it does not shrink at the same rate. */
@media (max-height: 660px) {
  .bm-lobby { padding-bottom: 0; }
  .bm-lobby .bm-label { margin-bottom: 1px; letter-spacing: .1em; line-height: 1.1; }
  .bm-lobby .bm-row { gap: 4px; margin-bottom: 3px; }
  .bm-lobby .bm-rect { min-height: 24px; padding: 1px 3px; font-size: calc(10.5px * var(--fs)); }
  .bm-lobby .bm-row-8 .bm-rect { font-size: calc(9.5px * var(--fs)); }
  .bm-diffs {
    flex-direction: row; justify-content: center;
    gap: 4px; margin-bottom: 3px;
  }
  .bm-diff-card { width: 28%; padding: 1px 4px; }
  .bm-diff-t { font-size: calc(10.5px * var(--fs)); }
  .bm-sum, .bm-split, .bm-bank { margin-bottom: 3px; padding: 2px 10px; }
  .bm-sum-line { padding: 0; font-size: calc(9.5px * var(--fs)); line-height: 1.2; }
  .bm-sum-line b { font-size: calc(10.5px * var(--fs)); }
  .bm-bank-cap { font-size: calc(9px * var(--fs)); line-height: 1.1; }
  .bm-bank-val { font-size: calc(14px * var(--fs)); margin-top: 0; line-height: 1.15; }
  .bm-split-math { margin-bottom: 0; font-size: calc(10px * var(--fs)); }
  .bm-split-math b { font-size: calc(14px * var(--fs)); }
  .bm-lobby .bm-sum-grid { gap: 3px; }
  .bm-lobby .bm-sum-cell { padding: 2px 1px; }
  .bm-lobby .bm-sum-cell b { font-size: calc(10.5px * var(--fs)); }
  .bm-lobby .bm-sum-cell span { font-size: calc(7.5px * var(--fs)); }
  /* the CTA's 9-slice caps come down with it: 26px caps can't fit inside a
     44px button, so the slice is re-scaled rather than clipped */
  .bm-lobby .bm-start { --pill-h: 40px; font-size: calc(12.5px * var(--fs)); }
  .bm-start ~ .btn-secondary { margin-top: 2px; padding: 2px; }
}

/* what this print is worth, in place of the risk chips the match used to carry */
.mk-stake {
  display: flex; justify-content: center; gap: 18px;
  margin-top: 10px;
  font-size: calc(11.5px * var(--fs)); color: #8FA9C4;
}
.mk-stake b { font-weight: 800; font-variant-numeric: tabular-nums; }
.mk-stake b.up { color: var(--pw-bull, #1FCBA0); }
.mk-stake b.down { color: var(--pw-bear, #E5484D); }

/* the match's own top line: what you have, and how long the match has left */
.mk-topline {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 4px 0 5px;
}
.mk-balance, .mk-matchclock { display: flex; flex-direction: column; gap: 1px; }
.mk-matchclock { text-align: right; }
.mk-balance-cap {
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: #8FA9C4;
}
.mk-balance-val, .mk-matchclock-val {
  font-size: calc(19px * var(--fs)); font-weight: 800;
  font-variant-numeric: tabular-nums; color: var(--text);
  transition: color .2s ease;
}
.mk-balance-val.up { color: var(--pw-bull, #1FCBA0); }
.mk-balance-val.down { color: var(--pw-bear, #E5484D); }
.mk-matchclock-val { color: var(--cyan); }
.mk-clock-bar.match { margin-bottom: 8px; }
.mk-clock-bar.match span { background: linear-gradient(90deg, var(--cyan), var(--magenta)); }

/* ===================== DISCIPLINE STREAK =====================
   Today's scorecard and the calendar behind it. Everything that can be
   borrowed is: the summaries are .bt-summary rows, the add button is the
   journal's .j-add, and the calendar is the journal's .j-cal with the day's
   section count where the journal puts P&L. Only the wrappers are new. */
.ds-head {
  text-align: center;
  font-size: calc(19px * var(--fs)); font-weight: 800;
  color: var(--cyan); text-shadow: 0 0 16px rgba(61,223,255,.6);
  margin: 2px 0 4px;
}
.ds-head.full { color: var(--teal); text-shadow: 0 0 20px rgba(47,230,194,.75); }
.ds-sub {
  text-align: center;
  font-size: calc(12.5px * var(--fs)); line-height: 1.5; color: #9FC0E0;
  margin: 0 auto 16px; max-width: 300px;
}
/* The scorecard is a stack of collapsed headline rows, one per completed
   section, each opening on its own. No box around them — the caption and the
   row are the grouping, so the stack reads as one list rather than three
   panels that happen to sit under each other. */
.ds-rows { display: flex; flex-direction: column; gap: 14px; }
.ds-row { display: flex; flex-direction: column; }
.ds-row .ci-expand { margin-top: 0; }
/* a section with nothing logged keeps the row's shape and loses its caret */
.ci-expand-off {
  display: flex; align-items: center; justify-content: center;
  width: 100%; max-width: 300px;
  margin: 0 auto;
  padding: 9px 14px;
  border-radius: 12px;
  border: 1px dashed rgba(120,150,180,.28);
  background: rgba(9,13,30,.35);
}
.ci-expand-off .ci-expand-lbl {
  color: #6E86A6; font-style: italic; font-weight: 700;
}
.ds-row .ds-note { text-align: center; margin: 8px 0 0; }
.ds-card-cap {
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: #8FA9C4;
  text-align: center;
  margin-bottom: 6px;
}
.ds-note {
  margin-top: 3px;
  font-size: calc(11.5px * var(--fs)); color: #9FC0E0;
}
/* one block per trade; the caption only shows when a day holds more than one.
   Matches .bt-summary's own width so a stacked day reads like a single one. */
.ds-entries {
  display: flex; flex-direction: column; gap: 12px;
  width: 100%; max-width: 300px;
}
.ds-entry-cap {
  font-size: calc(10px * var(--fs)); font-weight: 800;
  letter-spacing: .14em; text-transform: uppercase; color: var(--cyan);
  margin-bottom: 5px;
}
/* A day's trades are a list, not a short verdict. .ci-result-inline centres a
   result inside the space the questions left, which works while the result is
   a title and a line — but a stack of trades plus the add button is taller
   than that box, and a centred overflow spills out of BOTH ends, over the
   category row underneath. The stack anchors to the top and takes its natural
   height instead. */
.ci-result.ci-result-stack {
  flex: 0 0 auto;
  min-height: 0;
  justify-content: flex-start;
}
.ci-result-inline .ds-entry-cap { text-align: left; }
.ds-entry { width: 100%; }
.at-add { margin-top: 16px; }
.at-add .j-add { margin: 0 auto; width: 58px; height: 58px; }
.at-add .j-add::before { width: 22px; height: 3px; }
.at-add .j-add::after  { width: 3px;  height: 22px; }

/* the calendar's day states: a full four-section day, and a started one */
.ds-cal { margin-top: 6px; }
.j-day.ds-full { background: rgba(47,230,194,.13); border-color: rgba(47,230,194,.45); }
.j-day.ds-part { background: rgba(61,223,255,.08); border-color: rgba(61,223,255,.34); }
.ds-day-n {
  font-size: 8.5px; font-weight: 700; line-height: 1.1; color: #9FC0E0;
}
.j-day.ds-full .ds-day-n { color: var(--teal); }

/* ===================== COLLAPSED COMPLETED STATE =====================
   Before Trade and each After Trade entry show a headline and nothing else
   until it is tapped. Same disclosure shape as the prop-firm summary pill:
   the label is the tap target and the caret turns over when it opens. Start
   Day is deliberately not part of this — its result stays fully visible. */
.ci-expand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  max-width: 300px;
  margin: 6px auto 2px;
  padding: 9px 14px;
  border-radius: 12px;
  border: 1px solid rgba(61,223,255,.24);
  background: rgba(9,13,30,.6);
  text-align: center;
}
.ci-expand-lbl {
  font-size: calc(13px * var(--fs)); font-weight: 800;
  letter-spacing: .04em; color: var(--teal);
}
.ci-expand-caret { flex: 0 0 auto; display: grid; place-items: center; width: 16px; }
.ci-expand-caret img {
  width: 14px; height: 14px; object-fit: contain;
  transition: transform .2s ease;
}
.ci-expand.open .ci-expand-caret img { transform: rotate(180deg); }
.ci-expand:active { filter: brightness(1.3); transform: scale(.99); }
/* The section's own headline, at the scale .ci-result-title reads at. The
   caret goes under it rather than beside it: at this size the label wraps on
   a narrow phone, and a wrapped label leaves the caret stranded out at the
   right-hand edge with the text centred away from it. */
.ci-expand-lg {
  flex-direction: column;
  max-width: none;
  margin: 0 auto 10px;
  padding: 4px 0;
  border: 0;
  background: none;
  gap: 2px;
}
.ci-expand-lg .ci-expand-lbl {
  font-size: calc(23px * var(--fs)); letter-spacing: .04em;
  text-shadow: 0 0 20px rgba(47,230,194,.75);
}
.ci-expand-lg .ci-expand-caret { width: 20px; }
.ci-expand-lg .ci-expand-caret img { width: 18px; height: 18px; }
/* the recap sits directly under its own headline, not floating from it */
.ci-expand + .bt-summary { margin-top: 8px; }


/* ===================== CHART OVERLAY, BOTH PLATFORMS =====================
   The crosshair and the three drawing tools are shared by the desktop panel
   and the phone's chart, so these rules live outside the desktop media query
   the panel layout is written in. Nested there they applied at 1200px and up
   only, which left the phone's SVG with no size at all — the drawings landed
   about 1.56x out, which is the box's own aspect ratio. */
.dc-overlay, .dc-cross, .dc-labels { position: absolute; inset: 0; pointer-events: none; }
.dc-svg { width: 100%; height: 100%; overflow: visible; }
.dc-shape {
  fill: none;
  stroke: var(--cyan);
  stroke-width: 1.5px;
  pointer-events: stroke;
}
.dc-shape.fib { stroke: rgba(61,223,255,.65); stroke-dasharray: 4 3; }
.dc-shape.sel { stroke: var(--magenta); stroke-width: 2px; }
.dc-handle { fill: var(--magenta); stroke: #fff; stroke-width: 1px; pointer-events: all; }
.dc-overlay { pointer-events: none; }
.dc-overlay .dc-svg { pointer-events: none; }
.dc-overlay .dc-shape, .dc-overlay .dc-handle { pointer-events: all; }
.dc-fib-lbl {
  position: absolute;
  right: 3px;
  transform: translateY(-50%);
  font-size: 9px; font-weight: 700; white-space: nowrap;
  color: #9FC0E0; text-shadow: 0 0 6px rgba(0,0,0,.9);
}
/* crosshair: two hairlines and the two readouts they point at */
.dc-cross-v, .dc-cross-h { position: absolute; background: rgba(61,223,255,.5); }
.dc-cross-v { top: 0; bottom: 0; width: 1px; }
.dc-cross-h { left: 0; right: 0; height: 1px; }
.dc-read {
  position: absolute;
  padding: 1px 5px;
  border-radius: 4px;
  background: rgba(61,223,255,.9);
  color: #041018;
  font-size: 9.5px; font-weight: 800;
  white-space: nowrap;
  pointer-events: none;
}
.dc-read-p { right: 2px; transform: translateY(-50%); }
.dc-read-t { bottom: 2px; transform: translateX(-50%); }


/* The chart's control buttons. Shared by the desktop panel and the phone's
   chart, so they live at top level: inside the desktop media query they left
   the toolbar on a phone as a row of bare words. */
.dc-tool {
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid rgba(120,150,180,.32);
  background: rgba(5,9,22,.5);
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .06em; color: #8FA9C4;
}
.dc-tool.on { border-color: var(--cyan); color: var(--cyan);
  box-shadow: 0 0 12px -3px rgba(61,223,255,.6); }
.dc-tool.off { opacity: .4; }
.dc-del.on, .dc-del:not(.off) { border-color: rgba(255,61,154,.5); color: #FF6B9D; }

/* ---- the phone's chart: two dropdowns and the ticker, inside the plot ----
   Nine timeframes and five tools as two rows of pills cost the chart most of
   its height on a phone. They collapse into a pair of buttons sitting over
   the plot's top-left corner, which is what lets the plot start immediately
   under the mode toggle and take that height back.

   The wrapper does not take the pointer — the chart under it still pans and
   pinches — only the buttons and the open menu do. */
.tp-menus {
  /* under the ticker rather than beside it: centred on a phone's chart box,
     the ticker and these two buttons cannot share a line without one of them
     running into the other */
  position: absolute; top: 27px; left: 6px;
  display: flex; gap: 5px;
  pointer-events: none;
  z-index: 3;
}
.tp-menu-wrap { position: relative; pointer-events: auto; }
.tp-menu-btn {
  display: flex; align-items: center; gap: 5px;
  min-width: 44px;
  padding: 3px 8px;
  border-radius: 8px;
  border: 1px solid rgba(120,150,180,.35);
  background: rgba(5,9,22,.88);
  font-size: calc(9.5px * var(--fs)); font-weight: 800; letter-spacing: .04em;
  color: #9FC0E0;
}
.tp-menu-btn.on { border-color: var(--cyan); color: var(--cyan); }
.tp-menu-btn i {
  width: 0; height: 0; margin-top: 2px;
  border: 3.5px solid transparent; border-top-color: currentColor;
}
.tp-menu {
  position: absolute; top: calc(100% + 4px); left: 0;
  display: flex; flex-direction: column; gap: 2px;
  min-width: 76px; max-height: 172px; overflow-y: auto;
  padding: 4px;
  border-radius: 10px;
  border: 1px solid rgba(61,223,255,.38);
  background: rgba(4,8,20,.97);
  box-shadow: 0 6px 20px rgba(0,0,0,.6);
}
.tp-menu-item {
  padding: 5px 9px;
  border: 0; border-radius: 6px; background: none;
  text-align: left; white-space: nowrap;
  font-size: calc(10.5px * var(--fs)); font-weight: 700; color: #9FC0E0;
}
.tp-menu-item.on { background: rgba(61,223,255,.16); color: var(--cyan); }
.tp-menu-item.del { color: #FF6B9D; }
.tp-menu-item.off { opacity: .4; }

/* the ticker reads across the top of the plot rather than above the box */
.tp-ticker {
  position: absolute; top: 6px; left: 50%; transform: translateX(-50%);
  max-width: calc(100% - 120px);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: calc(11px * var(--fs)); font-weight: 800; letter-spacing: .03em;
  color: #EAF6FF; text-shadow: 0 0 8px rgba(2,4,12,.95);
  pointer-events: none; z-index: 2;
}
.tp-chg {
  position: absolute; top: 7px; right: 9px;
  font-size: calc(10px * var(--fs)); font-weight: 800;
  text-shadow: 0 0 8px rgba(2,4,12,.95);
  pointer-events: none; z-index: 2;
}
.tp-chg.up { color: var(--pw-bull, #1FCBA0); }
.tp-chg.down { color: var(--pw-bear, #E5484D); }
/* the height the two rows of pills used to take */
.tp-chart.tall { height: 300px; }
/* a short phone did not have that height to give in the first place */
@media (max-height: 740px) { .tp-chart.tall { height: 226px; } }

/* the phone's chart carries the same three tools as the desktop panel */
.tp-toolbar { display: flex; gap: 5px; margin-bottom: 7px; }
.tp-toolbar .dc-tool { flex: 1 1 0; padding: 5px 4px; text-align: center; }
.tp-chart { position: relative; }
.tp-chart.drawing { cursor: crosshair; }
.tp-chart .dc-overlay, .tp-chart .dc-cross { position: absolute; inset: 0; }

/* the switch between the $ÆWAY tape and the real-instrument chart */
.tp-mode { display: flex; gap: 6px; margin-bottom: 8px; }
.tp-mode-btn {
  flex: 1 1 0;
  padding: 6px 8px;
  border-radius: 999px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(9,13,30,.6);
  color: #9FC0E0;
  font-size: calc(10.5px * var(--fs)); font-weight: 800; letter-spacing: .06em;
}
.tp-mode-btn.on {
  border-color: var(--cyan); color: #F2FBFF;
  background: rgba(61,223,255,.14);
  box-shadow: 0 0 12px rgba(61,223,255,.22);
}

/* $ÆWAY: the tape has no axis, no ticker chips and no price of any kind —
   only the shape, and the two calls under it */
.ae-head .tp-quote b, .ae-head .dc-quote b { letter-spacing: .06em; }
.ae-chart { cursor: default; touch-action: auto; }
/* the chart opens empty and says so, rather than looking like it failed */
.ae-empty {
  /* the track is a flex row, so this has to claim the width before it can
     centre anything in it */
  flex: 1 1 auto;
  display: flex; align-items: center; justify-content: center;
  height: 100%;
}
.ae-empty-line {
  font-size: calc(11px * var(--fs)); font-weight: 700;
  letter-spacing: .04em; color: #5F7C99;
}
.ae-panel { margin-top: 9px; }
.ae-gen-row { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
.ae-gen {
  flex: 1 1 0;
  min-height: 38px;
  border-radius: 12px;
  border: 1px solid var(--cyan);
  background: rgba(61,223,255,.12);
  color: #F2FBFF;
  font-size: calc(12px * var(--fs)); font-weight: 800;
  letter-spacing: .1em; text-transform: uppercase;
}
.ae-gen:active { transform: translateY(1px); }
.ae-note { flex: 0 0 auto; font-size: calc(10.5px * var(--fs)); color: #7E9CBB; }
.ae-calls { display: flex; gap: 9px; }
.ae-call {
  flex: 1 1 0;
  min-height: 52px;
  border-radius: 14px;
  border: 1px solid transparent;
  font-size: calc(14px * var(--fs)); font-weight: 900;
  letter-spacing: .1em; text-transform: uppercase;
  color: #04121A;
}
.ae-call.up { background: linear-gradient(180deg, #5CF0D2, #1FCBA0); box-shadow: 0 0 16px rgba(47,230,194,.35); }
.ae-call.down { background: linear-gradient(180deg, #FF7C7C, #E5484D); box-shadow: 0 0 16px rgba(229,72,77,.35); }
.ae-call.on { outline: 2px solid #F2FBFF; outline-offset: 1px; }
.ae-call:active { transform: translateY(1px); }
/* on a short phone the two calls are what has to be on screen, not the last
   forty candles — the tape gives up the height */
@media (max-height: 740px) {
  .ae-chart { height: 70px; }
  .ae-gen { min-height: 34px; }
  .ae-call { min-height: 44px; }
}

/* saved patterns */
.tp-savebar { display: flex; gap: 5px; margin-top: 8px; }
.tp-savebar .dc-tool { flex: 1 1 0; text-align: center; }
.pat-list { margin-top: 7px; display: flex; flex-direction: column; gap: 5px; }
.pat-row { display: flex; gap: 5px; align-items: stretch; }
.pat-open {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 7px 10px;
  border-radius: 10px;
  border: 1px solid rgba(120,150,180,.28);
  background: rgba(9,13,30,.6);
  text-align: left;
}
.pat-sym { font-size: calc(12px * var(--fs)); font-weight: 800; color: #F2FBFF; }
.pat-sym small { margin-left: 6px; font-size: calc(9.5px * var(--fs)); font-weight: 700; color: var(--cyan); }
.pat-meta { font-size: calc(10px * var(--fs)); color: #7E9CBB; white-space: nowrap; }
.pat-del {
  flex: 0 0 auto; width: 34px;
  border-radius: 10px;
  border: 1px solid rgba(255,61,154,.35);
  background: rgba(255,61,154,.1);
  color: #FF6B9D; font-weight: 800;
}
.pat-chart { cursor: default; touch-action: auto; }
.tp-pat-tf { font-size: calc(10.5px * var(--fs)); font-weight: 800; color: var(--cyan); }

/* the practice loop: the chart, then the two questions under it */
.tp-prac-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 4px;
}
.tp-prac-cap {
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  letter-spacing: .16em; text-transform: uppercase; color: var(--cyan);
}
.tp-prac-score { font-size: calc(11px * var(--fs)); color: #9FC0E0; }
.tp-prac-score b { color: #F2FBFF; font-variant-numeric: tabular-nums; }
/* the questions have to sit under the chart without pushing Submit off the
   bottom of a phone, so the practice chart is shorter than the one on the
   Chart tab and everything under it is on a tighter rhythm */
#tpPracChart { height: 102px; }
.tp-prac-q, .tp-prac-mark, .tp-prac-done { margin-top: 5px; }
.tp-prac-q .bt-opts { gap: 5px; }
.tp-prac-q .bt-opt { min-height: 28px; padding: 4px 3px; font-size: calc(10px * var(--fs)); }
/* the two nine-slice labels and the submit pill, scaled down for this screen.
   The caps have to come down with the height — a fixed cap taller than the
   box is what squashes a nine-slice frame into a lozenge. */
.tp-prac-q .bt-q {
  margin: 4px 0 4px; min-height: 34px;
  border-width: 15px 18px;
  border-image: url("../assets/buttons-icon/label-button@2x.png") 40 48 fill / 15px 18px stretch;
  font-size: calc(11.5px * var(--fs));
}
.tp-prac-q .ci-submit {
  height: 44px; margin: 6px auto 2px;
  border-width: 19px 22px;
  border-image: url("../assets/buttons-icon/label-button@2x.png") 40 48 fill / 19px 22px stretch;
  font-size: calc(12.5px * var(--fs));
}
.bt-opt.up.on { border-color: var(--teal); color: var(--teal); }
.bt-opt.down.on { border-color: var(--magenta); color: var(--magenta); }
.tp-prac-line {
  padding: 7px 12px; margin-bottom: 7px;
  border-radius: 10px;
  font-size: calc(12px * var(--fs)); font-weight: 700;
  border: 1px solid rgba(120,150,180,.28);
  background: rgba(9,13,30,.6);
}
.tp-prac-line.ok { border-color: rgba(47,230,194,.5); color: var(--teal); }
.tp-prac-line.no { border-color: rgba(255,61,154,.45); color: #FF6B9D; }
.tp-prac-done { text-align: center; }
.tp-prac-done .btn-primary, .tp-prac-done .btn-secondary { width: 78%; margin: 10px auto 0; }

/* ==================== ÆWAY: the market screen ====================
   The chart fills whatever is left after the head and the calls, so the panel
   becomes a column and the chart box the thing that flexes. Everything else in
   the Tools panel keeps the layout it had, which is what .aw-fill is for. */
#cardScroll .ip-panel.aw-fill {
  height: 100%;
  display: flex; flex-direction: column;
  min-height: 0;
}
/* The body is the column and the chart box is the one thing in it that
   stretches. Everything else — the mode toggle, the head, the calls — is its own
   height, and the chart takes whatever is left. */
.ip-panel.aw-fill .tp-body {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
}
.ip-panel.aw-fill .tp-body { margin-bottom: 0; }

.aw-head { margin-bottom: 6px; flex: 0 0 auto; }
.aw-head .tp-quote b { font-size: calc(13px * var(--fs)); letter-spacing: .1em; }
/* the tag that says what this market is. It is also the way in to the admin
   page, under a long press — see awIsAdmin(). */
.aw-sim {
  display: inline-block;
  margin-left: 7px; padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid rgba(143,169,196,.38);
  background: rgba(143,169,196,.10);
  color: #9FC0E0;
  font-size: calc(8.5px * var(--fs)); font-weight: 800;
  letter-spacing: .05em; text-transform: uppercase;
  vertical-align: 2px;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}

.aw-box {
  position: relative;
  /* basis 0, so the leftover height is shared by the chart alone rather than in
     proportion to what each child happens to contain */
  flex: 1 1 0;
  min-height: 132px;
  border-radius: 14px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.24));
  background: rgba(7,10,24,.72);
  overflow: hidden;
}
.aw-canvas {
  position: absolute; inset: 0;
  display: block; width: 100%; height: 100%;
  /* the gesture handler owns this surface: without it the browser pans and
     pinch-zooms the page before a pointermove is ever seen */
  touch-action: none;
  -webkit-user-select: none; user-select: none;
}
.aw-box.aw-dead {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 14px;
}
.aw-dead-why { font-size: calc(9.5px * var(--fs)); color: #6F8CA8; text-align: center; }

/* the readout: the crosshair's candle, or the newest one when nothing is held */
.aw-read {
  position: absolute; top: 4px; left: 7px; right: 58px;
  display: flex; flex-direction: column; gap: 1px;
  font-size: calc(8.5px * var(--fs));
  color: #8FA9C4;
  pointer-events: none;
  text-shadow: 0 0 7px rgba(2,4,12,.95), 0 0 3px rgba(2,4,12,.95);
  z-index: 2;
}
.aw-read-when { font-weight: 800; color: #C7DCEF; letter-spacing: .03em; margin-right: 2px; }
.aw-read-when i { font-style: normal; font-weight: 700; color: #6F8CA8; font-size: .9em; }
/* a short plot: one line, and only what cannot be read off the candle itself */
.aw-box.tight .aw-read { flex-direction: row; flex-wrap: wrap; gap: 4px 7px; align-items: baseline; }
.aw-box.tight .aw-read-ohlc > .o,
.aw-box.tight .aw-read-ohlc > .h,
.aw-box.tight .aw-read-ohlc > .l,
.aw-box.tight .aw-read-vol > .m { display: none; }
.aw-box.tight .aw-menus { top: 26px; }
.aw-read-ohlc { display: flex; flex-wrap: wrap; gap: 5px; align-items: baseline; }
.aw-read-ohlc i { font-style: normal; font-weight: 800; color: #E6F2FB; margin-left: 2px; }
.aw-read-ohlc i.up, .aw-read-vol b.up, .aw-read-ohlc em.up { color: var(--pw-bull, #1FCBA0); }
.aw-read-ohlc i.down, .aw-read-vol b.down, .aw-read-ohlc em.down { color: var(--pw-bear, #E5484D); }
.aw-read-ohlc em { font-style: normal; font-weight: 800; }
.aw-read-vol { display: flex; flex-wrap: wrap; gap: 7px; }
.aw-read-vol b { font-weight: 800; }
.aw-read-vol b.flat { color: #8FA9C4; }
.aw-read-vol b i { font-style: normal; font-weight: 700; opacity: .72; margin-left: 2px; }
.aw-read-vol b.aw-est { opacity: .6; text-transform: uppercase; letter-spacing: .06em; }
.aw-read-dim { color: #5F7C99; }

/* the timeframe menu reuses the instrument chart's dropdown, lowered to clear
   the three-line readout above it */
.aw-menus { top: 46px; left: 7px; }
.aw-box .tp-menu {
  position: absolute; top: calc(100% + 4px); left: 0;
  display: flex; flex-direction: column; gap: 3px;
  padding: 5px;
  border-radius: 10px;
  border: 1px solid rgba(120,150,180,.35);
  background: rgba(5,9,22,.96);
  pointer-events: auto; z-index: 5;
}
.aw-box .tp-menu-item {
  padding: 5px 12px; border-radius: 7px;
  border: 1px solid transparent; background: none;
  color: #9FC0E0; font-size: calc(10px * var(--fs)); font-weight: 800;
  text-align: left; white-space: nowrap;
}
.aw-box .tp-menu-item.on { border-color: var(--cyan); color: var(--cyan); }

/* back to the newest candle. Only there when the chart has been panned off it. */
.aw-jump {
  position: absolute; right: 60px; bottom: 22px;
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 1px solid rgba(61,223,255,.5);
  background: rgba(5,9,22,.92);
  color: var(--cyan);
  font-size: calc(11px * var(--fs)); font-weight: 900;
  line-height: 1;
  z-index: 3;
}
.aw-jump:active { filter: brightness(1.4); }

/* ---- the calls ---- */
.aw-head, .aw-panel, .ip-panel.aw-fill .tp-mode { flex: 0 0 auto; }
.aw-panel { margin-top: 8px; }
/* no prediction open, no line, no height held for one */
.aw-live:empty { display: none; }
.aw-live { margin-bottom: 5px; }
.aw-open {
  font-size: calc(9.5px * var(--fs)); color: #9FC0E0;
  display: flex; flex-wrap: wrap; gap: 4px; align-items: baseline;
}
.aw-open b { font-weight: 900; letter-spacing: .06em; }
.aw-open.bull b { color: var(--pw-bull, #1FCBA0); }
.aw-open.bear b { color: var(--pw-bear, #E5484D); }
.aw-open i { font-style: normal; font-weight: 800; }
.aw-open i.up { color: var(--pw-bull, #1FCBA0); }
.aw-open i.down { color: var(--pw-bear, #E5484D); }

.aw-calls { align-items: stretch; gap: 7px; }
.aw-calls .ae-call { min-height: 46px; font-size: calc(13px * var(--fs)); }
.aw-calls .ae-call:disabled { opacity: .42; }
/* the countdown sits between the two calls, which is where the reference puts it */
.aw-count {
  flex: 0 0 auto;
  min-width: 70px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px;
  border-radius: 14px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.6);
  color: #E6F2FB;
  font-size: calc(15px * var(--fs)); font-weight: 900;
  font-variant-numeric: tabular-nums;
  letter-spacing: .04em;
}
.aw-count i {
  font-style: normal; font-size: calc(8px * var(--fs)); font-weight: 800;
  letter-spacing: .08em; color: #7E9CBB; text-transform: uppercase;
}
.aw-count.locked { color: #7E9CBB; font-size: calc(11px * var(--fs)); letter-spacing: .08em; }

.aw-foot {
  display: flex; align-items: center; gap: 9px;
  margin-top: 7px;
  font-size: calc(9.5px * var(--fs));
}
.aw-bal { font-weight: 900; color: #E6F2FB; font-size: calc(11px * var(--fs)); }
.aw-bal i { font-style: normal; font-weight: 700; color: #7E9CBB; font-size: calc(9px * var(--fs)); }
.aw-note { color: var(--cyan); flex: 1 1 auto; min-width: 0; }
.aw-link {
  margin-left: auto;
  padding: 3px 9px;
  border-radius: 999px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.5);
  color: #9FC0E0;
  font-size: calc(9.5px * var(--fs)); font-weight: 800;
}
.aw-link + .aw-link { margin-left: 0; }
.aw-adm-ask { gap: 6px; }
.aw-adm-pass { flex: 1 1 auto; min-width: 0; }

/* on a short phone the two calls are what has to be on screen; the chart gives
   up the height rather than the controls */
@media (max-height: 740px) {
  .aw-calls .ae-call { min-height: 40px; }
  .aw-count { min-width: 62px; font-size: calc(13px * var(--fs)); }
  .aw-box { min-height: 104px; }
  .aw-read { font-size: calc(8px * var(--fs)); }
  .aw-head { margin-bottom: 3px; }
  .aw-panel { margin-top: 5px; }
  .aw-foot { margin-top: 5px; }
  .aw-head .tp-quote b { font-size: calc(12px * var(--fs)); }
  .ip-panel.aw-fill .tp-mode { margin-bottom: 5px; }
  .ip-panel.aw-fill .tp-tabs { margin-bottom: 7px; }
}

/* ---- point history ---- */
.aw-hist-top { margin: 2px 0 8px; }
.aw-hist { display: flex; flex-direction: column; gap: 6px; }
.aw-hrow {
  padding: 7px 9px;
  border-radius: 11px;
  border: 1px solid rgba(120,150,180,.22);
  background: rgba(7,10,24,.6);
}
.aw-hrow.up { border-left: 3px solid var(--pw-bull, #1FCBA0); }
.aw-hrow.down { border-left: 3px solid var(--pw-bear, #E5484D); }
.aw-hrow.flat { border-left: 3px solid #5F7C99; }
.aw-hrow-top { display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; }
.aw-hrow-top b { font-size: calc(12px * var(--fs)); font-weight: 900; }
.aw-hrow-top b.up { color: var(--pw-bull, #1FCBA0); }
.aw-hrow-top b.down { color: var(--pw-bear, #E5484D); }
.aw-hrow-top b.flat { color: #8FA9C4; }
.aw-hrow-side {
  font-size: calc(9px * var(--fs)); font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase;
}
.aw-hrow-side.bull { color: var(--pw-bull, #1FCBA0); }
.aw-hrow-side.bear { color: var(--pw-bear, #E5484D); }
.aw-hrow-when { font-size: calc(9px * var(--fs)); color: #7E9CBB; margin-left: auto; }
.aw-hrow-why { margin-top: 3px; font-size: calc(9px * var(--fs)); color: #8FA9C4; line-height: 1.45; }

/* ---- admin ---- */
.aw-adm { display: flex; flex-direction: column; gap: 3px; }
.aw-adm-sw { display: flex; gap: 6px; margin-bottom: 6px; }
.aw-adm-sw .tp-mode-btn { display: flex; flex-direction: column; gap: 1px; padding: 5px 6px; }
.aw-adm-sw .tp-mode-btn i {
  font-style: normal; font-size: calc(8px * var(--fs)); font-weight: 700;
  letter-spacing: .06em; opacity: .75; text-transform: uppercase;
}
.aw-adm-h4 {
  margin: 11px 0 3px;
  font-size: calc(10px * var(--fs)); font-weight: 900;
  letter-spacing: .08em; text-transform: uppercase; color: var(--cyan);
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
}
.aw-adm-row {
  display: flex; align-items: baseline; gap: 8px;
  padding: 3px 0;
  border-bottom: 1px solid rgba(120,150,180,.12);
  font-size: calc(9.5px * var(--fs));
}
.aw-adm-row.bad { color: #FFC4C6; }
.aw-adm-k { color: #8FA9C4; flex: 1 1 auto; min-width: 0; }
.aw-adm-v { font-weight: 800; color: #E6F2FB; text-align: right; white-space: nowrap; }
.aw-adm-v.es { min-width: 58px; color: #9FC0E0; }
.aw-adm-h { font-size: calc(8.5px * var(--fs)); color: #6F8CA8; font-weight: 700; }
.aw-adm-flag {
  margin: 5px 0;
  padding: 6px 8px;
  border-radius: 9px;
  border: 1px solid rgba(61,223,255,.26);
  background: rgba(61,223,255,.07);
  font-size: calc(9px * var(--fs)); color: #9FC0E0; line-height: 1.45;
}
.aw-adm-flag.bad { border-color: rgba(229,72,77,.4); background: rgba(229,72,77,.09); color: #FFC4C6; }
.aw-adm-flag.ok { border-color: rgba(31,203,160,.34); background: rgba(31,203,160,.07); }
.aw-adm-say {
  margin: 7px 0 3px;
  font-size: calc(10.5px * var(--fs)); font-weight: 800; color: #E6F2FB; line-height: 1.45;
}
.aw-adm-ass { display: flex; flex-wrap: wrap; gap: 9px; margin: 5px 0; }
.aw-adm-ass label {
  display: flex; align-items: center; gap: 5px;
  font-size: calc(9px * var(--fs)); color: #8FA9C4;
}
.aw-adm-in { width: 56px; padding: 3px 6px; text-align: center; }
.aw-adm-act { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 7px 0; }
.aw-cmp-wrap { margin: 5px 0; }
.aw-cmp {
  display: block; width: 100%; height: 86px;
  border-radius: 10px;
  border: 1px solid rgba(120,150,180,.22);
  background: rgba(7,10,24,.6);
}
.aw-cmp-key { margin-top: 4px; font-size: calc(8.5px * var(--fs)); color: #6F8CA8; line-height: 1.5; }
.aw-cmp-key b { font-weight: 800; }
.aw-cmp-key b.k1 { color: #E6F2FB; }
.aw-cmp-key b.k2 { color: var(--cyan); }

/* the ÆWAY panel on the desktop layout: the same screen, its own box */
.aw-desk { display: flex; flex-direction: column; height: 100%; min-height: 0; }

/* Reset balance, in Settings */
.set-bal { font-size: calc(13px * var(--fs)); font-weight: 900; color: #E6F2FB; margin-bottom: 6px; }
.set-bal i { font-style: normal; font-weight: 700; font-size: calc(9.5px * var(--fs)); color: #7E9CBB; }
.set-ask { font-size: calc(9.5px * var(--fs)); color: #9FC0E0; margin-bottom: 6px; line-height: 1.45; }

/* ==================== Create Match: who, then what ====================
   The settings screen used to be four tall buttons per setting with a line of
   prose under each. It overflowed a 390×844 phone by 172 pixels with two
   settings on it, and this build has five — so a setting is one row now: a
   label and a segmented control, with the prose that used to be under every
   option said once, at the bottom. */

/* ---- the choice ---- */
.pw-cm-pick { display: flex; flex-direction: column; gap: 10px; margin: 10px 0 14px; }
.pw-cm-who {
  display: flex; flex-direction: column; gap: 3px;
  padding: 13px 15px;
  border-radius: 14px;
  border: 1px solid var(--pw-line, rgba(61,223,255,.26));
  background: rgba(7,10,24,.68);
  text-align: left;
}
.pw-cm-who:active { filter: brightness(1.25); }
.pw-cm-who-t {
  font-size: calc(14px * var(--fs)); font-weight: 900;
  letter-spacing: .04em; color: #F2FBFF;
}
.pw-cm-who-s { font-size: calc(10.5px * var(--fs)); color: #8FA9C4; line-height: 1.4; }

/* ---- which one is being set up, and the way to the other ---- */
.pw-cm2-who {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin: 2px 0 9px;
  font-size: calc(12.5px * var(--fs)); font-weight: 900;
  letter-spacing: .05em; color: var(--cyan);
}
.pw-cm2-swap {
  margin-left: auto;
  padding: 0; border: 0; background: none;
  font-size: calc(10px * var(--fs)); font-weight: 700;
  color: #8FA9C4;
}
.pw-cm2-swap:active { color: var(--cyan); }

/* ---- one row per setting ---- */
.pw-cm2-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 0;
  border-bottom: 1px solid rgba(120,150,180,.13);
}
.pw-cm2-k {
  flex: 1 1 auto; min-width: 0;
  font-size: calc(11px * var(--fs)); font-weight: 700; color: #C7DCEF;
}
.pw-cm2-seg {
  flex: 0 0 auto;
  display: flex; gap: 4px;
}
.pw-cm2-opt {
  min-width: 34px;
  padding: 6px 7px;
  border-radius: 9px;
  border: 1px solid rgba(120,150,180,.3);
  background: rgba(5,9,22,.55);
  color: #9FC0E0;
  font-size: calc(11px * var(--fs)); font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.pw-cm2-opt.on {
  border-color: var(--cyan); color: #F2FBFF;
  background: rgba(61,223,255,.16);
  box-shadow: 0 0 10px rgba(61,223,255,.2);
}
.pw-cm2-opt:disabled { opacity: .45; }
/* a locked row still says what the match will play at, it just cannot be moved */
.pw-cm2-row.locked .pw-cm2-k { color: #7E9CBB; }

.pw-cm2-note {
  margin: 8px 0 0;
  font-size: calc(9.5px * var(--fs)); color: #8FA9C4; line-height: 1.45;
}
.pw-cm2-sum {
  margin: 7px 0 11px;
  padding: 7px 10px;
  border-radius: 10px;
  border: 1px solid rgba(61,223,255,.22);
  background: rgba(61,223,255,.07);
  font-size: calc(10.5px * var(--fs)); font-weight: 800;
  color: #D9ECFA; letter-spacing: .02em;
}

/* the whole screen is a column that fits, so the button sits at the end of the
   settings rather than off the bottom of them */
.pw-create.pw-cm2 { display: flex; flex-direction: column; }
/* pushed to the foot of the card, not stretched to fill it: .pw-over-pill is
   shared with the result screen, where it IS a row item that grows */
.pw-cm2 .pw-cm-go { margin-top: auto; flex: 0 0 auto; }
.pw-cm2 .pw-cm2-sum { flex: 0 0 auto; }

@media (max-height: 740px) {
  .pw-cm2-row { padding: 3px 0; }
  .pw-cm2-opt { padding: 4px 6px; min-width: 29px; font-size: calc(10.5px * var(--fs)); }
  .pw-cm2-k { font-size: calc(10.5px * var(--fs)); }
  .pw-cm2-sum { margin: 4px 0 7px; padding: 5px 9px; font-size: calc(10px * var(--fs)); }
  .pw-cm2-note { margin-top: 4px; font-size: calc(9px * var(--fs)); }
  .pw-cm2-who { margin: 0 0 6px; font-size: calc(11.5px * var(--fs)); }
  .pw-cm-who { padding: 10px 13px; }
}


/* ---- what a match is set to, in one line ----
   The same sentence in three places: over the board while it is being played,
   under the row in Match History, and at the top of a replay. */
.pw-set-line {
  font-size: calc(9.5px * var(--fs)); font-weight: 700;
  letter-spacing: .02em; color: #8FA9C4;
}
.pw-set-line.board {
  margin: 0 0 5px;
  text-align: center;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pw-set-line.review { margin: 5px 0 9px; }
@media (max-height: 740px) {
  .pw-set-line.board { font-size: calc(8.5px * var(--fs)); margin-bottom: 3px; }
}

/* a match that was scaled onto the chart's 25-point ruler says both figures */
.pw-perf-scaled { color: var(--cyan) !important; }
