/* Furball Rodeo: the page around the room. Every colour, font, size, space and
   radius that matters comes from tokens.css; there are no literal colours
   here, and scripts/test/contrast.test.mjs checks that. Layout: one screen. A
   petrol HUD strip on top, the room filling the rest, cards over a scrim for
   the title and the end of a round. */
html,body{height:100%}
body{
  margin:0;background:var(--petrol);color:var(--paper);
  font-family:var(--font-body);overflow:hidden;overscroll-behavior:none;
  -webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;
}
/* The safe area: --safe-area-inset-* where the shell sets it (Capacitor 8's
   SystemBars does on Android, where env() is 0 under edge-to-edge), env()
   otherwise (iOS, the web). */
#app{
  height:100%;box-sizing:border-box;display:flex;flex-direction:column;
  /* the room and the cards stay out of the home indicator's band (the iOS
     shell is full-bleed); the HUD clears the top itself */
  padding-bottom:var(--safe-area-inset-bottom,env(safe-area-inset-bottom,0px));
}

.hud{
  display:flex;align-items:flex-end;gap:var(--s3);
  /* clear the status bar, notch, camera hole and Dynamic Island where the page
     runs under them (index.html has viewport-fit=cover; the shells are
     full-bleed and full screen) */
  padding-top:max(8px,var(--safe-area-inset-top,env(safe-area-inset-top,0px)));
  padding-bottom:10px;
  padding-left:max(var(--s4),var(--safe-area-inset-left,env(safe-area-inset-left,0px)));
  padding-right:max(var(--s4),var(--safe-area-inset-right,env(safe-area-inset-right,0px)));
  background:var(--petrol);
}
.stat{display:flex;flex-direction:column;gap:3px;min-width:0}
.lab{font:600 var(--text-xs)/1 var(--font-body);letter-spacing:.1em;text-transform:uppercase;color:var(--mist)}
.val{font:400 var(--display-lg)/1 var(--font-display);color:var(--marigold);font-variant-numeric:tabular-nums}
.val.sm{font-size:var(--display-md);color:var(--paper)}
.combo{align-self:center;background:var(--marigold);color:var(--petrol);font:400 var(--display-sm)/1 var(--font-display);padding:6px 11px;border-radius:var(--r-pill)}
.combo[hidden]{display:none}
.lives{margin-left:auto;display:flex;flex-direction:column;gap:6px;align-items:flex-end}
.lives .lab{white-space:nowrap}
.pips{display:flex;gap:6px;height:16px;align-items:center}
.pip{width:14px;height:14px;box-sizing:border-box;border-radius:50%;background:var(--signal)}
.pip.gone{background:transparent;box-shadow:inset 0 0 0 2px var(--mist)}

/* The HUD's buttons: pause while a round runs, home and settings on a card.
   Icons are drawn in currentColor: mist, the HUD label colour, already
   measured against petrol. */
.hudbtn{
  align-self:center;flex:none;width:var(--target);height:var(--target);margin-left:calc(-1*var(--s2));margin-right:-10px;
  display:grid;place-items:center;padding:0;border:0;border-radius:var(--r-pill);
  background:transparent;color:var(--mist);cursor:pointer;
}
.hudbtn[hidden]{display:none}
/* the recorder's dot: signal red, beside the strip's button, only while recording is on */
.rec{align-self:flex-end;flex:none;width:10px;height:10px;margin-bottom:3px;border-radius:50%;background:var(--signal)}
.rec[hidden]{display:none}
#playtestRows[hidden]{display:none}
.hudbtn svg{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:3;stroke-linecap:round;stroke-linejoin:round}
.hudbtn:focus-visible{outline:var(--focus-width) solid var(--focus-on-petrol);outline-offset:-2px}
/* On a card the strip is the way around the cards: settings where pause is in
   a round, and home at the left end over the score. The round's numbers step
   aside for home, kept in place so the room below never moves, except on the
   pause card, where how the round stands is still worth seeing. */
.hud{position:relative}
.hud.cards :is(.stat,.combo,.lives){visibility:hidden}
#home{position:absolute;bottom:10px;margin:0;left:calc(max(var(--s4),var(--safe-area-inset-left,env(safe-area-inset-left,0px))) - 12px)}
#gear svg{stroke-width:2}

#stage{position:relative;flex:1;min-height:0;background:var(--petrol)}
#cv{position:absolute;inset:0;width:100%;height:100%;display:block;touch-action:none}

