/* The four numbers below are MAXIMA, not fixed sizes. fitLayout() in
   grid-composer.js measures the real viewport and writes smaller values onto
   :root, so a 4-bar song fills a laptop and a 16-bar chromatic one still lands
   inside an iPad instead of running off the right edge. Everything that used to
   hard-code a matching number -- the row gap, the pill font sizes, the cell
   inset -- now derives from these, or shrinking the grid would leave the type
   and the padding at desktop size and the rows would collide. */
:root {
  --label-width: 108px;
  --step-size: 46px;
  --row-height: 34px;
  --row-gap: 6px;
  --ruler-height: 28px;
  /* How much floating chrome sits above the page. The arcade puts a fixed Menu
     pill and the coin purse across the top with nothing reserving space for
     them, so the song name and the Save button rendered UNDERNEATH both.
     fitLayout() measures that bar; 0 is right for PK-5, whose game bar is part
     of the layout and pushes the page down on its own. */
  --chrome-reserve: 0px;
  --app-radius: 0px;
  --surface: rgba(255, 255, 255, 0.92);
  --surface-strong: #ffffff;
  --surface-soft: rgba(249, 252, 255, 0.86);
  --ink: #1e355c;
  --soft-ink: #687998;
  --border: #dce8fb;
  --border-strong: #c5daf8;
  --blue: #2aa0df;
  --blue-dark: #157bc0;
  --danger: #ef6262;
  --danger-dark: #d94f4f;
  --playhead: rgba(76, 186, 255, 0.14);
  --shadow:
    0 30px 70px rgba(34, 73, 120, 0.12),
    0 10px 22px rgba(34, 73, 120, 0.08);
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body {
  margin: 0;
  min-height: 100%;
}

body {
  min-height: 100vh;
  font-family: "Nunito", "Avenir Next Rounded", "Trebuchet MS", "Verdana", sans-serif;
  color: var(--ink);
  background: #ffffff;
  padding: 0;
}

body.grid-composer-page .shopify-section-group-header-group,
body.grid-composer-page #shopify-section-header,
body.grid-composer-page [id*="shopify-section"][id*="header"],
body.grid-composer-page .shopify-section-group-footer-group,
body.grid-composer-page #shopify-section-footer,
body.grid-composer-page [id*="shopify-section"][id*="footer"],
body.grid-composer-page [id*="shopify-section"][id*="announcement"] {
  display: none !important;
}

body.grid-composer-page #MainContent,
body.grid-composer-page main#MainContent {
  margin-top: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}

button,
input,
select {
  font: inherit;
}

button {
  border: 0;
  cursor: pointer;
}

.app {
  width: 100%;
  margin: 0 auto;
  position: relative;
  /* A phone held sideways: the Dynamic Island takes one side, and the grid's
     row labels (E, D, C, Clap, Stomp) sat under it. */
  box-sizing: border-box;
  padding-left: env(safe-area-inset-left, 0px);
  padding-right: env(safe-area-inset-right, 0px);
}

.shell {
  position: relative;
  background: #ffffff;
  border: 0;
  border-radius: var(--app-radius);
  overflow: visible;
}

.boot-loader {
  position: absolute;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  gap: 10px;
  background: rgba(251, 253, 255, 0.88);
  backdrop-filter: blur(4px);
  transition: opacity 0.18s ease;
}

.boot-loader.done {
  opacity: 0;
}

.boot-loader-dot {
  width: 24px;
  height: 24px;
  border-radius: 999px;
  border: 3px solid #cfe0f8;
  border-top-color: var(--blue);
  animation: bootSpin 0.82s linear infinite;
}

.boot-loader-text {
  margin: 0;
  font-weight: 800;
  color: #4c6695;
}

@keyframes bootSpin {
  to { transform: rotate(360deg); }
}

.hero-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: calc(12px + var(--chrome-reserve)) 14px 10px;
  position: relative;
  z-index: 30;
}

.settings-kicker,
.section-kicker {
  margin: 0;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.76rem;
  font-weight: 900;
  color: #5d88b8;
}

.title-row {
  display: flex;
  align-items: center;
  gap: 8px;
  position: relative;
  min-width: 0;
  flex: 1 1 auto;
}

