/* Undercooked — screen styles (phase 07 task 02). * * Rules this file must keep (base.css's, extended): * - every byte is same-origin: no @import, no web fonts, no remote images (A12); * - the palette, spacing and type scale exist only as base.css custom properties, * so a `[data-palette]` swap (e.g. `data-palette="cb"` for the colourblind-safe * alternate in assets/palette.css) recolours the screens automatically; * - 44x44 minimum hit targets (base.css --uc-hit) on every interactive control; * - the layout is fluid from a 360px phone to a 4K desktop without breakpoints; * - motion is decorative: prefers-reduced-motion turns all of it off; * - visible focus rings: base.css's :focus-visible rule covers every element here. */ .screen-root { display: grid; justify-items: center; } /* The screens share the phase-01 panel skin; each owns its content. */ .panel.lobby, .panel.result, .panel.error, .panel.connecting, .panel.countdown { max-width: 40rem; } .section-label { margin: 0; font-size: var(--uc-step--1); text-transform: uppercase; letter-spacing: 0.08em; color: var(--uc-ink-muted); } /* ------------------------------------------------------------- landing */ .join-field { display: grid; gap: var(--uc-space-1); flex: 1 1 10rem; } /* ------------------------------------------------------------- connecting */ .connecting { text-align: center; } #connecting-text { margin: 0; font-size: var(--uc-step-1); } /* ------------------------------------------------------------- lobby */ .lobby-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--uc-space-2); } .room-code { margin: 0; font-family: var(--uc-font-ui); font-size: var(--uc-step-2); font-weight: 800; letter-spacing: 0.3em; color: var(--uc-accent); } .code-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--uc-space-2); } .seat-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--uc-space-1); } .seat { display: flex; align-items: center; gap: var(--uc-space-1); min-height: calc(var(--uc-hit) - 12px); padding: 0 var(--uc-space-2); background: var(--uc-bg); border: 1px solid var(--uc-line); border-radius: var(--uc-radius); } .chip { width: 1rem; height: 1rem; border-radius: 50%; flex: none; border: 1px solid var(--uc-line); } /* The 4-colour seat palette (server/seats.py `SEAT_PALETTE`, * docs/PROTOCOL.md "Lobby"). Colours ride on classes, not inline * `style` attributes — the CSP's `style-src 'self'` blocks the * latter (a console error). */ .chip-red { background: #e5484d; } .chip-blue { background: #3b9eff; } .chip-green { background: #3ddc84; } .chip-amber { background: #ffb224; } .seat-index { color: var(--uc-ink-muted); font-size: var(--uc-step--1); } .seat-name { flex: 1; overflow-wrap: anywhere; } .crown { color: var(--uc-accent); font-size: var(--uc-step-1); } .ready-badge, .ghost-badge { font-size: var(--uc-step--1); text-transform: uppercase; letter-spacing: 0.08em; padding: 0.1rem 0.5rem; border-radius: var(--uc-radius); border: 1px solid var(--uc-line); } .ready-badge { color: var(--uc-accent-ink); background: var(--uc-accent); border-color: var(--uc-accent); } .ghost-badge { color: var(--uc-ink-muted); } .lobby-controls { display: flex; flex-wrap: wrap; align-items: center; gap: var(--uc-space-2); } #ready-btn { min-width: 12rem; } .level-pick { display: grid; gap: var(--uc-space-1); } #level-picker { min-height: var(--uc-hit); padding: 0 var(--uc-space-2); background: var(--uc-bg); color: var(--uc-ink); border: 1px solid var(--uc-line); border-radius: var(--uc-radius); font: inherit; } #level-picker:disabled { opacity: 0.6; } #start-btn:disabled { opacity: 0.55; cursor: not-allowed; } .session { margin-top: var(--uc-space-2); } .session h3 { margin: 0 0 var(--uc-space-1); font-size: var(--uc-step-0); } .session p, .session li { margin: 0; } .bests { margin: var(--uc-space-1) 0 0; padding-left: 1.25rem; display: grid; gap: 0.25rem; } #spectator-note { margin: var(--uc-space-2) 0 0; } #lobby-banner { margin: var(--uc-space-2) 0 0; } /* ------------------------------------------------------------- countdown */ .countdown { text-align: center; } .countdown-num { margin: 0; font-family: var(--uc-font-ui); font-size: clamp(5rem, 20vw, 11rem); font-weight: 800; line-height: 1; color: var(--uc-accent); } @media (prefers-reduced-motion: no-preference) { .countdown-num { animation: countdown-pulse 1s var(--uc-ease); } @keyframes countdown-pulse { from { transform: scale(1.25); opacity: 0.4; } to { transform: scale(1); opacity: 1; } } } /* ------------------------------------------------------------- play */ .play-screen { display: grid; gap: var(--uc-space-2); width: 100%; max-width: 46rem; } .play-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--uc-space-2); } #play-banner { margin: 0; } #kcanvas { width: 100%; aspect-ratio: 2 / 1; background: var(--uc-bg); border: 1px solid var(--uc-line); border-radius: var(--uc-radius); } .hud { min-height: calc(var(--uc-hit) - 8px); } /* The HUD (task 04): the order rail, the score bar, the timer, the status row. The timer's colour bands carry a non-colour cue too: `low` (amber) and `critical` (red) each add a striped background and a label word (`hurry` / `now`). */ .hud-grid { display: grid; grid-template-columns: minmax(12rem, 1fr) minmax(10rem, 1fr) auto; gap: var(--uc-space-2); align-items: start; } @media (max-width: 40rem) { .hud-grid { grid-template-columns: 1fr; } } .hud-orders .section-label { margin: 0 0 var(--uc-space-1); } .ticket-list { display: grid; gap: var(--uc-space-1); } .ticket { display: grid; grid-template-columns: auto 1fr auto; grid-template-rows: auto auto; align-items: center; gap: 2px var(--uc-space-1); padding: var(--uc-space-1) var(--uc-space-2); background: var(--uc-surface-2); border: 1px solid var(--uc-line); border-radius: var(--uc-radius); } .ticket.oldest { border-color: var(--uc-accent); box-shadow: 0 0 0 1px var(--uc-accent); } .ticket-icon { width: 1.4rem; height: 1.4rem; grid-row: span 2; } .ticket-pts { font-family: var(--uc-font-ui); font-weight: 700; } .ticket-bar { grid-column: 2 / 4; height: 0.4rem; background: var(--uc-bg); border-radius: 999px; overflow: hidden; } .ticket-bar-fill { height: 100%; background: var(--uc-accent); } .hud-score-line { margin: 0; font-family: var(--uc-font-ui); } .hud-streak { display: inline-flex; align-items: center; gap: 0.25rem; margin-left: var(--uc-space-1); color: var(--uc-accent); } .hud-streak img { width: 1.2rem; height: 1.2rem; } .score-bar { margin-top: var(--uc-space-1); height: 0.5rem; background: var(--uc-bg); border: 1px solid var(--uc-line); border-radius: 999px; overflow: hidden; } .score-bar-fill { height: 100%; background: var(--uc-accent); } .hud-timer { padding: var(--uc-space-1) var(--uc-space-2); border: 1px solid var(--uc-line); border-radius: var(--uc-radius); font-family: var(--uc-font-ui); font-size: var(--uc-step-1); min-width: 5.5rem; text-align: center; } /* The non-colour halves: the striped background + the label word. */ .hud-timer-low { color: var(--uc-accent); border-color: var(--uc-accent); background: repeating-linear-gradient( 45deg, transparent 0 0.5rem, color-mix(in srgb, var(--uc-accent) 18%, transparent) 0.5rem 1rem ); } .hud-timer-critical { color: var(--uc-danger); border-color: var(--uc-danger); background: repeating-linear-gradient( 45deg, transparent 0 0.5rem, color-mix(in srgb, var(--uc-danger) 22%, transparent) 0.5rem 1rem ); } .hud-timer-label { margin-left: 0.4rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; font-size: var(--uc-step--1); } .hud-meta { display: grid; gap: 0.35rem; align-content: start; } .hud-dirty, .hud-conn { font-family: var(--uc-font-ui); } .hud-conn.is-live { color: var(--uc-ink-muted); } .hud-conn.is-down { color: var(--uc-danger); } #hud-spectator { margin: 0; color: var(--uc-accent); } .emote-row { display: flex; flex-wrap: wrap; gap: var(--uc-space-1); } .emote { min-width: var(--uc-hit); min-height: var(--uc-hit); padding: 0 var(--uc-space-2); font-size: var(--uc-step-1); } .overlay { position: fixed; inset: 0; display: grid; place-items: center; background: color-mix(in srgb, var(--uc-bg) 82%, transparent); z-index: 10; } .overlay p { margin: 0; padding: var(--uc-space-3); background: var(--uc-surface); border: 1px solid var(--uc-line); border-radius: var(--uc-radius); font-size: var(--uc-step-1); } /* ------------------------------------------------------------- result */ .result { text-align: center; } #result-word { font-size: var(--uc-step-2); margin: 0; } .stars { margin: var(--uc-space-1) 0; font-size: var(--uc-step-2); letter-spacing: 0.15em; } .star.filled { color: var(--uc-accent); } .star { color: var(--uc-line); } @media (prefers-reduced-motion: no-preference) { .star.filled { animation: star-pop 600ms var(--uc-ease); } @keyframes star-pop { from { transform: scale(0.3); } 60% { transform: scale(1.3); } to { transform: scale(1); } } } #score-line, #best-line, #counters-line { margin: var(--uc-space-1) 0; } #result-players { text-align: left; } .result-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--uc-space-2); margin-top: var(--uc-space-2); } /* ------------------------------------------------------------- error */ .error h2 { margin: 0 0 var(--uc-space-1); } #error-detail, #error-code { margin: 0 0 var(--uc-space-2); } #error-code { color: var(--uc-ink-muted); font-family: var(--uc-font-ui); letter-spacing: 0.15em; } .error-actions { display: flex; flex-wrap: wrap; gap: var(--uc-space-2); } /* ------------------------------------------------------------- shared */ /* Screen-reader-only: the result announcement, focusable nowhere. */ .visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } /* ------------------------------------------------------------- help (task 05) */ /* The `?`-key in-game help: a body-level fixed overlay over the panel skin, dismissed by its Close button, the backdrop click, or the keyboard's `?`/`Esc` (the module's `Esc` branch defers to it while it is open). The rows are `getKeyMap()`'s (the README's controls section renders the same thing). */ .help-overlay { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center; background: color-mix(in srgb, var(--uc-bg) 72%, transparent); } .help-panel { width: min(30rem, calc(100vw - 2 * var(--uc-space-3))); margin: 0; max-width: none; } .help-title { display: flex; align-items: center; justify-content: space-between; gap: var(--uc-space-2); } .help-heading { font-size: var(--uc-step-1); } .help-rows { display: grid; gap: var(--uc-space-1); } .help-row { display: grid; grid-template-columns: auto 1fr; gap: var(--uc-space-2); align-items: baseline; } .help-keys { font-family: var(--uc-font-ui); font-size: var(--uc-step--1); color: var(--uc-accent); background: var(--uc-surface-2); border: 1px solid var(--uc-line); border-radius: calc(var(--uc-radius) / 2); padding: 0.1rem 0.45rem; white-space: nowrap; } .help-action { color: var(--uc-ink); } .help-foot { margin: 0; color: var(--uc-ink-muted); font-size: var(--uc-step--1); } @media (prefers-reduced-motion: no-preference) { .help-overlay { animation: uc-help-fade 120ms var(--uc-ease); } } @keyframes uc-help-fade { from { opacity: 0; } }