/* The banner over the room: a level's name, or an introduction with one line
   on how the new thing works. It sits on a petrol plate so it reads on the
   light floor, and it is never wider than the phone (--display-banner). */
#banner{
  position:absolute;left:50%;top:18%;transform:translateX(-50%);
  width:max-content;max-width:calc(100% - 2*var(--s4));box-sizing:border-box;
  padding:var(--s3) var(--s5) 14px;border-radius:var(--r-lg);background:var(--plate);
  text-align:center;pointer-events:none;
  font:400 var(--display-banner)/1.05 var(--font-display);color:var(--marigold);
}
#banner[hidden]{display:none}
#banner.show{animation:bannerpop var(--dur-banner) ease-out both}
#banner small{
  display:block;margin:var(--s2) auto 0;max-width:300px;
  font:600 var(--text-lg)/1.3 var(--font-body);color:var(--paper);
}
#banner.intro.show{animation-duration:var(--dur-intro)}
@keyframes bannerpop{
  0%{transform:translateX(-50%) scale(.6);opacity:0}
  15%{transform:translateX(-50%) scale(1.1);opacity:1}
  30%{transform:translateX(-50%) scale(1)}
  80%{opacity:1}
  100%{opacity:0;transform:translateX(-50%) scale(1.04)}
}

.overlay{
  /* the card is centred by its own auto margins, not by align-items: a card
     taller than the space would otherwise overflow at the top too, out of
     reach of scrolling (seen in Brave on Android, whose bars leave less room) */
  position:absolute;inset:0;display:flex;
  /* scrolls when a card is taller than the room, up and down only, and the
     scroll never hands over to the page or bounces the room behind it */
  background:var(--scrim);overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;
  /* below the HUD and above #app's bottom padding already, so no top or bottom safe area here */
  padding-block:var(--s4);
  padding-left:max(var(--s4),var(--safe-area-inset-left,env(safe-area-inset-left,0px)));
  padding-right:max(var(--s4),var(--safe-area-inset-right,env(safe-area-inset-right,0px)));
}
.overlay[hidden]{display:none}
.card{
  margin:auto;width:min(100%,360px);box-sizing:border-box;background:var(--paper);color:var(--petrol);
  padding:var(--s5) var(--s5) 18px;border-radius:var(--r-lg);box-shadow:0 18px 40px rgba(var(--petrol-rgb),.45);
}
.card[hidden]{display:none}
/* One focus ring for everything on a card: petrol, with a gap of paper between
   ring and control, so it reads around petrol-filled buttons too. Headings
   take focus when a card opens (game.js showCard) but draw no ring: no key
   reaches them (tabindex -1), the card appearing is the change, and the next
   Tab lights the first button. */
.card :is(button,a):focus-visible{outline:var(--focus-width) solid var(--focus-on-paper);outline-offset:var(--focus-gap)}
.card :is(h1,h2):focus{outline:none}
.kicker{margin:0;font:700 var(--text-xs)/1 var(--font-body);letter-spacing:.16em;text-transform:uppercase;color:var(--petrol-2)}
.card h1,.card h2{font:400 var(--display-xl)/.95 var(--font-display);margin:6px 0 10px;text-wrap:balance}
.lead{margin:0 0 var(--s3);font:400 var(--text-md)/1.4 var(--font-body)}
.rules{display:flex;flex-wrap:wrap;gap:var(--s2);margin:0}
.rules dt{align-self:start;background:var(--marigold);padding:var(--s1) 9px;border-radius:var(--r-sm);font:700 var(--text-xs)/1.2 var(--font-body);letter-spacing:.08em;text-transform:uppercase}
.rules dd{margin:0;font:400 var(--text-md)/1.35 var(--font-body);min-width:0}
.rules>div{flex:1 0 100%;display:flex;align-items:baseline;gap:var(--s3)}   /* one move each; those unlocked later stay hidden until then */
.rules>div[hidden]{display:none}
.rules>div.known{flex:none}         /* a move met before the newest: its tag alone, side by side */
.rules>div.known dd{display:none}
.rules dt .what{display:none}
.rules>div.known dt .what{display:inline}   /* known: the pill says what the move is for ("Tap to clap"), as a bare verb said nothing (the owner, 2026-10-27) */
.gain{margin:0 0 var(--s3);font:400 var(--display-lg)/1 var(--font-display);color:var(--petrol)}
/* stars for a cleared level: earned ones marigold with a petrol edge, the rest an outline */
.stars{margin:-4px 0 var(--s3);font:400 2.5rem/1 system-ui,sans-serif;letter-spacing:4px}
.stars[hidden]{display:none}
.stars span{color:transparent;-webkit-text-stroke:2px var(--petrol-2)}
.stars span.on{color:var(--marigold);-webkit-text-stroke:2px var(--petrol)}

