#wpl-wrapper * { -webkit-tap-highlight-color: transparent; box-sizing: border-box; }
#wpl-wrapper button { font-family: inherit; }
body {
  box-sizing: border-box;
  background: #f2efe9;
  margin: 0;
  padding: 14px 16px;
}
#wpl-wrapper {
  --wpl-cream: #f2efe9;
  --wpl-card: #fffdf8;
  --wpl-ink: #2a2f34;
  --wpl-muted: #8a8b82;
  --wpl-tan: #efe9e0;
  --wpl-tan-hover: #e3dcd0;
  --wpl-tan-text: #55565a;
  --wpl-accent: #14A3C7;
  --wpl-accent-dark: #0e8fb0;
  --wpl-line: #e5ded2;
  --wpl-prog-bg: #e2f5fa;
  --wpl-prog-hover: #cfeaf2;
  --wpl-prog-border: #cdeaf2;
  --wpl-lift-shadow: 0 4px 10px rgba(42,38,32,0.10);
  --wpl-active-shadow: 0 3px 10px rgba(42,38,32,0.16);

  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  box-sizing: border-box;
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  padding: 16px 32px 16px;
  background: var(--wpl-card);
  border-radius: 20px;
  box-shadow: 0 4px 24px rgba(60,50,20,0.08);
  color: var(--wpl-ink);
  position: relative;
}

/* ---------- Header ---------- */
.wpl-header { text-align: center; margin-bottom: 8px; }
.wpl-eyebrow {
  font-size: 11px;
  font-weight: 700;
  color: var(--wpl-muted);
  text-transform: uppercase;
  letter-spacing: 1.6px;
  margin-bottom: 6px;
}
.wpl-title {
  font-family: 'Fraunces', Georgia, 'Times New Roman', serif;
  font-size: 32px;
  font-weight: 600;
  color: var(--wpl-ink);
  line-height: 1.15;
}
.wpl-subtitle { font-size: 14px; font-weight: 500; color: var(--wpl-muted); margin-top: 6px; }
/* A one-line "pick a key, then a chord type" hint briefly lived here,
   2026-09-07, to orient a cold first-time visitor -- cut again the same
   day once Chris set a hard rule: "the shell can't get bigger. it was
   the perfect size on my phone before." Every extra line has a real
   height cost, so the fix for "people don't understand the flow" has to
   come from the existing elements (step badges below, tab bar) rather
   than adding new ones. */
/* Overlaid on the card (position:absolute), not in normal flow — this is
   deliberate so the countdown never affects #wpl-wrapper's height or pushes
   the header/tabs/piano down (Chris: "doesn't effect the size, but sits in
   a visually good place"). #wpl-wrapper is given position:relative (see
   top of this file) so this positions relative to the card, not the page. */
.wpl-trial-note {
  display: none;
  position: absolute;
  top: 14px;
  right: 16px;
  z-index: 3;
  text-align: center;
  padding: 6px 12px;
  background: #e2f5fa;
  border: 1px solid #cdeaf2;
  border-radius: 10px;
  line-height: 1.3;
}
.wpl-trial-label {
  display: block;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.3px;
  color: var(--wpl-tan-text);
}
.wpl-trial-clock {
  display: block;
  font-size: 13px;
  font-weight: 800;
  color: var(--wpl-accent-dark);
  font-variant-numeric: tabular-nums;
}
/* Default (above the 520px breakpoint) reservation — covers the common
   embed widths between phone and the 1100px desktop max-width, where the
   card is narrower than the eyebrow text's clear margin needs. */

/* ---------- Top tab bar ---------- */
/* Chris, 2026-09-07: people he showed the app to cold "didn't notice the
   top tabs either" -- a plain text label + thin underline apparently
   reads as inert page furniture, not as "3 different tools live here,"
   next to the same large colored buttons that were already winning the
   attention fight against the numbered step labels. Chris's own
   reference: real manila folder tabs -- a raised, filled shape that
   visibly sits "in front of" and connects to whatever's open beneath it,
   with the other (unopened) folders receding behind the divider line.
   Implemented as a classic connected-tab shape rather than a literal
   folder's single-side notch (that notch is a physical filing detail,
   not a web-tab convention): each tab gets its own rounded-top card
   filled with the resting tan color; the active one switches to the
   same background as the content card below it and its bottom edge
   overlaps .wpl-tabbar's divider line (negative margin-bottom, exactly
   the line's own thickness) so the line visually disappears under it --
   the "this folder is open and connected to what you're looking at"
   effect.
   Round 2, Chris (screenshot): "the buttons are rounded, and the tabs
   are square. plus the way the tabs are connected looks weird with
   that gray line." Bumped radius 8px->12px to match .prog-tab's
   corner roundness -- the app's other most-rounded element -- so the
   tabs read as clearly rounded instead of near-square. Tried a
   shadow-only active state next (no border) -- Round 3, Chris
   (screenshot): "it sinks down and the lower shadow make it look
   separated from the lower body. it needs to be a part of the body."
   Tried giving every tab the same visible border next -- fixed the
   float, but then (Chris, describing the mental model precisely):
   "the body will have a line above it that's under the tabs. when a
   tab is clicked, the upper border will wrap over and around the
   clicked then continue until it reaches the other side." That's the
   actual spec: ONE continuous horizontal line (.wpl-tabbar's own
   border-bottom, edge to edge) is the top of the body and runs
   underneath every unclicked tab uninterrupted; only the active tab's
   own border detours up and over it -- left side up, across the top,
   down the right side -- before the line resumes. So only .active
   gets a real border (left/top/right); unclicked tabs are borderless
   fills that simply sit above the line. The active tab's own ::after
   strip erases the exact segment of that line running under it
   (rather than a margin-bottom trick, which previously shifted its
   whole box down under align-items:flex-end and misaligned its top
   with the other tabs -- Chris: "the top of the clicked tab is lower
   than the unclicked tabs"). Padding-top differs by exactly the
   border's own width (6.5px active vs 8px unclicked) so both states
   still resolve to the same total box height -- no jump when a
   different tab becomes active.
   Chris: "don't let the unclicked tabs touch. should be 1px space
   between them." Small explicit gap between every tab so the
   continuous line still shows through as a thread connecting them,
   rather than one solid tan bar. */
