/* KIMCHIWORK UI. Soft painted paper over the live planet: warm cream cards
   with a thin ink line, hand-cut rounded corners and a soft drop shadow (no
   hard comic offsets). Fredoka for headings and buttons, Patrick Hand for
   data, Kalam for what the residents say.

   COLOUR (measured on the paper #FBF5E6):
     --red    #D2452F  kimchi red: fills with white text 4.5:1, and accents
     --green  #7FAE45  cabbage green: ink text on it only, never white
     --ink    #27303F  text and lines
     --sky    #7EC3E6  the page behind the canvas, the loading screen, the wipe

   CHINESE: none of the three has Chinese glyphs, so every stack falls
   through to PingFang SC, Hiragino Sans GB, Noto Sans SC or Microsoft YaHei
   (per glyph: Latin text keeps its hand font). src/i18n.js sets <html
   lang="zh-CN"> and the html:lang(zh) block at the end evens the spacing.

   Element ids and classes are queried by src/ui.js, src/game.js,
   src/landing.js and src/selftest.js: restyle freely, rename nothing. */

html, body { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: #7EC3E6; touch-action: none; -webkit-text-size-adjust: 100%; }
body { font-family: 'Patrick Hand', 'Kalam', 'PingFang SC', 'Hiragino Sans GB', 'Noto Sans SC', 'Microsoft YaHei', ui-rounded, system-ui, sans-serif; color: #27303F; font-size: 19px; -webkit-font-smoothing: antialiased; }
canvas#gl { display: block; position: fixed; inset: 0; width: 100vw; height: 100vh; }
#ui {
  position: fixed; inset: 0; pointer-events: none; user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
  --ink: #27303F; --ink-line: rgba(39, 48, 63, 0.78); --mut: #5C6372; --line: rgba(39, 48, 63, 0.16); --row: rgba(39, 48, 63, 0.05);
  --paper: #FBF5E6; --paper-2: #F3EAD3; --paper-glass: rgba(251, 245, 230, 0.93);
  --red: #D2452F; --red-dk: #B5371F; --green: #7FAE45; --green-dk: #4E7A2A; --green-lt: #DCEBB0;
  --sky: #7EC3E6; --yellow: #F2C14E; --teal: #7EC3E6;
  --shadow: 0 2px 0 rgba(39, 48, 63, 0.12), 0 10px 26px rgba(28, 52, 84, 0.18);
  --shadow-sm: 0 2px 0 rgba(39, 48, 63, 0.14), 0 4px 12px rgba(28, 52, 84, 0.12);
  --shadow-lg: 0 3px 0 rgba(39, 48, 63, 0.12), 0 18px 44px rgba(20, 40, 66, 0.26);
  --cut: 19px 16px 20px 17px / 17px 20px 16px 19px;
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/%3E%3CfeColorMatrix values='0 0 0 0 0.5 0 0 0 0 0.4 0 0 0 0 0.28 0 0 0 0.07 0'/%3E%3C/filter%3E%3Crect width='120' height='120' filter='url(%23n)'/%3E%3C/svg%3E");
  --wave: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='8' viewBox='0 0 40 8'%3E%3Cpath d='M0 4c5 0 5-3 10-3s5 3 10 3 5-3 10-3 5 3 10 3' fill='none' stroke='%237FAE45' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
  --display: 'Fredoka', 'Patrick Hand', 'PingFang SC', 'Hiragino Sans GB', 'Noto Sans SC', 'Microsoft YaHei', ui-rounded, system-ui, sans-serif;
  --voice: 'Kalam', 'Patrick Hand', 'PingFang SC', 'Hiragino Sans GB', 'Noto Sans SC', 'Microsoft YaHei', ui-rounded, system-ui, sans-serif;
}
#ui * { box-sizing: border-box; }
/* zero specificity, so a class (.btn, .chip, .next) can set its own font and colour */
:where(#ui) button { font: inherit; color: inherit; cursor: pointer; }
#ui :focus-visible { outline: 2.5px solid var(--red); outline-offset: 2px; }
.head { font-family: var(--display); font-weight: 600; letter-spacing: 0.01em; }

/* paper cards */
.card { background: var(--grain), var(--paper-glass); border: 1.5px solid var(--ink-line); border-radius: var(--cut); box-shadow: var(--shadow); pointer-events: auto; }
.card.tilt { transform: rotate(-0.5deg); }

/* HUD top-left: the KIMCHI counter and the wallet pill */
#hud { position: absolute; left: calc(16px + env(safe-area-inset-left, 0px)); top: calc(14px + env(safe-area-inset-top, 0px)); display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
#points { position: relative; display: flex; align-items: center; gap: 9px; height: 46px; padding: 0 16px 0 6px; border-radius: 999px; }
#points .ic { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%; background: var(--red); flex: none; }
#points .ic svg { width: 22px; height: 22px; }
#points .head { font-size: 24px; line-height: 1; font-variant-numeric: tabular-nums; }
#points .lbl { font: 600 12px/1 var(--display); color: var(--red-dk); letter-spacing: 0.14em; }
#points .gain { position: absolute; left: 100%; margin-left: 10px; top: 9px; padding: 3px 10px; border-radius: 999px; background: var(--green); color: var(--ink); font: 600 16px/1.2 var(--display); box-shadow: var(--shadow-sm); opacity: 0; transform: translateY(6px); transition: opacity 0.3s, transform 0.3s; white-space: nowrap; }
#points .gain.show { opacity: 1; transform: translateY(0); }
#wallet-pill { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 14px 0 11px; border-radius: 999px; font-size: 16px; cursor: pointer; box-shadow: var(--shadow-sm); }
#wallet-pill .dot { width: 9px; height: 9px; border-radius: 50%; background: #B9B2A6; box-shadow: 0 0 0 3px rgba(185, 178, 166, 0.25); }
#wallet-pill.on .dot { background: var(--green); box-shadow: 0 0 0 3px rgba(127, 174, 69, 0.28); }

/* side buttons */
.side { position: absolute; right: calc(16px + env(safe-area-inset-right, 0px)); display: flex; flex-direction: column; gap: 10px; }
.side.top { top: calc(14px + env(safe-area-inset-top, 0px)); }
.side.bottom { bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
.sbtn { width: 54px; height: 54px; padding: 0; display: grid; place-items: center; border-radius: 50% 47% 52% 49% / 49% 52% 47% 50%; transition: transform 0.15s ease, background-color 0.15s; position: relative; }
.sbtn svg { width: 26px; height: 26px; stroke: var(--ink); fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.sbtn:hover { transform: translateY(-2px); }
.sbtn:active { transform: translateY(1px); }
.sbtn .badge { position: absolute; top: -2px; right: -2px; width: 15px; height: 15px; border-radius: 50%; background: var(--red); box-shadow: 0 0 0 2.5px var(--paper); display: none; }
.sbtn.dot .badge { display: block; animation: kw-pulse 1.8s ease-in-out infinite; }
.sbtn.on { background: var(--red); border-color: var(--red-dk); }
.sbtn.on svg { stroke: #fff; }
@keyframes kw-pulse { 50% { transform: scale(1.18); } }

/* floating talk prompt over a resident */
#prompt { position: absolute; transform: translate(-50%, -100%); height: 40px; padding: 0 16px 0 5px; display: none; align-items: center; gap: 9px; border-radius: 999px; font: 18px/1 var(--voice); white-space: nowrap; }
#prompt.show { display: flex; animation: kw-rise 0.18s ease-out; }
#prompt kbd { display: inline-grid; place-items: center; min-width: 29px; height: 29px; padding: 0 7px; border-radius: 999px; background: var(--red); color: #fff; font: 600 15px/1 var(--display); }
/* on touch the pill is the button you tap: no keyboard key, a red button big enough for a thumb */
.touch #prompt { height: 46px; padding: 0 20px; background: var(--grain), var(--red); border-color: var(--red-dk); color: #fff; font-size: 19px; box-shadow: 0 6px 16px rgba(150, 40, 20, 0.28); }
.touch #prompt kbd { display: none; }
@keyframes kw-rise { from { opacity: 0; margin-top: 6px; } }

/* dialogue: a paper sheet with the speaker's name on a red tab */
#dialog { position: absolute; left: 50%; bottom: calc(24px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); width: min(660px, calc(100vw - 32px)); padding: 26px 24px 16px; display: none; border-radius: 24px 20px 25px 21px / 21px 25px 20px 24px; box-shadow: var(--shadow-lg); background: var(--grain), var(--paper); cursor: pointer; }
#dialog.show { display: block; animation: kw-pop 0.2s ease-out; }
#dialog .who { position: absolute; left: 18px; top: -17px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; max-width: calc(100% - 36px); }
#dialog .who .head { padding: 7px 16px 6px; border-radius: 999px; background: var(--red); color: #fff; font-size: 19px; line-height: 1; box-shadow: var(--shadow-sm); }
#dialog .who .role { padding: 4px 11px; border-radius: 999px; background: var(--green-lt); border: 1px solid rgba(78, 122, 42, 0.35); color: var(--green-dk); font: 600 12px/1.2 var(--display); letter-spacing: 0.08em; text-transform: uppercase; }
#dialog .who .role:empty { display: none; }
#dialog .text { min-height: 60px; padding-right: 44px; font: 21px/1.38 var(--voice); }
#dialog .next { position: absolute; right: 14px; bottom: 12px; width: 40px; height: 40px; padding: 0; display: grid; place-items: center; background: var(--red); border: 0; border-radius: 50%; box-shadow: 0 3px 8px rgba(140, 40, 20, 0.28); transition: transform 0.12s; }
#dialog .next:hover { transform: translateX(2px); }
#dialog .next svg { width: 20px; height: 20px; stroke: #fff; fill: none; stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }
#dialog .dots { position: absolute; right: 20px; top: 11px; font: 500 13px/1 var(--display); color: var(--mut); letter-spacing: 0.08em; }
@keyframes kw-pop { from { opacity: 0; transform: translateX(-50%) translateY(10px) scale(0.98); } }

/* panels (deliveries / emotes / customise / wallet) */
.panel { position: absolute; right: calc(84px + env(safe-area-inset-right, 0px)); top: calc(14px + env(safe-area-inset-top, 0px)); width: min(380px, calc(100vw - 110px)); max-height: calc(100vh - 36px); overflow: auto; overscroll-behavior: contain; padding: 16px 18px 18px; display: none; border-radius: 24px 20px 25px 21px / 21px 25px 20px 24px; box-shadow: var(--shadow-lg); background: var(--grain), var(--paper); scrollbar-width: thin; scrollbar-color: rgba(39, 48, 63, 0.3) transparent; }
.panel.show { display: block; animation: kw-drop 0.16s ease-out; }
.panel h3 { position: relative; margin: 0 0 14px; padding-bottom: 10px; font: 600 22px/1.1 var(--display); display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.panel h3::after { content: ''; position: absolute; left: 0; right: 0; bottom: -2px; height: 8px; background: var(--wave) 0 0 / 40px 8px repeat-x; opacity: 0.9; }
.panel h3 small { font: 500 14px/1 var(--display); color: var(--mut); }
.panel.bottom { top: auto; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
@keyframes kw-drop { from { opacity: 0; transform: translateY(-6px); } }
.check { list-style: none; margin: 0; padding: 0; }
.check li { display: flex; gap: 10px; padding: 8px 4px; border-top: 1px dashed var(--line); align-items: flex-start; line-height: 1.25; font-size: 17px; }
.check li:first-child { border-top: none; }
.check .box { width: 22px; height: 22px; flex: none; border: 1.5px solid var(--ink-line); border-radius: 7px 6px 7px 6px; margin-top: 1px; display: grid; place-items: center; background: var(--paper); }
.check .box svg { width: 14px; height: 14px; stroke: var(--ink); fill: none; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; display: none; }
.check li.done .box { background: var(--green); border-color: var(--green-dk); }
.check li.done .box svg { display: block; }
.check li.done .t { opacity: 0.6; text-decoration: line-through; text-decoration-color: rgba(39, 48, 63, 0.4); }
.check li.locked { opacity: 0.4; }
.check li.current { margin: 2px -6px; padding: 9px 10px; border-top-color: transparent; border-radius: 14px; background: rgba(210, 69, 47, 0.08); box-shadow: inset 3px 0 0 var(--red); }
.check li.current.wet { background: rgba(62, 155, 214, 0.1); box-shadow: inset 3px 0 0 #3E9BD6; }   /* k2-carry: the parcel got wet */
.check li.current + li { border-top-color: transparent; }
.check li.current .t { font-weight: 700; }
.check li.current .box { border-color: var(--red); }
.check .pts { margin-left: auto; font: 600 14px/1.4 var(--display); color: var(--red-dk); white-space: nowrap; }
.check li.done .pts, .check li.locked .pts { color: var(--mut); }
.check .sub { display: block; font-size: 15px; font-weight: 400; color: var(--mut); }
.emotes { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.emotes button { aspect-ratio: 1; padding: 0; border: 1px solid var(--line); border-radius: 16px; background: var(--paper-2); display: grid; place-items: center; transition: transform 0.12s, background 0.12s, border-color 0.12s; }
.emotes button:hover { background: #fff; border-color: var(--ink-line); transform: translateY(-2px); }
.emotes svg { width: 30px; height: 30px; stroke: var(--ink); fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.row { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: 9px 0; }
.row .lbl { width: 72px; font: 600 12px/1 var(--display); color: var(--mut); letter-spacing: 0.1em; text-transform: uppercase; }
.swatch { width: 26px; height: 26px; border-radius: 50%; border: 1.5px solid var(--ink-line); padding: 0; box-shadow: var(--shadow-sm); transition: transform 0.1s; }
.swatch:hover { transform: translateY(-1px); }
.swatch.on { outline: 2.5px solid var(--red); outline-offset: 2px; }
.chip { height: 30px; padding: 0 12px; border: 1px solid var(--line); border-radius: 999px; background: var(--paper-2); font-size: 15px; }
.chip.on { background: var(--red); border-color: var(--red-dk); color: #fff; }
#cust-name { width: 170px; height: 34px; padding: 0 14px; border: 1.5px solid var(--ink-line); border-radius: 999px; background: #fff; color: var(--ink); font: 500 17px/1 var(--display); outline: none; user-select: text; -webkit-user-select: text; }
#cust-name:focus-visible { outline: 2.5px solid var(--red); outline-offset: 2px; }
/* the Wardrobe: Shuffle first and full width, then a stepper per slot */
.wardrobe .sub { margin: -4px 0 10px; color: var(--mut); font-size: 15px; line-height: 1.3; }
.wardrobe .shuffle { width: 100%; min-height: 44px; margin-bottom: 6px; }
.wardrobe .row { margin: 8px 0 0; }
.step { display: flex; align-items: center; gap: 6px; margin: 6px 0; }
.step .lbl { width: 64px; flex: none; font: 600 12px/1 var(--display); color: var(--mut); letter-spacing: 0.1em; text-transform: uppercase; }
.step .arr { width: 32px; height: 32px; flex: none; padding: 0; display: grid; place-items: center; border: 1.5px solid var(--ink-line); border-radius: 50%; background: var(--paper-2); box-shadow: var(--shadow-sm); transition: transform 0.1s, background 0.1s; }
.step .arr:hover { background: #fff; transform: translateY(-1px); }
.step .arr svg { width: 16px; height: 16px; stroke: var(--ink); fill: none; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.step .val { flex: 1; min-width: 0; text-align: center; font: 500 16px/1.2 var(--display); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wardrobe .keep { margin-top: 4px; }
/* the Wardrobe on a phone (html.compact; assets/phone.css hangs the panel
   under the menu button): two columns, so the whole panel fits a turned
   phone (390 tall) without scrolling and stays clear of the courier in the
   middle. Shuffle and Keep share the top row (CSS order), then the five
   steppers and the name, each a small label over its control. */
html.compact #ui #customize { width: min(380px, calc(100% - var(--sa-l) - var(--sa-r) - 24px)); }
html.compact #ui .wardrobe { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; align-items: end; }
html.compact #ui .wardrobe .sub { display: none; }
html.compact #ui .wardrobe .shuffle { order: -2; min-height: 38px; margin: 0; padding: 0 12px; font-size: 16px; }
html.compact #ui .wardrobe .keep { order: -1; margin: 0; height: 38px; }
html.compact #ui .wardrobe .step, html.compact #ui .wardrobe .row { display: grid; grid-template-columns: 28px minmax(0, 1fr) 28px; gap: 3px 2px; align-items: center; margin: 0; }
html.compact #ui .wardrobe .step .lbl, html.compact #ui .wardrobe .row .lbl { grid-column: 1 / -1; width: auto; font-size: 10px; }
html.compact #ui .wardrobe .step .arr { width: 28px; height: 28px; }
html.compact #ui .wardrobe .step .val { font-size: 13px; letter-spacing: -0.01em; }
html.compact #ui .wardrobe #cust-name { grid-column: 1 / -1; width: 100%; height: 28px; font-size: 15px; }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 42px; padding: 0 18px; border: 0; border-radius: 24px 21px 25px 20px / 21px 25px 20px 24px; background: var(--grain), var(--red); color: #fff; box-shadow: 0 6px 16px rgba(150, 40, 20, 0.24), 0 2px 4px rgba(120, 30, 15, 0.16); font: 600 17px/1 var(--display); letter-spacing: 0.01em; pointer-events: auto; transition: transform 0.14s ease, box-shadow 0.14s ease, background-color 0.14s; }
.btn svg { width: 20px; height: 20px; stroke: currentColor; fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.btn:hover { transform: translateY(-1px); box-shadow: 0 9px 20px rgba(150, 40, 20, 0.28), 0 3px 6px rgba(120, 30, 15, 0.18); }
.btn:active { transform: translateY(1px); box-shadow: 0 3px 8px rgba(150, 40, 20, 0.24); }
.btn.ghost { background: var(--grain), var(--paper); color: var(--ink); border: 1.5px solid var(--ink-line); box-shadow: var(--shadow-sm); }
.btn.sm { min-height: 32px; padding: 0 13px; font-size: 14px; }
.btn:disabled { opacity: 0.55; cursor: default; transform: none; }
.muted { color: var(--mut); font-size: 15px; line-height: 1.4; }
.addr { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px; }
.board { list-style: none; margin: 8px 0 0; padding: 0; font-size: 16px; }
.board li { display: flex; gap: 8px; align-items: baseline; padding: 5px 0; border-top: 1px dashed var(--line); }
.board li:first-child { border-top: none; }
.board .rank { width: 22px; font: 600 13px/1 var(--display); color: var(--mut); }
.board .pts { margin-left: auto; font: 600 15px/1 var(--display); color: var(--red-dk); }
.badge-lic { display: inline-block; margin-left: 4px; padding: 2px 8px; border-radius: 999px; background: var(--green); color: var(--ink); font: 600 11px/1.3 var(--display); letter-spacing: 0.06em; vertical-align: 1px; }

/* toast */
#toast { position: absolute; left: 50%; top: calc(16px + env(safe-area-inset-top, 0px)); transform: translateX(-50%); max-width: min(560px, calc(100vw - 200px)); padding: 9px 18px; border-radius: 16px; font: 17px/1.3 var(--voice); text-align: center; opacity: 0; transition: opacity 0.25s, transform 0.25s; pointer-events: none; }
#toast.show { opacity: 1; }
/* the deliveries list hangs from the top right: toasts wait at the bottom while it is open */
#ui:has(#checklist.show) #toast { top: auto; bottom: calc(76px + env(safe-area-inset-bottom, 0px)); left: calc((100vw - 470px) / 2); max-width: min(560px, calc(100vw - 510px)); }

/* end screen + overlays */
.overlay { position: absolute; inset: 0; display: none; place-items: center; padding: 16px; background: rgba(28, 56, 84, 0.3); pointer-events: auto; }
.overlay.show { display: grid; animation: kw-fade 0.2s ease-out; }
.overlay .card { width: min(520px, calc(100vw - 32px)); padding: 28px 28px 24px; text-align: center; border-radius: 26px 22px 27px 23px / 23px 27px 22px 26px; box-shadow: var(--shadow-lg); background: var(--grain), var(--paper); }
.overlay h2 { margin: 0 0 6px; font-size: 32px; line-height: 1.05; color: var(--red); }
.overlay .big { font-size: 52px; margin: 10px 0 0; line-height: 1; }
.overlay .actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 18px; }
@keyframes kw-fade { from { opacity: 0; } }

/* bubbles above heads (emotes) and resident name tags */
.bubble { position: absolute; transform: translate(-50%, -100%); padding: 6px; background: #fff; border: 1.5px solid var(--ink-line); border-radius: 16px 16px 16px 4px; box-shadow: var(--shadow-sm); pointer-events: none; }
.bubble svg { width: 30px; height: 30px; stroke: var(--ink); fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; display: block; }
/* a name tag is centred on its anchor (head + 0.35 m), not hung above it. Its height is fixed: game.js (TAG_HALF) drops a marked resident's tag by half of it under the quest marker (src/quest.js) */
.tag { position: absolute; transform: translate(-50%, -50%); height: 24px; padding: 0 10px; background: var(--paper-glass); border: 1px solid rgba(39, 48, 63, 0.4); border-radius: 999px; box-shadow: 0 3px 8px rgba(28, 52, 84, 0.16); font: 500 13px/22px var(--display); pointer-events: none; white-space: nowrap; }
.tag.mark { background: var(--red); border-color: var(--red-dk); color: #fff; }

/* controls hint */
#hint { position: absolute; left: 50%; bottom: calc(22px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); display: flex; align-items: center; gap: 4px; padding: 6px 14px; border-radius: 999px; font-size: 15px; color: var(--mut); background: rgba(251, 245, 230, 0.86); box-shadow: var(--shadow-sm); transition: opacity 0.5s; pointer-events: none; white-space: nowrap; }
#hint.hide { opacity: 0; }
/* it ran over the bottom-left of an open panel and showed through the dialogue; it waits, and comes back if nobody has walked yet */
#ui:has(.panel.show) #hint, #ui:has(#dialog.show) #hint, #ui:has(.overlay.show) #hint { opacity: 0; transition-duration: 0.15s; }
#hint kbd { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 6px; margin: 0 1px; border: 1px solid rgba(39, 48, 63, 0.35); border-radius: 7px; background: #fff; box-shadow: 0 1.5px 0 rgba(39, 48, 63, 0.2); color: var(--ink); font: 600 11px/1 var(--display); }

/* touch stick + jump */
#stick { position: absolute; width: 120px; height: 120px; border-radius: 50%; border: 1.5px solid rgba(39, 48, 63, 0.45); background: rgba(251, 245, 230, 0.32); box-shadow: 0 6px 18px rgba(28, 52, 84, 0.16); display: none; transform: translate(-50%, -50%); }
#stick .nub { position: absolute; left: 50%; top: 50%; width: 48px; height: 48px; border-radius: 50%; background: var(--paper); border: 1.5px solid var(--ink-line); box-shadow: var(--shadow-sm); transform: translate(-50%, -50%); }
#stick.show { display: block; }
#jump { position: absolute; right: calc(90px + env(safe-area-inset-right, 0px)); bottom: calc(28px + env(safe-area-inset-bottom, 0px)); width: 66px; height: 66px; padding: 0; border-radius: 50%; border: 0; display: none; place-items: center; background: var(--grain), var(--red); color: #fff; font: 600 15px/1 var(--display); letter-spacing: 0.06em; box-shadow: 0 6px 16px rgba(150, 40, 20, 0.28); }
#jump:active { transform: translateY(2px) scale(0.97); }
.touch #jump { display: grid; }
#ui:has(#dialog.show) #jump, #ui:has(.panel.show) #jump, #ui:has(.overlay.show) #jump { display: none; }
.touch #hint { display: none; }

@media (max-width: 720px) {
  body { font-size: 17px; }
  #hud { left: 10px; top: 10px; }
  #points { height: 40px; padding: 0 13px 0 5px; } #points .ic { width: 30px; height: 30px; } #points .head { font-size: 20px; }
  #wallet-pill { height: 30px; font-size: 14px; }
  .side { right: 10px; } .side.top { top: 10px; } .side.bottom { bottom: 10px; }
  .sbtn { width: 46px; height: 46px; } .sbtn svg { width: 22px; height: 22px; }
  .panel { right: 64px; width: calc(100vw - 80px); padding: 14px 14px 16px; }
  #dialog { bottom: 12px; padding: 24px 16px 14px; } #dialog .text { font-size: 18px; min-height: 50px; }
  #dialog .who .head { font-size: 17px; }
  /* the dialogue takes the bottom of a phone; the bottom buttons step aside until it closes */
  #ui:has(#dialog.show) .side.bottom { opacity: 0; pointer-events: none; }
  #toast { max-width: calc(100vw - 130px); font-size: 15px; top: 100px; }
  /* on a phone the open list fills the screen: the toast sits over its heading, never over the rows */
  #ui:has(#checklist.show) #toast { top: calc(6px + env(safe-area-inset-top, 0px)); bottom: auto; left: calc(50% - 27px); max-width: calc(100vw - 110px); padding: 7px 14px; }
  .overlay h2 { font-size: 27px; } .overlay .big { font-size: 42px; }
}

/* the presence room: a tiny dot and a head count under the wallet pill */
#realm { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 9px 0 8px; border-radius: 999px; font: 500 12px/1 var(--display); letter-spacing: 0.04em; color: var(--mut); box-shadow: var(--shadow-sm); background: rgba(251, 245, 230, 0.82); pointer-events: none; }
#realm .dot { width: 7px; height: 7px; border-radius: 50%; background: #B9B2A6; }
#realm[data-state="online"] .dot { background: var(--green); box-shadow: 0 0 0 2.5px rgba(127, 174, 69, 0.28); }
#realm[data-state="connecting"] .dot { background: var(--yellow); animation: kw-blink 1.2s ease-in-out infinite; }
@keyframes kw-blink { 50% { opacity: 0.3; } }

/* ghost mode (src/game.js setGhost, ui.setGhost): a spectator has no points,
   deliveries, customise, emotes or talk prompt; a ghost bar offers the wallet */
#ghostbar { position: absolute; left: 50%; bottom: calc(22px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); display: none; align-items: center; gap: 12px; width: max-content; max-width: calc(100vw - 180px); padding: 7px 8px 7px 9px; border-radius: 999px; font-size: 15px; line-height: 1.25; }
#ghostbar .gi { display: grid; place-items: center; flex: none; width: 34px; height: 34px; border-radius: 50%; background: #EDEAF8; }
#ghostbar .gi svg { width: 22px; height: 22px; stroke: var(--ink); fill: #FFFFFF; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
#ghostbar .gt { color: var(--mut); }
#ghostbar .btn { flex: none; }
#ui.ghost #ghostbar { display: flex; }
#ui.ghost .tag.mark { background: var(--paper-glass); border-color: rgba(39, 48, 63, 0.4); color: var(--ink); }   /* no next stop for a ghost */
#ui.ghost #points, #ui.ghost [data-panel="checklist"], #ui.ghost [data-panel="customize"], #ui.ghost [data-panel="emotes"], #ui.ghost #prompt, #ui.ghost #end, #ui.ghost #hint { display: none !important; }
#hint-ghost { display: none; }
#ui.ghost #hint-ghost { display: flex; position: absolute; left: 50%; bottom: calc(80px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%); align-items: center; gap: 4px; padding: 6px 14px; border-radius: 999px; font-size: 15px; color: var(--mut); background: rgba(251, 245, 230, 0.86); box-shadow: var(--shadow-sm); pointer-events: none; white-space: nowrap; transition: opacity 0.5s; }
#ui.ghost #hint-ghost.hide, #ui.ghost:has(.panel.show) #hint-ghost { opacity: 0; }
#hint-ghost kbd { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 6px; margin: 0 1px; border: 1px solid rgba(39, 48, 63, 0.35); border-radius: 7px; background: #fff; box-shadow: 0 1.5px 0 rgba(39, 48, 63, 0.2); color: var(--ink); font: 600 11px/1 var(--display); }
.touch #hint-ghost { display: none !important; }
/* on touch the jump button lifts a ghost high and brings it back */
#ui.ghost #jump { font-size: 0; }
#ui.ghost #jump::after { content: attr(data-fly); font: 600 15px/1 var(--display); letter-spacing: 0.06em; }   /* ui.js sets data-fly in the player's language */

/* the X link at the foot of the wallet panel */
.xlink { display: inline-flex; align-items: center; gap: 7px; margin-top: 14px; padding: 5px 12px 5px 10px; border: 1px solid var(--line); border-radius: 999px; background: var(--paper-2); color: var(--ink); font: 500 14px/1 var(--display); text-decoration: none; }
.xlink:hover { background: #fff; border-color: var(--ink-line); }
.xlink svg { width: 14px; height: 14px; fill: currentColor; stroke: none; }

@media (max-width: 720px), (max-height: 520px) {
  /* a phone keeps the ghost bar to the icon and the button */
  #ghostbar .gt { display: none; }
  #ghostbar { gap: 8px; padding: 5px 6px 5px 6px; max-width: calc(100vw - 140px); }
  #realm { height: 20px; font-size: 11px; }
}

/* ---- job board (src/jobsui.js): the board panel, the tracker for the job in
   hand, the reward card, earnings and the today / week / all-time boards */
#jobs { width: min(470px, calc(100vw - 110px)); }
.jb-hana { margin: 0 0 12px; padding: 9px 12px; border-radius: 14px 12px 15px 11px; background: var(--paper-2); font: 17px/1.35 var(--voice); }
.jb-hana b { margin-right: 4px; padding: 2px 9px; border-radius: 999px; background: var(--red); color: #fff; font: 600 13px/1.2 var(--display); }
.jb-note { margin: 0 0 10px; }
.jb-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin: 2px 0 10px; }
.jb-stats > div { padding: 7px 8px 6px; border: 1px solid var(--line); border-radius: 12px 10px 13px 11px; background: var(--paper-2); text-align: center; }
.jb-stats b { display: block; font: 600 19px/1.1 var(--display); font-variant-numeric: tabular-nums; }
.jb-stats span { font: 500 12px/1.2 var(--display); color: var(--mut); letter-spacing: 0.04em; }
.jb-h { margin: 12px 0 4px; font: 600 13px/1 var(--display); color: var(--mut); letter-spacing: 0.1em; text-transform: uppercase; }
.jobs { list-style: none; margin: 0; padding: 0; }
.job { display: grid; grid-template-columns: auto 1fr auto auto; align-items: center; gap: 4px 9px; padding: 8px 2px; border-top: 1px dashed var(--line); }
.job:first-child { border-top: none; }
.job .jt { min-width: 0; line-height: 1.2; font-size: 16px; }
.job .jt b { font-weight: 400; }
.job .sub { display: block; font-size: 14px; color: var(--mut); }
.job .pay { font: 600 15px/1 var(--display); color: var(--red-dk); white-space: nowrap; font-variant-numeric: tabular-nums; }
.job .act { display: grid; place-items: center; min-width: 58px; }
.job .act .btn { min-width: 58px; }
.job .act.ok svg { width: 26px; height: 26px; padding: 4px; border-radius: 50%; background: var(--green); stroke: var(--ink); fill: none; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.job.done { opacity: 0.55; }
.job.done .jt b { text-decoration: line-through; text-decoration-color: rgba(39, 48, 63, 0.4); }
.job.mine { margin: 2px -6px; padding: 9px 8px; border-top-color: transparent; border-radius: 14px; background: rgba(210, 69, 47, 0.08); box-shadow: inset 3px 0 0 var(--red); }
.job.mine + .job { border-top-color: transparent; }
.kind { display: inline-block; min-width: 74px; text-align: center; padding: 3px 8px; border-radius: 999px; font: 600 11px/1.2 var(--display); letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; background: #DCEEF6; color: #1F5878; }
.k-route .kind { background: var(--green-lt); color: var(--green-dk); }
.k-rush .kind { background: var(--red); color: #fff; }
.k-gather .kind { background: #F6E3B8; color: #7A5418; }
.k-lantern .kind { background: #2F3A5A; color: #FBE7B0; }
.k-feast .kind { background: #F08A24; color: var(--ink); }
.jb-fine { margin: 12px 0 0; font-size: 14px; }
.jb-tabs { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 4px; }
.board li.me { margin: 0 -6px; padding: 5px 6px; border-radius: 10px; background: rgba(127, 174, 69, 0.18); }

/* the job in hand, top centre; the toast steps down under it */
#job-track { position: absolute; left: 50%; top: calc(14px + env(safe-area-inset-top, 0px)); transform: translateX(-50%); max-width: min(440px, calc(100vw - 280px)); padding: 7px 14px 8px; display: none; flex-direction: column; gap: 3px; border-radius: 18px 15px 19px 16px / 16px 19px 15px 18px; cursor: pointer; }
#job-track.show { display: flex; animation: kw-drop 0.18s ease-out; }
#job-track .jt-top { display: flex; align-items: center; gap: 8px; min-width: 0; }
#job-track .jt-title { font: 600 16px/1.15 var(--display); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#job-track .jt-next { display: flex; align-items: center; gap: 8px; font-size: 16px; line-height: 1.2; white-space: nowrap; }
#job-track .jt-step { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
#job-track .jt-arrow { display: grid; place-items: center; flex: none; width: 24px; height: 24px; border-radius: 50%; background: var(--red); transition: transform 0.12s linear; }
#job-track .jt-arrow svg { width: 15px; height: 15px; fill: #fff; }
#job-track .jt-dist { margin-left: auto; font: 600 14px/1 var(--display); color: var(--mut); font-variant-numeric: tabular-nums; }
#job-track .jt-clock { font: 600 15px/1 var(--display); font-variant-numeric: tabular-nums; }
#job-track .jt-clock:empty { display: none; }
#job-track .jt-clock.hurry { padding: 3px 8px; border-radius: 999px; background: var(--red); color: #fff; animation: kw-pulse 0.9s ease-in-out infinite; }
#ui:has(#job-track.show) #toast { top: calc(86px + env(safe-area-inset-top, 0px)); }
#ui:has(.panel.show) #job-track { display: none; }

/* a landed job: the pay on a paper card under the tracker */
#job-reward { position: absolute; left: 50%; top: calc(96px + env(safe-area-inset-top, 0px)); transform: translateX(-50%); display: flex; align-items: center; gap: 12px; padding: 10px 20px 10px 10px; border-radius: 22px 18px 23px 19px / 19px 23px 18px 22px; box-shadow: var(--shadow-lg); opacity: 0; visibility: hidden; transition: opacity 0.3s, visibility 0s 0.3s; pointer-events: none; }
#job-reward.show { opacity: 1; visibility: visible; transition: opacity 0.2s; animation: kw-pop 0.28s ease-out; }
#job-reward .ic { display: grid; place-items: center; width: 48px; height: 48px; border-radius: 50%; background: var(--red); flex: none; }
#job-reward .ic svg { width: 30px; height: 30px; }
#job-reward .rw-pts { font-size: 26px; line-height: 1.05; color: var(--red-dk); }
#job-reward .rw-title { font-size: 17px; line-height: 1.25; }
#job-reward .rw-note { font-size: 14px; }
#ui:has(#job-reward.show) #toast { opacity: 0; }
#ui:has(#job-reward.show) #prompt { opacity: 0; }   /* the card sits where a close resident's prompt floats */

@media (max-width: 720px), (max-height: 500px) {
  /* phones: the tracker is one compact line, and the board fills the side */
  #job-track { top: calc(8px + env(safe-area-inset-top, 0px)); max-width: calc(100vw - 230px); padding: 5px 10px; }
  #job-track .jt-top { display: none; }
  #job-track .jt-next { font-size: 14px; gap: 6px; }
  #job-track .jt-arrow { width: 20px; height: 20px; }
  #ui:has(#job-track.show) #toast { top: calc(52px + env(safe-area-inset-top, 0px)); }
  #job-reward { top: calc(56px + env(safe-area-inset-top, 0px)); padding: 7px 14px 7px 7px; }
  #job-reward .ic { width: 38px; height: 38px; } #job-reward .rw-pts { font-size: 21px; }
  .jb-hana { font-size: 15px; padding: 7px 10px; margin-bottom: 8px; }
  .jb-stats { gap: 6px; margin-bottom: 6px; }
  .jb-stats > div { padding: 4px 6px; }
  .jb-stats b { display: inline; font-size: 16px; } .jb-stats span { margin-left: 4px; font-size: 11px; }
  .job { padding: 6px 2px; }
  .job .jt { font-size: 15px; } .job .sub { font-size: 13px; }
}
@media (max-height: 500px) {
  /* a landscape phone: the job board button makes three on top, so the side
     buttons take the phone size or the two columns meet (selftest overlap) */
  .side { gap: 8px; } .sbtn { width: 46px; height: 46px; } .sbtn svg { width: 22px; height: 22px; }
}
@media (max-width: 720px) {
  /* a narrow portrait phone: the kind chip rides above the title */
  .job { grid-template-columns: 1fr auto auto; }
  .job .kind { grid-column: 1 / -1; justify-self: start; }
}

/* ---- the load (k2-carry, src/carry.js): the parcels he carries, bottom
   left. A snail and his pace once the stack slows him, a wave while he is in
   the water, the drip mark while a parcel is wet. A ghost carries nothing. */
#load { position: absolute; left: calc(16px + env(safe-area-inset-left, 0px)); bottom: calc(16px + env(safe-area-inset-bottom, 0px)); display: flex; align-items: center; gap: 6px; height: 38px; padding: 0 12px 0 5px; border-radius: 999px; font: 600 15px/1 var(--display); color: var(--ink); box-shadow: var(--shadow-sm); pointer-events: none; }
#load[hidden] { display: none; }
#load .ic { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: #C9A06A; flex: none; }
#load .ic svg { width: 18px; height: 18px; fill: #F3E3C3; stroke: var(--ink); stroke-width: 1.5; stroke-linejoin: round; }
#load .n { font-size: 20px; font-variant-numeric: tabular-nums; }
#load .lbl { font-weight: 500; font-size: 13px; color: var(--mut); letter-spacing: 0.04em; }
#load .slow, #load .wat, #load .wet { display: inline-flex; align-items: center; gap: 3px; padding: 3px 7px 3px 5px; border-radius: 999px; font-size: 13px; }
#load .slow[hidden], #load .wat[hidden], #load .wet[hidden] { display: none; }
#load .slow { background: var(--paper-2); color: var(--ink); font-variant-numeric: tabular-nums; }
#load svg { flex: none; }
#load .slow svg { width: 17px; height: 17px; fill: none; stroke: var(--ink); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
#load .wat { padding: 3px 5px; background: #DDF1F7; }
#load .wat svg { width: 16px; height: 16px; fill: none; stroke: #2F7FB0; stroke-width: 2; stroke-linecap: round; }
#load .wet { padding: 3px 5px; background: #DDF1F7; }
#load .wet svg, #job-track .jt-wet svg, .jb-wet svg { width: 15px; height: 15px; fill: #3E9BD6; stroke: #F4FBFF; stroke-width: 1.4; stroke-linecap: round; }
#load.wet { border-color: #2F7FB0; }
#ui:has(#dialog.show) #load, #ui:has(.overlay.show) #load { opacity: 0; }
@media (max-width: 720px) { #ui:has(.panel.show) #load { opacity: 0; } }
/* a narrow desktop window: the chip stands over the key hint until the hint goes */
#load { transition: bottom 0.25s ease, opacity 0.2s; }
@media (max-width: 1180px) { html:not(.compact) body:not(.touch) #ui:has(#hint:not(.hide)) #load { bottom: calc(64px + env(safe-area-inset-bottom, 0px)); } }
/* a swimmer cannot jump: the jump button and the key hint step away (carry.js #ui.swim) */
#ui.swim #jump { display: none; }
#ui.swim #hint { opacity: 0; }
/* the tracker: how many more jobs are in hand, and the drip mark on a wet one */
#job-track .jt-more { flex: none; padding: 2px 7px; border-radius: 999px; background: var(--paper-2); font: 600 12px/1.2 var(--display); color: var(--mut); }
#job-track .jt-more:empty { display: none; }
#job-track .jt-wet { display: grid; place-items: center; flex: none; width: 22px; height: 22px; border-radius: 50%; background: #DDF1F7; }
#job-track .jt-wet[hidden] { display: none; }
#job-track.wet { border-color: #2F7FB0; }
.jb-wet { display: inline-grid; place-items: center; width: 22px; height: 22px; margin-right: 6px; border-radius: 50%; background: #DDF1F7; vertical-align: middle; }
.jb-held { margin: 2px 0 8px; font-size: 14px; }
#job-reward.wet .ic { background: #3E9BD6; }

/* ---- Chinese (src/i18n.js sets <html lang="zh-CN">): the stacks above fall
   through to a Chinese face for every Chinese glyph. Letter-spacing made for
   small Latin capitals spreads Chinese labels apart, so it closes up, and
   the residents' lines get a little more leading for the taller glyphs. */
html:lang(zh) #ui :is(.row .lbl, .step .lbl, .jb-h, .kind, #dialog .who .role, #points .lbl, #realm, .jb-stats span, #load .lbl, #options .op-sec h4, #options .op-row .lbl, #options-btn, #music-toggle) { letter-spacing: 0.02em; }
html:lang(zh) #ui #dialog .text { line-height: 1.5; }
html:lang(zh) #ui .jb-hana, html:lang(zh) #ui #toast { line-height: 1.45; }

/* harness: ?ui=0 hides every DOM layer (src/harness.js) */
html.harness-noui #ui, html.harness-noui #loading, html.harness-noui #wipe, html.harness-noui #veil { display: none !important; }