/* A quiet Back at the top of a long card (the cattery), for the thumb; the
   same card keeps a full-width one at its foot. */
.back{
  display:inline-flex;align-items:center;gap:var(--s1);min-height:var(--target);margin:-10px 0 var(--s1) -10px;padding:0 var(--s3) 0 var(--s2);
  border:0;border-radius:var(--r-pill);background:transparent;color:var(--petrol);font:700 var(--text-sm)/1 var(--font-body);cursor:pointer;
}
.back[hidden]{display:none}
.back svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}

/* Under Play on the title: where the player is (level and room) and the way
   into the picker, then the cattery. The result card pairs two quiet buttons
   side by side (.duo). */
.where{
  margin-top:var(--s2);width:100%;min-height:var(--target);display:flex;align-items:center;gap:var(--s3);
  padding:var(--s2) var(--s3) var(--s2) var(--s4);border:0;border-radius:var(--r-pill);background:transparent;color:var(--petrol);
  box-shadow:inset 0 0 0 2px var(--petrol);text-align:left;cursor:pointer;font:inherit;
}
.where[hidden]{display:none}
.where .words{display:flex;flex-direction:column;gap:3px;flex:1;min-width:0}
.where b{font:400 var(--display-sm)/1 var(--font-display)}
.where small{font:600 var(--text-sm)/1.2 var(--font-body);color:var(--petrol-2)}
.where svg{width:20px;height:20px;flex:none;fill:none;stroke:currentColor;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.duo{display:flex;gap:var(--s2);margin-top:var(--s2)}
.duo .cta{margin-top:0;flex:1;min-width:0}

/* The picker card: a row per room, its name left and where it stands right
   (levels cleared, what opens it, Unlock, In the app); the open room is
   petrol and its levels sit in an outlined body under it. A room not
   playable yet is disabled and its state says why. */
.rooms{list-style:none;margin:var(--s3) 0 0;padding:0;display:grid;gap:var(--s2)}
.room{
  width:100%;min-height:var(--target);display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  padding:var(--s2) var(--s4);border:0;border-radius:var(--r-md);background:transparent;color:var(--petrol);box-shadow:inset 0 0 0 2px var(--petrol);
  font:400 var(--display-sm)/1.1 var(--font-display);text-align:left;cursor:pointer;
}
.room small{flex:none;font:600 var(--text-sm)/1.2 var(--font-body);color:var(--petrol-2);text-align:right}
.room[aria-expanded="true"]{background:var(--petrol);color:var(--marigold);box-shadow:none;border-radius:var(--r-md) var(--r-md) 0 0}
.room[aria-expanded="true"] small{color:var(--paper)}
/* dashed: a row that says where a room stands, not a button to press */
.room:disabled{color:var(--petrol-2);box-shadow:none;outline:2px dashed var(--petrol-2);outline-offset:-2px;cursor:default}
.roombody{padding:var(--s2) var(--s2) var(--s2);border-radius:0 0 var(--r-md) var(--r-md);box-shadow:inset 0 0 0 2px var(--petrol)}
.roombody .levels{margin-top:0}
.roombody .more{margin-left:var(--s1)}
.more{margin:var(--s2) 0 0;font:600 var(--text-sm)/1.35 var(--font-body);color:var(--petrol)}
.more[hidden]{display:none}

/* the shelter promise under the cattery (issue #43) */
.shelters{margin:var(--s3) 0 0;font:500 var(--text-sm)/1.4 var(--font-body);color:var(--petrol)}
.shelters a{color:var(--petrol);font-weight:700;text-decoration:underline;text-underline-offset:2px}

/* the update notice (store apps only), at the top of the title card, where it
   covers nothing and is never seen during play */
.update{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:var(--s1) 6px;margin:0 0 14px;padding:var(--s3) var(--s2) var(--s2) 14px;border-radius:14px;box-shadow:inset 0 0 0 2px var(--petrol)}
.update[hidden]{display:none}
.update p{flex:1 0 100%;margin:0;font:600 var(--text-sm)/1.3 var(--font-body);color:var(--petrol)}
.update button{min-height:var(--target);padding:0 14px;border:0;border-radius:var(--r-pill);font:700 var(--text-sm)/1 var(--font-body);cursor:pointer}
.update .updatego{background:var(--petrol);color:var(--marigold)}
.update .updatelater{background:transparent;color:var(--petrol)}
.update button[hidden]{display:none}

/* the shop card: what the one purchase opens */
.shoplist{list-style:none;margin:10px 0 var(--s1);padding:0;display:grid;gap:6px;font:600 var(--text-md)/1.3 var(--font-body);color:var(--petrol)}
.shoplist li{display:flex;justify-content:space-between;gap:10px;padding:var(--s2) var(--s3);border-radius:10px;box-shadow:inset 0 0 0 2px var(--petrol)}
.shoplist li small{font-weight:400;color:var(--petrol-2)}
.shoplist li.soon{box-shadow:inset 0 0 0 1.5px var(--petrol-2);color:var(--petrol-2)}
.shopmsg{min-height:1.3em;margin:var(--s2) 0 0;font:500 var(--text-sm)/1.3 var(--font-body);color:var(--petrol)}
.cta:disabled{opacity:.6;cursor:default}

/* the level grid: cleared levels petrol, the one to play marigold, the rest
   outlined; locked ones are disabled. Only the rows up to the next level are
   shown until the room is cleared (game.js showLevels), with a line on how
   many follow. */
.levels{list-style:none;margin:var(--s3) 0 0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s2)}
.levels li{display:flex}           /* one height for every button, so a row lines up with or without stars */
.levels button{
  flex:1;height:var(--target);display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  padding:5px 0;border:0;border-radius:var(--r-md);background:transparent;color:var(--petrol);box-shadow:inset 0 0 0 2px var(--petrol);
  font:400 var(--display-sm)/1 var(--font-display);cursor:pointer;
}
.levels button small{font:400 var(--text-xs)/1 system-ui,sans-serif;letter-spacing:1px}
.levels button.done{background:var(--petrol);color:var(--marigold);box-shadow:none}
.levels button.current{background:var(--marigold);color:var(--petrol);box-shadow:none}
.levels button:disabled{color:var(--petrol-2);box-shadow:inset 0 0 0 2px var(--petrol-2);opacity:.5;cursor:default}
/* the bar toward the next unlock: a petrol fill in a petrol-2 outline on paper */
.track{
  -webkit-appearance:none;appearance:none;display:block;box-sizing:border-box;width:100%;height:16px;
  border:2px solid var(--petrol-2);border-radius:var(--r-pill);background:var(--paper);overflow:hidden;color:var(--petrol);
}
.track[hidden]{display:none}
.track::-webkit-progress-bar{background:var(--paper)}
.track::-webkit-progress-value{background:var(--petrol);border-radius:var(--r-pill)}
.track::-moz-progress-bar{background:var(--petrol);border-radius:var(--r-pill)}
.next{margin:var(--s2) 0 var(--s4);font:600 var(--text-md)/1.35 var(--font-body);color:var(--petrol)}
.found{margin:0 0 var(--s4)}
.found .pics{display:flex;flex-wrap:wrap;gap:var(--s2);margin-bottom:var(--s2)}
.found canvas{display:block;width:52px;height:52px;border-radius:12px;background:var(--floor)}
.found p{margin:0;font:600 var(--text-md)/1.35 var(--font-body);color:var(--petrol)}
.next .tag,.found .tag{display:inline-block;margin-right:6px;background:var(--marigold);color:var(--petrol);padding:2px var(--s2);border-radius:var(--r-sm);font:700 var(--text-xs)/1.4 var(--font-body);letter-spacing:.08em;text-transform:uppercase}
.result{display:flex;gap:var(--s6);margin:var(--s1) 0}
.result .stat .lab{color:var(--petrol-2)}
.result .val{color:var(--petrol)}
.cta{
  margin-top:14px;width:100%;min-height:var(--target);border:0;border-radius:var(--r-pill);background:var(--petrol);color:var(--marigold);
  font:400 var(--display-md)/1 var(--font-display);padding:13px var(--s4);cursor:pointer;
}
.cta:active{transform:scale(.98)}
/* the quieter button under the main one: petrol outline and text on paper */
.cta.ghost{margin-top:var(--s2);padding:11px;background:transparent;color:var(--petrol);box-shadow:inset 0 0 0 2px var(--petrol);font-size:var(--display-sm)}