.composition-name {
  flex: 0 1 220px;
  min-width: 0;
  border: 0;
  background: transparent;
  padding: 0 0 2px;
  border-bottom: 2px solid #dbe6f8;
  font-size: clamp(1.22rem, 1.8vw, 1.6rem);
  font-weight: 900;
  color: #153563;
}

.composition-name:focus {
  outline: none;
  border-color: #7bd0ef;
}

.title-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  position: relative;
  z-index: 40;
}

.transport-cluster {
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-end;
  align-items: center;
  gap: 8px;
  flex: 0 0 auto;
}

.icon-btn,
.primary-btn,
.ghost-btn,
.choice-btn,
.stepper-btn,
.settings-done-btn {
  border-radius: 16px;
  transition: transform 0.14s ease, box-shadow 0.14s ease, filter 0.14s ease, background 0.14s ease;
}

.icon-btn:active,
.primary-btn:active,
.ghost-btn:active,
.choice-btn:active,
.stepper-btn:active,
.settings-done-btn:active {
  transform: translateY(2px);
  filter: brightness(0.98);
}

.play-icon {
  width: 0;
  height: 0;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  border-left: 16px solid #fff;
}

.stop-icon {
  width: 16px;
  height: 16px;
  border-radius: 4px;
  background: #fff;
}

.icon-btn,
.ghost-btn,
.primary-btn {
  min-height: 40px;
  padding: 0 12px;
  font-weight: 900;
}

