/* The town's chrome: full-screen canvas, chips, speech bubbles, loader. */
/* The town's lettering (PLACEBO TOWN on the gate sign and the loader): Almendra Bold, OFL, self-hosted unmodified. */
@font-face { font-family: 'Town Sign'; src: url('/fonts/Almendra-Bold.ttf') format('truetype'); font-display: swap; }
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; overscroll-behavior: none; }
body { background: #9fd4f2; font: 15px/1.35 ui-rounded, "SF Pro Rounded", "Nunito", system-ui, -apple-system, sans-serif; color: #2d3a2a; -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; }
canvas { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; cursor: pointer; }
.chip { position: fixed; top: max(14px, env(safe-area-inset-top)); z-index: 3; display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: 999px; border: 0; background: rgba(255, 253, 246, .92); color: #2d3a2a; font: 600 14px/1 inherit; font-family: inherit; text-decoration: none; box-shadow: 0 3px 0 rgba(45, 58, 42, .18); cursor: pointer; }
.chip:active { transform: translateY(2px); box-shadow: 0 1px 0 rgba(45, 58, 42, .18); }
/* The sound chip sits under the weather chip (hud.css), on the same right edge. */
.sound { right: 16px; top: calc(max(14px, env(safe-area-inset-top)) + 42px); width: 40px; height: 32px; padding: 0; justify-content: center; }
.sound svg { width: 20px; height: 20px; }
.sound .cross, .sound[data-muted="1"] .wave { display: none; }
.sound[data-muted="1"] .cross { display: inline; }
.hint { position: fixed; left: 50%; bottom: max(18px, env(safe-area-inset-bottom)); transform: translateX(-50%); z-index: 3; margin: 0; padding: 8px 16px; border-radius: 999px; background: rgba(45, 58, 42, .72); color: #fffdf6; font-weight: 600; font-size: 13px; white-space: nowrap; transition: opacity .6s ease; pointer-events: none; }
.hint.gone { opacity: 0; }
#bubbles { position: fixed; inset: 0; z-index: 2; pointer-events: none; }
/* Speech bubbles in the town's own look: a soft cream cloud with a warm outline, the speaker's name on a tag
   that overlaps its corner, a tail down to the speaker; it pops in and the line types itself. */
.bubble { position: absolute; left: 0; top: 0; max-width: min(250px, 72vw); padding: 12px 15px 11px; border-radius: 22px 22px 22px 22px / 20px 20px 24px 24px; background: #fffaf0; color: #3b3326; font-weight: 700; font-size: 14.5px; line-height: 1.35; border: 2.5px solid #e9dcc0; box-shadow: 0 4px 0 rgba(90, 70, 40, .16), 0 10px 24px rgba(40, 30, 10, .12); transform: translate(-50%, -100%); opacity: 0; transition: opacity .25s ease; }
.bubble::after { content: ""; position: absolute; left: 50%; bottom: -11px; width: 18px; height: 14px; margin-left: -9px; background: #fffaf0; border: 2.5px solid #e9dcc0; border-top: 0; border-left: 0; border-radius: 0 0 6px 0; transform: skewX(-18deg) rotate(38deg); transform-origin: center; }
.bubble.edge::after { display: none; }
.bubble.show { opacity: 1; }
.bubble.show.pop { animation: pop .32s cubic-bezier(.3, 1.6, .5, 1); }
@keyframes pop { from { scale: .82; } to { scale: 1; } }
/* The speaker's name on a small wooden sign (8.11, bepo: not the plain tag): a planked board in the town's lettering,
   hung slightly askew, with a disc in the speaker's own colour (--c, set per resident in town.js). */
.bubble b { position: absolute; left: 12px; top: -17px; padding: 5px 11px 4px 24px; border-radius: 6px; border: 2px solid #6d4a30; background: repeating-linear-gradient(180deg, transparent 0 7px, rgba(90, 55, 25, .18) 7px 8px), linear-gradient(#c3925c, #9e6d42); color: #fff4d8; font: 400 16px/1 'Town Sign', Georgia, serif; letter-spacing: .05em; text-shadow: 0 1px 0 rgba(70, 40, 15, .65); box-shadow: 0 2px 0 rgba(70, 40, 15, .3); transform: rotate(-3deg); }
.bubble b::before { content: ""; position: absolute; left: 7px; top: 50%; width: 10px; height: 10px; margin-top: -5px; border-radius: 50%; background: var(--c, #e0703a); border: 2px solid #6d4a30; box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .18); }
.bubble:has(b) { padding-top: 18px; }
.bubble span u { text-decoration: none; visibility: hidden; }
.bubble span i { font-style: normal; }
.bubble.place { background: #3b4a33; color: #fffaf0; border-color: #3b4a33; padding: 6px 12px; font-size: 13px; border-radius: 999px; }
.bubble.place::after { display: none; }
/* Look at (8.19 (c) 2): the selected person's name sign stands over them; on a talk bubble the sign glows. */
.bubble.tag { padding: 0; background: none; border: 0; box-shadow: none; }
.bubble.tag::after { display: none; }
.bubble.tag b { position: relative; left: 0; top: 0; display: inline-block; }
.bubble.tag span { display: none; }
.bubble.sel b, .bubble.tag b { box-shadow: 0 2px 0 rgba(70, 40, 15, .3), 0 0 0 3px #fffaf0, 0 0 14px 4px rgba(255, 214, 120, .85); }
@media (prefers-reduced-motion: reduce) { .bubble.show.pop { animation: none; } }
/* Bro, the poodle (8.20a, 8.22e): a heart floats up when he is petted; a small cream card under him holds his
   commands, wrapping onto two rows (one on a wide screen), never wider than a phone. */
.poodle-heart { position: absolute; left: 0; top: 0; color: #e8546b; font-size: 22px; line-height: 1; transform: translate(-50%, -100%); text-shadow: 0 2px 0 rgba(90, 30, 40, .25); }
.poodle-card { position: absolute; left: 0; top: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; width: max-content; max-width: min(330px, calc(100vw - 16px)); padding: 6px; border-radius: 20px; background: #fffaf0; border: 2px solid #e9dcc0; box-shadow: 0 3px 0 rgba(90, 70, 40, .16); transform: translateX(-50%); pointer-events: auto; }
.poodle-card[hidden] { display: none; }
.poodle-card button { font: 700 13px/1 inherit; font-family: inherit; color: #3b3326; background: #f3e7cc; border: 0; border-radius: 999px; padding: 8px 12px; min-height: 32px; cursor: pointer; touch-action: manipulation; }
.poodle-card button.bark { background: #f6dcc0; }
.poodle-card button.grr { background: #ecc4b4; }
.poodle-card button:hover, .poodle-card button:focus-visible { background: #e9d6ad; }

/* The loader: the crest on dusky forest green, a thin line under it and one quiet status line; no drawn sky. */
.loader { --p: 0; position: fixed; inset: 0; z-index: 8; display: grid; place-content: center; justify-items: center; gap: 18px; background: radial-gradient(120% 90% at 50% 40%, #35553f, #1d2b22 70%); transition: opacity .7s ease .15s, visibility 0s .9s; }
.loader.done { opacity: 0; visibility: hidden; pointer-events: none; }
.loader .crest { width: 84px; height: 84px; filter: drop-shadow(0 6px 10px rgba(0, 0, 0, .35)); animation: breathe 2.4s ease-in-out infinite; }
@keyframes breathe { 50% { transform: translateY(-3px) scale(1.03); } }
.loader h1 { margin: -4px 0 0; font: 400 34px/1 'Town Sign', Georgia, serif; letter-spacing: .04em; color: #f6e7c1; text-shadow: 0 3px 0 rgba(0, 0, 0, .3); }
.loader .line { width: 140px; height: 3px; border-radius: 3px; background: rgba(246, 231, 193, .18); overflow: hidden; }
.loader .line i { display: block; height: 100%; width: calc(var(--p) * 100%); background: #f6e7c1; transition: width .3s ease; }
.loader p { margin: 0; font-weight: 700; font-size: 13px; letter-spacing: .02em; color: rgba(246, 231, 193, .75); }
@media (prefers-reduced-motion: reduce) { .loader * { animation: none !important; transition: none !important; } }
/* The gate: the walking hint waits until the visitor is inside; the conversation card sits at the bottom. */
body.gate .hint { display: none; }
.talk { position: fixed; left: 50%; bottom: max(16px, env(safe-area-inset-bottom)); transform: translateX(-50%); z-index: 3; width: min(440px, 100vw - 32px); display: grid; gap: 8px; padding: 12px; border-radius: 22px; background: rgba(255, 253, 246, .94); box-shadow: 0 4px 0 rgba(45, 58, 42, .2); }
.talk[hidden] { display: none; }
.talk .row { display: flex; gap: 8px; }
.talk button, .talk input { flex: 1 1 0; min-width: 0; min-height: 46px; padding: 0 14px; border-radius: 14px; border: 2px solid rgba(45, 58, 42, .18); background: #fffdf6; color: #2d3a2a; font: 600 15px/1.2 inherit; font-family: inherit; text-align: center; }
.talk button { cursor: pointer; }
.talk button:active { transform: translateY(2px); }
.talk .primary { background: #e0703a; border-color: #e0703a; color: #fffdf6; }
.talk .google { background: #fff; }
.talk input { text-align: left; }
.talk input:focus { outline: none; border-color: #e0703a; }
.talk .swatches { justify-content: center; gap: 12px; }
.talk .swatch { flex: none; width: 46px; min-height: 46px; padding: 0; border-radius: 50%; background: var(--c); border: 3px solid rgba(45, 58, 42, .18); }
.talk .swatch[aria-pressed="true"] { border-color: #e0703a; box-shadow: 0 0 0 3px #fffaf0 inset; }
.talk > button { flex: none; }
@media (max-width: 480px) { .talk .row:has(> :nth-child(3)) { flex-wrap: wrap; } .talk .row:has(> :nth-child(3)) > * { flex-basis: 100%; } }
/* The hold ring (town.js longPress): a ring under the finger that closes in during the half-second long press. */
.hold { position: fixed; left: -32px; top: -32px; z-index: 2; width: 64px; height: 64px; border-radius: 50%; border: 3px solid rgba(255, 253, 246, .95); box-shadow: 0 0 0 2px rgba(224, 112, 58, .5); pointer-events: none; opacity: 0; }
.hold.on { animation: hold .5s linear forwards; }
@keyframes hold { from { opacity: 0; scale: 1.25; } 20% { opacity: 1; } to { opacity: 1; scale: .55; } }
/* Another visitor (net.js): only their name sign while they are quiet, the cloud around it when they speak. */
.bubble.visitor.quiet { padding: 0; min-width: 0; background: none; border-color: transparent; box-shadow: none; }
.bubble.visitor.quiet::after { display: none; }
.bubble.visitor.quiet b { position: static; display: inline-block; }