/* The lesson card: the new thing's portrait beside what it does, then the goal */
.lesson{display:grid;grid-template-columns:auto 1fr;gap:var(--s3);align-items:start}
#lessonPortrait{display:block;width:96px;height:96px;border-radius:18px;background:var(--floor)}
#lessonPortrait[hidden]{display:none}
.goalline{margin:var(--s3) 0 0;font:400 var(--display-md)/1 var(--font-display);color:var(--petrol)}

/* The settings card: a row per setting with its switch at the right; the
   switch is petrol with a marigold word when on, outlined when off. */
.setrows{list-style:none;margin:var(--s2) 0 0;padding:0;display:grid}
.setrows li{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);min-height:var(--target);padding:var(--s1) 0;border-bottom:1.5px solid var(--mist)}
.setrows .name{font:600 var(--text-md)/1.3 var(--font-body);color:var(--petrol)}
.switch{
  min-width:76px;min-height:var(--target);padding:0 var(--s3);border:0;border-radius:var(--r-pill);background:transparent;color:var(--petrol);
  box-shadow:inset 0 0 0 2px var(--petrol);font:400 var(--display-sm)/1 var(--font-display);cursor:pointer;
}
.switch[aria-pressed="true"]{background:var(--petrol);color:var(--marigold);box-shadow:none}
#purchaseRows[hidden]{display:none}
.caption{margin:var(--s2) 0 0;font:400 var(--text-sm)/1.4 var(--font-body);color:var(--petrol-2)}

