* { box-sizing: border-box; }

html, body {
  margin: 0;
  min-height: 100%;
  background: #03060a;
  color: #fff;
  font-family: Arial, Helvetica, sans-serif;
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
}

/* mockup frame is 1448 x 1086 */
.cabinet {
  width: min(100vw, calc(100vh * 1448 / 1086));
  width: min(100vw, calc(100dvh * 1448 / 1086)); /* iOS Safari dynamic toolbar */
  aspect-ratio: 1448 / 1086;
  box-shadow: 0 28px 80px rgba(0,0,0,.75);
  /* 1em = 1/100 of cabinet width */
  font-size: min(1vw, calc(100vh * 1448 / 1086 / 100));
  font-size: min(1vw, calc(100dvh * 1448 / 1086 / 100));
}

.game {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: url("assets/bg.png") center / 100% 100% no-repeat;
}

/* ---- difficulty (measured rects) ---- */

.hardLabel {
  position: absolute;
  left: 85.704%;
  top: 4.05%;
  width: 11.603%;
  height: 2.45%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #d20100;
  font-size: 2.3em;
  font-weight: 700;
  letter-spacing: .04em;
  white-space: nowrap;
  text-shadow: .06em .08em .08em rgba(0,0,0,.9);
}

.stars {
  position: absolute;
  left: 85.704%;
  top: 6.722%;
  width: 11.603%;
  height: 2.578%;
}

.stars img {
  position: absolute;
  top: 0;
  height: 100%;
  width: auto;
}
.stars img:nth-child(1) { left: 0; }
.stars img:nth-child(2) { left: 20.84%; }
.stars img:nth-child(3) { left: 41.67%; }
.stars img:nth-child(4) { left: 61.91%; }
.stars img:nth-child(5) { left: 82.74%; }

/* ---- speech bubble text ---- */

.bubbleText {
  position: absolute;
  left: 5.525%;
  top: 64.457%;
  width: 14.641%;
  height: 7.827%;
  display: grid;
  place-items: center;
  text-align: center;
  color: #fff;
  font-size: 2.25em;
  font-style: italic;
  font-weight: 700;
  line-height: 1.15;
  text-shadow: .07em .09em .09em rgba(0,0,0,.85);
}

/* ---- lives ---- */

.hearts {
  position: absolute;
  left: 6.285%;
  top: 81.676%;
  width: 14%;
  height: 4.788%;
}

.hearts img {
  position: absolute;
  top: 0;
  height: 100%;
  width: auto;
}
.hearts img:nth-child(1) { left: 0; }
.hearts img:nth-child(2) { left: 33.11%; }
.hearts img:nth-child(3) { left: 66.22%; }
.hearts img.lost { filter: grayscale(1) brightness(.4); }

/* ---- board (measured grid rect) ---- */

.board {
  position: absolute;
  left: 27.348%;
  top: 19.061%;
  width: 49.378%;
  height: 55.249%;
}

.cell {
  position: absolute;
  z-index: 0;
  display: grid;
  place-items: center;
  background: transparent;
  font-family: Arial, Helvetica, sans-serif;
  font-size: 3.35em;
  font-weight: 700;
  line-height: 1;
  user-select: none;
  cursor: pointer;
}