.wpl-tabbar {
  display: flex;
  align-items: flex-end;
  gap: 1px;
  border-bottom: 1.5px solid var(--wpl-line);
  margin-bottom: 10px;
}
.wpl-tab {
  position: relative;
  /* Border is reserved at full width on EVERY tab, all the time --
     transparent when inactive, colored in when active. Chris (zoomed
     screenshot, comparing an active vs. inactive shot of the same
     tab): "the tab text moves when it's clicked... the border should
     move around the tab to create the movement, not move the tab."
     The old rule gave only .active a border at all (none -> 1.5px on
     three sides). Since flex:1 1 0 divides the row's width among the
     tabs by their flex-basis, adding/removing that 1.5px border
     changed each tab's own box-sizing:border-box outer width slightly
     as it toggled -- so the active tab's box (and its centered label)
     visibly shifted sideways instead of staying put. Reserving the
     same border on every tab at all times means toggling .active only
     flips border-color and background; the box a tab occupies, and
     where its text centers within it, never changes. */
  border: 1.5px solid transparent;
  border-bottom: none;
  background: var(--wpl-tan);
  border-radius: 12px 12px 0 0;
  cursor: pointer;
  padding: 8px 16px 10px;
  /* Fixed height, not just matching padding, so the active tab's top
     lines up with the others pixel-for-pixel. A border-width-based
     padding offset (padding-top reduced by the border's own 1.5px)
     looked right in theory, but Chris still saw "the clicked tab's
     top is shorter" -- Chromium was rendering the 1.5px border as a
     rounded 1px (computed style confirmed it), so the offset was
     wrong by the difference. Height is an explicit box-sizing:border-
     box value instead (see #wpl-wrapper's global border-box reset at
     the top of this file) -- immune to how any given browser rounds a
     fractional border, since the border simply eats into the content
     area rather than changing the box's own total height. */
  height: 34px;
  font-size: 14px;
  font-weight: 700;
  color: var(--wpl-tan-text);
  letter-spacing: 0.2px;
  transition: color 0.15s ease, background 0.15s ease;
  display: flex;
  /* flex-end, not center: pins the label a fixed distance (this
     padding's own bottom value) above the tab's bottom edge. Chris
     (zoomed screenshot): "it looks like the clicked tab text moves up
     1px. it can't move at all." The active tab is 1px taller on
     purpose (see .active below); with vertical centering, that extra
     height moves the box's own midpoint, so the centered label rides
     up with it. Anchoring to the bottom instead means the extra
     height lands as invisible padding stacked above the label -- the
     label's own position never changes, since the tab's bottom edge
     is itself already pinned by .wpl-tabbar's align-items:flex-end
     regardless of which tab is active. */
  align-items: flex-end;
  justify-content: center;
  gap: 6px;
  /* Unlike .prog-tab/.step-btn/.key-tab (the sub-rows within a panel),
     this row never got flex:1 -- with exactly 4 tabs today the fixed
     padding + font sizes below happen to fit every breakpoint, but a
     future 5th tab would just overflow or wrap the bar (adding height)
     instead of sharing the row width like every other button row in the
     app already does. flex:1 1 0 + min-width:0 makes this row self-
     adjusting the same way, so adding a tab is a markup-only change here
     too, not a new round of breakpoint tuning. white-space:nowrap keeps
     a label + its "Soon" pill on one line instead of wrapping inside
     the tab and growing the bar's height once the button gets narrower
     with more tabs sharing the row. */
  flex: 1 1 0;
  min-width: 0;
  white-space: nowrap;
}
.wpl-tab.active {
  /* 1px taller than the unclicked tabs (Chris: "that will help make
     it stand out more"), added at the TOP only -- align-items:
     flex-end on .wpl-tabbar keeps every tab's bottom pinned to the
     same line regardless of height, so a taller active tab pokes up
     above its neighbors instead of also pushing its bottom (and the
     body-fusion seam) out of place. */
  height: 35px;
  border-color: var(--wpl-line);
  background: var(--wpl-card);
  color: var(--wpl-accent-dark);
}
/* Erases the .wpl-tabbar divider line directly under the active tab --
   the "line wraps over and around the clicked tab" effect -- without
   touching the tab's own box model. A small absolutely-positioned
   strip, sized to the tab's own width and colored to match the body,
   sits just below it and paints over that one segment of the line. */
