/* #905: content-sized menus; a separate portrait race composition.
   Landscape race geometry remains unchanged. */
:root {
  --turn-edge: max(12px, env(safe-area-inset-left), env(safe-area-inset-right));
}
/* No double-tap-to-zoom anywhere: repeated taps on one control (the records toggle,
   steppers) must each register instead of zooming, and iOS then fires clicks without
   waiting for a second tap. Pinch-zoom and scrolling stay available (WCAG 1.4.4).
   touch-action is not inherited, so it is set on every element; :where() keeps it at
   zero specificity, so explicit rules (race pads' none, rails' pan-y) still win. */
:where(*) { touch-action: manipulation; }
:root body .rotate-panel { display: none !important; }
:root body .m8-home-shell { max-width: 1440px; margin-inline: auto; }
:root body .m8-home-menu { touch-action: pan-y pinch-zoom; }
:root body :is(.m8-dialog, .sound-guide-dialog, .install-guide-card) {
  max-width: calc(100vw - 2 * var(--turn-edge));
  max-height: calc(100dvh - max(24px, env(safe-area-inset-top) + env(safe-area-inset-bottom)));
  touch-action: pan-y pinch-zoom;
}
:root body :is(.m8-dialog-card, .sound-guide-card, .turn-dialog__body) { min-width: 0; overflow-wrap: anywhere; }
:root body :is(.m8-dialog-head, .sound-guide-head) { gap: 16px; }
:root body :is(.m8-dialog-head, .sound-guide-head) > button { flex-shrink: 0; min-width: 44px; min-height: 44px; }
:root body :is(.m8-dialog-head, .sound-guide-head) h2 { min-width: 0; }
:root body .track-intro-name { white-space: normal; overflow-wrap: anywhere; }

/* Reflow when track browser + menu (or preview + attributes) cannot fit. */

