:root {
  --bg: #ffe9f0; --card: #fff8fb; --ink: #4a2f3f; --muted: #9a7a8c; --accent: #ff7aa2; --accent-ink: #fff;
  --line: #f3cddb; --good: #6cc59a; --warn: #f2b84b; --bad: #e86d6d;
}
* { box-sizing: border-box; }
html, body { margin: 0; background: var(--bg); color: var(--ink); font: 15px/1.45 ui-rounded, "Nunito", system-ui, sans-serif; }
/* the screen's height as it is (dvh): 100vh is the height with Safari's bars away, taller than what shows, and the page
   scrolled by the difference */
body { display: flex; justify-content: center; min-height: 100vh; min-height: 100dvh; }
/* a game, not a page (10-31, user: "브라우저에서 확대되는거, 스크롤 생기는거 막아야될것같은데 더블클릭해서 확대된다거나
   꾹눌러서 텍스트 복사된다거나"): no double-tap zoom, no pull-to-refresh or bounce, no text picked up and no picture's menu on
   a long press — typing and your own link and name (to copy for a friend) excepted; pinching: main.js */
html { touch-action: manipulation; overscroll-behavior: none; }
body { overscroll-behavior: none; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
:is(input, textarea, .shareLink, #myId) { -webkit-user-select: text; user-select: text; -webkit-touch-callout: default; }
img { -webkit-user-drag: none; }
/* a room's screens (ui.js show): the page itself never moves */
html.still, html.still body { overflow: hidden; }
.app { width: min(100vw, 480px); padding: calc(12px + env(safe-area-inset-top)) 16px calc(16px + env(safe-area-inset-bottom)); }   /* no tab bar to keep room for (10-31) */
.screen[hidden], [hidden] { display: none !important; }
h2 { margin: 8px 0 12px; font-size: 22px; }
h3 { margin: 14px 0 6px; font-size: 14px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; }
canvas { display: block; }
/* Every scene keeps its own shape (the art never stretches); on short screens it shrinks so the buttons and the
   tab bar still fit without scrolling. --chrome is roughly everything else on the screen around the scene. */
.scene { --chrome: 330px; width: min(100%, calc(100dvh - var(--chrome))); min-width: 220px; margin: 0 auto; aspect-ratio: 1; border-radius: 18px; background: #fff; touch-action: none; }
#door .scene { --chrome: 200px; }
#visit .scene { --chrome: 300px; }
.runner { background: #bfe8ff; touch-action: none; }
.portrait { width: min(60%, calc(100dvh - 460px)); min-width: 140px; margin: 0 auto; aspect-ratio: 160 / 150; background: #fff; border-radius: 18px; }
.cert { display: block; width: auto; height: auto; max-width: min(100%, 360px); max-height: max(200px, calc(100dvh - 250px)); margin: 0 auto; border-radius: 12px; box-shadow: 0 6px 24px #e7b3c655; }   /* the buttons under it in sight on a 360 x 640 phone (11-01 QA) */
.caption { text-align: center; color: var(--muted); margin: 10px 4px; }
.row { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; margin: 10px 0; }
button { font: inherit; color: inherit; cursor: pointer; border: 0; }   /* its words the colour round it — Safari's own is blue (11-02, user: "게임내부에도 파란색 글씨잇어": Day 1, the tabs, the tiles…) */
.row.four { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: 6px; }   /* up to four, filling the row */
.row.four .pill { padding: 9px 4px; white-space: nowrap; font-size: 14px; }
.pill { background: var(--card); color: var(--ink); border: 2px solid var(--line); border-radius: 999px; padding: 9px 14px; }
.pill.small { padding: 5px 10px; font-size: 13px; }
.pill.accent, .big { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.pill.danger { color: var(--bad); border-color: #f5c2c2; }
.pill:disabled, .big:disabled { opacity: .45; cursor: default; }
.big { display: block; width: 100%; border-radius: 16px; padding: 14px; font-size: 17px; font-weight: 700; margin: 12px 0; }
.link { background: none; color: var(--muted); text-decoration: underline; display: block; margin: 8px auto; }
a { color: inherit; }   /* a link the colour of its words — never the browser's blue (11-02, user on Safari: "일부 a태그인가가 글씨색이 파란색으로") */
:is(#toLogin, #visitLogin) { text-decoration: none; }   /* (user: "Log in 밑줄 없애고") */
.link.inline { display: inline; margin: 0; padding: 0; font-size: inherit; }
label { display: block; margin: 10px 0; font-weight: 600; }
label small { font-weight: 400; color: var(--muted); }
input, select { display: block; width: 100%; margin-top: 4px; padding: 10px 12px; font: inherit; border: 2px solid var(--line); border-radius: 12px; background: #fff; color: var(--ink); }
.error { color: var(--bad); margin: 6px 0; }
.error.lineKept { min-height: 1.45em; line-height: 1.45; }   /* its line kept, empty or not: what's under it stays put */
.fine { font-size: 12px; color: var(--muted); text-align: center; }
.siteLinks { margin: 0; }
.siteLinks a { color: var(--muted); }
.banner { background: #fff3c4; border-radius: 12px; padding: 10px; margin-bottom: 10px; font-size: 13px; }
.swatches { display: flex; gap: 10px; flex-wrap: wrap; }
.swatch { width: 44px; height: 44px; border-radius: 50%; border: 3px solid #fff; box-shadow: 0 0 0 2px var(--line); position: relative; }
.swatch.on { box-shadow: 0 0 0 3px var(--accent); }
.swatch.missing { opacity: .45; }   /* not on the shelves: tried on, not kept (maker.js) */
.swatch.none::after { content: "∅"; position: absolute; inset: 0; display: grid; place-items: center; color: var(--muted); }
.swatch span { position: absolute; top: 48px; left: 50%; transform: translateX(-50%); font-size: 11px; color: var(--muted); white-space: nowrap; text-align: center; line-height: 1.3; }
.swatches { padding-bottom: 18px; column-gap: 16px; }
.swatches.priced { padding-bottom: 32px; }   /* a second line under each swatch: its price */
/* the maker (maker.js): rows of part tiles on the plain body, one art cell = one CSS pixel */
.maker h3 { margin: 12px 0 2px; }
.thumbs { display: flex; gap: 6px; overflow-x: auto; padding: 4px 2px 6px; scrollbar-width: none; }
.thumbs::-webkit-scrollbar { display: none; }
.thumb { flex: none; position: relative; min-width: 64px; height: 62px; padding: 2px 4px; border-radius: 12px; background: #fff; border: 2px solid var(--line); display: grid; place-items: center; }
.thumb canvas { display: block; image-rendering: pixelated; }
.thumb.on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.thumb.none { opacity: 0.35; }
.thumb small { position: absolute; right: 3px; bottom: 3px; font-size: 11px; }
/* a count on a tile (×2): a white chip with an outline over the picture, so it reads on any fur or colour (10-31, user:
   "x1 x2 같은 숫자도 잘안보여", then "중앙정렬아닌것같고, 배경검정은 너무 진한것같아") */
.thumb small, .tray .tile small.n, .swatch small { display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box;
  min-width: 20px; height: 18px; padding: 0 3px; border: 2px solid #d79bb4; border-radius: 8px; background: #fff; color: var(--ink); line-height: 1; }
.thumb em { font-style: normal; font-size: 13px; color: var(--muted); }
.noneX { font-style: normal; font-size: 24px; line-height: 1; color: var(--muted); }   /* none: a big ✕ (maker.js, closet.js) */
.thumb em.noneX, .tile .noneX { font-size: 24px; }
.pill.dim { opacity: 0.55; }
.maker .swatches { padding-bottom: 22px; row-gap: 30px; justify-content: center; }
.swatch small { position: absolute; right: -8px; top: -8px; font-size: 11px; }
.makerNeed { min-height: 1.4em; margin: 10px 0 0; }
.makerNeed .bad { color: var(--bad); }
.gameCard .badge.fav { background: #ffe1ea; color: #d4486b; }
/* the pantry (work.js): wishes with faces, the market's offers with their part */
.bookRow.wish img, .bookRow.offer img { image-rendering: pixelated; vertical-align: middle; margin-right: 6px; }
/* the pantry window: two tabs (the first line's room on the right is the ✕'s); one height for both, so the tabs stay put
   when switching; what was made as tiles, tap one to give or sell it; the market's offers as cards, two a row, their
   pictures in one height of box so the names line up */
.overlay .card:has(#pTabs) { height: min(440px, 88vh, calc(100dvh - 32px)); }
#pTabs { flex-wrap: nowrap; }
#pTabs .tab { flex: 1; white-space: nowrap; }
.thingGrid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 10px; }
.thingTile { position: relative; display: grid; justify-items: center; gap: 2px; padding: 8px 4px 6px; }
.thingTile .em { font-size: 26px; line-height: 1.1; }
.thingTile small { color: var(--muted); }
.offerCard .offerNeed { color: var(--muted); font-size: 12px; line-height: 1.25; text-align: center; }   /* what a trade still wants (work.js) */
.thingTile .wisher { position: absolute; top: 3px; right: 3px; width: 22px; height: 22px; image-rendering: pixelated; }
.pAct { flex-wrap: wrap; gap: 6px; }
#pAct { margin-top: 12px; }   /* the chosen one's give and sell, set off from the tiles (11-01, user: "pantry에서 음식 아이콘 눌렀을때 판매 ui랑 너무 붙어있어") */
#modalBody .bookRow.pAct > span:last-child { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 6px; }
.offerGrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.offerCard { display: grid; justify-items: center; align-content: start; gap: 4px; padding: 8px 6px; }
.offerCard .pic { height: 60px; display: grid; place-items: center; }
.offerCard img { image-rendering: pixelated; }
.offerCard b { font-size: 13px; }
.offerCard .pill { width: 100%; }
.bookRow.wish img { width: 30px; height: 30px; }
.bookRow.wish span, .bookRow.offer span { line-height: 1.5; }
.bookRow.wish small, .bookRow.offer small { color: var(--muted); }
.thumbs.wrap { flex-wrap: wrap; overflow: visible; justify-content: center; }
/* the capsules' lineup: a thing not found yet is a shadow, a rare one has the card's gold (special: pink) edge and a star */
#capsule h2.inside { margin: 20px 0 2px; font-size: 18px; text-align: center; }
#capsule h3 small { font-size: 11px; letter-spacing: 0; }
.thumb.locked canvas { filter: brightness(0); opacity: .16; }
.thumb.locked.known canvas { filter: none; opacity: .4; }   /* the looks: faded, in their own colours (capsule.js) */
.thumb.rare { border-color: #ffb020; }
.thumb.special { border-color: #ff5c9a; }
.thumb .tier { position: absolute; left: 4px; top: 2px; font-style: normal; font-size: 10px; line-height: 1; color: #e09000; }
.thumb.special .tier { color: #ff5c9a; }
.reveal { display: flex; gap: 10px; align-items: center; justify-content: center; }
.reveal span { flex: 1; display: grid; justify-items: center; }
.reveal small { color: var(--muted); font-size: 12px; }
.reveal.three img { width: 30%; }
/* the work sheet (work.js): who goes */
.who { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin: 6px 0; }
.whoChip { display: grid; justify-items: center; gap: 1px; padding: 4px 6px; border-radius: 12px; background: #fff; border: 2px solid var(--line); min-width: 62px; }
.whoChip img { width: 40px; height: 40px; image-rendering: pixelated; }   /* one picture cell a CSS pixel (maker.js faceURL) */
.whoChip b { font-size: 12px; } .whoChip small { font-size: 9px; color: #ff5c82; }
.whoChip.on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent); }
.whoChip:disabled { opacity: 0.4; }
/* the Family tab (familyhub.js): the one picked, standing, and what to do with it */
.famCard.card { display: flex; gap: 12px; align-items: center; padding: 8px 12px; margin: 4px 0 8px; width: auto; box-sizing: border-box; }   /* not .card's 18px (user: "여백이 너무많다"), nor its 380 px cap: as wide as the rows under it (user: "창이 클때 오른쪽끝까지
   안채워져") */
.famPortrait { image-rendering: pixelated; display: block; }   /* its own size (familyhub.js portrait) */
.famPic { flex: none; padding: 6px; background: #fff; border: 2px solid var(--line); border-radius: 12px; }   /* where the picture is: the same box for every one (user: "캐릭터 이미지의 영역을 표시") */
.famCard .famName { font-size: 20px; }
.famCard p { margin: 2px 0; text-align: left; }
.famActs .bookRow { width: 100%; flex-direction: column; align-items: flex-start; gap: 2px; text-align: left; }
.famActs .bookRow small { color: var(--muted); font-size: 12px; }
/* a row that opens something says so: a › on its right (user: "버튼이 바로 안보여서 헷갈린다") */
:is(.famActs .bookRow, #gameList .gameCard) { position: relative; padding-right: 30px; }
:is(.famActs .bookRow, #gameList .gameCard)::after { content: '›'; position: absolute; right: 12px; top: 50%;
  transform: translateY(-50%); font-size: 24px; line-height: 1; color: var(--accent); }
#modalButtons button:disabled { opacity: 0.45; }
.bad { color: var(--bad); }
#capRoll { margin: 6px 0 10px; }
#capRoll:disabled, #capSpares:disabled { opacity: 0.5; }
#capAd { margin-bottom: 8px; }
#modalBody img.shot { display: block; max-width: 100%; max-height: 58vh; margin: 0 auto; border-radius: 10px; }
#modalBody > img.shot:first-child { padding: 0; margin-top: 26px; }   /* in the middle, under ✕ — not the first line's room for it (4th QA: off to the left) */   /* a picture before it's saved (ui.js previewImage) */
#certDone { display: block; width: 100%; margin-top: 8px; }   /* under Save, as wide: one pair, not a stray small button (2nd QA) */
#stickers .pill { min-width: 44px; min-height: 36px; }
.hudBottom .guestbook.stickerHead { margin: 6px auto 0; font-size: 12px; }   /* what the row of six is (6th QA: known only from the toast; its ♥ read as the Like) */
#visit .guestbook, #visitBook { flex-wrap: nowrap; }   /* one line, slid sideways: the rows under it stay put (8th QA) */
/* the room as big as the phone allows (11-02, user: "다른사람방 방문했을때 방이 너무 작게보이는데": on a shorter screen — Instagram's
   browser — the rows under it left the room one whole-pixel step smaller): Pet · Like · Give a bone on one line, and the
   rows one not adopted never has (report; where next, while empty) not kept */
#visit .visitDo { flex-wrap: nowrap; }
#visit .visitDo .pill { white-space: nowrap; font-size: 14px; padding-left: 10px; padding-right: 10px; }
@media (max-width: 374px) { #visit .visitDo .pill { font-size: 13px; } }   /* a 360 phone: "Like · 123" too */
#visit.guest .visitFoot, #visit.guest .visitGo:not(:has(> :not([hidden]))) { display: none; }
#visit .guestbook > span { white-space: nowrap; }   /* "Their visitors" on one line (on a 360 phone it took two, and a row's height) */
#visit #visitRoom .row { margin: 6px 0; }
#visit .guestbook.stickerHead { margin-top: 4px; }
#visitBook { overflow-x: auto; scrollbar-width: none; }
#visitBook::-webkit-scrollbar { display: none; }
#visitBook > * { flex: none; }
#visit .visitGo { min-height: 46px; align-items: center; }   /* kept with nothing in it, so the row above doesn't move */
#visit .visitFoot { height: 22px; overflow: hidden; display: flex; align-items: center; justify-content: center; }
#visit .visitFoot > * { margin: 0; }
#visitBook [data-from] { cursor: pointer; }   /* a visitor's name: their room */   /* easier to hit (2nd QA: small and close) */
#visit .roomSide { position: fixed; top: 24%; z-index: 2; opacity: .85; }   /* up by the walls: at 42% they sat on the ones at the back of the floor (7th QA) */   /* a friend's house of more rooms: ‹ › at the sides */
#visit .roomSide.left { left: 8px; }
#visit .roomSide.right { right: 8px; }
.top { display: flex; justify-content: space-between; align-items: center; margin: 4px 0 10px; font-size: 17px; }
.coins b { font-size: 17px; }
.needs { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 14px; margin-bottom: 10px; font-size: 13px; }
.need { display: grid; grid-template-columns: 70px 1fr; align-items: center; gap: 6px; }
.bar { height: 10px; border-radius: 6px; background: #f6dbe5; overflow: hidden; }
.bar i { display: block; height: 100%; border-radius: 6px; background: var(--good); transition: width .4s; }
.guestbook { display: flex; gap: 8px; align-items: center; margin-top: 6px; font-size: 13px; color: var(--muted); }
.guestbook div { display: flex; gap: 6px; flex-wrap: wrap; }
.stamp { background: var(--card); border: 1px solid var(--line); border-radius: 999px; padding: 2px 8px; color: var(--ink); }
button.stamp { font: inherit; cursor: pointer; }   /* the 🔔's visitors: a name opens their room */
#modalBody .todoVisitors { margin: 12px 0 6px; font-size: 13px; color: var(--muted); }
#modalBody .visitorsList { display: flex; flex-wrap: wrap; gap: 6px; }
/* an empty place (ui.js emptyBox): a picture, what will be here, how it fills */
.empty { grid-column: 1 / -1; display: grid; justify-items: center; gap: 6px; margin: 4px 0; padding: 16px 14px; border: 2px dashed var(--line);
  border-radius: 14px; background: #fff8fb; text-align: center; }
.empty .emptyIcon { font-size: 30px; line-height: 1; }
.empty .emptyText { display: grid; gap: 2px; }
.empty .emptyText b { color: var(--ink); }
.empty .emptyText small { color: var(--muted); max-width: 30em; }
.empty.slim { display: flex; align-items: center; justify-items: start; gap: 10px; padding: 8px 12px; text-align: left; }
.empty.slim .emptyIcon { font-size: 22px; }
li.note .empty { flex: 1; margin: 0; }
.panel { background: var(--card); border: 2px solid var(--line); border-radius: 16px; padding: 12px; margin-top: 10px; text-align: center; }
.tabs { display: flex; gap: 6px; margin: 8px 0; flex-wrap: wrap; }
.tab { background: var(--card); border: 2px solid var(--line); border-radius: 10px; padding: 6px 12px; }
.tab.on { border-color: var(--accent); color: var(--accent); font-weight: 700; }
#settings .tab.on { background: var(--accent); color: #fff; }   /* the setting that is on, filled (11-01 QA: pink text read as off) */
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.tile { background: var(--card); border: 2px solid var(--line); border-radius: 14px; padding: 6px; text-align: center; font-size: 12px; }
.tile.on { border-color: var(--accent); }
.tile canvas { width: 100%; aspect-ratio: 1; }
.dyes { display: flex; justify-content: center; gap: 4px; margin-top: 4px; }
.dot { width: 16px; height: 16px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px var(--line); }
.dot.on { box-shadow: 0 0 0 2px var(--accent); }
.list { list-style: none; padding: 0; margin: 0; }
.list li, .friend { display: flex; align-items: center; gap: 10px; background: var(--card); border: 2px solid var(--line); border-radius: 14px; padding: 8px 12px; margin: 6px 0; }
.list li.me { border-color: var(--accent); }
.list li b:first-child { width: 28px; color: var(--muted); }
.list li span, .friend span { flex: 1; }
.friend .who { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }   /* a name on one line, cut with … rather than wrapped (5th QA) */
.friend .who small { display: block; overflow: hidden; text-overflow: ellipsis; }
.friend .sq { opacity: .6; margin-left: 4px; }   /* Remove: quieter than Visit, a step apart */
#board li[data-visit]:not([data-visit=""])::after { content: '›'; margin-left: 6px; color: var(--muted); font-weight: 700; }   /* a row opens that room (5th QA: nothing said so) */
.friend canvas { width: 64px; height: 64px; }   /* 1:1 (or 2:1 on retina) with the 64px face, no uneven pixels */
.toast { pointer-events: none; position: fixed; left: 50%; top: calc(64px + env(safe-area-inset-top)); bottom: auto; transform: translateX(-50%); width: max-content; max-width: calc(100vw - 32px); background: #4a2f3fee; color: #fff; padding: 10px 16px; border-radius: 999px; font-size: 14px; z-index: 30; }
html:is([data-screen="game"], [data-screen="walk"]) .toast, html .toast.low, html[data-screen] #toast.low { top: auto; bottom: calc(20px + env(safe-area-inset-bottom)); }   /* low: over a window — the home's own top lost to it (4th QA: a tall dark box) */   /* off the time bar and the game's words (11-01) */
html[data-screen="home"] #toast { top: var(--toastTop, calc(148px + env(safe-area-inset-top))); }
html[data-screen] #toast.moved { top: var(--toastAt); bottom: auto; }   /* off the field or button just touched (ui.js offTouched) */   /* under the First steps card and the bones (home.js sets it from them; 11-01 QA: "+10" covered the next step) */
.overlay { position: fixed; inset: 0; background: #4a2f3f88; display: grid; place-items: center; z-index: 20; padding: 16px; }
.elsewhere { z-index: 40; background: #4a2f3fcc; }   /* over everything, a modal too: nothing here till "Play here" */
.elsewhere .card { text-align: center; }
.elsewhere .eIcon { font-size: 40px; margin: 0; }
.overlay .card { position: relative; padding: 8px 10px 10px; display: flex; flex-direction: column; overflow: hidden; max-height: min(88vh, calc(100dvh - 32px)); }
/* the content scrolls, the buttons stay in sight however short the screen (user: "세로가 짧을때 done 버튼을 바로 볼수없다") */
#modalBody { flex: 1 1 auto; min-height: 0; overflow: auto; }
#modalButtons { flex: none; }
/* a window's content packed close (user: "모달에 쓸데없이 남는부분이 많거나"): the title level with the ✕, small gaps */
/* the title at the top left, level with the ✕ (user: "모달 타이틀은 왼쪽 상단으로 가는게 공간을 줄이는") */
/* one line of 24 px whose middle is the ✕'s (8 + 12 = 8 + 12): level with it (user: "타이틀 부분과 x 위치가 안맞는") */
#modalBody > :first-child { margin: 0 0 10px; min-height: 24px; line-height: 24px; padding: 0 32px 0 0; text-align: left !important; }   /* the title and ✕ apart from what follows (user: "To do 에서 타이틀 및 x 버튼이랑 내용이랑 너무 가깝다") */
#modalBody .fine { text-align: left; }
#modalBody > .reveal:first-child { padding: 0; }   /* the cards in the middle: no room kept for ✕ (it is hidden on a find) */
#modalButtons:empty { display: none; }
#modalBody p { margin: 4px 0; }
#modalBody h3 { margin: 8px 0 4px; }
#modalBody .bookRow { padding: 6px 8px; margin-bottom: 4px; }
#modalBody .bookRow > span:last-child:has(button) { display: flex; gap: 4px; flex: none; }
#modalBody .bookRow.offer img { width: auto !important; height: 32px; }
#modalButtons { margin: 8px 0 0; gap: 6px; }
#modalButtons .pill { padding: 6px 12px; }
.modalX { position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; padding: 0; border-radius: 50%; background: var(--card);
  border: 2px solid var(--line); color: var(--ink); font-size: 12px; line-height: 1; }
/* a screen's title stays at the top while its list scrolls (user: "메뉴가 상단에 유지가 안된다") */
.screen > header.top { position: sticky; top: 0; z-index: 5; margin-top: calc(-12px - env(safe-area-inset-top)); margin-left: -16px; margin-right: -16px;
  padding: calc(12px + env(safe-area-inset-top)) 16px 8px; background: #fffafc; border-bottom: 2px solid var(--line); }   /* set off from what scrolls under it, like the tabs below (user: "메뉴 헤더부분이 구분이 안되는") */
.card { background: #fff; border-radius: 18px; padding: 18px; width: min(100%, 380px); max-height: 80vh; overflow: auto; }
.card.ad { text-align: center; background: #222; color: #ddd; }
.count { font-size: 40px; color: #fff; }
/* phones held sideways: the game is laid out for upright phones, so ask to turn back */
.rotate { display: none; }
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  .rotate { display: grid; place-items: center; position: fixed; inset: 0; z-index: 40; background: var(--bg); text-align: center; font-size: 18px; }
  .rotate b { display: block; font-size: 40px; }
}
/* the link name field reads as the address it becomes */
.linkInput { display: flex; align-items: center; margin-top: 4px; border: 2px solid var(--line); border-radius: 12px; background: #fff; padding-left: 12px; }
.linkInput span { color: var(--muted); font-weight: 400; }
.linkInput input { border: 0; margin: 0; padding-left: 1px; }
.status { font-size: 13px; margin: -4px 0 8px; min-height: 1.45em; line-height: 1.45; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }   /* its line kept (adopt form) */
#adoptError { min-height: 1.45em; line-height: 1.45; }
/* the button kept in sight at the foot of the screen, its error just above it (5th and 9th QA at 360 x 640: 'Sign the papers'
   below the fold, a tap where it should be did nothing) */
.signBar { position: sticky; bottom: 0; z-index: 2; background: var(--bg); padding: 6px 0 calc(8px + env(safe-area-inset-bottom)); }
.signBar .error { margin: 0 0 6px; }
#nameError { min-height: 1.45em; line-height: 1.45; margin: 6px 0; }
.status.ok { color: var(--good); font-weight: 700; }
.status.bad { color: var(--bad); }
fieldset.choices { border: 2px solid var(--line); border-radius: 12px; margin: 12px 0; padding: 4px 12px 8px; }
fieldset.choices legend { font-weight: 600; padding: 0 4px; }
fieldset.choices legend small { font-weight: 400; color: var(--muted); }
.choice { display: flex; align-items: center; gap: 8px; margin: 6px 0; font-weight: 400; }
.choice input { display: inline-block; width: auto; margin: 0; accent-color: var(--accent); }
.chip { margin-left: 6px; padding: 1px 8px; border: 2px solid var(--line); border-radius: 999px; background: var(--card); font-size: 13px; font-weight: 700; }
.chip.due { border-color: var(--accent); color: var(--accent); }
.topRight, .topLeft { display: flex; align-items: center; gap: 6px; }
/* the to-do list's count on its 🔔 (todo.js): only when something waits — beside the button, not in it, since a pixel
   button's corners are cut with clip-path and that cut the count off too (10-31, user) */
.badged { position: relative; display: inline-flex; }
.dotN { z-index: 1; pointer-events: none; position: absolute; top: -3px; right: -3px; width: 10px; height: 10px; border-radius: 50%; background: #ff5c82; border: 2px solid #fff8fb; box-sizing: border-box; }
.dotN[hidden] { display: none; }
/* ☰ on the home's top bar (10-31, user: "settings이 자주쓰는게 아니잖아, collections 도 사실 보상받을때 빼고는 안킬거고"):
   the collection and settings under it, a dot on it when a set waits to be claimed */
#home > .moreMenu { position: fixed; z-index: 6; }
.moreMenu { width: max-content; display: grid; gap: 6px; padding: 6px; background: #fff8fbf2; border: 2px solid var(--line); border-radius: 12px; box-shadow: 0 4px 16px #4a2f3f22; }
.moreMenu[hidden] { display: none; }
.moreMenu .pill[hidden] { display: none; }   /* ☰'s Home screen, only where it can be added (home.js) */
.moreMenu .pill.small { display: flex; align-items: center; gap: 4px; justify-content: flex-start; text-align: left; margin: 0; width: 100%; height: 32px; padding: 0 12px; white-space: nowrap; }
.moreMenu .badge { font-style: normal; font-size: 11px; font-weight: 700; margin-left: 6px; padding: 1px 6px; border-radius: 999px; background: #ff5c82; color: #fff; }
.moreMenu .badge[hidden] { display: none; }
.todoN { z-index: 1; pointer-events: none; position: absolute; top: -5px; right: -2px; min-width: 16px; height: 16px; padding: 0 3px; border-radius: 8px; background: #ff5c82; color: #fff;
  font: normal 10px/16px "Fusion Pixel", ui-rounded, sans-serif; text-align: center; text-shadow: none; box-sizing: border-box; }
#modalBody .bookRow.todo { align-items: center; gap: 8px; }
#modalBody .bookRow.todo > span:first-child { flex: 1; min-width: 0; text-align: left; }
/* every screen's header the same way round (user: "버튼이 어디에 있을지 예상을 못하겠다"): ← back at the top left, the
   title, then what the screen shows (bones, a score) at the right; settings only from the home's ⚙. Everything up
   there one height (user: "day 2, 발바닥, 쉐어 같은게 크기가 달라서") */
header.top > .pill.back { flex: none; margin-right: 8px; font-size: 16px; }
header.top .pill.small:is(.back, .sq) { width: 32px; padding: 0; justify-content: center; }
.top > .back + * { margin-right: auto; }
.screen > header.top { min-height: 32px; box-sizing: content-box; }   /* one height on every screen, back button or not */
.top :is(.chip, .pill.small) { box-sizing: border-box; height: 32px; display: inline-flex; align-items: center; gap: 4px; padding: 0 10px; margin: 0; white-space: nowrap; }
.top .coins { display: inline-flex; align-items: center; gap: 4px; height: 32px; }
#visit.guest .scene { --chrome: 360px; }
#visitLocked p { margin: 6px 0; }
/* home: the room with its Decorate button in the corner */
.sceneWrap { --chrome: 330px; position: relative; width: min(100%, calc(100dvh - var(--chrome))); min-width: 220px; margin: 0 auto; }
.sceneWrap .scene { width: 100%; min-width: 0; }
.sceneBtn { position: absolute; top: 5%; right: 5%; box-shadow: 0 2px 8px #4a2f3f22; }
#decorate .scene { --chrome: 352px; }
.muted { color: var(--muted); font-weight: 600; font-size: 12px; }
.decoTools { display: flex; align-items: center; gap: 8px; margin: 0; height: 32px; }
.decoTools .sq { width: 32px; padding: 0; flex: none; }
.decoTools b { flex: 1; min-width: 0; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }   /* one line: the row keeps its height */
.decoTools b.muted { font-weight: normal; color: var(--muted); }
.tray { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 8px; scroll-snap-type: x proximity; }
.tray .tile { flex: 0 0 auto; min-width: 72px; display: grid; justify-items: center; align-content: start; gap: 0; padding: 4px; scroll-snap-align: start; overflow: hidden; }
/* one height on every tab and while a tab is filled in, so the room above never moves (user, 10-30: no layout shift) */
#decoTray { height: 92px; box-sizing: border-box; }   /* small tiles, one line each: the room gets the height */
#capMachines { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }   /* the four capsule machines, two by two at any width */
#capMachines .tab { margin: 0; }
.tray .tile { position: relative; }
.tray .tile .helpTag { position: absolute; top: 2px; left: 2px; padding: 0 3px; border: 1px solid var(--line); border-radius: 6px; background: var(--card); font-size: 12px; line-height: 16px; }   /* a care piece: how many out for how many animals */
.tray .tile canvas { width: auto; height: 36px; max-width: 60px; object-fit: contain; image-rendering: auto; aspect-ratio: auto; }
.tray .tile div { font-size: 11px; font-weight: 700; line-height: 1.2; }
.tray .tile small { font-size: 11px; color: var(--muted); }
.tray .tile :is(div, small) { white-space: nowrap; }   /* the tile as wide as its name (11-01 QA: 'Round r…' on a 360 phone) */
.doc h4 { margin: 12px 0 4px; }
.doc p { margin: 4px 0; font-size: 13px; }
#decoTabs { flex-wrap: nowrap; }
#decoTabs .tab { flex: 1; padding: 6px 4px; font-size: 13px; white-space: nowrap; }
/* dragging furniture or rubbing the pup must not select text or open the picture menu */
#decorate, .scene { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
/* rooms are drawn full screen behind the screen's buttons (any screen size) */
.world { position: fixed; inset: 0; width: 100vw; height: 100dvh; z-index: 0; display: block; touch-action: none;
  /* until the first frame (a room scene then paints its sky over it: room.js drawBackdrop) */
  background: radial-gradient(120% 80% at 50% 45%, #fff3f7 0%, #ffe3ec 70%, #ffd6e3 100%); -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.screen > :not(.world) { position: relative; z-index: 1; }
/* the look being made stays in sight while the rows below it scroll (10-30, user: "미리보는건 상위에 유지되어야하지않아?") */
#style > .previewPin, #welcome > .previewPin { position: sticky; top: 0; z-index: 3; background: var(--bg); padding: 6px 0 8px; }
/* the maker coming up over the basket (door.js openMaker): a sheet from below, the door seen behind it until it is up */
#style.rise { position: relative; z-index: 2; background: var(--bg); margin: 0 -16px; padding: 0 16px; min-height: 100dvh;
  border-radius: 18px 18px 0 0; box-shadow: 0 -6px 24px #4a2f3f33; animation: sheetUp .42s cubic-bezier(.2, .9, .3, 1.04) both; }
@keyframes sheetUp { from { transform: translateY(100%); } }
/* under the title bar, not behind it (user: "salon에서 화면을 내려가면 캐릭터 미리보기 화면이 잘린다"): the bar is 12 + 32 + 8 and its 2 px line */
#style > .previewPin, #welcome > .previewPin { top: calc(54px + env(safe-area-inset-top)); margin-top: -10px; padding-top: 16px; }   /* where it sits is where it sticks: the bar's 10 px below taken back (user: "고정된게아니라 왜 조금 위로 올라가는지") */
/* a screen's main button stays at the bottom however long the list above it (user: "change look에서 바로 done 버튼이 안보인다") */
/* down to the screen's edge: over the page's bottom padding too, or scrolled to the end it rose off the edge and left a
   strip under it (10-31, user: "make it yours 화면에서 맨아래로 내려가니까 10px 정도 남는거같은데") */
.screen > .doneBar { position: sticky; bottom: 0; z-index: 3; margin: 12px -16px calc(-16px - env(safe-area-inset-bottom)); padding: 8px 16px calc(8px + env(safe-area-inset-bottom));
  background: #fffafc; border-top: 2px solid var(--line); }   /* set off from what scrolls under it, like the header (user: "바텀부분이 구분이 안돼") */
.doneBar .big { margin: 0; }
/* what making or changing uses, and what went wrong, in the bar above its button: seen without scrolling (10-31, user:
   "new member에서 welcome home 이랑 안내 및 경고텍스트도 처음에 가려져있어") */
.doneBar :is(.makerNeed, #styleNote) { margin: 0 0 6px; text-align: center; }
.doneBar .error { margin: 0 0 6px; text-align: center; }
.hudTop { background: #fff8fbe8; border: 2px solid var(--line); border-radius: 16px; padding: 8px 12px 6px; box-shadow: 0 4px 16px #e7b3c633; }
.hudTop .top { margin: 0 0 6px; }
.hudTop .needs { margin-bottom: 2px; }
.hudTop.slim { padding: 6px 10px; }
.hudTop.slim .top { margin: 0; }
.hudTop .chip.day { margin-left: 0; }
/* the dock (docs/UX_PLAN.md 3-1): the one you're with, at the bottom where the thumb is */
.dock { background: #fff8fbf2; border: 2px solid var(--line); border-radius: 16px; padding: 8px 10px; margin: 6px 0 8px; box-shadow: 0 -2px 12px #e7b3c633; }
.dockHead { display: grid; grid-template-columns: auto auto auto 1fr auto; align-items: center; gap: 8px; margin-bottom: 6px; }
.dockHead .sq { width: 28px; height: 28px; padding: 0; justify-content: center; }
/* let go (home.js letGo): no panel, the room has the bottom (10-31, user: "아래 캐릭 목록이 나와서 좀 공간차지를 많이해보이거든");
   one chosen, its panel comes up as the camera goes in */
#home .dock.off { display: none; }
#home .dock:not(.looks) { animation: dockIn .25s ease-out; }
@keyframes dockIn { from { transform: translateY(24px); opacity: 0; } }
/* the look sheet (looks.js): where the dock was, taller, the room fitted above it; the rest of the home's buttons away
   while it's open (✕ or Done to come back) */
#home.styling :is(.hudTop, .homeRow, #roomActs, #roomBar, .guestbook, .dock:not(.looks)) { display: none !important; }
#home .looks { display: flex; flex-direction: column; height: min(60vh, calc(100dvh - 190px), 540px); padding-bottom: 8px; }
#home .looks[hidden] { display: none; }
.looksHead { display: flex; align-items: center; gap: 6px; }
.looksHead .tabs { flex: 1; margin: 0; flex-wrap: nowrap; }
.looksHead .tab { flex: 1; white-space: nowrap; }
.looksBody { flex: 1; min-height: 0; overflow: auto; margin: 6px -8px 0; padding: 0 8px; }
.looksBar { flex: none; padding-top: 8px; border-top: 2px solid var(--line); margin: 6px -8px 0; padding-left: 8px; padding-right: 8px; }
.looksBar :is(.fine, .makerNeed) { margin: 0 0 6px; text-align: center; }
.looksSay { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0 0 6px; min-height: 32px; }   /* what changed on the left, 🔮 More on the right (looks.js; user: "텍스트 왼쪽 버튼 오른쪽") */
.looksBar .looksSay .fine { margin: 0; text-align: left; flex: 1; min-width: 0; }
#looksMore { flex: none; margin: 0; }
/* one line each, cut short with … rather than wrapping: the bar keeps one height whatever is said (looks.js) */
.looksBar :is(#looksChanges, #looksNote, #looksNeed) { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.looksBar :is(#looksNote, #looksNeed) { height: 1.4em; min-height: 0; line-height: 1.4em; }
.looksBtns { display: flex; gap: 8px; }
.looksBtns .pill { flex: 1; margin: 0; white-space: nowrap; }
.looksBtns .big { flex: 2; width: auto; margin: 0; }
.looksBtns .big:disabled, .looksBtns .pill:disabled { opacity: .45; }
#looksChanges.some { color: var(--ink); }   /* something tried on: said plainly, not greyed */
.dockHead .chip { margin-left: 0; }
.dockHead .bar { height: 8px; }
.dockFace { padding: 0; background: none; border: 0; line-height: 0; }
.dockFace img { width: 40px; height: 40px; image-rendering: pixelated; border-radius: 10px; background: #fff; border: 2px solid var(--line); }
.floatBtn { display: block; margin: 8px 0 0 auto; box-shadow: 0 2px 8px #4a2f3f22; }
.screen > .hudBottom { position: fixed; left: 50%; transform: translateX(-50%); width: min(100vw, 480px); padding: 0 12px;
  bottom: calc(12px + env(safe-area-inset-bottom)); }
.hudBottom .guestbook { background: #fff8fbd9; border-radius: 999px; padding: 4px 10px; width: fit-content; }
.careBar { display: flex; align-items: center; gap: 8px; justify-content: space-between; margin: 6px 0; padding: 8px 10px 8px 14px;
  background: #fff8fbf2; border: 2px solid var(--line); border-radius: 16px; font-size: 14px; }
.careBar[hidden] { display: none; }
/* in the dock, the care line takes the Feed / Wash / Ball row's place at its height (user: "feed wash ball 이런것도 화면
   영역이 layout shift"); the room is fitted to the dock, so it stays put */
.dock .careBar { margin: 6px 0 0; padding: 0 0 0 4px; height: 36px; background: none; border: 0; border-radius: 0; box-shadow: none; }
.px .dock .careBar { font-size: 12px; }
.dock .careBar #careText { line-height: 16px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.dock:has(#careBar:not([hidden])) .careRow { display: none; }
.careBar #careText { flex: 1; min-width: 0; }
.careBar button { white-space: nowrap; flex: none; }
.careBar .meter { display: inline-block; width: 64px; height: 7px; margin-left: 6px; border-radius: 4px; background: rgba(120, 70, 90, .15); vertical-align: middle; overflow: hidden; }
.careBar .meter b { display: block; height: 100%; background: #8fd0ff; }
.hudBottom .row { margin: 8px 0; }
.say { background: #fffffff0; border: 2px solid var(--line); border-radius: 14px; padding: 8px 12px; color: var(--ink); }
.hudBottom .link { background: #fff8fbcc; border-radius: 999px; padding: 4px 10px; }
#decorate .hudBottom { background: #fff8fbf0; border-top: 2px solid var(--line); border-radius: 18px 18px 0 0; padding-top: 8px; bottom: 0; padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
#decorate .tabs { margin: 6px 0; gap: 4px; }
@media (max-width: 359px) { #decoTabs .tab { padding: 6px 2px; letter-spacing: 0; } }   /* five tabs (Care, 10-31) on one line on a narrow phone */
/* bond level, days together */
.bondRow { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 8px; margin: -2px 0 8px; font-size: 12px; }
.bondRow .chip.lv { margin: 0; background: #fff1c9; border-color: #f2d58a; }
.bar.xp { height: 8px; }
.bar.xp i { background: linear-gradient(90deg, #ffb347, #ff7aa2); }
.bar.xp.capped i { background: #d9c3cc; }
.bondRow small { color: var(--muted); white-space: nowrap; }
/* the first-day list */
.guide { display: grid; gap: 1px; width: fit-content; max-width: 70%; margin: 8px 0 0; padding: 6px 12px; background: #fffffff2; border: 2px solid var(--accent);
  border-radius: 14px; box-shadow: 0 3px 10px #e8577f33; cursor: pointer; font-size: 14px; text-align: left; }
.guide small { color: var(--muted); font-size: 11px; }
.guide .goalBar { display: block; height: 6px; margin-top: 3px; border-radius: 3px; background: rgba(120, 70, 90, .15); overflow: hidden; }   /* the next room, how far (guide.js goal) */
.guide .goalBar b { display: block; height: 100%; background: var(--accent); }
.guide:is(.adoptNow, .newCard) { background: var(--accent); color: #fff; }
.guide:is(.adoptNow, .newCard) small { color: #ffe3ec; }
.guide.newCard { text-align: left; font: inherit; }
.guide.newCard[hidden] { display: none; }
/* home: the first-day list and the buttons side by side, the buttons wrapping right to left */
.homeRow { display: flex; align-items: flex-start; gap: 8px; margin-top: 8px; }
.homeRow .guide { min-width: 0; }
.homeRow .guide { margin: 0; flex: 0 1 auto; }
.homeBtns { flex: 1 0 auto; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }   /* Decorate, the bones under it (user: "뼈다귀는 decorate 아래 떠있어도") */
.homeBtns .coins { margin: 0; height: 32px; display: inline-flex; align-items: center; gap: 4px; padding: 0 10px; background: #fff8fbf2; }
.homeBtns .floatBtn { margin: 0; white-space: nowrap; padding: 6px 9px; }
/* the care streak under the bones (user: "2day streak는 이벤트처럼 뼈다귀 아래 나와도되지않나") */
.homeBtns .shopBtns { display: flex; gap: 6px; }
/* the capsules beside the bones they're bought with (11-01, user: "캡슐이 … 뼈다귀 옆으로 옮기는게 좋지않을까") */
.homeBtns .coinRow { display: flex; gap: 6px; align-items: center; }
.homeBtns .coinRow .pill.small.sq { width: 32px; height: 32px; padding: 0; justify-content: center; margin: 0; background: #fff8fbf2; }
.homeBtns .shopBtns .pill.small.sq { width: 32px; height: 32px; padding: 0; justify-content: center; margin: 0; background: #fff8fbf2; }
/* the day and the care streak in one chip (10-31): tapped, how the streak grows */
.top #dayChip { cursor: pointer; }
.top #dayChip #streak[hidden] { display: none; }
.top #dayChip.short .long { display: none; }
.pill.nudge { animation: nudge .5s ease-in-out 3; }
@keyframes nudge { 50% { transform: scale(1.12); box-shadow: 0 0 0 4px #ff7aa255; } }
/* play */
.gameCard { display: flex; gap: 12px; align-items: center; width: 100%; text-align: left; padding: 10px 12px; margin: 0 0 8px; background: var(--card);
  border: 2px solid var(--line); border-radius: 16px; font: inherit; color: inherit; }
.gameCard .em { font-size: 34px; width: 44px; text-align: center; }
.gameCard b { font-size: 16px; }
.gameCard small { display: block; color: var(--muted); font-size: 12px; }
.gameCard.today { border-color: #f2c14e; background: #fffaf0; }
.gameCard .badge { font-style: normal; font-size: 11px; font-weight: 700; margin-left: 6px; padding: 1px 6px; border-radius: 999px; background: #ffe8a8; }
.gameCanvas { display: block; width: 100%; height: 60dvh; margin: 0 auto;   /* stage.js fitPlay sets its size */ touch-action: none;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; border-radius: 18px; box-shadow: 0 4px 16px #e7b3c644; }
.timebar { height: 6px; margin: 0 0 4px; }
.timebar i { background: linear-gradient(90deg, #8fd0ff, #ff7aa2); transition: none; }
/* the walk on a short phone: its panel tighter, so the park, the panel and the tabs fit without scrolling */
@media (max-height: 520px) { #walk .panel { margin-top: 6px; padding: 6px 10px; } #walk .panel p { margin: 2px 0; } #walk .panel .big { margin: 4px 0 0; padding: 8px; } }
@media (max-height: 520px) { .gameIntro, .gameResult { padding: 8px 10px; } .gameIntro p, .gameResult p { margin: 4px 0; font-size: 13px; } .gameResult .stars { font-size: 30px; } .gameIntro .big { padding: 8px; }
  .gameResult .row { gap: 4px; margin-top: 6px; } .gameResult .pill { padding: 4px 8px; font-size: 12px; } }
/* a game's picture (stage.js fitPlay): the room under the bar, edge to edge (out over the screen's side padding and down
   to its bottom), the picture in the middle of it; over the picture: the time left along its top, a strip of words while
   playing, the how-to and Start up in its sky, the end over most of it — nothing scrolls (11-01) */
.gameStage { display: flex; align-items: center; justify-content: center; margin: 0 -16px calc(-16px - env(safe-area-inset-bottom)); }
.gameFrame { position: relative; }
.gameFrame .gameCanvas { margin: 0; border-radius: 0; box-shadow: none; }
.gameFrame .timebar { position: absolute; top: 10px; left: 14px; right: 14px; margin: 0; z-index: 2; }   /* in from the edges (user: "시간초는 좌우 여백이 있어야할것같은데"); games.js pinToPlay puts it inside the play's top line */
.gameIntro, .gameResult { position: absolute; left: 12px; right: 12px; max-height: calc(100% - 24px); overflow: auto; padding: 12px 14px;
  background: #fffafcf0; border: 2px solid var(--line); border-radius: 14px; text-align: center; box-sizing: border-box; }
.gameIntro { top: 30px; }
.gameIntro p { margin: 6px 0; }
.gameIntro .big { margin: 10px 0 2px; padding: 12px; }
.gameResult { top: 50%; transform: translateY(-50%); padding: 16px 14px; }
.gameResult p { margin: 8px 0; font-size: 15px; }
.gameResult .stars { font-size: 40px; line-height: 1; }
.gameResult .row { justify-content: center; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.gameSay { position: absolute; top: 16px; left: 50%; transform: translateX(-50%); display: flex; align-items: center; gap: 10px; white-space: nowrap;
  padding: 6px 14px; background: #fffafce6; border: 2px solid var(--line); border-radius: 999px; z-index: 2; pointer-events: none; }
#game .gameSay { top: 28px; }   /* under the time bar */
#game .gameSay b { white-space: normal; text-align: center; }
#game .gameSay { white-space: normal; width: max-content; max-width: calc(100% - 32px); }   /* a long line wraps inside the screen (11-01 QA: Fetch's ran off both edges) */
.stars { font-size: 34px; color: #f2b632; margin: 0; letter-spacing: 4px; }
.stars .off { color: #e3d3dc; }
.thumbs.more { -webkit-mask-image: linear-gradient(to right, #000 82%, transparent); mask-image: linear-gradient(to right, #000 82%, transparent); }   /* a row going on to the right (maker.js) */
#bondLv { cursor: pointer; }
.bookRow .pic { width: 30px; height: 30px; object-fit: contain; image-rendering: pixelated; vertical-align: middle; margin-right: 6px; }   /* a clothing set's picture (book.js) */
.bookRow .pic.off { opacity: .35; filter: grayscale(1); }   /* a star not earned: plainly empty (2nd QA) */
/* the collection book */
.bookRow { display: flex; justify-content: space-between; align-items: center; gap: 8px; padding: 8px 10px; margin: 0 0 6px; background: var(--card);
  border: 2px solid var(--line); border-radius: 12px; font-size: 14px; }
.bookRow.full { border-color: #f2c14e; }
#bookBody .bookRow > :is(small, button) { flex: none; white-space: nowrap; }   /* "200 🦴" on one line, the name wraps instead (11-01, 320 px) */
.bookRow .dyes { display: flex; justify-content: flex-start; gap: 4px; margin-top: 4px; }   /* from the left, under the name (a single one sat in the middle: 11-01, user: "Collection 1개인게 왜 왼쪽 여백이 많아") */
.bookRow .dot { width: 14px; height: 14px; border-radius: 50%; display: inline-block; box-sizing: border-box; border: 2px solid var(--ink); box-shadow: none; background: var(--c); }
.bookRow .dot.off { border-color: var(--o, #d79bb4); background: color-mix(in srgb, var(--c) 35%, #fff); }
/* the home screen's sheet (homescreen.js): over the game, the game still in sight above it */
.hsWrap { position: fixed; inset: 0; z-index: 40; display: flex; align-items: flex-end; justify-content: center; background: #4a2f3f33; }
.hsWrap[hidden] { display: none; }
.hsSheet.arrowBelow { padding-bottom: calc(48px + env(safe-area-inset-bottom)); }   /* room for the arrow to Safari's bar */
.hsSheet { position: relative; width: min(100%, 480px); box-sizing: border-box; background: #fffafc; border: 2px solid var(--line); border-bottom: 0;
  border-radius: 18px 18px 0 0; padding: 16px 16px calc(14px + env(safe-area-inset-bottom)); text-align: center; }
.hsTitle { margin: 0 28px 8px; font-size: 16px; }
.hsWhy { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 0 0 12px; }
.hsWhy .chip { margin: 0; padding: 3px 10px; }
.hsHow { display: grid; justify-items: center; gap: 8px; }
.hsHow .big { margin: 0; width: 100%; }
.hsHow .fine { margin: 0; font-size: 13px; }
.hsCards { display: flex; align-items: center; justify-content: center; gap: 8px; }
.hsCard { display: grid; justify-items: center; align-content: start; gap: 2px; width: 120px; min-height: 96px; box-sizing: border-box; padding: 10px 6px 8px;
  background: var(--card); border: 2px solid var(--line); border-radius: 12px; font-size: 13px; line-height: 1.25; }
.px .hsCard .ico, .hsCard .hsGlyph { --s: 36px; height: 36px; margin: 0 0 4px; }   /* the pictures big (over px.css's own size) */
.hsCard .hsGlyph { font-size: 28px; line-height: 36px; }
.hsCard small { color: var(--muted); font-size: 11px; }
.hsCards > .ico { flex: none; }
.hsCards.three { gap: 4px; align-items: stretch; }   /* three steps on a 360 phone (iOS 26's Safari: ⋯ → Share → Add), one height */
.hsCards.three .hsCard { width: 86px; }
.hsCards.three > .ico { align-self: center; }
/* steps one under another, numbered (iOS 27's Safari has four) */
.hsSteps { list-style: none; counter-reset: hs; margin: 0; padding: 0; width: 100%; max-width: 320px; display: grid; gap: 6px; text-align: left; }
.hsSteps li { counter-increment: hs; display: grid; grid-template-columns: 16px 28px 1fr; align-items: center; gap: 8px; padding: 6px 10px;
  background: #fff; border: 2px solid var(--line); border-radius: 12px; }
.hsSteps li::before { content: counter(hs); font-weight: 700; color: var(--accent); text-align: center; }
.px .hsSteps .ico, .hsSteps .hsGlyph { --s: 28px; height: 28px; margin: 0; }
.hsSteps .ico.down { transform: rotate(90deg); }
.hsSteps small { color: var(--muted); font-size: 11px; }
#hsSkip { margin: 10px auto 0; }
/* where the browser's own button is: bouncing toward it */
.px .hsArrow { position: fixed; z-index: 41; --s: 32px; margin: 0; animation: hsBob .8s ease-in-out infinite alternate; pointer-events: none; }
.hsArrow[hidden] { display: none; }
.hsArrow.down { left: calc(50% - 16px); bottom: calc(4px + env(safe-area-inset-bottom)); --r: 90deg; }
.hsArrow.downRight { right: 18px; bottom: calc(4px + env(safe-area-inset-bottom)); --r: 90deg; }
.hsArrow.downLeft { left: 22px; bottom: calc(4px + env(safe-area-inset-bottom)); --r: 90deg; }   /* iOS 27's Safari: the menu left of the address */
.hsArrow.upRight { right: 14px; top: calc(8px + env(safe-area-inset-top)); --r: -90deg; }
@keyframes hsBob { from { transform: rotate(var(--r)) translateX(0); } to { transform: rotate(var(--r)) translateX(8px); } }
.workWhyTitle { margin: 4px 0 8px; }   /* Work before a second one: what it brings, why two (work.js) */
.why { list-style: none; padding: 0; margin: 0 0 10px; text-align: left; }
.why li { display: flex; gap: 8px; align-items: flex-start; margin: 0 0 8px; font-size: 14px; line-height: 1.45; }
.why .whyIcon { flex: none; width: 20px; text-align: center; }
#settings > .pill { margin: 0 6px 6px 0; }
#settings .fine { font-size: 14px; line-height: 1.45; text-align: left; margin: 0 0 8px; }   /* what a setting does, readable (11-01, user: "설정에 others 이거 글씨도 너무 작다") */
#settings .soundRow { justify-content: flex-start; margin: 0; }   /* from the left like every other button here (11-01, user: "music on 이랑 sounds on 만 중앙절렬이다") */
#settings .soundRow .pill { margin: 0 0 6px; }
.shareLink { margin: 6px 0; padding: 8px 10px; border: 2px solid var(--line); border-radius: 10px; background: var(--card); text-align: center; overflow-wrap: anywhere; }   /* the pup's link in Share (social.js) */
/* a selected piece's colour swatches (decorate) */
.decoDyes { display: flex; gap: 8px; justify-content: center; align-items: center; margin: 6px 0 0; height: 28px; }   /* kept when empty */
.decoDyes .dye { width: 24px; height: 24px; border-radius: 50%; border: 3px solid #fff; box-shadow: 0 0 0 2px var(--line); padding: 0; }
.decoDyes .dye.on { box-shadow: 0 0 0 3px var(--accent); }
.decoDyes .dye.locked { opacity: .55; }
#decoTabs .tab[data-tab="house"] { flex: 0 0 auto; padding: 6px 10px; }
.bar.move { height: 12px; margin: 8px 0; }
.bar.move i { background: var(--accent); }
/* best rooms: rows open the room */
#board li[data-visit]:not([data-visit=""]) { cursor: pointer; }
#board li.note { background: none; border: 0; color: var(--muted); font-size: 12px; justify-content: center; text-align: center; }

#toDecorate .badge.ev { margin-left: 4px; padding: 0 2px; background: none; }

/* no video buttons once videos stopped coming this visit (ui.js adsOn) */
.noAds #visitTreat { display: none; }

/* rooms (base step 3): the room bar on the home screen and the house map (house.js) */
.roomBar { display: flex; justify-content: center; align-items: center; gap: 8px; margin-bottom: 6px; }
/* the room's things only when looking at the room (home.js viewMode): with one chosen, the bottom is its */
#home:not(.roomMode):not(.building) :is(#roomActs, #roomBar) { display: none; }
/* …and with one chosen, its things in the same place, the same height, so nothing moves (user: "사진찍는거나 옷갈아입는걸,
   룸 컨트롤 부분쪽에 나타내면 되는거아니야?") */
#home:is(.roomMode, .building, .styling) #petBar { display: none; }
#petPrev[hidden], #petNext[hidden] { display: none; }
/* Back to the whole room over the row's › , the row's own height left as it was (nothing under it moves) */
#petBar { position: relative; }
#home #toRoom { position: absolute; right: 0; bottom: calc(100% + 6px); }
#petBar > * { flex: none; }
@media (max-width: 359px) { #petBar { gap: 6px; } #petBar .pill { padding-left: 8px; padding-right: 8px; } }   /* ‹ Change look · Photo › on a narrow phone */
/* too wide for the screen (home.js fitBar): Photo as its picture, then Change look too */
#petBar.tight #toPhoto span, #petBar.tighter #toLook span { display: none; }
/* which room of how many and ＋, one chip, a line between (home.js roomLabel) */
#roomActs .roomChip { gap: 0; padding-right: 0; }
#roomActs .roomChip:has(#toGrow[hidden]) { padding-right: 10px; }   /* the house as big as it gets: n/n alone */
.roomChip .grow { align-self: stretch; display: inline-flex; align-items: center; gap: 4px; margin-left: 8px; padding: 0 10px; background: none; border: 0;
  border-left: 2px solid var(--line); border-radius: 0; font: inherit; color: var(--accent); }
/* the favourite's star grey until this room is it */
#favRoom:not(.on) :is(.ico, .star) { filter: grayscale(1) opacity(.45); }
#favRoom.on { border-color: var(--accent); }
/* ‹ › at the row's two ends: the same place for every room and in the one chosen's row, whatever is between them (10-31,
   user: "방향키 위치가 달라지는게 별론데") */
:is(#roomPrev, #petPrev) { margin-right: auto; }
:is(#roomNext, #petNext) { margin-left: auto; }
#home :is(#roomPrev, #roomNext, #petPrev, #petNext) { width: 42px; min-width: 0; padding: 0; }
/* the rows as wide as they are (nothing squeezed); a room's long name cut short rather than the row pushed off */
:is(#roomActs, #roomBar) > * { flex: none; }
#roomActs .roomChip { min-width: 0; max-width: calc(100% - 92px); flex: 0 1 auto; }
#roomName { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* the house view's line: what to do there, said, not a button */
#roomBar .note { font-size: 12px; color: var(--muted); background: #fff8fbd9; border-radius: 999px; padding: 4px 10px; white-space: nowrap; text-align: center; }
#roomBar .note small { display: block; font-size: 11px; color: var(--accent); }   /* the next member's goal (home.js nextGoal) */
#roomBar .note[hidden] { display: none; }
#home .buildSpot { min-width: 34px; height: 34px; padding: 0; display: grid; place-items: center; font-size: 18px; }   /* one more room: a small ＋ */
#roomBar { min-height: 32px; }   /* its height kept with nothing in it (one room): nothing below moves */
#decoTitle { white-space: nowrap; }   /* one line, the room's name (no bones there: nothing here costs any — 11-02, user: "Decorate에 이제 뼈다귀 헤더에 안넣어도 되잖아") */

.roomBar[hidden] { display: none; }
.roomBar .pill { min-width: 40px; }
/* the room's name and the arrows either side one height, as in the title bars (10-31, user: "Room 1 이랑 방 옮기는 버튼이랑
   크기가 달라") */
.roomBar :is(.chip, .pill.small) { box-sizing: border-box; height: 32px; display: inline-flex; align-items: center; justify-content: center;
  gap: 6px; padding: 0 10px; margin: 0; white-space: nowrap; }
#wName { width: 100%; }
/* building on the home screen (home.js): a button over each spot a room can go, where the room's outline is drawn —
   centred with `translate`, so a pressed button's transform (px.css: down a pixel) doesn't throw it off (user: "누르면 버튼이 움직이고") */
#home.building .dock { display: none; }   /* building a room: no one's panel (user: "캐릭터 선택창이 그대로 떠있을 필요가 있나?") */
#home > .buildSpots { position: fixed; inset: 0; pointer-events: none; z-index: 1; }   /* over the canvas (fixed, full screen), under the bars */
.buildSpot { position: absolute; translate: -50% -50%; pointer-events: auto; display: grid; justify-items: center; gap: 0;
  padding: 2px 8px 4px; line-height: 1.2; white-space: nowrap; }
.px #home .buildSpot, .buildSpot :is(b, small) { font-size: 12px; }   /* small: the room's outline round it shows */

/* how the one you're with is doing (home.js): hearts and a word, then the bowls */
#needs { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; }
/* the one you're with: four needs (the mark: what the furniture fills to), how well it works, hand care */
/* one line, the care buttons one line: the dock as low as it can be, the room as big */
.needBars { display: flex; align-items: center; gap: 6px; }
.needBars .need { display: flex; align-items: center; gap: 3px; font-size: 14px; flex: 1 1 0; min-width: 0; }
.needBars .bar { position: relative; flex: 1; height: 7px; border-radius: 4px; background: rgba(120, 70, 90, .15); overflow: hidden; }
.needBars .bar b { position: absolute; left: 0; top: 0; bottom: 0; background: var(--accent, #ff7aa2); border-radius: 4px; }
.needBars .bar u { position: absolute; top: 0; bottom: 0; width: 1px; background: rgba(80, 40, 60, .45); }
.needBars .need.low .bar b { background: var(--bad, #e0584f); }
.needBars .chip.eff { font-size: 12px; flex: none; margin-left: 0; }
.needBars .chip.eff.good { background: #e3f6df; }
.needBars .chip.eff.low { background: #fde3e1; }
.careRow { display: flex; align-items: center; gap: 6px; justify-content: flex-end; min-height: 36px; }
/* the home's edges one width all round, the panels close to the screen's edge, the dock as close to the bottom (no tab
   bar under it, 10-31): room for the room (user: "메뉴의 좌우 패딩이나 상태창 아래 여백 더 줄여서 공간을 만들고, 좌우 여백 통일성") */
#home > .hudTop, #home > .homeRow { margin-left: -8px; margin-right: -8px; }
#home > .hudBottom { padding: 0 8px; bottom: calc(8px + env(safe-area-inset-bottom)); }
/* home's bars and buttons a little see-through: the room shows behind them (10-31, user: "홈에 있는 ui는 투명도를 살짝 주는건 어떨지") */
#home .hudTop { background: #fff8fbc7; }
#home :is(.dock, .roomDock) { background: #fff8fbd4; }
#home :is(.pill, .chip):not(.accent) { background: #fff8fbd4; }
#home .hudTop.slim, #home :is(.dock, .roomDock) { padding-left: 8px; padding-right: 8px; }
#home :is(.dock, .roomDock) { margin-bottom: 0; padding-bottom: 6px; }
#home .dock .needs { margin-bottom: 0; }
@media (max-width: 359px) { .topRight .lbl { display: none; } }   /* a narrow phone: Share is its icon */
.careRow .work { margin-right: auto; }   /* the one you're with going out to work: apart from its care */
.careRow .pill { white-space: nowrap; }
.careRow.icons .pill { flex: 0 0 calc((100% - 24px) / 5); min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 3px 2px; line-height: 1.1; }
.careRow.icons .lbl { font-size: 11px; }   /* not room for the words beside them (home.js fitCare): under the icons, toolbar-like */
@media (max-width: 359px) { .careRow { gap: 4px; } .careRow .pill { padding-left: 6px; padding-right: 6px; } .careRow.icons .pill { flex-basis: calc((100% - 16px) / 5); } }   /* four in a line on a narrow phone */
.careRow .pill.want { border-color: var(--bad, #e0584f); color: var(--bad, #e0584f); }   /* the need that's low: this one (home.js WANT) */
.careRow .pill.dozing { opacity: .45; }   /* asleep: Feed, Wash, Play wait for ☀ Wake (home.js) */
#gameResult.settling { pointer-events: none; }   /* its buttons a moment after it comes up (games.js result) */
.careRow .pill.on { background: var(--accent, #ff7aa2); color: #fff; }   /* under way: tap again to stop */
/* what the furniture out adds to the hands (home.js helps): four small chips, never wider than the card */
/* one tile per care (home.js bars), from the left: its picture and word, its gauge, the furniture's +% under it; 🔨 Work and
   its × on the line under them (.careInfo), beside the furniture */
.careRow.tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; min-height: 0; }
.careRow.tiles .cell { position: relative; grid-row: 1; display: flex; min-width: 0; }
.careRow.tiles .c1 { grid-column: 1; } .careRow.tiles .c2 { grid-column: 2; } .careRow.tiles .c3 { grid-column: 3; }
.careRow.tiles .c4 { grid-column: 4; }
.careRow.tiles .tile { flex: 1; display: flex; flex-direction: column; align-items: stretch; gap: 3px; min-width: 0; margin: 0; padding: 6px 5px 7px; text-align: left;
  line-height: 1.1; white-space: nowrap; }
.careRow.tiles .tileHead { display: flex; align-items: center; gap: 3px; min-width: 0; height: 16px; }   /* not .top: the header's (space-between) */
.careRow.tiles .foot { display: block; height: 10px; font-size: 10px; font-style: normal; font-weight: 700; line-height: 10px; color: var(--muted); }
.careRow.tiles .plus { color: #2f9a5a; }
.careInfo .knack { font-size: 11px; color: var(--muted); }
.careInfo .knack.good { color: #2f9a5a; } .careInfo .knack.low { color: var(--bad, #e0584f); }
.careRow.tiles .pill.on .foot > * { color: #fff; }
.px .careRow.tiles .tileHead .ico { margin: 0; flex: none; }

.careRow.tiles .lbl { font-size: 11px; overflow: hidden; text-overflow: clip; }
.careRow.tiles .bar { display: block; position: relative; width: 100%; height: 6px; border-radius: 3px; background: rgba(120, 70, 90, .3); overflow: hidden; }
.careRow.tiles .bar b { position: absolute; left: 0; top: 0; bottom: 0; background: var(--accent, #ff7aa2); }
.careRow.tiles .bar.low b { background: var(--bad, #e0584f); }
.careRow.tiles .bar.none { visibility: hidden; }
.careInfo .work.soon { opacity: .45; }   /* not open yet: a tap says when */
.careInfo { display: flex; justify-content: space-between; align-items: center; gap: 6px; }
.careInfo .pill { box-sizing: border-box; height: 32px; margin: 0; display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }   /* Work and Furniture one size */
.careInfo .chip { margin: 0; font-size: 12px; }
.careInfo .chip.eff.good { background: #e3f6df; }
.careInfo .chip.eff.low { background: #fde3e1; }
.helps { display: flex; flex-wrap: wrap; gap: 4px; }   /* all four partly there on a narrow phone: two lines, never cut */
.helps .chip { flex: 1 1 auto; margin-left: 0; padding: 1px 2px; font-size: 12px; font-weight: 400; text-align: center; white-space: nowrap; }
.helps .chip.off { opacity: .6; }
.bookRow.todo.done { opacity: .5; }   /* done in this look at the list: kept in its place (todo.js keepPlaces) */
[data-explain] { cursor: pointer; }
.chip.eff[data-explain]::after, .furn[data-explain]::after, .helps[data-explain]::after { content: '?'; display: inline-grid; place-items: center; width: 13px; height: 13px; margin-left: 3px; border-radius: 50%; background: rgba(120, 70, 90, .18); font-size: 9px; line-height: 1; vertical-align: 1px; }   /* tap for what it is (4th QA: not found by two) */
.helps[data-explain]::after { align-self: center; margin-left: 0; }   /* the card's numbers: a tap says what they are (home.js explain) */
ul.plain { list-style: none; padding: 0; margin: 6px 0; display: grid; gap: 4px; }
@media (max-width: 359px) { .helps .chip:not(.off) .n { display: none; } }   /* a narrow phone: what it adds, the count on a tap (title) */
#parkStats:empty { display: none; }   /* the park: nothing to count before the walk starts (park.js who) */

/* the park's names and +bones (park.js tag): page text over the pixel picture, under the buttons */
#park > .parkTags { position: fixed; inset: 0; pointer-events: none; overflow: hidden; z-index: 1; }   /* over the canvas, under the bars that come after it (.screen > :not(.world) would make it a box in the flow) */
.parkTag { position: absolute; left: 0; top: 0; font-size: 12px; line-height: 1.25; padding: 1px 6px; border-radius: 6px;
  background: rgba(255, 255, 255, 0.88); color: #5a4636; white-space: nowrap; will-change: transform; }
.parkTag.me { color: #e8577f; }
.parkTag.pop { background: none; color: #e8577f; font-weight: 700; text-shadow: 0 1px 0 #fff; }
#park .hudBottom .fine { text-shadow: 0 1px 0 #fff, 0 0 4px #fff, 0 0 2px #fff; transition: opacity .6s; }   /* the park's hint over the pictures */
#park #parkHi.far { opacity: .55; }   /* no one in reach of a hello (park.js hiReach) */
#park .hudBottom { pointer-events: none; }   /* a tap through the hint reaches the park; Hello at the side, off the middle (3rd QA: it hid the ones walking there) */
#park .hudBottom button { pointer-events: auto; }
#park .hudBottom .row { justify-content: flex-end; }
#park .hudBottom .fine.quiet { opacity: 0; }
#loginError, #recError { min-height: 1.45em; }
#wanderAbout { min-height: 4.2em; }   /* what random visits are, or why they're off: the same room either way */

/* the first screen while the game comes (index.html #loading; 11-01): the pup hops on the spot — two frames of the
   sprite, twice its size, whole pixels — over the name and a bar the pictures fill; it fades when the first screen shows */
.splash { position: fixed; inset: 0; z-index: 50; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; background: linear-gradient(#ffc0a3 50%, #a9b075 50%); transition: opacity .25s; overflow: hidden; }
/* behind it the door's own day (11-01, user: "로딩화면 배경은 배경이 너무 심심하지않나"): the sky, clouds, hills and grass as
   room.js drawBackdrop draws them, the park's tree and bush beside the pup (assets/ui/splash_bg.png, 960 x 440 art pixels,
   its horizon at row 220), 2 screen pixels to an art pixel as the pup; the horizon a little above the pup's feet, so it
   stands on the grass. Past its edges the top sky colour above and the grass's below */
.splash::before { content: ""; position: absolute; z-index: -1; left: 50%; top: calc(50% - 12px - 440px); width: 1920px; height: 880px;
  margin-left: -960px; background: url("assets/ui/splash_bg.png") 0 0 / 1920px 880px no-repeat; image-rendering: pixelated; }
.splash.gone { opacity: 0; pointer-events: none; }
.splashPup { width: 132px; height: 160px; background: url("assets/ui/splash_pup.png") 0 0 / 264px 160px no-repeat;
  image-rendering: pixelated; animation: splashHop .9s steps(1) infinite; }
@keyframes splashHop { 0% { background-position: 0 0; transform: translateY(0); } 35% { background-position: -132px 0; transform: translateY(-12px); }
  55% { transform: translateY(-6px); } 70% { background-position: 0 0; transform: translateY(0); } }
.splashName { margin: 0; line-height: 0; }
/* the logo's name, 3 screen pixels to an art pixel (270 wide: fits a 320 phone) */
.splashName img { width: 270px; height: 45px; image-rendering: pixelated; }
.splashBar { width: min(220px, 60vw); height: 12px; box-sizing: border-box; border: 2px solid #d79bb4; background: #fff8fb; }
.splashBar i { display: block; height: 100%; width: 0; background: #ff9bb8; transition: width .2s; }
.splashTip { margin: 0; min-height: 1.5em; font: 13px/1.5 "Fusion Pixel", ui-rounded, system-ui, sans-serif; color: var(--muted); text-align: center; padding: 0 16px; }
.splashTip .link { font: inherit; }

/* waiting on the server (server.js remote): three dots blinking in turn at the top, over the game, under the
   loading screen */
.busy { position: fixed; top: calc(8px + env(safe-area-inset-top)); left: 50%; transform: translateX(-50%); z-index: 40; display: none;
  gap: 5px; padding: 6px 9px; background: #fff8fb; border: 2px solid #d79bb4; pointer-events: none; }
.busy.on { display: flex; }
.busy i { width: 6px; height: 6px; background: #ff9bb8; animation: busyDot .9s steps(1) infinite; }
.busy i:nth-child(2) { animation-delay: .3s; }
.busy i:nth-child(3) { animation-delay: .6s; }
@keyframes busyDot { 0% { opacity: 1; } 33% { opacity: .25; } }

/* the capsule opening (capsule.js throwIn): a throw, three wobbles, a burst. The 12-pixel 🔮 icon at 120 px: one of its
   pixels is 10 px, and it only ever moves, grows or jolts by whole ones of those (never turned or stretched) */
#capFx { position: fixed; inset: 0; z-index: 35; display: grid; place-items: center; background: #4a2f3fcc; cursor: pointer; transition: opacity .25s, background-color .5s; }
#capFx.out { opacity: 0; pointer-events: none; }
#capFx .stage { position: relative; width: 0; height: 0; }
#capFx .ball { position: absolute; left: -60px; top: -60px; width: 120px; height: 120px; }   /* at rest where it lands: the throw only in the animation */
#capFx .ball:not(.in) { visibility: hidden; }
#capFx .size { position: absolute; inset: 0; }
#capFx .ball.in { animation: capThrow .7s linear forwards; }
#capFx .ball.in .size { animation: capSpin .7s step-end forwards; }
@keyframes capThrow {   /* up from the bottom in an arc and down, then a hop of two pixels and one of one */
  0% { transform: translate(-24vw, 60vh); animation-timing-function: cubic-bezier(.2, .6, .4, 1); }
  40% { transform: translate(-8vw, -24vh); animation-timing-function: cubic-bezier(.6, 0, .9, .5); }
  66% { transform: translate(0, 0); animation-timing-function: step-end; }
  70% { transform: translate(0, -20px); animation-timing-function: step-end; }
  80% { transform: translate(0, -10px); animation-timing-function: step-end; }
  86% { transform: translate(0, 0); animation-timing-function: step-end; }
  92% { transform: translate(0, -10px); animation-timing-function: step-end; }
  100% { transform: translate(0, 0); } }
@keyframes capSpin {    /* bigger a pixel size at a time as it comes (4, 6, 8, 10 px), flipped each beat like a spin */
  0% { transform: scale(.4); } 12% { transform: scale(-.4, .4); } 22% { transform: scale(.6); } 32% { transform: scale(-.6, .6); }
  42% { transform: scale(.8); } 52% { transform: scale(-.8, .8); } 60% { transform: scale(.8); } 66%, 100% { transform: scale(1); } }
#capFx .ball.wob { animation: capJolt .4s step-end; }
@keyframes capJolt {    /* the wobble: a pixel left, right, left, a little hop, still */
  0% { transform: translate(-10px, 0); } 18% { transform: translate(10px, 0); } 36% { transform: translate(-10px, 0); }
  54% { transform: translate(10px, -10px); } 72% { transform: translate(0, 0); } 100% { transform: translate(0, 0); } }
#capFx .half { position: absolute; inset: 0; transition: transform .45s cubic-bezier(.2, .8, .3, 1), opacity .4s .1s; }
#capFx .half .ico { --s: 120px; margin: 0; display: block; }
#capFx .half.capUp { clip-path: inset(0 0 50px 0); }       /* split along its dark middle row (pixels 60-70 px): that row goes up with the top */
#capFx .half.capDown { clip-path: inset(70px 0 0 0); }
#capFx .seam { position: absolute; left: 0; right: 0; top: 60px; height: 10px; background: #fff; opacity: var(--lit, 0); transition: opacity .2s; }   /* the middle row lights up, a little more each wobble */
#capFx .hint { position: absolute; bottom: calc(18% + env(safe-area-inset-bottom)); left: 0; right: 0; text-align: center; margin: 0; color: #fff; font-size: 12px; opacity: .75; transition: opacity .2s; }
#capFx.pop { background-color: #fff3f8cc; }   /* the flash of the burst, the colour of what it is */
#capFx.pop.rare { background-color: #fff1c2d9; }
#capFx.pop.special { background-color: #ffe3f1e6; }
#capFx.pop .hint, #capFx.pop .seam { opacity: 0; }
#capFx.pop .capUp { transform: translate(-40px, -90px); opacity: 0; }
#capFx.pop .capDown { transform: translate(30px, 80px); opacity: 0; }
#capFx .spark { position: absolute; left: -5px; top: -5px; width: 10px; height: 10px; background: #ff9ebd; animation: capSpark .55s ease-out forwards; pointer-events: none; }
#capFx.rare .spark { background: #f5b82e; }
#capFx.special .spark:nth-of-type(3n) { background: #ff8fb1; } #capFx.special .spark:nth-of-type(3n+1) { background: #6fb7e8; } #capFx.special .spark:nth-of-type(3n+2) { background: #f5b82e; }
@keyframes capSpark { from { transform: translate(0, 0); } to { transform: translate(var(--x), var(--y)); opacity: 0; } }
@media (prefers-reduced-motion: reduce) { #capFx .ball.in, #capFx .ball.in .size { animation-duration: .01s; } }
/* the card after the burst: a smooth pop, a touch past its size and back (11-02, user: "카드가 확대되었다가 줄어드는데 애니메이션
   되는게 아니라 끊기네" — it went in two steps) */
#modalBody .reveal.burst { animation: revealIn .42s cubic-bezier(.2, 1.35, .4, 1) both; }
@keyframes revealIn { from { transform: scale(.82); opacity: 0; } 40% { opacity: 1; } to { transform: scale(1); opacity: 1; } }

/* the room's card (index.html #roomDock): the one chosen's card (.dock, .dockHead) for a room — its picture, name, the
   favourite and Decorate; who is in it under that */
#home:not(.roomMode) #roomDock, #home.building #roomDock, #home:not(.building) #roomBar { display: none; }
.roomDock { border: 2px solid var(--line); border-radius: 16px; padding: 8px 10px; margin: 6px 0 8px; box-shadow: 0 -2px 12px #e7b3c633; background: #fff8fbf2; }   /* as .dock (a class of its own: home.js finds the one chosen's as '#home .dock') */
.roomFace { display: grid; place-items: center; width: 40px; height: 40px; box-sizing: border-box; background: #fff; border: 2px solid var(--line); border-radius: 10px; }
.roomFace .ico { --s: 28px; margin: 0; }
/* its head a row: the picture, the name, then the favourite and Decorate at the end (one room: Decorate alone there) */
.roomHead { display: flex; }
.roomHead #roomName { white-space: nowrap; flex: 0 1 auto; }
.roomHead .gap { flex: 1; }
.roomHead .roomFace { flex: none; }
.roomHead .pill.small { flex: none; box-sizing: border-box; height: 32px; display: inline-flex; align-items: center; gap: 6px; padding: 0 10px; margin: 0; white-space: nowrap; }
.roomHead.tight #favRoom span, .roomHead.tighter #toDecorate span { display: none; }   /* a narrow phone (home.js fitBar) */
.roomWho { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; min-height: 36px; }   /* a chip's height: the card the same with no one in it */
.roomWho .whoHere { display: inline-flex; align-items: center; gap: 6px; }
.roomWho .whoHere img { width: 22px; height: 22px; image-rendering: pixelated; }
.roomWho .none { color: var(--muted); font-size: 12px; }
