/* Self-contained layout for the gr.Server frontend. game.css styles all render.py internals (battle-frame, sprites, meters, character-sheet, overlays' inner HTML, keyframes) and provides :root tokens. This file owns ONLY the custom shell: page chrome, setup screens, the gameplay shell, the action decks, and overlay wrappers — using tw-* class names so the Gradio-tuned rules in game.css never apply to them. */ * { box-sizing: border-box; } [hidden] { display: none !important; } body { margin: 0; background: radial-gradient(1200px 600px at 50% -10%, #161228 0%, #0a0910 60%); color: var(--ink, #ddd9e8); font-family: "Segoe UI", system-ui, -apple-system, sans-serif; } #app { max-width: 1500px; margin: 0 auto; padding: .7rem 1.1rem 2.2rem; } /* ---------- title ---------- */ .tw-title { max-width: 560px; margin: 7vh auto; text-align: center; padding: 2.6rem 2.2rem; border: 1px solid #3e3553; background: #12101aee; border-radius: 16px; box-shadow: 0 0 50px #00000080, inset 0 0 30px #08060e; } .tw-title p { color: #c7bee0; line-height: 1.5; } .tw-hint { font-size: .74rem; color: #8a83a3; margin-top: 1.2rem; } .tw-hint code { color: #b8a6db; } /* ---------- buttons ---------- */ .tw-primary { padding: .7rem 1.8rem; font-size: 1rem; font-weight: 700; color: #1a130a; background: linear-gradient(180deg, #e0c084, #c79a4f); border: 0; border-radius: 10px; cursor: pointer; letter-spacing: .03em; box-shadow: 0 6px 18px #00000066; } .tw-primary:hover:not(:disabled) { filter: brightness(1.08); } .tw-primary:disabled { opacity: .45; cursor: not-allowed; } .tw-secondary { padding: .6rem 1.3rem; font-weight: 600; color: #d7cdf0; background: #1a1626; border: 1px solid #3e3553; border-radius: 10px; cursor: pointer; } .tw-secondary:hover { border-color: var(--violet, #8669c4); } /* ---------- setup panels ---------- */ .tw-panel { max-width: 1180px; margin: 2vh auto; padding: 1.4rem 1.6rem; border: 1px solid #3e3553; background: #12101aee; border-radius: 14px; } .tw-setup-actions { display: flex; gap: .8rem; justify-content: center; margin-top: 1.2rem; flex-wrap: wrap; } .tw-alloc-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: .8rem; margin-top: 1.2rem; } .tw-alloc-grid .stat-card { text-align: center; padding: .8rem .5rem; background: var(--card-bg, #12101a); border: 1px solid var(--card-border, #30283f); border-radius: 10px; } .tw-alloc-grid .stat-card strong { display: block; margin-bottom: .5rem; color: #e2d9f3; } .stat-stepper { display: flex; align-items: center; justify-content: center; gap: .6rem; } .stat-stepper button { width: 32px; height: 32px; font-size: 1.2rem; font-weight: 700; background: #1a1626; color: #e2d9f3; border: 1px solid #3e3553; border-radius: 8px; cursor: pointer; } .stat-stepper button:hover:not(:disabled) { border-color: var(--violet, #8669c4); } .stat-stepper button:disabled { opacity: .35; cursor: not-allowed; } .stat-value { font-size: clamp(.95rem, 2.5vw, 1.3rem); font-weight: 700; min-width: 2ch; } .alloc-remaining { grid-column: 1 / -1; text-align: center; color: #b8a6db; margin-top: .4rem; } .alloc-remaining b { color: var(--gold, #e0c084); } .tw-diff-row { display: flex; gap: .8rem; justify-content: center; margin: 1.2rem 0; flex-wrap: wrap; } .diff-btn { padding: .6rem 1.2rem; background: var(--card-bg, #171522); color: #cfc6e6; border: 1px solid var(--card-border, #30283f); border-radius: 10px; cursor: pointer; } .diff-btn.selected { border-color: #c79a4f; color: #f0e3c4; background: #1f1830; } .diff-btn:disabled { opacity: .6; cursor: default; } .tw-starter-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: .55rem; margin-top: 1rem; } .starter-card { white-space: pre-line; text-align: left; padding: .55rem .6rem; min-height: 84px; background: var(--card-bg, #12101a); color: #eef3fb; border: 1px solid var(--card-border, #30283f); border-radius: 8px; cursor: pointer; font-size: .8rem; line-height: 1.18; } .starter-card:hover { border-color: var(--violet, #8669c4); background: #191522; } @media (max-width: 900px) { .tw-starter-grid { grid-template-columns: repeat(2, 1fr); } .tw-alloc-grid { grid-template-columns: repeat(2, 1fr); } } /* ---------- gameplay shell: sidebar LEFT, main right (matches original) ---------- */ .tw-shell { display: flex; align-items: flex-start; gap: 1rem; } .tw-sidebar { flex: 0 0 300px; max-width: 320px; min-width: 270px; position: sticky; top: .5rem; max-height: calc(100vh - 1rem); overflow-y: auto; background: var(--card-bg, #12101a); border: 1px solid #3e3553; border-radius: 12px; padding: .5rem .7rem; } .tw-sidebar-head { display: flex; align-items: center; justify-content: space-between; gap: .5rem; } .tw-sidebar-head h2 { margin: 0; font-size: clamp(.85rem, 2.5vw, 1.1rem); } .tw-main { flex: 1; min-width: 0; } .tw-toggle { padding: .25rem .6rem; font-size: .78rem; color: #cfc6e6; background: #1a1626; border: 1px solid #3e3553; border-radius: 7px; cursor: pointer; } .tw-toggle:hover { border-color: var(--violet, #8669c4); } #show-sidebar { margin-bottom: .5rem; } /* stage = positioning context for the action decks (mirrors original .stage-stack) */ .tw-stage { position: relative; width: min(100%, 1250px, calc((100dvh - 300px) * 16 / 9)); margin: 0 auto; padding-bottom: clamp(3.8rem, 7vh, 4.8rem); } #stage-narration { position: absolute; z-index: 16; top: 8%; left: 18%; width: 50%; pointer-events: none; } .tw-log { margin: .5rem 0; min-height: 2rem; padding: .5rem .8rem; background: #111019; border-left: 3px solid var(--violet, #8669c4); color: #f1e4b9; font-size: clamp(.72rem, 1.8vw, .85rem); } .tw-fulllog { margin-top: .4rem; } .tw-fulllog summary { cursor: pointer; color: #b8a6db; font-size: clamp(.72rem, 1.8vw, .85rem); } /* ---------- action decks (overlay the bottom of the frame, original look) ---------- */ .tw-deck { position: absolute; bottom: 0; z-index: 8; padding: .55rem; border: 1px solid var(--card-border, #30283f); background: var(--deck-bg, #12101ae8); box-shadow: 0 10px 28px #0009, inset 0 1px #8490a31a; } .tw-deck-basic { left: 2%; width: 34%; height: 72px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .45rem; } .tw-deck-right { right: 2%; width: min(59%, 720px); } .tw-deck-right.tw-deck-open { min-height: clamp(184px, 25vh, 224px); } .tw-deck-toggles { display: grid; grid-template-columns: 1fr 1fr; gap: .45rem; height: 72px; } .tw-deck-title { color: #d9c7ff; font-size: clamp(.6rem, 1.2vw, .78rem); font-weight: 800; letter-spacing: .1em; text-transform: uppercase; margin-bottom: .35rem; } .tw-deck-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .4rem; } .tw-deck .tw-back { margin-top: .4rem; width: 100%; text-align: center; min-height: 2rem; } .tw-empty { color: var(--card-muted, #aaa2bd); font-size: .85rem; padding: .4rem; } .tw-thinking { right: 2%; width: min(59%, 720px); padding: .7rem; color: #d9c7ff; text-align: center; } .tw-thinking p { margin: .3rem 0 0; font-size: .8rem; color: var(--card-muted, #aaa2bd); } .tw-narrating .tw-card { opacity: 0.42; cursor: not-allowed !important; pointer-events: none; } /* action cards — reproduce original .action-card look */ .tw-card { min-height: 0; min-width: 0; padding: .42rem .55rem; white-space: pre-line; text-align: left; font-weight: 600; line-height: 1.14; font-size: clamp(.72rem, .82vw, .88rem); color: #eef3fb; background: var(--card-bg, #12101a); border: 1px solid var(--card-border, #30283f); border-radius: 0; cursor: pointer; } .tw-deck-basic .tw-card { height: 100%; } .tw-card:hover:not(:disabled) { background: #191522; border-color: var(--violet, #8669c4); } .tw-card:disabled { color: #746d80; background: #0f0d15cc; border-color: #292333; cursor: not-allowed; } /* ---------- overlays (victory / evolution / defeat / ascension / preview) ---------- */ .tw-overlay { position: absolute; inset: 0; z-index: 20; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .7rem; padding: 1rem; background: #07060bd9; } .tw-overlay-card { max-width: 92%; max-height: 90%; overflow: auto; padding: 1rem 1.2rem; background: var(--card-bg, #12101a); border: 1px solid #4a3f63; border-radius: 12px; box-shadow: 0 12px 40px #000a; text-align: center; } .tw-overlay .reward-actions, .tw-overlay .level-skill-actions, .tw-overlay .replacement-actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: .5rem; margin-top: .6rem; } .tw-overlay .reward-footer, .tw-overlay .heal-actions, .tw-overlay .preview-actions { display: flex; gap: .6rem; align-items: center; justify-content: center; margin-top: .7rem; flex-wrap: wrap; } .tw-overlay .reward-count { color: #b8a6db; font-size: .85rem; } .tw-card.primary { background: linear-gradient(180deg, #e0c084, #c79a4f); color: #1a130a; border: 0; font-weight: 700; } .tw-card.primary:hover:not(:disabled) { filter: brightness(1.08); } .reward-icon { width: 26px; height: 26px; vertical-align: middle; margin-right: .4rem; image-rendering: pixelated; } /* ---------- tutorial overlay ---------- */ .tw-tutorial { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; background: #06050aee; padding: 1rem; } .tw-tutorial-card { width: min(720px, 100%); max-height: 88vh; display: flex; flex-direction: column; background: #12101a; border: 1px solid #4a3f63; border-radius: 14px; box-shadow: 0 16px 50px #000b; overflow: hidden; } #tutorial-content { flex: 1; overflow-y: auto; padding: 1.4rem 1.6rem; } .tw-tutorial-nav { flex: 0 0 auto; display: flex; gap: .6rem; align-items: center; justify-content: center; padding: .7rem 1rem; border-top: 1px solid #2e2840; background: #0e0c17; } .tw-tutorial-nav .tw-card { min-width: 90px; text-align: center; padding: .45rem .8rem; } .tw-tutorial-nav .tw-card.primary { background: linear-gradient(180deg,#e0c084,#c79a4f); color:#1a130a; border:0; font-weight:700; } .tw-tutorial-nav .tw-card:disabled { opacity: .35; cursor: not-allowed; } /* heal preview line in evolution-healing overlay */ .tw-heal-preview { margin: .5rem 0 1rem; font-size: 1rem; color: #d9c7ff; } .tw-heal-preview b { color: #e0c084; } .tw-heal-gain { color: #9fd7ba; font-size: .9rem; } /* How to Play button spacing on title screen */ .tw-title .tw-secondary { display: block; margin: .6rem auto 0; } /* ---------- loading overlay (no backdrop-filter — keeps screenshots working) ---------- */ .tw-loading { position: fixed; inset: 0; z-index: 300; display: flex; align-items: center; justify-content: center; background: #06050aee; } .tw-loading-card { display: flex; flex-direction: column; align-items: center; gap: 1rem; padding: 2rem 2.5rem; border: 1px solid #3e3553; background: #12101a; border-radius: 14px; } .tw-loading-card span { color: #d9c7ff; letter-spacing: .04em; } .tw-rune { width: 42px; height: 42px; border: 3px solid #3e3553; border-top-color: #c79a4f; border-radius: 50%; animation: tw-spin .9s linear infinite; } .tw-rune-sm { width: 20px; height: 20px; border-width: 2px; margin: 0 auto .4rem; } @keyframes tw-spin { to { transform: rotate(360deg); } } /* ---------- bgm mute button (fixed top-left) ---------- */ .tw-mute-btn { position: fixed; top: .6rem; left: .6rem; z-index: 500; padding: .25rem .5rem; font-size: .85rem; line-height: 1; color: #d9c7ff; background: #1a162699; border: 1px solid #3e3553; border-radius: 7px; cursor: pointer; } .tw-mute-btn:hover { border-color: var(--violet, #8669c4); } .tw-mute-off { opacity: .45; text-decoration: line-through; } @media (max-width: 900px) { .tw-shell { flex-direction: column; } .tw-sidebar { flex: none; width: 100%; max-width: none; min-width: 0; position: static; max-height: none; } } @media (max-width: 600px) { #app { padding: .4rem .5rem 1.2rem; } .tw-title { margin: 2vh auto; padding: 1.4rem 1rem; } .tw-panel { padding: .8rem .9rem; } .tw-stage { padding-bottom: clamp(2.4rem, 7vh, 3.8rem); } .tw-deck-right.tw-deck-open { min-height: clamp(110px, 25vh, 184px); } .tw-starter-grid { grid-template-columns: repeat(2, 1fr); } .tw-alloc-grid { grid-template-columns: repeat(2, 1fr); } }