@media (max-width: 46em) {

  :root body .install-gate .install-shell { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  :root body .install-gate { overflow-y: auto; padding: 20px var(--turn-edge); }
  :root body .install-icon { max-height: 26dvh; width: auto; max-width: 100%; }
  :root body .install-card { min-width: 0; }
  :root body :is(.m8-settings-grid, .m8-guide-grid, .turn-achievements-grid) { grid-template-columns: minmax(0, 1fr); }
}

/* Portrait: two lower corner readouts, upward intensity, clear centre of road.
   Tilt uses a single reachable drive pad; steering-pad play keeps the opposite
   thumb zone. Handedness mirrors the complete composition. */
@media (orientation: portrait) {
  :root {
    --turn-race-pad-width: clamp(138px, 43vw, 210px);
    --turn-race-pad-height: clamp(180px, 24dvh, 228px);
    /* One 44px action row, then clear air before the drive pad. */
    --turn-race-footer: 68px;
    --turn-race-bottom: max(var(--turn-race-footer), calc(env(safe-area-inset-bottom) + var(--turn-race-footer)));
  }
  :root body .topbar { gap: 10px; }
  /* A fixed grid, never content-sized: SPEED · LAP · POSITION, then TIME · BEST.
     Digits are tabular, so a changing value never moves a chip. Without rivals the
     POSITION cell is unused and SPEED and LAP share the first row. */
  :root body .stats {
    display: grid; flex: 1 1 auto; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 6px; min-width: 0;
  }
  :root body .stats > .chip { grid-column: span 2; width: auto; min-width: 0; height: auto; min-height: 42px; padding: 6px; overflow: hidden; font-size: max(var(--turn-text-floor), .52rem); }
  :root body .stats > .chip:nth-child(n + 4) { grid-column: span 3; }
  :root body .stats:has(> .race-position-hud[hidden]) > .chip:nth-child(-n + 2) { grid-column: span 3; }
  :root body .stats > .race-position-hud[hidden] { display: none !important; }
  :root body .stats .chip strong { overflow: hidden; font-size: .8rem; font-variant-numeric: tabular-nums; text-overflow: clip; white-space: nowrap; }
  :root body .map-wrap { width: clamp(70px, 21vw, 128px); flex-shrink: 0; }
  :root body .controls { display: block; left: var(--turn-edge); right: var(--turn-edge); bottom: var(--turn-race-bottom); height: var(--turn-race-pad-height); }
  :root body .controls .pedals { position: absolute; right: 0; bottom: 0; left: auto; padding: 0; }
  :root.turn-left-handed-controls body .controls .pedals { left: 0; right: auto; }
  :root body .drive-stack { width: var(--turn-race-pad-width); --drive-pad-height: var(--turn-race-pad-height); --drift-lock-bubble-width: 38px; --shift-bubble-width: 38px; --reverse-bubble-width: 38px; }
  :root body .drive-pad { border-radius: 24px; }
  :root body .drive-pad :is(.drive-zone, .drive-gas-zone, .drive-brake-zone) { font-size: .78rem; }
  :root body .drive-stack :is(.drive-lock-bubble, .drive-shift-bubble, .drive-reverse-bubble) span { font-size: max(var(--turn-text-floor), .65rem); }
  :root body .manual-steer { left: var(--turn-edge); right: auto; bottom: var(--turn-race-bottom); width: calc(100vw - 2 * var(--turn-edge) - var(--turn-race-pad-width) - 46px); max-width: 210px; height: 106px; }
  :root.turn-left-handed-controls body .manual-steer { right: var(--turn-edge); left: auto; }
  :root body .manual-steer-knob { width: 54px; }
  :root body .controls .utility-group {
    position: fixed; inset: auto var(--turn-edge) max(8px, env(safe-area-inset-bottom));
    display: flex; flex-wrap: nowrap; justify-content: flex-start; gap: 6px; transform: none;
  }
  /* One row, never two: buttons keep their natural width; what does not fit moves
     into the race ☰ (ui/race-menu.js). */
  :root body .utility-group .utility { flex: 0 0 auto; min-height: 44px; padding: 6px 10px; white-space: nowrap; font-size: max(var(--turn-text-floor), .66rem); }
  /* BOOST sits directly above the drive pad, next to the BOOST zone it reports on,
     instead of in the gap between the pad and the menu row. */
  /* It stays centred on its own left edge (translateX(-50%)), like everywhere else,
     so the full / empty / overcharge flash keyframes keep working unchanged. */
  :root body .boost-hud {
    left: calc(100% - var(--turn-edge) - (var(--turn-race-pad-width) / 2));
    bottom: calc(var(--turn-race-bottom) + var(--turn-race-pad-height) + 10px);
    width: var(--turn-race-pad-width);
  }
  :root.turn-left-handed-controls body .boost-hud { left: calc(var(--turn-edge) + (var(--turn-race-pad-width) / 2)); }
  /* Docked at the screen edge, OVERCHARGE widens the bar toward the road only, so its
     end stays on screen (#1313). The bar keeps translateX(-50%) for its keyframes; its
     centre moves by half the extra width instead. */
  :root body .boost-hud > div {
    left: calc(50% - var(--boost-overcharge-width) / 2);
    transition: left 80ms linear, width 80ms linear, background 120ms ease, box-shadow 120ms ease;
  }
  :root.turn-left-handed-controls body .boost-hud > div { left: calc(50% + var(--boost-overcharge-width) / 2); }
  :root body #scoreFeedback {
    top: auto; bottom: calc(var(--turn-race-bottom) + var(--turn-race-pad-height) + 54px);
    left: var(--turn-edge); right: var(--turn-edge); width: auto; height: var(--turn-score-panel-height);
    display: flex; flex-direction: row; justify-content: space-between;
    --turn-score-panel-height: 92px;
    --score-feedback-paper-height: var(--turn-score-panel-height);
  }
  :root.turn-left-handed-controls body #scoreFeedback { flex-direction: row-reverse; }
  :root body .score-feedback-row { flex: 0 0 min(32%, 180px); width: min(32%, 180px); height: var(--turn-score-panel-height); margin: 0; }
  /* A third of a phone is too narrow for LAST and BEST side by side once a record
     has four digits, so each gets its own line and the panel is tall enough for both. */
  :root body .score-feedback-history { flex-direction: column; align-items: flex-start; gap: 3px; }
  :root body .score-feedback-history .score-feedback-best { margin-left: 0; }
  :root body .score-feedback-state { padding: 7px; height: 100%; }
  :root body .score-feedback-heading, :root body .score-feedback-lap { font-size: max(var(--turn-text-floor), .5rem); }
  :root body .score-feedback-values strong { font-size: clamp(.9rem, 4vw, 1.25rem); }
  :root body .score-feedback-values b { font-size: max(var(--turn-text-floor), .65rem); }
  /* Each gauge is the same horizontal instrument as in landscape, tucked under its
     panel, so it never rises into the car's line. */
  :root body #scoreFeedback .score-feedback-gauge-shell {
    inset: calc(100% - 3px) 6px auto; width: auto; height: 22px;
    transform: translateZ(0) scaleX(1); transform-origin: left center;
  }
  :root body #scoreFeedback[data-drift-gauge-extended="false"] .score-feedback-gauge-shell[data-score-channel="drift"],
  :root body #scoreFeedback[data-flow-gauge-extended="false"] .score-feedback-gauge-shell[data-score-channel="flow"],
  :root body #scoreFeedback[data-drift-gauge-visible="false"] .score-feedback-gauge-shell[data-score-channel="drift"],
  :root body #scoreFeedback[data-flow-gauge-visible="false"] .score-feedback-gauge-shell[data-score-channel="flow"] { transform: translateZ(0) scaleX(0); }
  :root body #scoreFeedback :is(.score-feedback-meter, .score-feedback-gauge) { border-radius: 0 0 10px 10px; }
  :root body #scoreFeedback .score-feedback-callout { inset: auto auto 4px 4px; width: max-content; max-width: 38%; min-width: 0; padding: 4px; }
  :root body #scoreFeedback .score-feedback-callout[data-channel="flow"] { left: auto; right: 4px; }
  :root.turn-left-handed-controls body #scoreFeedback .score-feedback-callout[data-channel="drift"] { left: auto; right: 4px; }
  :root.turn-left-handed-controls body #scoreFeedback .score-feedback-callout[data-channel="flow"] { left: 4px; right: auto; }
  :root body .lap-result-toast,
  :root.turn-left-handed-controls body .lap-result-toast { inset: max(10px, env(safe-area-inset-top)) var(--turn-edge) auto; width: auto; height: auto; min-height: 70px; }
  :root body .message { top: 22%; max-width: calc(100% - 24px); }
}