.icon-btn,
.ghost-btn {
  background: linear-gradient(180deg, #f8fbff, #edf4ff);
  color: #3a5a89;
  border: 2px solid #d5e3fa;
  box-shadow: 0 8px 18px rgba(86, 122, 180, 0.1);
}

.transport-icon-btn,
.ghost-btn,
.primary-btn {
  width: 40px;
  min-width: 40px;
  height: 40px;
  padding: 0;
  display: grid;
  place-items: center;
}

.transport-icon-btn svg,
.ghost-btn svg,
.primary-btn svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.play-icon-btn {
  background: linear-gradient(180deg, #33afea, #1690d6);
  border: 2px solid #1690d6;
  color: #ffffff;
  box-shadow: 0 8px 18px rgba(39, 147, 212, 0.2);
}

.stop-icon-btn {
  background: linear-gradient(180deg, #fa7d72, #ef6262);
  border: 2px solid #ef6262;
  color: #ffffff;
  box-shadow: 0 8px 18px rgba(234, 98, 98, 0.18);
}

.icon-btn.is-active,
.choice-btn.is-active,
.split-btn.is-active {
  background: linear-gradient(180deg, #daf4ff, #c9ebff);
  border-color: #7bc9ee;
  color: #17629a;
}

.danger-btn {
  color: #9b3f3f;
  border-color: #f5cece;
  background: linear-gradient(180deg, #fff6f6, #ffe6e6);
}

.primary-btn {
  color: #fff;
  background: linear-gradient(180deg, #33afea, #1590d6);
  box-shadow: 0 8px 0 var(--blue-dark), 0 16px 26px rgba(39, 147, 212, 0.22);
}

.workspace {
  padding: 0 10px 8px;
}

.timeline-shell {
  padding: 0;
  border-radius: 0;
  background: transparent;
  border: 0;
}

.timeline-ruler,
.grid-matrix {
  min-width: max-content;
}

.timeline-ruler {
  display: grid;
  grid-template-columns: var(--label-width) repeat(var(--steps, 1), var(--step-size));
  align-items: stretch;
  margin-bottom: 8px;
}

.ruler-label,
.ruler-step {
  min-height: var(--ruler-height);
  display: grid;
  place-items: center;
  font-weight: 900;
  font-size: 0.82rem;
  color: #5b7095;
}

.ruler-label {
  justify-items: start;
  padding-left: 10px;
}

.ruler-step {
  border-left: 1px solid rgba(120, 180, 236, 0.28);
  background: rgba(255, 255, 255, 0.82);
}

.ruler-step.is-beat {
  color: #2d5f9d;
  border-left-width: 2px;
  border-left-color: rgba(101, 154, 215, 0.55);
}

.ruler-step.is-bar {
  color: #1f4f8e;
  border-left-width: 4px;
  border-left-color: rgba(74, 161, 240, 0.92);
}

.ruler-step.is-subdivision-label {
  color: rgba(91, 112, 149, 0.5);
}

.ruler-step.is-alt-beat {
  background: rgba(222, 228, 236, 0.5);
}

.grid-scroll {
  overflow-x: auto;
  overflow-y: hidden;
  padding: 0 0 6px;
  overscroll-behavior-x: contain;
}

/* Reachable is not the same as discoverable: without a cue the song simply
   looks like it ends at the screen edge. A soft fade on the right says there is
   more, and only appears while there actually is. mask-image rather than an
   overlay so it cannot intercept the very gesture it is advertising. */
.grid-scroll.is-pannable {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 26px), transparent 100%);
}

.grid-stage {
  min-width: max-content;
}

.section-block {
  position: relative;
}

.grid-matrix {
  display: grid;
  gap: var(--row-gap);
}

.grid-row {
  display: grid;
  grid-template-columns: var(--label-width) repeat(var(--steps, 1), var(--step-size));
  align-items: stretch;
  min-height: var(--row-height);
}

.row-label {
  position: sticky;
  left: 0;
  z-index: 4;
  display: grid;
  place-items: center;
  min-height: var(--row-height);
  margin-right: var(--row-gap);
  padding: 0 6px;
  border-radius: 12px;
  border: 0;
  background: var(--row-color, #8cc7ff);
  color: var(--row-text-color, #ffffff);
  font-weight: 900;
  text-align: center;
  box-shadow:
    inset 0 -3px 0 rgba(0, 0, 0, 0.08),
    8px 0 16px rgba(255, 255, 255, 0.92);
}

.row-label:hover {
  filter: brightness(1.03);
}

.row-pill-text {
  display: block;
  line-height: 1;
  /* Capped by the row, not just by taste: at --row-height 20px a 14px pill
     overflows its own capsule. The min() keeps the desktop size exactly as it
     was and only bites once the fitter starts shrinking rows. */
  font-size: min(0.88rem, calc(var(--row-height) * 0.42));
  font-weight: 900;
  letter-spacing: -0.02em;
}

.row-label-low .row-pill-text {
  font-size: min(1rem, calc(var(--row-height) * 0.47));
  font-weight: 1000;
}

.row-label-high .row-pill-text {
  font-size: min(0.84rem, calc(var(--row-height) * 0.4));
  font-weight: 800;
  text-transform: none;
}

.row-label-drum .row-pill-text {
  font-size: min(0.78rem, calc(var(--row-height) * 0.37));
  font-weight: 900;
}

.grid-cell {
  position: relative;
  min-width: var(--step-size);
  min-height: var(--row-height);
  border-radius: clamp(4px, calc(var(--step-size) * 0.17), 8px);
  border: 1px solid rgba(130, 184, 230, 0.18);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(245, 250, 255, 0.92));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.76);
  /* Drag-to-paint needs the gesture, so the browser must not pan... UNLESS the
     grid is wider than the screen, in which case panning is the only way to
     reach the rest of the song. grid-composer.js measures that on every fit and
     toggles .is-pannable - see updatePanMode(). */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.grid-scroll.is-pannable .grid-cell {
  touch-action: pan-x pan-y;
}

.grid-cell.is-alt-beat {
  background:
    linear-gradient(180deg, rgba(236, 240, 245, 0.96), rgba(228, 233, 240, 0.9));
}

.grid-cell::after {
  content: "";
  position: absolute;
  /* 4px of inset inside a 20px cell leaves a 12px dot; proportional inset keeps
     a filled cell reading as filled at every size. */
  inset: clamp(2px, calc(var(--step-size) * 0.09), 4px);
  border-radius: clamp(3px, calc(var(--step-size) * 0.13), 6px);
  background: transparent;
  transition: background 0.12s ease, transform 0.12s ease, box-shadow 0.12s ease;
}

/* iOS holds :hover after a tap, so the last-touched cell kept a blue tint
   that reads as "on" beside the real .is-active cells — a sequencer lying
   about its own pattern. */
@media (hover: none) { .grid-cell:hover::after { background: transparent; } }
.grid-cell:hover::after {
  background: rgba(84, 178, 239, 0.08);
}

.grid-cell.is-active::after {
  background: var(--cell-color, #5bbdff);
  box-shadow:
    inset 0 -3px 0 rgba(0, 0, 0, 0.08),
    0 8px 12px color-mix(in srgb, var(--cell-color, #5bbdff) 36%, white 64%);
  transform: scale(0.96);
}

.grid-cell.is-playhead {
  background:
    linear-gradient(180deg, rgba(120, 212, 255, 0.18), rgba(104, 197, 255, 0.12)),
    linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(245, 250, 255, 0.92));
}

.grid-cell.is-playhead.is-active::before {
  content: "";
  position: absolute;
  inset: 2px;
  border-radius: 8px;
  border: 2px solid rgba(65, 165, 236, 0.82);
}

.grid-cell.is-bar-start {
  border-left-width: 4px;
  border-left-color: rgba(74, 161, 240, 0.92);
}

.grid-cell.is-beat-start {
  border-left-width: 2px;
  border-left-color: rgba(101, 154, 215, 0.58);
}

.grid-divider {
  height: 1px;
  margin: calc(var(--row-gap) + 3px) 0 var(--row-gap);
  background: linear-gradient(90deg, transparent, rgba(151, 179, 221, 0.48), transparent);
}

.footer-bar {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  padding: 14px 18px 18px;
}

.tempo-block {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: 1;
}

.tempo-label,
.tempo-value,
.footer-status {
  font-weight: 900;
}

.tempo-label {
  min-width: 58px;
  color: #3c5f8f;
}

.tempo-slider {
  flex: 1;
  accent-color: var(--blue);
}

.tempo-value {
  min-width: 88px;
  color: #1d73af;
}

.footer-status {
  color: var(--soft-ink);
  text-align: right;
}

.message {
  position: absolute;
  left: 50%;
  bottom: 74px;
  transform: translateX(-50%);
  min-width: 180px;
  max-width: min(80vw, 460px);
  padding: 12px 16px;
  border-radius: 999px;
  background: rgba(24, 51, 88, 0.92);
  color: #fff;
  font-weight: 800;
  text-align: center;
  box-shadow: 0 18px 34px rgba(24, 51, 88, 0.2);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}

.message.is-visible {
  opacity: 1;
  transform: translateX(-50%) translateY(-4px);
}

.saved-panel {
  position: absolute;
  right: 14px;
  top: calc(100% + 10px);
  width: min(460px, calc(100vw - 28px));
  max-height: min(54vh, 420px);
  overflow: auto;
  padding: 12px;
  border-radius: 20px;
  border: 2px solid #d8e5fb;
  background: rgba(255, 255, 255, 0.98);
  box-shadow: 0 24px 44px rgba(43, 78, 126, 0.16);
  z-index: 120;
}

.saved-title {
  margin: 0 0 10px;
  font-size: 1rem;
  color: #285081;
}

.saved-list {
  display: grid;
  gap: 10px;
}

.saved-item {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 12px 14px;
  border-radius: 16px;
  border: 2px solid #e5eefc;
  background: linear-gradient(180deg, #ffffff, #f7fbff);
}

.saved-meta {
  display: grid;
  gap: 2px;
}

.saved-meta strong {
  color: #1c436f;
}

.saved-meta span {
  font-size: 0.84rem;
  color: var(--soft-ink);
}

.saved-actions {
  display: flex;
  gap: 8px;
}

.saved-actions button {
  min-height: 38px;
  padding: 0 12px;
  border-radius: 12px;
  font-weight: 900;
  color: #335784;
  background: #eef5ff;
  border: 1px solid #d8e6fb;
}

.saved-actions button.delete-btn {
  color: #9a4040;
  background: #fff1f1;
  border-color: #f5d4d4;
}

.saved-empty {
  padding: 16px 10px;
  border-radius: 16px;
  background: #f7fbff;
  text-align: center;
  color: var(--soft-ink);
  font-weight: 800;
}

.settings-modal {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 28px;
}

.settings-scrim {
  position: absolute;
  inset: 0;
  background: rgba(23, 48, 84, 0.2);
  backdrop-filter: blur(4px);
}

.settings-dialog {
  position: relative;
  width: min(1080px, 100%);
  padding: 28px 28px 34px;
  border-radius: 36px;
  background: rgba(255, 255, 255, 0.98);
  box-shadow: 0 32px 60px rgba(23, 48, 84, 0.2);
}

.settings-close {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 58px;
  height: 58px;
  border-radius: 999px;
  background: #fff;
  border: 2px solid #e2e8f3;
  color: #111;
  font-size: 2.1rem;
  line-height: 1;
}

.settings-header h2 {
  margin: 6px 0 0;
  font-size: clamp(1.8rem, 2.6vw, 2.4rem);
  color: #1f426f;
}

.settings-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 30px;
  margin-top: 24px;
}

.setting-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  min-height: 96px;
  border-bottom: 1px solid rgba(224, 232, 243, 0.9);
}

.setting-row-wide {
  grid-column: 1 / -1;
}

.setting-label {
  font-size: clamp(1.1rem, 1.9vw, 1.45rem);
  font-weight: 800;
  color: #616872;
}

.setting-value-wrap,
.setting-choice-group {
  display: flex;
  align-items: center;
  gap: 14px;
  justify-content: flex-end;
}

.setting-value-text,
.setting-note {
  font-size: clamp(1.2rem, 2vw, 1.75rem);
  font-weight: 800;
  color: #2aa0df;
  text-align: right;
}

.setting-note {
  max-width: 620px;
  font-size: 1rem;
  line-height: 1.4;
}

.setting-stepper {
  display: flex;
  gap: 10px;
}

.stepper-btn {
  width: 52px;
  height: 52px;
  border-radius: 999px;
  background: #fff;
  color: #2aa0df;
  border: 2px solid #e1e7f0;
  font-size: 2rem;
  line-height: 1;
}

.choice-btn {
  min-height: 48px;
  padding: 0 18px;
  border: 2px solid #dce6f6;
  background: #fff;
  color: #597194;
  font-weight: 900;
}

.split-group .choice-btn {
  min-width: 56px;
}

/* A button, not a balloon. The old 132px circle overflowed the dialog's
   bottom corner and drew itself half-clipped (Andrea's "done button looks
   weird"). A wide pill ends the sheet the way every other dialog does. */
.settings-done-btn {
  display: grid;
  place-items: center;
  width: min(340px, 100%);
  height: 62px;
  margin: 26px auto 0;
  border-radius: 999px;
  color: #fff;
  background: linear-gradient(180deg, #36ace9, #2197da);
  box-shadow: 0 8px 20px rgba(39, 147, 212, 0.3);
  font-size: 1.5rem;
  font-weight: 900;
  letter-spacing: 0.02em;
}

@media (max-width: 1100px) {
  .hero-bar,
  .footer-bar {
    grid-template-columns: 1fr;
    display: grid;
  }

  .transport-cluster {
    justify-content: flex-start;
  }

  .settings-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 760px) {
  body {
    padding: 0;
  }

  .hero-bar,
  .workspace,
  .footer-bar {
    padding-left: 12px;
    padding-right: 12px;
  }

  .title-row {
    flex: 1 1 auto;
  }

  .title-actions {
    justify-content: flex-start;
  }

  .icon-btn,
  .primary-btn,
  .ghost-btn {
    min-height: 46px;
  }

  /* Kept as insurance only. The nine-button row that clipped Save off the
     screen is now seven (Save / Open / Settings moved into the gear), which
     fits a phone with room to spare - but a future button must wrap rather
     than disappear off the edge again. */
  .transport-cluster {
    flex-wrap: wrap;
  }

  .settings-dialog {
    padding: 20px 18px 26px;
  }

  .settings-close {
    width: 48px;
    height: 48px;
    font-size: 1.8rem;
  }

  .settings-done-btn {
    height: 56px;
    font-size: 1.3rem;
  }
}

/* ── The gear menu ─────────────────────────────────────────────────────────
   Save, Open and Settings. They were three of nine buttons in a row that
   needed 424px on a 369px phone, which clipped Save off the screen edge; the
   transport and the eraser are what a child reaches for mid-song, so those
   stayed out and these three folded in here.

   Anchored to the button rather than the header, so it opens under the gear at
   any width. Above the grid's own stacking, below a settings modal. */
.tools-menu-wrap {
  position: relative;
  display: inline-flex;
}

.tools-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 8px);
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
  border-radius: 18px;
  border: 2px solid #d8e5fb;
  background: rgba(255, 255, 255, 0.98);
  box-shadow: 0 22px 40px rgba(43, 78, 126, 0.18);
  z-index: 130;
}

/* Inside the menu each one gets its label back: an icon alone is guessable in
   a toolbar of six, ambiguous in a list of three. */
.tools-menu > button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-width: 172px;
  min-height: 48px;
  padding: 0 14px;
  justify-content: flex-start;
  font-weight: 800;
  font-size: 1rem;
}

.tools-menu > button svg {
  flex: 0 0 auto;
}

.tools-menu > button::after {
  content: attr(data-label);
}

/* The gear reads as pressed while its menu is open. */
#toolsBtn.is-active {
  background: #dbeafe;
  border-color: #93c5fd;
}

/* ── The rotate hint ──────────────────────────────────────────────────────
   Sits over the workspace, not over the whole app: the transport stays visible
   and usable behind it, so this reads as advice rather than a modal wall.
   Pointer events only on the card, so a tap anywhere else still reaches the
   game underneath. */
.rotate-hint {
  position: fixed;
  inset: 0;
  z-index: 125;
  display: grid;
  place-items: center;
  padding: 20px;
  pointer-events: none;
  background: rgba(27, 35, 62, 0.34);
  backdrop-filter: blur(2px);
}

.rotate-hint-card {
  pointer-events: auto;
  width: min(320px, 100%);
  text-align: center;
  padding: 22px 20px 18px;
  border-radius: 22px;
  background: #fff;
  box-shadow: 0 24px 50px rgba(27, 35, 62, 0.3);
}

.rotate-hint-icon svg {
  width: 46px;
  height: 46px;
  fill: none;
  stroke: #099695;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.rotate-hint-title {
  margin: 8px 0 4px;
  font-size: 1.2rem;
  font-weight: 900;
  color: #1b233e;
}

.rotate-hint-body {
  margin: 0 0 16px;
  font-size: 0.95rem;
  font-weight: 600;
  color: #5d6780;
  line-height: 1.45;
}

.rotate-hint-btn {
  width: 100%;
  min-height: 48px;
}

/* The phone is already sideways: nothing to ask for. Belt and braces with the
   JS check, so a stale hidden state can never leave this over a landscape game. */
@media (orientation: landscape) {
  .rotate-hint { display: none; }
}

/* Free tier (2026-09-23): only SAVING needs the unlock. Save stays in the gear
   menu and opens the wall; it dims gently and carries the lock chip at the
   row's right edge (order puts it after the ::after label). */
.tools-menu > #saveBtn.is-locked { opacity: .8; }
#saveBtn .save-lock-chip { order: 1; margin-left: auto; pointer-events: none; line-height: 1; }

/* QA 2026-10-24 (A06): at 568×320 the settings sheet was 790px tall in a 320px screen and nothing
   scrolled (the page moved instead), so Tempo, Split beats and Done were out of reach. The sheet is now
   never taller than the screen: the title and Done stay put and the rows between them scroll inside it
   (overscroll contained, so the composer behind never moves). Short screens get a compact sheet. */
.settings-dialog {
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 56px);
  max-height: calc(100dvh - 56px);
  box-sizing: border-box;
}
.settings-header { flex: 0 0 auto; padding-right: 64px; }
.settings-grid {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  touch-action: pan-y;
}
.settings-done-btn { flex: 0 0 auto; }
/* an iPad held sideways has room for the two-column sheet (one column ran 800px tall at 1024×768) */
@media (orientation: landscape) and (min-width: 700px) {
  .settings-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-height: 560px) {
  .settings-modal { padding: 10px max(12px, env(safe-area-inset-right)) 10px max(12px, env(safe-area-inset-left)); }
  .settings-dialog { max-height: calc(100vh - 20px); max-height: calc(100dvh - 20px); padding: 14px 18px 14px; border-radius: 24px; }
  .settings-close { top: 10px; right: 10px; width: 44px; height: 44px; font-size: 1.7rem; }
  .settings-kicker { margin: 0; }
  /* the arcade's back arrow (top-left, above every sheet) sits on the title's first letters otherwise */
  .settings-header { padding-left: 48px; min-height: 44px; }
  .settings-header h2 { font-size: 1.35rem; margin-top: 0; }
  .settings-grid { margin-top: 8px; }
  .setting-row { min-height: 58px; }
  .setting-label { font-size: 1.05rem; }
  .settings-done-btn { height: 48px; margin-top: 10px; font-size: 1.2rem; }
}