.cell:not(.given) { color: #0b3fb0; }
.cell.given { color: #1a1a1a; }

.cell.selected::before {
  content: "";
  position: absolute;
  inset: 7% 8%;
  background: #8ed4f2;
  border: .12em solid #e21a1a;
  border-radius: .06em;
  box-shadow: inset 0 0 .3em rgba(255,255,255,.6);
  z-index: -1;
}

.cell.same::before {
  content: "";
  position: absolute;
  inset: 9% 10%;
  background: rgba(255, 225, 120, .75);
  z-index: -1;
}

.cell.wrong { color: #8c000a; }
.cell.wrong::before {
  content: "";
  position: absolute;
  inset: 9% 10%;
  background: rgba(255, 90, 107, .65);
  z-index: -1;
}

.cell.good::before {
  content: "";
  position: absolute;
  inset: 9% 10%;
  background: rgba(103, 234, 165, .6);
  z-index: -1;
}

.cell.selected.wrong::before,
.cell.selected.good::before {
  inset: 7% 8%;
  border: .12em solid #e21a1a;
}

/* ---- number pad (contiguous original tiles) ---- */

.numberPad {
  position: absolute;
  z-index: 12;
  left: 26.796%;
  top: 78.361%;
  width: 51.934%;
  height: 10.589%;
  display: grid;
  grid-template-columns: repeat(9, 1fr);
}

.numberPad button {
  position: relative;
  min-width: 0;
  padding: 0;
  border: 0;
  background-color: transparent;
  cursor: pointer;
  font-size: 0;
  overflow: hidden;
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.numberPad button .padSprite {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  opacity: 1;
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* Mobile Safari was still flashing a blank tile when the selected sprite
   became visible before it had painted. Keep the normal tile visible at all
   times and place the selected tile over it. If the selected art takes a
   frame to paint, the normal art remains underneath instead of a blank gap. */
.numberPad button .padSprite.norm { opacity: 1; }
.numberPad button .padSprite.sel { opacity: 0; }
.numberPad button[data-state="sel"] .padSprite.sel { opacity: 1; }

.numberPad button:active { opacity: 1; }

/* ---- LCD readouts (measured rects) ---- */

.lcd {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  line-height: 1;
  color: #e9cd22;
  font-family: "Courier New", monospace;
  font-weight: 700;
  font-style: italic;
  white-space: nowrap;
  text-shadow: 0 0 .28em rgba(190, 255, 30, .45);
}

.lcdTimer  { left: 84.461%; top: 28.637%; width: 10.704%; height: 5.157%; font-size: 3.22em; }
.lcdScore  { left: 83.840%; top: 45.396%; width: 12.155%; height: 4.420%; font-size: 2.16em; }
.lcdPuzzle { left: 86.188%; top: 61.142%; width: 8.287%;  height: 4.236%; font-size: 2.785em; }
.lcdHints  { left: 89.572%; top: 76.611%; width: 4.144%;  height: 3.407%; font-size: 2.5em; }
.lcdHints i, .lcdPuzzle i {
  font-style: italic;
  font-family: Arial, sans-serif;
  font-weight: 700;
  font-size: .72em;
  margin: 0 .1em;
}

/* ---- tap zones over the baked controls bar ---- */

.legendZone {
  position: absolute;
  top: 91%;
  height: 9%;
  border: 0;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.legendZone:active { background: rgba(255,255,255,.08); }

.panelZone {
  position: absolute;
  left: 82.5%;
  top: 74%;
  width: 15.5%;
  height: 10.5%;
  border: 0;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* ---- menu overlay ---- */

.menuPanel {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  background: rgba(0, 0, 0, .72);
  z-index: 50;
}

.menuPanel.hidden { display: none; }

/* Blur what's BEHIND an open menu by filtering the underlying content,
   not with backdrop-filter. backdrop-filter mirror-reflected the number
   pad at the clipped viewport edge on mobile (a Blink bug in this
   overflow:hidden / dvh layout). A plain filter blurs cleanly with no
   phantom reflection. The panels themselves stay sharp. */
.game:has(> .menuPanel:not(.hidden)) > :not(.menuPanel) {
  filter: blur(3px);
}

.menuCard {
  width: min(72%, 760px);
  border-radius: 1.4em;
  padding: 2em;
  background: linear-gradient(180deg, rgba(6,20,44,.97), rgba(3,8,18,.98));
  border: .13em solid rgba(255,255,255,.18);
  box-shadow: 0 2em 5em rgba(0,0,0,.6);
  text-align: center;
}

.menuCard h1 {
  margin: 0 0 .3em;
  text-transform: uppercase;
  font-size: 4.6em;
  font-weight: 900;
  font-style: italic;
  line-height: .9;
  color: white;
  text-shadow: .07em .07em 0 #d00000, .13em .13em 0 #001b55;
}

.menuCard p {
  color: #cbeaff;
  font-size: 1.6em;
}

.menuCard label {
  display: block;
  margin: 1em auto .35em;
  font-size: 1.5em;
  font-weight: 900;
  text-transform: uppercase;
}

.menuCard select,
.menuCard button {
  width: min(360px, 90%);
  display: block;
  margin: .6em auto;
  padding: .85em 1em;
  border: 0;
  border-radius: .75em;
  font-size: 1.8em;
  font-weight: 900;
}

.menuCard select {
  background: #e2f8ff;
  color: #08101b;
}

.menuCard button {
  cursor: pointer;
  background: linear-gradient(180deg, #ffe984, #ff8e00);
  color: #09101b;
  box-shadow: 0 .3em 0 #8a3d00;
}

/* ---- end screen ---- */

.endPanel { z-index: 40; }

.endStats {
  display: flex;
  justify-content: center;
  gap: 3em;
  margin: 1.2em 0 .4em;
}

.endStats span {
  display: block;
  font-size: 1.4em;
  font-weight: 900;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: #9db8d6;
}

.endStats strong {
  display: block;
  margin-top: .15em;
  font-family: "Courier New", monospace;
  font-style: italic;
  font-size: 2.4em;
  color: #e9cd22;
  text-shadow: 0 0 .28em rgba(233, 205, 34, .45);
}


.builderBadge {
  display: block;
  width: min(46%, 330px);
  margin: .4em auto 1em;
  line-height: 0;
  opacity: .96;
  transition: transform .12s ease, opacity .12s ease;
}

.builderBadge:hover,
.builderBadge:focus-visible {
  opacity: 1;
  transform: scale(1.025);
}

.builderBadge img {
  display: block;
  width: 100%;
  height: auto;
  filter: drop-shadow(0 .35em .65em rgba(0,0,0,.55));
}

.menuCard button.secondary {
  background: linear-gradient(180deg, #dfe9f2, #93a5b5);
  box-shadow: 0 .3em 0 #4a5966;
}

/* ---- splash logo ---- */

.welcome {
  margin: 0 0 .5em;
  color: #cbeaff;
  font-size: 1.9em;
  font-style: italic;
  font-weight: 700;
}

.menuLogo {
  display: block;
  width: 88%;
  max-width: 640px;
  margin: 0 auto .8em;
  filter: drop-shadow(0 .5em 1.2em rgba(0,0,0,.6));
}

/* ---- touch behaviour ---- */

html, body { overflow: hidden; }

.game, .game * {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
}

.menuCard select { user-select: auto; }

/* ---- rotate prompt (small portrait screens only) ---- */

.rotate {
  position: absolute;
  inset: 0;
  z-index: 80;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5em;
  background: rgba(2, 6, 14, .96);
  text-align: center;
}

.rotate img { width: 78%; max-width: 480px; }
.rotate p { margin: 0; font-size: 2.2em; font-weight: 700; font-style: italic; color: #cbeaff; }
.rotate span { font-size: 5em; color: #ffb400; animation: spinhint 2s ease-in-out infinite; }

@keyframes spinhint {
  0%, 100% { transform: rotate(0deg); }
  50% { transform: rotate(-90deg); }
}

@media (orientation: portrait) and (max-width: 740px) {
  .rotate { display: flex; }
}

/* ---- touch control bar (coarse pointers only) ---- */

.mobileBar {
  display: none;
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  top: 92.1%;
  height: 7.9%;
  z-index: 10;
  background: #060606;
  align-items: stretch;
  justify-content: space-evenly;
  padding-bottom: max(env(safe-area-inset-bottom, 0px), 6px);
}

.mobileBar button {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .6em;
  border: 0;
  background: transparent;
  color: #e8e8e8;
  font-family: Arial, sans-serif;
  font-size: 1.5em;
  font-weight: 900;
  letter-spacing: .04em;
  white-space: nowrap;
  text-shadow: .07em .09em .07em #000;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.mobileBar button:active { background: rgba(255,255,255,.07); }
.mobileBar img { height: 2.9em; width: auto; } /* matches the baked circle size */

/* The right-hand label sat a touch too close to the screen edge in
   portrait, so bias that one button slightly left without disturbing
   the rest of the bar alignment. */
#mMenuBtn { padding-right: .8em; }

@media (pointer: coarse) {
  .mobileBar { display: flex; }
  .legendZone { display: none; }
}

.portraitLogo { display: none; }
.rooneyAvatar { display: none; }   /* portrait-only; desktop has him in bg.png */

/* ================= PORTRAIT LAYOUT - mobile browsers only ================= */

@media (orientation: portrait) and (pointer: coarse) {
  .rotate { display: none !important; }

  .cabinet {
    width: 100vw;
    aspect-ratio: auto;
    height: 100vh;
    height: 100dvh;
    font-size: 1vw;
  }

  .game {
    display: flex;
    flex-wrap: wrap;
    flex-direction: row;
    align-content: center;
    align-items: flex-start;
    gap: 1.6vw;
    padding: 2vw 2vw calc(56px + env(safe-area-inset-bottom, 0px));
    background: linear-gradient(180deg, #050b16 0%, #0a1730 45%, #0c2410 100%);
  }

  .hardLabel, .stars, .panelZone { display: none; }

  /* Menu / pause / end cards: the whole card is sized in em, which in
     portrait was scaling off .cabinet's 1vw font (~4px) and rendering
     microscopic. Re-root the em scale on the panel so the card and all
     its contents come up to a legible mobile size in one place. */
  .menuPanel { font-size: 2.6vw; }
  .menuCard  {
    width: min(88%, 440px);
    padding: 1.5em 1.3em;
    border-radius: 1.1em;
  }
  .menuCard h1 { font-size: 3.9em; }
  .menuLogo { width: 84%; }
  .builderBadge { width: min(56%, 260px); margin: .5em auto .85em; }

  .portraitLogo {
    display: block;
    order: 1;
    width: 100%;
    height: auto;
  }

  .lcd {
    order: 2;
    position: static;
    width: calc(25% - 1.2vw);
    aspect-ratio: 270 / 162;
    background-size: 100% 100%;
    background-repeat: no-repeat;
    display: flex;
    align-items: center;
    justify-content: center;
    height: auto;
    left: auto; top: auto;
  }

  #timer       { background-image: url("assets/p_timer.png");  padding-top: 2.03vw; font-size: 3.94vw; }
  #score       { background-image: url("assets/p_score.png");  padding-top: 2.03vw; font-size: 2.64vw; }
  #puzzleCount { background-image: url("assets/p_puzzle.png"); padding-top: 2.03vw; font-size: 3.41vw; }
  #hints       { background-image: url("assets/p_hints.png");  padding-top: 2.11vw; font-size: 3.06vw; }

  /* Portrait speech bubble + LIVES box are drawn in CSS, not from the
     photographic reference crops. Those crops carried baked-in fringe
     (p_lives had a shirt-red border ring, p_bubble sat on a dark base)
     that looked like garbage on the flat portrait background. Clean
     vector panels in the same palette instead. Desktop/landscape still
     use the arcade art. */
  .controlsHelp { display: none; }   /* strip control instructions in portrait */

  /* Rooney speaker avatar: circular head-and-shoulders crop taken from the
     bg art at his detected face position, framed with a light ring + soft
     shadow. Sits at the start of the bubble row so he appears to be saying
     the hint line. Uses horizontal space only - the board keeps its size. */
  .rooneyAvatar {
    display: block;
    order: 3;
    align-self: center;
    width: 17%;
    height: auto;
    aspect-ratio: 1 / 1;
    border-radius: 50%;
    object-fit: cover;
    border: .5vw solid #dfe7ef;
    box-shadow: 0 .6vw 1.6vw rgba(0,0,0,.55), 0 0 0 .18vw rgba(0,0,0,.5);
    background: #0a0c10;
  }

  .bubbleText {
    order: 3;
    position: relative;
    align-self: center;
    width: 45%;
    left: auto; top: auto;
    height: auto;
    min-height: 26vw;
    background: linear-gradient(180deg, #163a68 0%, #0b2142 100%);
    border: .55vw solid #7fbdec;
    border-radius: 3.2vw;
    box-shadow: inset 0 0 3vw rgba(130,190,245,.22), 0 1vw 2.4vw rgba(0,0,0,.5);
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    overflow: visible;
    padding: 3.2vw 3.4vw;
    font-size: 4.6vw;
    line-height: 1.14;
  }

  .bubbleText::before {          /* tail border, points left toward Rooney */
    content: "";
    position: absolute;
    left: -3.4vw;
    top: 50%;
    transform: translateY(-50%);
    width: 0; height: 0;
    border-top: 3vw solid transparent;
    border-bottom: 3vw solid transparent;
    border-right: 3.4vw solid #7fbdec;
  }
  .bubbleText::after {           /* tail fill */
    content: "";
    position: absolute;
    left: -2.4vw;
    top: 50%;
    transform: translateY(-50%);
    width: 0; height: 0;
    border-top: 2.4vw solid transparent;
    border-bottom: 2.4vw solid transparent;
    border-right: 2.6vw solid #163a68;
  }

  .hearts {
    order: 4;
    position: relative;
    align-self: center;
    width: calc(34% - 1.6vw);
    height: auto;
    left: auto; top: auto;
    aspect-ratio: 354 / 159;
    background: linear-gradient(180deg, #23272f 0%, #0a0c10 100%);
    border: .6vw solid #bd1c1c;
    border-radius: 2.4vw;
    box-shadow: inset 0 0 3vw rgba(0,0,0,.7), 0 0 2vw rgba(189,28,28,.4);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2.2vw;
    overflow: hidden;
  }

  .hearts::before {
    content: "LIVES";
    position: absolute;
    top: 1.4vw; left: 0; right: 0;
    text-align: center;
    color: #e7eef6;
    font: 900 2.6vw/1 Arial, sans-serif;
    letter-spacing: .16em;
  }

  .hearts img {
    position: static;
    height: 6vw;
    width: auto;
    margin-top: 3.8vw;         /* clear the LIVES label */
  }

  .boardWrap {
    order: 5;
    position: relative;
    left: auto; top: auto;
    width: min(100%, calc((100dvh - 400px) * 812 / 694));
    margin: 0 auto;
    height: auto;
    aspect-ratio: 812 / 694;
    background: url("assets/p_boardframe.png") center / 100% 100% no-repeat;
    container-type: inline-size;
  }

  .board {
    position: absolute;
    /* NOTE: no `inset` shorthand here - it would reset left/top to auto
       and shift the whole grid off the frame (the V19 portrait bug). */
    left: 5.91%;
    top: 7.06%;
    width: 88.05%;
    height: 86.46%;
  }

  .cell { font-size: 6.78cqw; }

  .numberPad {
    order: 6;
    position: static;
    width: 100%;
    height: auto;
    left: auto; top: auto;
    aspect-ratio: 752 / 115;
  }

  .mobileBar {
    top: auto;
    bottom: 0;
    height: calc(50px + env(safe-area-inset-bottom, 0px));
    padding-bottom: max(env(safe-area-inset-bottom, 0px), 8px);
  }

  .mobileBar button { font-size: 14px; }
  .mobileBar img { height: 26px; }
  #mMenuBtn { padding-right: 10px; }
}