/* Portrait with device rotation (Erik): no steering pad, so DRIFT above FLOW stand in
   its place, level with RESTART LAP, instead of either side of the car. They stay
   clear of the LOCK, SHIFT and R bubbles beside the drive pad, and handedness
   mirrors them with the pad. Steering-pad play keeps the panels above. The two
   gauges meet between the cards: DRIFT's hangs 19px below its card, FLOW's sits
   19px above its own, hence the gap. */
@media (orientation: portrait) and (min-width: 19.01em) and (min-height: 30.01em) {
  :root:has(.manual-steer[hidden]) body #scoreFeedback {
    --turn-score-stack-gap: 44px;
    bottom: var(--turn-race-bottom); left: var(--turn-edge); right: auto;
    width: min(max(calc((100vw - 2 * var(--turn-edge)) * .32), 114px), 180px, calc(100vw - 2 * var(--turn-edge) - var(--turn-race-pad-width) - 46px));
    height: auto; flex-direction: column; justify-content: flex-end; gap: var(--turn-score-stack-gap);
  }
  :root.turn-left-handed-controls:has(.manual-steer[hidden]) body #scoreFeedback { left: auto; right: var(--turn-edge); flex-direction: column; }
  :root:has(.manual-steer[hidden]) body .score-feedback-row { flex: 0 0 auto; width: 100%; }
  :root:has(.manual-steer[hidden]) body #scoreFeedback .score-feedback-gauge-shell[data-score-channel="flow"] { inset: auto 6px calc(100% - 3px); }
  :root:has(.manual-steer[hidden]) body #scoreFeedback .score-feedback-gauge-shell[data-score-channel="flow"] .score-feedback-gauge { border-radius: 10px 10px 0 0; }
  :root:has(.manual-steer[hidden]) body #scoreFeedback .score-feedback-callout,
  :root.turn-left-handed-controls:has(.manual-steer[hidden]) body #scoreFeedback .score-feedback-callout { inset: auto auto 4px 4px; max-width: calc(100% - 8px); }
  /* DRIFT's callout sits on the DRIFT card, above FLOW when FLOW shows. */
  :root:has(.manual-steer[hidden]) body #scoreFeedback:has(> .score-feedback-flow-row:not([hidden])) .score-feedback-callout[data-channel="drift"] {
    bottom: calc(var(--turn-score-panel-height) + var(--turn-score-stack-gap) + 4px);
  }
}