.wpl-tab.active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1.5px;
  height: 1.5px;
  background: var(--wpl-card);
}
.wpl-tab-soon {
  font-size: 9px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--wpl-muted);
  background: var(--wpl-tan);
  border-radius: 5px;
  padding: 2px 5px;
}
.wpl-tab.active .wpl-tab-soon { color: var(--wpl-accent-dark); background: #e6f6fb; }

/* ---------- Shared instrument block (key selector + readout + piano) —
   stays in the same position across every tab; only .wpl-panel below it
   swaps content. ---------- */
.wpl-instrument { margin-bottom: 10px; }
/* Chris (desktop only): "there is not enough space above #1 and below
   the tabs. move #1 and everything in this image down a few pixels so
   everything is closer to #2. but don't move #2." #1 sits right below
   .wpl-tabbar's own margin-bottom, and #2 sits right below
   .wpl-instrument's -- moving #1 down without moving #2 means growing
   the first gap and shrinking the second by the same amount, so the
   total space the whole instrument block occupies (and therefore where
   #2 lands) never changes, only where #1 sits within it. */
@media (min-width: 521px) {
  .wpl-tabbar { margin-bottom: 14px; }
  .wpl-instrument { margin-bottom: 6px; }
}

/* ---------- Section labels ---------- */
/* Chris, 2026-09-07: people he sent the app to cold "didn't really
   understand the flow... their eyes were naturally drawn to the big blue
   buttons instead of working from the top down." These labels are the
   only thing telling someone there IS a top-down order (1, then 2, then
   3), but at 11px muted gray they lost every visual fight against the
   large colored buttons directly below them.
   First pass enlarged the label text itself (11px->13px) and its
   margin (5px->7px) too, on top of adding the circle -- but that grew
   the shell's total height, and Chris set a hard rule right after:
   "the shell can't get bigger. it was the perfect size on my phone
   before." So font-size/margin-bottom here are back to their exact
   original values (measured: at these values the circle adds zero net
   height to the row, since a small circle fits inside the existing
   line box). All the emphasis now comes from the circle alone --
   .step-num, sized to stay within that existing row height.
   Circle color: teal (var(--wpl-accent)) was the same color as an
   already-selected/active button directly below it, so the badge
   visually blended into the button row instead of standing apart from
   it -- Chris: "should the 1,2,3 buttons be in red?" Switched to the
   app's existing right-hand/chord-tone red (#f87171) rather than
   inventing a new color, since it's already established elsewhere in
   this same UI as "a note of emphasis," just applied to step numbers
   instead of piano keys -- and unlike teal, it never appears on any
   button in this row, so it can't blend in the same way. */
.section-label {
  font-size: 11px;
  font-weight: 700;
  color: var(--wpl-muted);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  margin-bottom: 5px;
  display: flex;
  align-items: center;
  gap: 6px;
}
/* Chris (zoomed screenshot), after three rounds of centering attempts
   (padding-based, then line-height-based, then an SVG <text> with
   text-anchor="middle"/dominant-baseline="central" -- see this file's
   git history for all three): every one of them, including the SVG
   <text> version, still routes the digit through Chris's own device
   font to draw the glyph, and a font's glyph can simply have unequal
   left/right (or top/bottom) side-bearings for a given character --
   text-anchor="middle" centers the glyph's ADVANCE BOX, not necessarily
   the ink inside it. That's the same failure mode every time: a fix
   that measures centered on this sandbox's font doesn't transfer to
   Chris's actual device font, which is exactly what he flagged after
   the SVG-text version too ("still not centered... not sure how that
   will look on different devices" -- his own words, correctly
   identifying the risk before agreeing to another guess).
   Removes the font from the equation entirely: 1/2/3 are now drawn as
   plain SVG paths (.step-num-glyph below), not text. A path's
   coordinates are exact numbers Claude placed by hand, not a glyph
   some font's rendering engine draws -- so centering is a property of
   the geometry itself (every curve's left/right extent was drawn
   symmetric around x=7, the circle's own center) and is therefore
   identical on every device and browser, forever. Nothing left to
   verify per-device: there's no font substitution left that could
   shift it.
   Chris then looked at the actual drawn shapes (in index.html) and
   asked for small optical adjustments on top of that exact geometric
   center: "2 and 3 need to be 1px higher in the circle. 1 needs to be
   1px to the right." This is a normal, expected step for hand-drawn
   glyphs -- mathematically centering a shape's bounding box doesn't
   always look centered to the eye (a "2"/"3"'s flat bottom vs. rounded
   top, or "1"'s off-center vertical stroke, can visually read as
   low/left even when the coordinates are exactly symmetric) -- and
   unlike every previous round, this adjustment is safe to make on
   Claude's own judgment/sandbox: the path coordinates themselves ARE
   the rendered pixels now, with no font left in between to differ by
   device. */
.step-num {
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}
/* Chris: "the 1,2,3 red circles need to be a tiny bit bigger" -- then,
   after seeing it applied everywhere: "don't make the mobile red
   circles bigger, that was just for desktop." Desktop only. */
@media (min-width: 521px) {
  .step-num { width: 14px; height: 14px; }
}
.step-num circle { fill: #f87171; }
.step-num-glyph {
  fill: none;
  stroke: #fff;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- Shared button feel: progression tabs, key tabs, step buttons
   all hover/select the same way — a quiet lift, no colored ring. Progression
   tabs get their own light-blue rest color (matching the reference); key
   tabs and step buttons share the tan. ---------- */
.prog-tab, .key-tab, .step-btn {
  border: 1.5px solid var(--wpl-line);
  cursor: pointer;
  text-align: center;
  color: var(--wpl-ink);
  min-width: 0;
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease, color 0.15s ease;
}
.prog-tab.active, .key-tab.active, .step-btn.active {
  background: var(--wpl-accent); color: #fff; border-color: var(--wpl-accent);
  box-shadow: var(--wpl-active-shadow);
  transform: translateY(0);
  /* Chris, 2026-09-06, from a frame-by-frame screen recording: "the blue
     buttons taking 9 frames [0.15s] to fade in... gives the appearance of
     being late when the piano lights up completely in 1 or 2 frames." The
     OLD button fading back to tan still uses the shared 0.15s transition
     above (the plain, non-.active rule) -- Chris confirmed that half
     "looks good" (the previous selection melting away). Only fading IN
     was the problem: CSS applies whichever transition value is declared
     on the state a property is arriving at, so redeclaring transition
     here without background makes a newly-active button's fill snap on
     immediately instead of easing in -- matching how its own text color
     and the piano's own highlight already snap with no transition at all
     (see .prog-tab.active .num etc. above and light() in piano-engine.js).
     border-color/box-shadow/transform keep easing at 0.15s -- only the
     background fill itself was the one reading as late. */
  transition: border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

/* ---------- Progression tabs ---------- */
.prog-tab {
  flex: 1; border-radius: 12px; padding: 14px 6px;
  background: var(--wpl-prog-bg); border-color: var(--wpl-prog-border);
  /* center (not flex-start): all 5 progression names are now single
     words (Foundation/Smooth/Soft/Big/Full), so every button's .num +
     .name block is the same height and centers identically — no more
     risk of a 2-line-wrapped name pushing one button's .num out of
     line with the rest. If a future name gets long enough to wrap
     again, revisit this (see git history 2026-08-30 for the prior
     flex-start fix and why it was needed then). */
  display: flex; flex-direction: column; justify-content: center;
  min-height: 78px;
}
/* Chris, 2026-09-06, from a screen recording: "on the bottom row it's
   correct, the button text changes from white to black right when you
   click it... but on the top row... the black text slowly fades to
   white making it look like the button is very slightly delayed."
   .step-btn.active already sets its own .n/.l colors explicitly further
   below, which is why it snaps instantly -- .prog-tab .num/.name never
   had that, so they were only ever inheriting .prog-tab.active's own
   `color: #fff`, which fades over the shared 0.15s color transition
   above. Explicit color here (like .step-btn's) makes it snap the same
   way, since neither .num nor .name declares its own transition. */
.prog-tab.active .num { color: #fff; }
.prog-tab.active .name { color: rgba(255,255,255,0.85); }
.prog-tab .num { font-weight: 800; font-size: 22px; line-height: 1.2; }
/* margin-top: 4px matches the vertical gap every other "label + caption"
   pairing in the app uses (.step-btn's flex gap:4px, both for the
   Progressions step-row and the Chords position row) — Chris, 2026-09-02:
   "make it all equal" after comparing this row's spacing to the step-row's
   and finding this one tighter (was 2px here, 1px on the Chords quality
   row's override below — now both 4px, one shared standard). */
.prog-tab .name { font-size: 12px; font-weight: 600; opacity: 0.9; margin-top: 4px; }

/* ---------- Key tabs ---------- */
.key-tab {
  flex: 1; border-radius: 8px; padding: 9px 0; font-weight: 600; font-size: 13px;
  background: var(--wpl-tan); color: var(--wpl-tan-text);
  white-space: nowrap;
  /* Fixed (px, not ratio) line-height so box height depends only on
     padding, never on font-size — .key-tab-wide sets a smaller
     font-size for 2-letter labels (Db/Eb/F#/Ab/Bb) and, since it never
     redeclares line-height, inherits this exact px value, keeping its
     row the same height as the 1-letter keys next to it. */
  line-height: 15px;
  /* Chris, 2026-09-06: "the choose a key buttons need to have the black
     text change to white immediately when clicking a new button like the
     bottom 2 rows do, instead of fading into white." .step-btn/.prog-tab
     snap instantly because their visible text lives in child .n/.l/.num/
     .name spans that never declare their own transition — explicit color
     set directly on those children (see .step-btn.active .n etc. above)
     just switches with no animation. .key-tab has no such child span;
     its label is a plain text node directly inside .key-tab itself, so
     it was inheriting the shared .prog-tab/.key-tab/.step-btn color
     transition below and fading over 0.15s instead of snapping. Redeclare
     the transition here without color (background/border/shadow/transform
     still ease) to opt this element back out of the color fade. */
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.key-tab.locked { opacity: 0.55; }

/* ---------- Step buttons ---------- */
.step-btn {
  flex: 1;
  border-radius: 8px;
  padding: 9px 4px 7px;
  background: var(--wpl-tan);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 60px;
}
.step-btn.active .n { color: #fff; }
.step-btn.active .l { color: rgba(255,255,255,0.85); }
/* RH/LH-colored hand initials on the Scales "Choose a View" buttons
   (see handColoredLabel/VIEW_HAND_CLASS in ui.js). Plain colored text --
   two earlier contrast attempts (a white text-shadow halo, then a solid
   white badge) both read as visual smudges once Chris saw them rendered.
   Chris, 2026-09-06: "keep the red and blue colors as is, but when it's
   clicked blue, then maybe make them a whiter red and whiter blue, that
   will make it pop more against a blue background" -- the .active
   overrides below lighten each hue only while its own button is the
   selected one (background becomes --wpl-accent teal), same idea as
   .n/.l above but a separate rule since these spans need their own hue,
   not white. */
.wpl-hand-rh { color: #f87171; }
.wpl-hand-lh { color: #38bdf8; }
.step-btn.active .wpl-hand-rh { color: #fecaca; }
.step-btn.active .wpl-hand-lh { color: #bfdbfe; }
/* Chris, 2026-09-06: "the buttons should pulse like the piano notes do" +
   "does the top row [Chords' Choose a Position] need the same highlight"
   as the bottom row already had -- .prog-tab never had a .playing rule at
   all (only .step-btn did), even though ui.js already toggles "playing"
   onto #wpl-position-tabs2's .prog-tab buttons every step (Chords tab)
   same as it does for .step-btn (Progressions' chord row); it was just
   silently doing nothing. Added .prog-tab.playing here so Chords' step
   highlight works the same way Progressions' already did, plus an
   animation so each new step's ring blooms in and settles rather than
   just snapping on -- same idea as the piano keys' own played-note flash
   (flashPlayedKey in piano-engine.js), so a step changing on the buttons
   reads as part of the same "this just played" language as the keys
   lighting up, not a separate effect. ui.js removes then re-adds the
   class on a fresh element each step (not the same node twice in a row
   in the common case), which is what lets this animation restart cleanly
   without needing piano-engine.js's reflow trick.
*/
.step-btn.playing, .prog-tab.playing {
  border-color: #f59e0b;
  box-shadow: 0 0 0 1px rgba(245,158,11,0.35);
  animation: wpl-step-pulse 1s ease-out;
}
/* Chris, 2026-09-06: "the gold ring is still too big. reduce it by
   another 50%." Resting ring down from 2px to 1px, pulse peak from 3px
   to 1.5px -- same proportions as before, just half the spread. */
@keyframes wpl-step-pulse {
  from { box-shadow: 0 0 0 1.5px rgba(245,158,11,0.6); }
  to { box-shadow: 0 0 0 1px rgba(245,158,11,0.35); }
}
/* Chris, 2026-09-02, follow-up (after reviewing Chords v2): "the Major/Minor
   titles on the OLD Chords tab's bottom row look bigger/bolder than Chords
   v2's... make that change on chords2 to match" + "make the progressions
   tab lower row title match... so the shell fonts are the same size" +
   later, after a scoped fix still left Practice's row out: "why do I keep
   having to tell you to resize text? they should be the same on all the
   tabs... unless the text on a button is too long." So this is the BASE
   rule now (not a per-ID override) — every consumer of plain .step-btn .n
   automatically gets the same weight/size with no per-tab patching needed:
   Progressions' #wpl-step-row, Chords v2's #wpl-quality-row2, AND
   Practice's #wpl-scale-hands-row/#wpl-scale-direction-row/
   #wpl-scale-octaves-row (Right/Both, Up/Down/Up-Dn, 1-2-3 8ve) all share
   this one rule. Matches the OLD Chords tab's #wpl-chord-quality-tabs
   .prog-tab .num sizing exactly (800/16px desktop, see that rule further
   down) — that's the one row this whole family is modeled on. Captions
   (.l) are untouched; only rows that use them (step-row, quality-row2) are
   affected, at 12px as before. */
.step-btn .n { font-weight: 800; color: var(--wpl-ink); font-size: 16px; line-height: 1.2; }
/* Chris, 2026-09-04: top-row subtitle (.prog-tab .name) and bottom-row
   subtitle (.step-btn .l) read as two different colors -- .name has no
   color of its own (inherits --wpl-ink at 0.9 opacity from the shared
   .prog-tab/.key-tab/.step-btn rule above), .l was hardcoded to
   --wpl-muted (gray). Matching .l to the same treatment (drop the
   hardcoded color, add the same 0.9 opacity) makes every subtitle the
   same color everywhere .step-btn .l is used -- Progressions' step-row,
   Chords v2's quality-row2, Scales' view-row. */
.step-btn .l { font-size: 12px; opacity: 0.9; line-height: 1.2; }

/* Full label ("Right Hand", "Left Hand") vs short label ("RH", "LH") --
   Chris, 2026-09-04: short only on mobile, full on desktop. Short is the
   default/safe-everywhere text; full switches on at each consumer's own
   min-width query below. (The Choose a Scale row's title used to need
   this too, to abbreviate "Pentatonic" to "Pent" -- Chris, 2026-09-05,
   moved "Pentatonic" down to the button's subtitle instead, always
   spelled out, so that row no longer uses these classes at all -- see
   .wpl-name-wide below.) */
.wpl-lbl-full { display: none; }
.wpl-lbl-short { display: inline; }
/* Scale readout ("C", "Cm", ...): spelled-out Major/Minor only above the
   readout box's own mobile/desktop split (140px box starts here, same
   breakpoint the .wpl-readout-row mobile override below uses) -- Chris,
   2026-09-05: "on desktop... change the text back from C to C Major and
   Cm to C Minor." Below this width the compact "C"/"Cm" stays (matches
   the smaller 112px/88px boxes at narrower widths). */
@media (min-width: 521px) {
  #wpl-chord-name .wpl-lbl-full { display: inline; }
  #wpl-chord-name .wpl-lbl-short { display: none; }
}
/* On-key note/number labels: same 11px/10px (white/black) at every width
   until now -- Chris, 2026-09-05: "on desktop only, can you make the note
   names/number names any bigger?" Base size (mobile/tablet keys are too
   narrow for anything bigger) stays the original inline-style values;
   only bumped from 521px up, same "desktop" threshold as the readout
   box above. */
.key-label-white { font-size: 11px; }
.key-label-black { font-size: 10px; }
@media (min-width: 521px) {
  .key-label-white { font-size: 15px; }
  .key-label-black { font-size: 13px; }
}
/* Choose a Scale row's title (.num) is always "Major"/"Minor" now --
   Chris, 2026-09-05, reordering the row into 2 groups of 3 -- so it no
   longer needs its own downscoped size like the old "Pentatonic" title
   did; it just uses the same .prog-tab .num sizing as every other row
   (12px/14px/22px across the same 340/520 breakpoints).
   "Pentatonic" moved down to be the subtitle (.name) instead, always
   spelled out rather than abbreviated to "Pent". .wpl-name-wide still
   flags just those two buttons' subtitles (see SCALE_TYPES "wide" flag
   in ui.js) for the 521-619px tier below, where "Scale"/"Blues" keep the
   row's normal, larger .name size and only "Pentatonic" needs its own
   smaller size to avoid wrapping.
   Below 521px, though, Chris, 2026-09-05 (mobile only): "make Pentatonic
   bigger... then reduce the subtitles Scale and Blues to be the same
   size as Pentatonic" -- so the two mobile tiers (see #wpl-scale-type-row
   .prog-tab .name further down, at the 341-520px and <=340px breakpoints)
   drop the .wpl-name-wide restriction and size ALL THREE subtitles
   (Scale/Pentatonic/Blues) the same, at the largest size that still fits
   "Pentatonic" -- the longest of the three -- at that tier's narrowest
   real device width (Playwright-verified: candidate sizes tested against
   the button's actual measured width, with wrap/overflow checked directly
   via scrollHeight and scrollWidth, at real phone widths 320-520px rather
   than the full theoretical breakpoint range, since e.g. 341-359px has no
   real device and its own tighter "pinch" from the row's padding/gap
   shrinking right at that boundary). 9px still covers 521-619px; 620px+
   is wide enough for the row's own normal .name size (12px) with real
   margin, so no override is needed there. */
@media (min-width: 521px) and (max-width: 619px) {
  #wpl-scale-type-row .prog-tab .name.wpl-name-wide { font-size: 9px; }
}
/* "Right Hand"/"Left Hand" became "RH Fingers"/"LH Fingers" (Chris,
   2026-09-04), shown at every width (nFull===nShort for this row again --
   "Finger Patterns" briefly lived here on 2026-09-05 but Chris caught it:
   "no! not 'finger patterns' on the bottom row! only the scale / view
   part above the piano," so this row is back to "RH Fingers"/"LH
   Fingers", see SCALE_VIEWS in ui.js) -- so unlike "Note"/"Number", this
   row's text can't just avoid wrapping by getting shorter below some
   breakpoint on its own; the fix here is shrinking the row's own
   .step-btn .n font at the widths where it otherwise wraps.
   Chris, 2026-09-05 (mobile only): "make the titles bigger, but don't
   let LH and RH fingers wrap... make the bottom subtitles the same text
   size as the top row subtitles." The old flat 8px/7px for all of
   <=520px actually still wrapped "RH Fingers"/"LH Fingers" at real
   320px-wide phones (Playwright-confirmed: scrollHeight jumps to a 2nd
   line at 8px there), so the <=520px tier is now split into four
   narrower bands, each the largest .n size that keeps "RH Fingers" on
   one line at that band's narrowest *real* device width (forced
   white-space:nowrap + measured scrollWidth against the button's actual
   width, tested across every common phone width 320-520px, not the
   theoretical breakpoint continuum): 7px for <=340px (real floor: 320px);
   8px for 341-374px (real floor: 360px); 8.25px for 375-411px (real
   floor: 375px); 9px for 412-520px (real floor: 412px). .l (the
   subtitle) is set to match the Choose a Scale row's own new unified
   subtitle size at the same two breakpoints it uses (7.75px <=340px,
   8px 341-520px) per Chris's "same as the top row" instruction, rather
   than following the .n tiers above -- both sets of numbers were
   verified together (all six buttons' .n and .l, at every real width
   320-520px) with zero wraps or overflow. 10px/9px still covers
   521-589px; 12px/10px still covers 590-899px; 900px+ keeps the row's
   standard, unscoped 16px/12px (already verified to fit there). */
@media (max-width: 340px) {
  #wpl-scale-view-row .step-btn .n { font-size: 7px; }
  #wpl-scale-view-row .step-btn .l { font-size: 7.75px; }
}
@media (min-width: 341px) and (max-width: 374px) {
  #wpl-scale-view-row .step-btn .n { font-size: 8px; }
  #wpl-scale-view-row .step-btn .l { font-size: 8px; }
}
@media (min-width: 375px) and (max-width: 411px) {
  #wpl-scale-view-row .step-btn .n { font-size: 8.25px; }
  #wpl-scale-view-row .step-btn .l { font-size: 8px; }
}
@media (min-width: 412px) and (max-width: 520px) {
  #wpl-scale-view-row .step-btn .n { font-size: 9px; }
  #wpl-scale-view-row .step-btn .l { font-size: 8px; }
}
@media (min-width: 521px) and (max-width: 589px) {
  #wpl-scale-view-row .step-btn .n { font-size: 10px; }
  #wpl-scale-view-row .step-btn .l { font-size: 9px; }
}
@media (min-width: 590px) and (max-width: 899px) {
  #wpl-scale-view-row .step-btn .n { font-size: 12px; }
  #wpl-scale-view-row .step-btn .l { font-size: 10px; }
}

/* Choose a View row: every button now has both a title and a subtitle
   (Note/Names, Scale/Degrees, RH/1 Octave, etc, 2026-09-04) so plain
   .step-btn centering (shared rule above) already puts every title on
   the same plane -- no per-row override needed, same as Progressions'
   own step-row. (Earlier attempt used flex-start to compensate for 2
   of the 6 buttons having no subtitle; not needed once the labels
   were split.) */

/* ---------- Chord / number readout ---------- */
/* Two equal-width columns spanning the row edge to edge (no gap, no side
   padding), each value centered within its own half -- Chris, 2026-09-07:
   the old approach (both boxes a fixed width just big enough for "Root
   High"/"Root Low", grouped near the middle via justify-content:center +
   gap) left "D♭m Pentatonic" too little room and it silently wrapped to a
   hidden 2nd line on phones. Rather than keep shrinking text to fit a
   narrow box, each column now stretches "from the center of the screen to
   the end of the screen on both sides" (Chris) at every width, desktop
   included, and the same row is shared by all three tabs (Chord/Number,
   Position/Number, Scale/View) so this applies everywhere uniformly. No
   horizontal padding here means the columns reach the exact same
   left/right edges as the piano frame below.
   (A hand-with-numbered-fingers icon briefly lived in this row too,
   2026-09-05 -- removed again: even capped at a modest max size it was
   still taller than the readout boxes on every tier, which grew the
   row's own height and visibly pushed the piano down every time a
   Fingers view was selected. Chris: "your hand is too big which pushed
   that row down which made the entire shell move down... just delete
   the hand." A real PNG image, sized to fit inside the existing box
   height instead of growing it, is the likely next approach if he
   supplies one -- flagged here so the reasoning isn't lost if it comes
   back.) */
/* Chris (zoomed screenshot, desktop): "i was wrong about moving the
   scale / view out so much, it needs to be moved back in toward the
   middle. close enough that the text doesn't wrap." Each side used to
   be a fixed width:50% of the whole instrument card (set in index.html
   inline, up to 1100px wide -- see #wpl-wrapper's max-width), so
   "Scale" and "View" centered themselves at each half's own midpoint --
   roughly a quarter of the way in from either edge, with a wide gap of
   empty space between them.
   First fix dropped the fixed width entirely so each side would
   shrink-wrap its own label -- but a shrink-wrapped, centered-as-a-pair
   layout re-centers on every render, so a short value ("D♭m") sits in a
   different spot than a long one ("D♭m Pentatonic") even though it's
   the same on-screen column -- Chris: "they're moving in and out
   depending on the text length. they need to be fixed at the closest
   position where the longest text doesn't wrap" (both mobile and
   desktop). Fixed here instead: each column gets an explicit width
   (see the breakpoint overrides below), sized to the single widest
   string this app can ever put in EITHER column -- measured directly
   via Playwright by rendering every real chord name (transposed
   through all 12 keys), position name, scale name, and view label into
   the actual #wpl-chord-name element at each font-size tier and taking
   the max scrollWidth, then padded a bit further for safety margin
   against font differences on Chris's own device (see this file's git
   history/PR notes for the measured numbers). Text still centers
   within that fixed box via text-align:center (in index.html), so a
   short value just sits centered in the same unmoving box instead of
   shrinking the box around itself. */
.wpl-readout-row { display: flex; align-items: flex-end; justify-content: center; gap: 64px; margin: 8px 0 6px; }
.wpl-readout-row > div { width: 160px; }
.wpl-readout-label { font-size: 13px; color: var(--wpl-muted); }
/* Numbers/symbols ("C", "1", "5/7") read fine big and bold; full words
   ("Root High", "1st Inv") look oversized/heavy at the same size, so
   ui.js's setReadoutValue() adds this class whenever the raw value is
   longer than any real number/symbol ever gets (see ui.js comment). */
#wpl-chord-name.long-label, #wpl-step-label.long-label { font-size: 18px !important; }

/* ---------- Piano ---------- */
#wpl-piano-frame { background: #1e293b; border-radius: 12px; padding: 5px; }
/* Each white/black key's own look (piano-engine.js's buildKeyboard,
   which still sets each key's position/size inline since that's
   computed per-key -- only the shared, static look lives here). Bottom
   corners are rounded on every key, matching a real keyboard's rounded
   key-fronts. Top corners stay square on every key EXCEPT the two at
   the very outer ends of the whole keyboard (.wpl-key-first/-last,
   added by buildKeyboard) -- Chris (zoomed screenshot): "the first and
   last piano keys need to be rounded at the top to match the round at
   the bottom. don't round the top of any of the middle keys though,
   just the first and last." Matching the bottom radius exactly (5px
   white / 4px black) so the outer corner reads as one continuous
   curve, not two different curves stacked. */
.wpl-white-key {
  flex: 1;
  background: linear-gradient(#fff, #f1f5f9);
  border: 1px solid #cbd5e1;
  border-radius: 0 0 5px 5px;
  position: relative;
  cursor: pointer;
}
.wpl-white-key.wpl-key-first { border-top-left-radius: 5px; }
.wpl-white-key.wpl-key-last { border-top-right-radius: 5px; }
.wpl-black-key {
  background: linear-gradient(#1e293b, #334155);
  border: 1px solid #000;
  border-radius: 0 0 4px 4px;
  cursor: pointer;
}
#wpl-status {
  text-align: center;
  font-size: 12px;
  color: var(--wpl-muted);
  margin-top: 3px;
  height: 18px;
  line-height: 18px;
  overflow: hidden;
}

/* ---------- Playback bar ---------- */
.wpl-playbar {
  display: flex;
  align-items: center;
  gap: 18px;
  background: var(--wpl-tan);
  border: 1.5px solid var(--wpl-line);
  border-radius: 14px;
  padding: 9px 18px;
  margin-top: 22px;
  flex-wrap: wrap;
}
.wpl-bpm {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 180px;
}
.wpl-bpm-label { font-size: 12px; font-weight: 700; color: var(--wpl-tan-text); white-space: nowrap; }
.wpl-bpm-value { font-size: 13px; font-weight: 800; color: var(--wpl-ink); width: 40px; text-align: right; font-variant-numeric: tabular-nums; }
.wpl-bpm input[type="range"] {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 5px;
  border-radius: 3px;
  background: linear-gradient(var(--wpl-accent),var(--wpl-accent)) 0/var(--pct,50%) 100% no-repeat, #ddd2b3;
  outline: none;
}
.wpl-bpm input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--wpl-accent);
  border: 2.5px solid var(--wpl-card);
  box-shadow: 0 1px 4px rgba(60,50,20,0.3);
  cursor: pointer;
  margin-top: -0.5px;
}
.wpl-bpm input[type="range"]::-moz-range-thumb {
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--wpl-accent); border: 2.5px solid var(--wpl-card);
  box-shadow: 0 1px 4px rgba(60,50,20,0.3); cursor: pointer;
}

.wpl-playbar-controls { display: flex; align-items: center; gap: 8px; }
.wpl-toggle-btn {
  display: flex; align-items: center; gap: 6px;
  border: 1.5px solid var(--wpl-line);
  background: var(--wpl-card);
  color: var(--wpl-tan-text);
  font-weight: 700;
  font-size: 12.5px;
  padding: 9px 13px;
  border-radius: 9px;
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease, color 0.15s ease;
  white-space: nowrap;
  min-width: 0;
}
.wpl-toggle-btn.active { background: var(--wpl-accent); border-color: var(--wpl-accent); color: #fff; box-shadow: var(--wpl-active-shadow); }
.wpl-toggle-btn .wpl-icon { font-size: 14px; line-height: 1; }

.wpl-play-btn {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  border: 1.5px solid var(--wpl-accent);
  background: var(--wpl-accent);
  color: #fff;
  font-weight: 800;
  font-size: 13px;
  padding: 10px 18px;
  border-radius: 9px;
  cursor: pointer;
  box-shadow: var(--wpl-active-shadow);
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
  white-space: nowrap;
  min-width: 132px;
}
.wpl-play-btn.playing { background: #f59e0b; border-color: #f59e0b; }

/* ---------- Panels (the shell doesn't move on tab switch — the key
   selector + piano above this live in .wpl-instrument and never move at
   all, regardless of tab) ----------
   All 4 panels are stacked in the SAME grid cell (grid-row/grid-column:1),
   so .wpl-panels sizes itself to whichever panel is naturally tallest —
   automatically, with no min-height number to keep in sync by hand. Only
   the active one is visible; the rest sit underneath at visibility:hidden
   (not display:none, which would remove them from the height calculation
   entirely and defeat the whole point). Chris (2026-08-28): "I don't want
   to keep adjusting vertical heights for things" when adding future tabs
   or content — this is the fix, do NOT go back to per-panel min-height
   tuning. Adding tab #5 someday just means adding a 5th `.wpl-panel` in
   here; its height is picked up automatically. */
.wpl-panels { display: grid; }
.wpl-panel {
  grid-row: 1;
  grid-column: 1;
  visibility: hidden;
  pointer-events: none;
  /* Without this, a grid item's default min-width:auto lets its own
     content's min-content size force the shared grid COLUMN wider than
     the wrapper — the width equivalent of the height "tallest wins"
     trick above, but as a bug: one panel's non-wrapping row (e.g. the
     Scales settings row) can blow out the column and drag every OTHER
     panel to that same width, overflowing the card on narrow screens
     (Chris, 2026-08-31 — caught via Playwright at 390px). min-width:0
     lets the item shrink to the column's real size so its own flex/text
     content wraps instead. */
  min-width: 0;
}
.wpl-panel.active {
  visibility: visible;
  pointer-events: auto;
}

/* ---------- Coming soon panel ---------- */
.wpl-soon {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20px;
  text-align: center;
  color: var(--wpl-muted);
}
.wpl-soon-icon { font-size: 34px; margin-bottom: 12px; }
.wpl-soon-title { font-size: 17px; font-weight: 700; color: var(--wpl-ink); margin-bottom: 6px; }
.wpl-soon-text { font-size: 13.5px; max-width: 380px; margin: 0 auto; line-height: 1.5; }

/* ---------- Demo lock overlay (covers readout + piano + legend + status
   when a locked key is tapped in demo mode; the key-selector row above it
   stays outside this wrapper and always clickable). ---------- */
.wpl-instrument-display { position: relative; }
.wpl-instrument-display.locked .wpl-instrument-content {
  filter: blur(2.5px);
  opacity: 0.35;
  pointer-events: none;
  user-select: none;
}
.wpl-lock-overlay {
  display: none;
  position: absolute;
  inset: 0;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 5;
}
.wpl-lock-overlay.show { display: flex; }
.wpl-lock-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 8px;
  background: var(--wpl-card);
  border: 1.5px solid var(--wpl-line);
  border-radius: 16px;
  padding: 22px 30px;
  box-shadow: 0 10px 28px rgba(42,38,32,0.22);
}
.wpl-lock-icon { font-size: 28px; }
.wpl-lock-title { font-size: 19px; font-weight: 800; color: var(--wpl-ink); }
.wpl-lock-cta {
  display: inline-block;
  margin-top: 4px;
  padding: 13px 30px;
  background: var(--wpl-accent);
  border: 1.5px solid var(--wpl-accent);
  color: #fff;
  font-weight: 800;
  font-size: 15.5px;
  border-radius: 10px;
  text-decoration: none;
  box-shadow: var(--wpl-active-shadow);
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}

/* ---------- Hover states — real hover devices only ----------
   iOS Safari (and touch browsers generally) fires a CSS :hover state on tap
   and never clears it until a different element is tapped, since touch has
   no mouseleave. Every "lift" effect below was written assuming hover means
   "the cursor is over this" — on a phone it instead meant "the last thing I
   tapped," so tapping Click made Loop look permanently hovered until the
   next tap moved the stuck state onto Loop. Scoping all of it to
   (hover: hover) and (pointer: fine) means only real mice/trackpads ever
   see these effects; touch just gets the immediate tap feedback with
   nothing left stuck afterward. */
@media (hover: hover) and (pointer: fine) {
  .wpl-tab:hover { color: var(--wpl-ink); }
  .wpl-tab.active:hover { color: var(--wpl-accent-dark); }
  .prog-tab:hover, .key-tab:hover, .step-btn:hover {
    box-shadow: var(--wpl-lift-shadow);
    transform: translateY(-1.5px);
  }
  .prog-tab.active:hover, .key-tab.active:hover, .step-btn.active:hover { background: var(--wpl-accent-dark); border-color: var(--wpl-accent-dark); }
  .prog-tab:hover { background: var(--wpl-prog-hover); border-color: var(--wpl-prog-hover); }
  .key-tab:hover { background: var(--wpl-tan-hover); border-color: var(--wpl-tan-hover); }
  .step-btn:hover { background: var(--wpl-tan-hover); border-color: var(--wpl-tan-hover); }
  .wpl-toggle-btn:hover { background: var(--wpl-tan-hover); border-color: var(--wpl-tan-hover); box-shadow: var(--wpl-lift-shadow); transform: translateY(-1.5px); }
  .wpl-toggle-btn.active:hover { background: var(--wpl-accent-dark); border-color: var(--wpl-accent-dark); }
  .wpl-play-btn:hover { background: var(--wpl-accent-dark); border-color: var(--wpl-accent-dark); transform: translateY(-1.5px); }
  .wpl-play-btn.playing:hover { background: #d97706; border-color: #d97706; }
  .wpl-lock-cta:hover { background: var(--wpl-accent-dark); border-color: var(--wpl-accent-dark); transform: translateY(-1.5px); }
}

@media (max-width: 520px) {
  html, body { overflow-x: hidden; }
  #wpl-wrapper { padding: 16px 10px 18px !important; width: 100%; max-width: 100%; overflow-x: hidden; }
  .wpl-trial-note { top: 8px; right: 6px; padding: 4px 7px; border-radius: 8px; }
  .wpl-trial-label { font-size: 7.5px; }
  .wpl-trial-clock { font-size: 10.5px; }
  /* Keep the centered eyebrow/title/subtitle clear of the corner badge —
     without this, centered header text can run right under it on narrow
     screens (the badge is position:absolute, so it doesn't reserve space
     on its own). */
  #wpl-wrapper.wpl-has-trial-badge .wpl-header { padding-right: 100px; }
  /* Chris, 2026-09-02: "the black border around the piano on mobile seems
     too thick. it looks more proportionate on desktop." Desktop's frame
     padding-to-frame-height ratio is 5/(118+2*5) ≈ 3.9%; mobile's old 4px
     padding on a 55px piano (frame = 55+2*4 = 63px) was ≈ 6.3% — visibly
     chunkier. "don't want that to move everyting up in the shell" — so the
     FRAME's total height must stay exactly 63px through every pass below.
     First pass used padding:2.5px + piano height:58px (58+2*2.5=63) which
     matched the ratio, but Chris then noticed "why does the left border
     seem thicker than the right border" — a real, measured artifact: a
     2.5px (half-pixel) padding lands asymmetrically on the device pixel
     grid, rendering 2 solid dark pixels on the left edge vs only 1 on the
     right (confirmed via pixel-level screenshot scanning). Second pass
     went to a whole-number padding:2px + piano height:59px (59+2*2=63,
     frame height still exactly preserved), which fixed the left/right
     symmetry — but Chris then noticed "the rounded corners are getting
     cut off" on mobile: with only 2px of dark material and an 8px
     border-radius shared by both the frame and the inner piano, there was
     barely any dark corner left to show the curve — the piano's own key
     content pokes almost right up to the rounded edge (confirmed via a
     15x cropped zoom of the top-left corner: the blue highlighted key's
     rounded top corner is nearly flush with the frame's own curve, with
     only a sliver of dark pixels between them). Chris: "make the mobile
     border 1px bigger all the way around" — padding goes to 3px (still a
     whole number, so the left/right pixel-symmetry fix above is
     unaffected) and piano height compensates down to 57px (57+2*3=63,
     frame height still exactly the same 63px as every prior pass — "don't
     want that to move everyting up in the shell" still holds). border-
     radius stays 8px (unchanged) since it already matches #wpl-piano's
     own fixed inline border-radius:8px (index.html) — shrinking it would
     make the outer frame corner tighter than the inner piano's corner,
     which looks wrong. */
  #wpl-piano { height: 57px !important; }
  #wpl-piano span { font-size: 6px !important; }
  /* Black-key labels with an accidental ("E♭", "♭3", "C♯") stack on two
     lines here instead of running side by side -- a black key at this
     width is only ~6px wide, not enough for 2 characters at any legible
     size. Stacked in the label's own left-to-right order (see
     setKeyLabelText in piano-engine.js), so "E♭" is E-over-♭ but "♭3" is
     ♭-over-3 -- Chris, 2026-09-05: "stack the black keys on mobile," then
     "I dont' like 7b where 7 is on top of the flat. it needs to be
     reversed to flat is on top." Accidental line bumped from 5px to 6px
     the same day: "make the # and flat symbols on mobile be larger.
     there is more room to fit them." */
  #wpl-piano .key-label-stacked { display: flex !important; flex-direction: column; align-items: center; justify-content: center; gap: 0; }
  #wpl-piano .key-label-stacked .key-label-main { display: block; line-height: 1; }
  #wpl-piano .key-label-stacked .key-label-accidental { display: block; line-height: 1; font-size: 6px !important; }
  #wpl-piano-frame { padding: 3px !important; border-radius: 8px !important; }
  /* Chris (zoomed screenshot): "mobile keys at the bottom are too
     rounded, make them more like the desktop." Desktop's 5px/4px radius
     is a fixed value, but mobile keys are much narrower (many more keys
     fit in a lot less width), so that same absolute radius reads as a
     proportionally bigger curve relative to a key's own width -- more
     rounded-looking even though the number never changed. Scaled down
     to keep the same look-and-feel as desktop at mobile's narrower key
     width. */
  .wpl-white-key { border-radius: 0 0 3px 3px; }
  .wpl-white-key.wpl-key-first { border-top-left-radius: 3px; }
  .wpl-white-key.wpl-key-last { border-top-right-radius: 3px; }
  .wpl-black-key { border-radius: 0 0 2px 2px; }
  .wpl-title { font-size: 22px; }
  .prog-tab { padding: 8px 2px; min-height: 59px; }
  .prog-tab .num { font-size: 14px; }
  /* Chris, 2026-09-02: "the sub fonts on the top row can be a little
     bigger... make sure 'foundation' text looks good cause that's the
     longest text" — shared by Progressions' own top row (5 buttons, the
     tighter fit) and Chords v2's position row (4 buttons, more room per
     button). Playwright nowrap-probe against Progressions' narrower
     buttons — the binding case — at this breakpoint: "Foundation" fits up
     to 10.5px (57.16px natural vs 58.41px available) and wraps at 10.75px;
     10px keeps a real ~4px margin below that, still a clear step up from
     the old 8px. */
  .prog-tab .name { font-size: 10px; }
  .key-tab { padding: 6px 0; font-size: 11px; line-height: 12px; }
  /* 2-letter keys (Db/Eb/F#/Ab/Bb) keep the SAME font-size as the
     1-letter keys (Chris: text must match, not shrink) — only
     letter-spacing tightens slightly so the extra character still fits
     the same flex:1 box without wrapping. */
  .key-tab.key-tab-wide { letter-spacing: -0.3px; }
  #wpl-key-tabs { gap: 3px !important; }
  .step-btn { padding: 5px 1px; min-height: 44px; }
  /* Base rule now (see the desktop rule above), so every .step-btn .n
     consumer (step-row, quality-row2, Practice's Hand/Direction/Octaves)
     moves together automatically. */
  .step-btn .n { font-size: 11px; }
  .step-btn .l { font-size: 10px; }
  /* #wpl-position-tabs2 / #wpl-quality-row2 (Chords v2's own two rows)
     added to this shared list — Chris, 2026-09-02: "the mobile horizontal
     spacing between the buttons are not the same on progressions, practice
     and chords2" — these two rows were left out when this rule was first
     written (before Chords v2 existed) and were still falling back to
     their own 8px inline gap (index.html) at this breakpoint instead of
     shrinking with every other row's buttons. */
  #wpl-prog-tabs, #wpl-step-row, #wpl-scale-type-row, #wpl-scale-view-row, #wpl-position-tabs2, #wpl-quality-row2 { gap: 4px !important; }
  #wpl-prog-tabs, #wpl-scale-type-row, #wpl-position-tabs2 { margin-bottom: 6px !important; }
  /* Chris, 2026-09-01: "why do you have 3 rows of buttons? make it
     identical to chords/progressions that have 2 rows" — this row (Hand +
     Direction + Octaves) used to force Octaves onto its own 2nd line here
     via .wpl-scale-break, with its own compact min-height/font tuned just
     to fit that 2-line layout in Practice's height budget. Now that
     index.html removed the forced break, this row is a single line of 8
     .step-btns exactly like Progressions' #wpl-step-row / Chords' two
     rows — it inherits their shared .step-btn sizing above (gap/margin
     folded into the same selectors) instead of a bespoke override, and
     with only ONE line instead of two, Practice's total height only
     shrinks further below Chords/Progressions's shared max, so there's
     no shell-height risk (confirmed via qa/check-dimensions.js). */
  /* Chris: "same with mobile, move in not as much as desktop but closer
     toward the middle, but don't let the text wrap." Smaller gap than
     desktop's since the whole card is already much narrower here --
     the two sides sit closer to the middle by default at this width,
     so they need less pulling-in than the up-to-1100px-wide desktop
     card does. */
  .wpl-readout-row { margin: 4px 0 2px; gap: 20px; }
  .wpl-readout-row > div { height: 40px !important; width: 130px; }
  /* Choose a Scale row's subtitles (Scale/Pentatonic/Blues), unified --
     see the .wpl-name-wide comment further up for the full breakdown.
     This is the 341-520px tier (8px), scoped generically (not just
     .wpl-name-wide) so Scale/Blues shrink down to match Pentatonic
     instead of keeping the unscoped 10px .prog-tab .name mobile size. */
  #wpl-scale-type-row .prog-tab .name { font-size: 8px; }
  /* line-height is a fixed px value (not the desktop inline style's em-relative
     1.3), shared by both the normal and .long-label sizes below, so a
     short value ("C4") and a long one ("2nd Inv") sit on the same vertical
     center in the readout instead of the smaller font pulling its line up
     (Chris: "it sits higher than C4... it needs to be centered horizontally
     with C4"). */
  .wpl-readout-row #wpl-chord-name, .wpl-readout-row #wpl-step-label { font-size: 19px !important; line-height: 25px !important; }
  .wpl-readout-row #wpl-chord-name.long-label, .wpl-readout-row #wpl-step-label.long-label { font-size: 15px !important; line-height: 25px !important; }
  /* Chris: "the spacing above #2 and below the buttons of #3 could be
     a tiny bit less. it looks like bigger gaps there than the rest."
     This 16px mobile-only override was bigger than the 10px desktop
     uses -- with #wpl-status hidden right below it on mobile (see
     below), that extra margin read as leftover empty space rather
     than intentional breathing room. Matched back to desktop's 10px. */
  .wpl-instrument { margin-bottom: 10px; }
  .wpl-legend { font-size: 12px !important; gap: 14px !important; }
  .wpl-legend-dot { width: 9px !important; height: 9px !important; margin-right: 4px !important; }
  /* Chris: keep the "Tap any chord..." hint on desktop, but drop it on
     mobile — narrow screens don't have room for it without crowding the
     "3." heading above the step/position row. */
  #wpl-status { display: none; }
  .wpl-tab { padding: 7px 5px 9px; height: 27px; font-size: 9.5px; gap: 3px; }
  .wpl-tab.active { height: 28px; }
  .wpl-tab-soon { font-size: 7px; padding: 1.5px 3px; }
  .wpl-lock-card { padding: 16px 18px; }
  .wpl-lock-title { font-size: 16px; }
  .wpl-lock-cta { padding: 11px 22px; font-size: 14px; }
  /* Same note as .wpl-instrument above -- 22px above the tempo bar
     (the desktop value, inherited here by default) read as an
     oversized gap once the buttons/labels around it are mobile-sized. */
  .wpl-playbar { gap: 12px; padding: 10px 12px; margin-top: 14px; }
  .wpl-bpm { min-width: 100%; order: 1; }
  .wpl-playbar-controls { order: 2; width: 100%; justify-content: space-between; }
  .wpl-toggle-btn, .wpl-play-btn { flex: 1; justify-content: center; min-width: 0; }
}

/* Extra-narrow safety net (2026-08-29): some embed contexts (e.g. a course
   platform sidebar that does not collapse on mobile) can hand our iframe
   less width than a normal phone screen. Below this the 520px mobile
   sizing can still be too wide for Loop/Click/Play or the progression/
   chord rows to fit without clipping, so shrink further and let the
   playbar buttons wrap onto a second line as a last resort instead of
   being cut off. */
@media (max-width: 340px) {
  #wpl-wrapper { padding: 12px 6px 14px !important; }
  .wpl-trial-note { top: 5px; right: 4px; padding: 2px 4px; border-radius: 6px; }
  .wpl-trial-label { display: none; }
  .wpl-trial-clock { font-size: 8px; }
  /* Header text itself also shrinks a touch here, on top of the smaller
     badge/reservation, specifically so "Worship Piano Lab" and the eyebrow
     still fit on one line each at the narrowest widths we support (as low
     as 288px — the ThriveCart-sidebar-squeeze case) instead of wrapping to
     a 2nd line, which would grow the header's height and start moving
     everything below it — the exact "changes the vertical layout" problem
     this badge is required not to cause. */
  #wpl-wrapper.wpl-has-trial-badge .wpl-header { padding-right: 50px; }
  #wpl-wrapper.wpl-has-trial-badge .wpl-eyebrow { font-size: 9px; letter-spacing: 1px; margin-bottom: 4px; }
  #wpl-wrapper.wpl-has-trial-badge .wpl-title { font-size: 18px; }
  #wpl-wrapper.wpl-has-trial-badge .wpl-subtitle { font-size: 11px; margin-top: 3px; }
  .prog-tab { padding: 6px 1px; min-height: 52px; }
  .prog-tab .num { font-size: 12px; }
  /* Same "a little bigger, keep Foundation on one line" request as the 520px
     rule above — Playwright nowrap-probe at this narrower breakpoint:
     "Foundation" fits up to 8.75px (47.64px natural vs 48.80px available,
     ~1.2px margin) and wraps at 9px, so 8.5px keeps a real ~2.5px margin
     while still stepping up from the old 7px. */
  .prog-tab .name { font-size: 8.5px; }
  .step-btn { padding: 4px 1px; min-height: 40px; }
  /* Same value the shared 520px rule above already uses, so no change is
     needed stepping down into this breakpoint. */
  .step-btn .n, .step-btn .l { font-size: 9px; }
  .key-tab { font-size: 9.5px; padding: 5px 0; line-height: 11px; }
  .key-tab.key-tab-wide { letter-spacing: -0.4px; }
  #wpl-key-tabs { gap: 2px !important; }
  /* Same fix as the 520px rule above: #wpl-position-tabs2 / #wpl-quality-row2
     added so Chords v2's own two rows shrink their gap along with every
     other row at this breakpoint too. */
  #wpl-prog-tabs, #wpl-step-row, #wpl-scale-type-row, #wpl-scale-view-row, #wpl-position-tabs2, #wpl-quality-row2 { gap: 3px !important; }
  /* Chords v2 (#wpl-panel-chords2): quality row's captions are plain
     .step-btn .l, which is 9px at this breakpoint (shared rule above) —
     fine for Progressions' own short captions ("2m", "1/3"), but Min7's
     "1-♭3-5-♭7" wraps to a 2nd line at 9px in this row's slightly
     different padding (Playwright probe: needs ≤8.25px to clear 35.3px of
     available width; wraps at 8.5px). Chris, 2026-09-02: "reduce text
     size only as much as to prevent wrapping... only on a smaller phone"
     — so this ONLY overrides the caption size, ONLY at this narrowest
     breakpoint (nothing changes at 340–520px or desktop, where it already
     fits at the shared 10px/12px sizes with room to spare), and only down
     to 8px — 2px of real margin below the exact 8.25px threshold, not
     shaved to the bone. */
  #wpl-quality-row2 .step-btn .l { font-size: 8px; }
  .wpl-readout-row > div { height: 34px !important; width: 100px; }
  /* Overrides the 341-520px tier's 8px above -- this narrowest phone
     tier (real floor: 320px) has slightly less room, so Scale/Pentatonic/
     Blues are unified at 7.75px here instead (see .wpl-name-wide comment
     near the 521-619px tier for the full breakdown). */
  #wpl-scale-type-row .prog-tab .name { font-size: 7.75px; }
  .wpl-readout-row #wpl-chord-name, .wpl-readout-row #wpl-step-label { font-size: 15px !important; }
  /* 11.5px. Was briefly dropped to 10px to squeeze "Finger Patterns" into
     this 88px box on real phones, but Chris shortened the View readout's
     finger-view label to "Fingers" instead (see VIEW_READOUT_LABELS in
     ui.js) -- same length as "Numbers", which already fit fine here --
     so the extra shrink is no longer needed and this reverts to the size
     tuned for the longest Scale readout values (Cm Pentatonic, etc). */
  .wpl-readout-row #wpl-chord-name.long-label, .wpl-readout-row #wpl-step-label.long-label { font-size: 11.5px !important; }
  .wpl-playbar { gap: 6px; padding: 8px 8px; }
  .wpl-playbar-controls { gap: 5px; flex-wrap: wrap; row-gap: 6px; }
  .wpl-toggle-btn, .wpl-play-btn { padding: 7px 5px; font-size: 10.5px; }
  .wpl-play-btn { min-width: 0; }
}
@media (max-height: 500px) {
  #wpl-piano { height: 95px !important; }
  #wpl-piano span { font-size: 8px !important; }
  /* Same two-line stacking as the portrait tier above -- landscape phones
     hit this height-based query at widths this app never gave black-key
     labels any stacking treatment at all, so a 2-character "C♯"/"♭3" ran
     side by side and didn't fit a black key here either (~10-14px wide)
     -- Chris, 2026-09-05: "on mobile landscape, the black notes are not
     stacked." Slightly bigger than the portrait tier's sizes since these
     keys have a bit more room. */
  #wpl-piano .key-label-stacked { display: flex !important; flex-direction: column; align-items: center; justify-content: center; gap: 0; }
  #wpl-piano .key-label-stacked .key-label-main { display: block; line-height: 1; }
  #wpl-piano .key-label-stacked .key-label-accidental { display: block; line-height: 1; font-size: 7px !important; }
  #wpl-piano-frame { padding: 4px !important; border-radius: 8px !important; }
}
