/* 线下 · 城市地图和店铺 (js/apps/offline-town.js). Lives inside .oh-root (offline-home.css): the same white chips with a 2px outline and a 3px drop shadow, the same
   centred dialogs (the home's own). The map is above the home (z 10), a shop above the map (z 12); the dialogs (z 20), the phone-screen fade (z 50) and the toast
   stay above both. Button rules start with #companion-body so they win over companion.css's blanket button styles. */
.ot-root { position: absolute; inset: 0; z-index: 10; pointer-events: none; }
.ot-map, .ot-scene { position: absolute; inset: 0; display: none; overflow: hidden; pointer-events: auto; user-select: none; -webkit-user-select: none; }
.ot-root.map-on .ot-map { display: block; background: #9CB98A; touch-action: none; cursor: grab; }
.ot-root.scene-on .ot-scene { display: block; z-index: 2; background: var(--oh-panel); }
.ot-root.scene-on .ot-map { visibility: hidden; }   /* the map keeps its place (and its camera) under the shop */
.ot-c, .ot-sc { position: absolute; left: 0; top: 0; image-rendering: pixelated; }
/* the town: the picture (400 x H native pixels, a whole multiple bigger) with the signs and the people's badges laid over it; the camera moves .ot-mcam */
.ot-mcam { position: absolute; left: 0; top: 0; will-change: transform; }
.ot-tsigns { position: absolute; inset: 0; pointer-events: none; }
.ot-tsign { position: absolute; transform: translate(-50%, -100%); font-size: 12px; line-height: 1; padding: 3px 7px; white-space: nowrap; pointer-events: none; background: var(--sw) repeating-linear-gradient(0deg, var(--sw) 0 6px, var(--sw2) 6px 7px); color: var(--sink); border: 2px solid var(--sed); box-shadow: 0 2px 0 0 var(--sed), inset 0 2px 0 0 var(--shl); }
.ot-tsign.locked { filter: saturate(.4); opacity: .85; }
.ot-pins { position: absolute; inset: 0; }
.ot-hud { position: absolute; left: 12px; right: 12px; top: calc(10px + var(--sat, 0px)); display: flex; align-items: center; justify-content: space-between; gap: 8px; z-index: 5; pointer-events: none; }
.ot-hud > * { pointer-events: auto; }
.ot-r { display: flex; gap: 6px; }
.ot-bar { position: absolute; left: 12px; right: 12px; bottom: calc(14px + var(--sab, 0px)); display: flex; justify-content: flex-end; gap: 8px; align-items: stretch; z-index: 5; }
.ot-mode { flex: 1; background: var(--oh-panel); color: var(--oh-ink); border: 2px solid var(--oh-edge); box-shadow: 0 3px 0 0 var(--oh-edge); padding: 8px 12px; font-size: 13px; display: flex; flex-direction: column; justify-content: center; min-width: 0; }
.ot-mode small { color: var(--oh-ink2); font-size: 11px; }
#companion-body .ot-bar .oh-pxbtn { flex-direction: column; gap: 2px; font-size: 11px; min-width: 56px; }
.ot-badge { position: absolute; transform: translate(-50%, -100%); width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; font-size: 13px; border: 2px solid #2E3A4F; box-shadow: 0 2px 0 0 #2E3A4F; pointer-events: none; }
.ot-badge.him { color: #fff; z-index: 2; }
.ot-badge.him:after { content: ''; position: absolute; right: -5px; top: -5px; width: 8px; height: 8px; background: #F2708E; border: 2px solid #fff; animation: oh-blink 1s steps(2) infinite; }
/* dialogs of the town (the dialog itself is the home's) */
.ot-here { display: flex; align-items: center; gap: 8px; margin: 10px 0 2px; font-size: 13px; }
.ot-av { width: 26px; height: 26px; flex: none; color: #fff; display: flex; align-items: center; justify-content: center; border: 2px solid var(--oh-edge); font-size: 12px; }
.ot-btns { margin-top: 12px; }
.ot-bar2 { height: 8px; border: 2px solid #2E3A4F; margin-top: 10px; background: #fff; }
.ot-bar2 i { display: block; height: 100%; background: #E8879C; }
.ot-buylist { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 12px; }
#companion-body .ot-buyit { display: flex; justify-content: space-between; align-items: center; min-height: 44px; padding: 0 10px; border: 2px solid var(--oh-edge); background: var(--oh-panel); color: var(--oh-ink); font-size: 13px; cursor: pointer; box-shadow: 0 2px 0 0 var(--oh-edge); border-radius: 0; }
#companion-body .ot-buyit b { font-weight: 600; color: var(--oh-ink2); margin-left: 4px; white-space: nowrap; }
#companion-body .ot-buyit span { flex: 1; text-align: left; min-width: 0; }
.ot-buyit .gi { width: 24px; height: 24px; image-rendering: pixelated; flex: none; margin-right: 6px; background: var(--oh-soft); border: 2px solid var(--oh-edge); padding: 0; }
#companion-body .ot-buyit.on { background: var(--oh-accent); color: var(--oh-accent-ink); }
#companion-body .ot-buyit.on b { color: var(--oh-accent-ink); }
.ot-buybar { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: 13px; }
.ot-buybar small { display: block; color: var(--oh-ink2); font-size: 11px; margin-top: 2px; }
#companion-body .ot-buybar .oh-pxbtn { background: var(--oh-accent); color: var(--oh-accent-ink); min-width: 76px; }
#companion-body .ot-buybar .oh-pxbtn[disabled] { opacity: .45; }
/* the shop */
.ot-hits { position: absolute; inset: 0; pointer-events: none; }   /* only the people take taps, the floor under them is the canvas's */
#companion-body .ot-hit { pointer-events: auto; position: absolute; background: none; border: 0; padding: 0; cursor: pointer; border-radius: 0; }
.ot-hit .nm { position: absolute; left: 50%; top: -6px; transform: translate(-50%, -100%); font-size: 11px; background: var(--oh-panel); color: var(--oh-ink); border: 2px solid var(--oh-edge); padding: 1px 5px; white-space: nowrap; }
.ot-bub { position: absolute; color: #2E3A4F; border: 16px solid transparent; border-image: var(--b9) 8 fill / 16px; padding: 0 2px; line-height: 14px; font-size: 12px; opacity: 0; transform: translate(-50%, calc(-100% + 6px)); transition: opacity .15s, transform .15s; white-space: nowrap; pointer-events: none; image-rendering: pixelated; }
.ot-bub.emo { border: 0; border-image: none; padding: 0; }
.ot-bub.emo .emoa { display: block; width: calc(16px * var(--S, 2)); height: calc(16px * var(--S, 2)); background-size: calc(64px * var(--S, 2)) 100%; background-repeat: no-repeat; image-rendering: pixelated; transform-origin: 20% 100%; animation: ot-emoa .8s steps(4) infinite, ot-emopop .24s steps(3) 1; }
@keyframes ot-emoa { from { background-position: 0 0; } to { background-position: calc(-64px * var(--S, 2)) 0; } }
@keyframes ot-emopop { from { transform: scale(.5); } to { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .ot-bub.emo .emoa { animation: none; } }
.ot-bub.show { opacity: 1; transform: translate(-50%, -100%); }
.ot-flash { position: absolute; inset: 0; background: #fff; opacity: 0; pointer-events: none; }
.ot-flash.go { animation: ot-flash .5s steps(3); }
@keyframes ot-flash { 0% { opacity: .9; } 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .ot-badge.him:after, .ot-flash.go { animation: none; transition: none; } }
/* 已打烊 in the place card's sub line: red (a lighter red on the dark panel) */
.ot-shut { color: #C0392B; font-weight: 600; }
.oh-root.night .ot-shut { color: #FF8A80; }
:root[data-theme="dark"] .oh-root .ot-shut { color: #FF8A80; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .oh-root .ot-shut { color: #FF8A80; } }
/* the shop's picture and everything on it moves together (the camera follows the walker when the room is taller than the screen) */
.ot-cam { position: absolute; inset: 0; }
/* 门牌: the same wooden sign as the buttons at the top, hung over a door */
.ot-sign { position: absolute; transform: translate(-50%, -100%); font-size: 10px; line-height: 1; padding: 3px 5px; white-space: nowrap; pointer-events: none; background: var(--sw) repeating-linear-gradient(0deg, var(--sw) 0 6px, var(--sw2) 6px 7px); color: var(--sink); border: 2px solid var(--sed); box-shadow: 0 2px 0 0 var(--sed), inset 0 2px 0 0 var(--shl); }
/* sitting down: the little wooden buttons at the bottom (看窗外 / 看手机 / 发呆 / 起身) */
.ot-acts { position: absolute; left: 50%; bottom: calc(14px + var(--sab, 0px)); transform: translate(-50%, 12px); display: flex; gap: 6px; opacity: 0; pointer-events: none; transition: opacity .2s, transform .25s steps(4); z-index: 3; }
.ot-acts.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
#companion-body .ot-acts button { white-space: nowrap; flex: none; min-height: 44px; padding: 0 12px; font-size: 12px; cursor: pointer; border-radius: 0; background: var(--sw) repeating-linear-gradient(0deg, var(--sw) 0 6px, var(--sw2) 6px 7px); color: var(--sink); border: 2px solid var(--sed); box-shadow: 0 3px 0 0 var(--sed), inset 0 2px 0 0 var(--shl); }
#companion-body .ot-acts button:active { transform: translateY(2px); box-shadow: 0 1px 0 0 var(--sed), inset 0 2px 0 0 var(--shl); }
@media (prefers-reduced-motion: reduce) { .ot-acts { transition: none; } }
/* 角色的家 (js/apps/offline-town.js, design _handoff/charhome-cool/design.md): 摆放 in a character's home - the bar at the bottom, the button that goes to the other room, the 添加家具 dialog */
.ot-root [hidden] { display: none !important; }
.ot-root.editing .ot-sc { touch-action: none; cursor: grab; }
.ot-roombtn { position: absolute; left: 12px; top: calc(62px + var(--sat, 0px)); z-index: 5; white-space: nowrap; }
.ot-edit { position: absolute; left: 8px; right: 8px; bottom: calc(10px + var(--sab, 0px)); display: flex; flex-direction: column; align-items: center; gap: 6px; z-index: 4; }
.ot-edit small { font-size: 11px; line-height: 1.4; padding: 3px 8px; background: rgba(46, 58, 79, .85); color: #fff; max-width: 100%; }
.ot-editbtns { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
#companion-body .ot-editbtns .oh-pxbtn { white-space: nowrap; font-size: 12px; }
.ot-catalog { max-height: 56vh; overflow-y: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
.ot-catalog::-webkit-scrollbar { display: none; }
.ot-cat-t { margin: 10px 0 4px; font-size: 12px; color: var(--oh-ink2); }
.ot-cat-g { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
#companion-body .ot-cat { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 4px; padding: 6px 2px; min-height: 96px; border: 2px solid var(--oh-edge); background: var(--oh-panel); color: var(--oh-ink); cursor: pointer; border-radius: 0; box-shadow: 0 3px 0 0 var(--oh-edge); }
#companion-body .ot-cat:active { transform: translateY(2px); box-shadow: 0 1px 0 0 var(--oh-edge); }
.ot-cat img { image-rendering: pixelated; max-width: 100%; }
.ot-cat span { font-size: 11px; line-height: 1.2; text-align: center; }
/* the dev editor of the town's default layout (js/apps/offline-town-editor.js; TOWN_EDITOR in offline-town.js is off for everybody) */
.ot-edit-open[hidden] { display: none !important; }
.ot-edit-ui { position: absolute; left: 12px; right: 12px; bottom: calc(14px + var(--sab, 0px)); z-index: 6; display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; }
.ot-edit-ui[hidden] { display: none !important; }
.ot-edit-ui .oh-pxbtn { white-space: nowrap; font-size: 12px; }
.ot-edit-tip { position: absolute; left: 50%; top: calc(62px + var(--sat, 0px)); transform: translateX(-50%); z-index: 6; background: rgba(46, 58, 79, .88); color: #fff; font-size: 12px; padding: 5px 10px; white-space: nowrap; pointer-events: none; }
.ot-edit-tip[hidden] { display: none !important; }
.ot-edit-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; max-height: 56vh; overflow-y: auto; scrollbar-width: none; }
.ot-edit-grid::-webkit-scrollbar { display: none; }
.ot-edit-grid .it { border: 2px solid var(--oh-edge); background: #fff; height: 64px; display: flex; align-items: center; justify-content: center; padding: 0; }
.ot-edit-grid .it img { max-width: 56px; max-height: 56px; image-rendering: pixelated; }
.ot-edit-sec { grid-column: 1 / -1; font-size: 12px; color: var(--oh-ink2); margin: 6px 2px 0; }
.ot-edit-ta { width: 100%; height: 220px; font: 12px monospace; box-sizing: border-box; }
/* 店里: the buttons at the top (设置 / 摆放), the bar of 摆放 and the buttons that come up when you sit are frosted glass */
#companion-body .ot-scene .ot-hud .oh-pxbtn, #companion-body .ot-scene .ot-edit .oh-pxbtn, #companion-body .ot-scene .ot-acts button, .ot-scene .ot-hud .oh-status {
  background: color-mix(in srgb, var(--oh-panel) 58%, transparent); color: var(--oh-ink); border: 1px solid rgba(255, 255, 255, .5); border-radius: 22px;
  box-shadow: 0 8px 20px rgba(40, 60, 90, .16); -webkit-backdrop-filter: blur(18px) saturate(1.4); backdrop-filter: blur(18px) saturate(1.4); }
#companion-body .ot-scene .ot-hud .oh-pxbtn:active, #companion-body .ot-scene .ot-edit .oh-pxbtn:active, #companion-body .ot-scene .ot-acts button:active { box-shadow: 0 4px 10px rgba(40, 60, 90, .16); }
.ot-scene .ot-hud .oh-status::before, .ot-scene .ot-hud .oh-status::after { display: none; }
.ot-scene .ot-hud .oh-status b { color: var(--oh-ink); }
#companion-body .ot-scene .ot-hud .oh-pxbtn.on { background: var(--oh-accent); color: var(--oh-accent-ink); }
/* 毛玻璃圆角 (the rest of the town's chrome; the buttons, status bars and the mode card are glass in styles/offline-home.css): the tip bars, the progress bar, the small tiles */
#companion-body .ot-root .ot-edit small, #companion-body .ot-root .ot-edit-tip { border-radius: 14px; background: rgba(46, 58, 79, .8); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); padding: 5px 12px; }
#companion-body .ot-root .ot-bar2 { border: 0; border-radius: 6px; background: var(--gl2); overflow: hidden; }
#companion-body .ot-root .ot-edit-grid .it { border-radius: 12px; background: var(--gl2); }
/* 面包店集章卡: 2 x 5 cells, a stamped one shows the stamp, the last says 赠 */
.ot-stampcard { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin: 10px 0; }
.ot-stampcard span { aspect-ratio: 1; display: grid; place-items: center; border: 2px dashed #C8A06A; border-radius: 10px; background: #FBF4E8; color: #B0473A; font-size: 16px; }
.ot-stampcard span.on { border-style: solid; background: #F6E2C8; }
.ot-stampcard img { width: 32px; height: 32px; image-rendering: pixelated; }
.ot-edit-open { margin-right: auto; }   /* (developer switch only) stays at the left when the bar is pushed right */