/* The cattery: one row per cat type, portrait and words */
.cattery{list-style:none;margin:6px 0 0;padding:0;display:grid;gap:var(--s3)}
.cattery li{display:grid;grid-template-columns:64px 1fr;gap:var(--s3);align-items:center}
.cattery canvas{display:block;width:64px;height:64px;border-radius:14px;background:var(--floor)}
.cattery .name{margin:0;font:400 var(--display-md)/1.05 var(--font-display);color:var(--petrol)}
.cattery .count{margin:2px 0 0;font:700 var(--text-xs)/1.4 var(--font-body);letter-spacing:.1em;text-transform:uppercase;color:var(--petrol-2)}
.cattery .line{margin:2px 0 0;font:400 var(--text-sm)/1.35 var(--font-body);color:var(--petrol)}
.cattery .how{margin:4px 0 0;font:400 var(--text-sm)/1.35 var(--font-body);color:var(--petrol-2)}   /* the lesson the cat came with, once met */
.cattery .coats{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2);margin-top:var(--s2)}
.cattery .coats canvas{width:36px;height:36px;border-radius:10px}
.cattery .coats .count{margin:0}
.cattery .unmet .name,.cattery .unmet .line{color:var(--petrol-2)}

@media (prefers-reduced-motion:reduce){
  #banner.show{animation:none;opacity:1}
  .cta:active{transform:none}
}

/* The tester build's "Say something" card (app/tester.js): four faces as
   big targets, then a box for words. A face alone is enough. */
.faces{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s2);margin:var(--s2) 0 var(--s3)}
.face{display:grid;justify-items:center;gap:2px;min-height:calc(var(--target) + 20px);padding:var(--s1);border:0;border-radius:var(--r-lg);
background:transparent;color:var(--petrol);box-shadow:inset 0 0 0 2px var(--petrol);font:600 var(--text-xs)/1.2 var(--font-body);cursor:pointer}
.face span{font-size:1.6rem;line-height:1.2}
.face[aria-pressed="true"]{background:var(--petrol);color:var(--marigold);box-shadow:none}
.saylabel{display:block;font:600 var(--text-sm)/1.3 var(--font-body);color:var(--petrol);margin-bottom:var(--s1)}
#sayText{display:block;width:100%;box-sizing:border-box;min-height:88px;padding:var(--s2) var(--s3);border:0;border-radius:var(--r-lg);
box-shadow:inset 0 0 0 2px var(--petrol);background:transparent;color:var(--petrol);font:400 var(--text-md)/1.4 var(--font-body);resize:vertical}
#sayText:focus-visible{outline:var(--focus-width) solid var(--focus-on-paper);outline-offset:var(--focus-gap)}
/* the level's question's reactions: words, so they wrap instead of four columns */
.faces.chips{display:flex;flex-wrap:wrap}
.faces.chips .face{flex:1 1 auto;min-height:var(--target);align-content:center;padding:var(--s1) var(--s3);font-size:var(--text-sm)}
#sayChips[hidden]{display:none}