/* Emergency sizes: trade decoration/spacing before touch targets or content. */
@media (max-width: 22em) and (orientation: portrait) {
  :root { --turn-edge: max(8px, env(safe-area-inset-left), env(safe-area-inset-right)); --turn-race-pad-width: 136px; }
  :root body .manual-steer { border-width: 3px; }
  /* Keep race utility labels on one line so the menu rows stay 44px tall and clear
     of the drive pad. */
  :root body .utility-group .utility { padding-inline: 6px; white-space: nowrap; }
  :root body .manual-steer::before, :root body .manual-steer::after { font-size: 1.5rem; }
  /* DRIFT COMBO and a five-digit BEST need about 114px at the 11px text floor; a
     third of a 320px phone is 97px. The panels keep that minimum, with tighter
     spacing, and still leave the car its lane between them. */
  :root body .score-feedback-row { flex-basis: max(32%, 114px); width: max(32%, 114px); }
  :root body .score-feedback-state { padding: 6px 5px; }
  :root body :is(.score-feedback-heading, .score-feedback-lap, .score-feedback-history .score-feedback-lap) { letter-spacing: .03em; }
}
@media (max-height: 38em) and (orientation: portrait) {
  :root { --turn-race-pad-height: 168px; }
  :root body #scoreFeedback { --turn-score-panel-height: 84px; }
}
@media (max-height: 24em) {
  :root body .m8-dialog-card { padding: 12px; }
  :root body .m8-dialog-head { flex-wrap: wrap; }
}
.turn-orientation-status { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
/* The track loading TIP (#1041): a yellow card with the rotate-device symbol on a paper
   badge across its top edge, and one line to read before the track has loaded. */
:root body .turn-orientation-hint {
  position: absolute; inset: auto var(--turn-edge) max(20px, env(safe-area-inset-bottom));
  max-width: 420px; margin-inline: auto; padding: 36px 16px 16px;
  border: 3px solid var(--turn-outline); border-radius: 16px; background: var(--yellow); color: var(--turn-ink);
  box-shadow: 4px 4px 0 var(--turn-shadow-color); pointer-events: none; text-align: center;
}
.turn-orientation-icon {
  position: absolute; top: 0; left: 50%; display: grid; place-items: center; width: 64px; height: 50px;
  border: 3px solid var(--turn-outline); border-radius: 12px; background: var(--turn-surface-page); color: var(--turn-text);
  box-shadow: 3px 3px 0 var(--turn-shadow-color); transform: translate(-50%, -58%) rotate(-4deg);
}
.turn-orientation-icon svg { display: block; width: 40px; height: 40px; overflow: visible; }
.turn-orientation-phone { transform-box: fill-box; transform-origin: center; animation: turn-orientation-rotate 1.2s cubic-bezier(.3, 0, .2, 1) .35s both; }
@keyframes turn-orientation-rotate { from { transform: rotate(0deg); } to { transform: rotate(90deg); } }
.turn-orientation-hint strong { display: block; font-size: max(var(--turn-text-floor, 11px), 1rem); font-weight: 1000; line-height: 1.15; letter-spacing: .02em; }
/* Over a staged race the TIP is a compact chip: the symbol beside its line, just under
   the race message (STEERING CENTRED), so the cars and HUD stay in view (#1238). */
:root body .turn-orientation-hint.is-staged {
  z-index: 30; top: 22%; bottom: auto; margin-top: 56px;
  display: flex; align-items: center; gap: 10px;
  width: max-content; max-width: min(340px, calc(100% - 2 * var(--turn-edge)));
  padding: 6px 14px 6px 6px; border-radius: 12px; text-align: start;
}
:root body .turn-orientation-hint.is-staged .turn-orientation-icon {
  position: static; flex: none; width: 40px; height: 36px;
  border-width: 2px; border-radius: 9px; box-shadow: none; transform: none;
}
:root body .turn-orientation-hint.is-staged .turn-orientation-icon svg { width: 28px; height: 28px; }
:root body .turn-orientation-hint.is-staged strong { font-size: max(var(--turn-text-floor, 11px), 0.8125rem); }
@media (prefers-reduced-motion: reduce) {
  .turn-orientation-phone { animation: none; }
}
@media (prefers-reduced-motion: reduce) {
  :root body #scoreFeedback * { animation: none !important; transition: none !important; }
}

@media (max-width: 19em), (max-height: 30em) and (orientation: portrait) {
  :root { --turn-race-pad-width: 120px; --turn-race-pad-height: 128px; }
  :root:has(.utility-group[data-menu-state]) { --turn-race-footer: 56px; }
  :root body .controls .utility-group { flex-wrap: nowrap; justify-content: flex-start; overflow-x: auto; pointer-events: auto; padding: 0 3px 3px 0; margin: 0 -3px -3px 0; }
  :root body .utility-group .utility { flex: 0 0 auto; }
  :root body .drive-stack { --drift-lock-bubble-width: 30px; --shift-bubble-width: 30px; --reverse-bubble-width: 30px; }
  :root body .manual-steer { height: 76px; width: calc(100vw - 2 * var(--turn-edge) - var(--turn-race-pad-width) - 36px); }
  :root body .manual-steer-knob { width: 40px; }
  :root body .map-wrap { display: none; }
  :root body .stats { gap: 3px; }
  :root body .stats .chip { padding: 4px; min-height: 32px; }
  :root body .stats .chip strong { font-size: max(var(--turn-text-floor), .66rem); }
  :root body #scoreFeedback { top: 80px; bottom: auto; height: 44px; }
  :root body .score-feedback-row { height: 44px; flex-basis: 45%; width: 45%; }
  :root body .score-feedback-state { padding: 3px 5px; }
  :root body .score-feedback-values strong { font-size: .9rem; }
  :root body #scoreFeedback .score-feedback-gauge-shell { height: 8px; }
  /* Score and COMBO only: the LAP footer and the LAST/BEST records give way here. */
  :root body :is(.score-feedback-footer, .score-feedback-history) { display: none; }
}

/* Touch targets: every control reaches --turn-target-min in every orientation
   (WCAG 2.5.5). Text buttons grow to the minimum height; small icon controls keep
   their visual size and gain a transparent hit area instead. GARAGE's step and
   rotate buttons are 44px targets in their own right. */
:root body :is(.turn-music-home-toggle, .m8-home-menu > button, .garage-shift-trigger, .utility-group .utility) {
  min-height: var(--turn-target-min);
}
:root body .utility-group .utility {
  min-width: var(--turn-target-min);
}
:root body :is(.m8-about-trigger) {
  position: relative;
}
:root body :is(.m8-about-trigger)::after {
  content: "";
  position: absolute;
  inset: min(0px, calc((100% - var(--turn-target-min)) / 2));
}

/* Trophy Road tiles: at the 11px floor a tile cannot also carry the reward name and
   state word (both were truncated or overlapping at every width), so it shows the
   icon, the threshold and the earned / locked badge. The name and state stay in each
   button's accessible name and in the detail sheet; NEXT keeps its outline and the
   NEXT summary card above the road. */
:root body .turn-trophy-road-marker small,
:root body .turn-trophy-road-marker .turn-trophy-road-marker-state {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
:root body .turn-trophy-road-landmark b {
  white-space: nowrap;
}

/* Race ACHIEVEMENTS is the same trophy button as on Home's app bar: an icon with the
   count beside it. The word stays as the accessible name (achievements/view.js),
   and the row keeps room for every label at full length. */
:root body .utility-group .turn-race-achievements-button {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 56px;
  padding-inline: 12px;
}
:root body .utility-group .turn-race-achievements-button::before {
  content: "";
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
  background: currentColor;
  -webkit-mask: var(--turn-trophy-icon) center / contain no-repeat;
  mask: var(--turn-trophy-icon) center / contain no-repeat;
}
:root body .utility-group .turn-race-achievements-button .turn-achievements-trigger-label {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
:root body .utility-group .turn-race-achievements-button .turn-achievements-trigger-badge {
  position: static;
  width: auto;
  min-width: 22px;
  height: 22px;
  padding: 0 5px;
  line-height: 18px;
  transform: none;
  box-shadow: none;
}
/* The blank-screen eye is a square icon control: it keeps 44 × 44 instead of
   growing with the row (its aspect ratio would otherwise make the whole row taller). */
:root body .utility-group .turn-screen-blank-control {
  flex: 0 0 var(--turn-target-min);
  width: var(--turn-target-min);
  height: var(--turn-target-min);
}
/* HUD digits are tabular in every orientation, so a changing time or speed never
   shifts its label or neighbours. */
:root body :is(.stats .chip strong, .stats .chip strong span, #scoreFeedback strong) {
  font-variant-numeric: tabular-nums;
}

/* Landscape race: utility labels never truncate. If a row ever outgrows the space
   beside the drive pad it scrolls sideways instead, and BOOST keeps clear air
   above it. A scrolling row clips at its padding edge, so the row carries room for
   the buttons' 3px control shadow (padding) without moving them (margin). */
@media (orientation: landscape) {
  :root body .utility-group .utility { flex: 0 0 auto; }
  :root body .controls .utility-group { min-width: 0; overflow-x: auto; scrollbar-width: none; justify-content: flex-start; padding: 0 3px 3px 0; margin: 0 -3px -3px 0; }
  :root.turn-left-handed-controls body .controls .utility-group { justify-content: flex-end; }
  /* Clear air between the action row and the drive pad. */
  :root body .controls { column-gap: 24px; }
}
@media (orientation: landscape) and (max-height: 500px) {
  :root body .boost-hud { bottom: calc(max(8px, env(safe-area-inset-bottom)) + var(--turn-target-min) + 20px); }
}
