:host { display: block; block-size: 100%; } .combat { display: grid; grid-template-columns: minmax(0, 1fr) clamp(13rem, 17vw, 17rem); gap: var(--ar-space-4); block-size: 100%; } /* ---------- stage ---------- */ // The stage is a container so the status row reflows on its own width: the // surrounding rails can squeeze it narrow while the viewport is still wide. .combat__stage { position: relative; display: grid; container-type: inline-size; grid-template-rows: auto minmax(0, 1fr) auto; gap: var(--ar-space-4); min-block-size: 26rem; padding: var(--ar-space-4); overflow: hidden; border: 1px solid var(--ar-border); background-color: var(--ar-bg); background-image: url('/images/backgrounds/Aschestrasse.png'); background-position: center; background-repeat: no-repeat; background-size: cover; box-shadow: var(--ar-shadow-raised); } @supports ( background-image: image-set( url('/images/backgrounds/runtime/Aschestrasse-960.jpg') type('image/jpeg') 1x ) ) { .combat__stage { background-image: image-set( url('/images/backgrounds/runtime/Aschestrasse-960.jpg') type('image/jpeg') 1x ); } } .combat__stage::before { position: absolute; z-index: 0; inset: 0; content: ''; background: linear-gradient(180deg, rgb(4 6 8 / 0.72) 0%, rgb(4 6 8 / 0.1) 26%, rgb(4 6 8 / 0.66) 100%); pointer-events: none; } /* ---------- combatant status ---------- */ .combat__status { position: relative; z-index: 2; display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: start; gap: var(--ar-space-4); } .fighter { display: flex; align-items: center; gap: var(--ar-space-3); min-inline-size: 0; } .fighter--monster { justify-content: flex-end; } .fighter__icon { flex: 0 0 auto; inline-size: clamp(2.75rem, 5vw, 3.75rem); block-size: clamp(2.75rem, 5vw, 3.75rem); object-fit: cover; border-radius: 50%; box-shadow: 0 0 0 1px var(--ar-border-highlight), 0 0.3rem 0.9rem rgb(0 0 0 / 0.8); } .fighter__meter { display: grid; gap: 0.3rem; min-inline-size: 0; flex: 1 1 auto; max-inline-size: 22rem; } .fighter--monster .fighter__meter { justify-items: end; text-align: end; } .fighter__name { margin: 0; overflow: hidden; color: var(--ar-text); font-family: Georgia, 'Times New Roman', serif; font-size: clamp(0.95rem, 1.5vw, 1.15rem); letter-spacing: 0.02em; text-overflow: ellipsis; text-shadow: 0 0.1rem 0.5rem rgb(0 0 0 / 0.95); white-space: nowrap; } .fighter__level { color: var(--ar-gold); font-family: system-ui, sans-serif; font-size: var(--ar-font-sm); letter-spacing: 0.08em; text-transform: uppercase; } /* ---------- hp bars ---------- */ .bar { position: relative; display: block; inline-size: 100%; block-size: 1.25rem; overflow: hidden; border: 1px solid var(--ar-border); background: rgb(0 0 0 / 0.72); box-shadow: inset 0 0 0.6rem rgb(0 0 0 / 0.9); } .bar__fill { position: absolute; z-index: 0; inset-block: 0; inset-inline-start: 0; display: block; background: linear-gradient(180deg, #d0564a, #8e2b23); } .bar--monster .bar__fill { inset-inline-start: auto; inset-inline-end: 0; } .bar__text { position: relative; z-index: 1; display: grid; block-size: 100%; place-items: center; color: var(--ar-text); font-size: var(--ar-font-sm); font-variant-numeric: tabular-nums; letter-spacing: 0.04em; text-shadow: 0 0.05rem 0.25rem rgb(0 0 0 / 1); } /* ---------- round marker ---------- */ .combat__round { margin: 0; align-self: center; padding: var(--ar-space-1) var(--ar-space-5); border-block: 1px solid var(--ar-border-highlight); color: var(--ar-gold); background: linear-gradient(90deg, transparent, rgb(9 11 13 / 0.9) 18%, rgb(9 11 13 / 0.9) 82%, transparent); font-family: Georgia, 'Times New Roman', serif; font-size: clamp(0.95rem, 1.4vw, 1.1rem); letter-spacing: 0.14em; text-transform: uppercase; white-space: nowrap; } /* ---------- battlefield ---------- */ .combat__field { position: relative; z-index: 1; display: grid; grid-template-columns: 1fr 1fr; align-items: end; min-block-size: 0; } .sprite { display: block; max-inline-size: 100%; inline-size: auto; object-fit: contain; object-position: bottom; filter: drop-shadow(0 0.5rem 0.9rem rgb(0 0 0 / 0.7)); } /* Six 384px frames laid out horizontally; frame 0 is the resting stance. */ .sprite--player { justify-self: start; block-size: 80%; aspect-ratio: 1; transform: scaleX(-1); background-image: url('/images/combat/sprites/warrior-attack-sheet-384.png'); background-repeat: no-repeat; background-position: 0% 0; background-size: 600% 100%; } .sprite--hit { background-image: url('/images/combat/sprites/warrior-hit-sheet-384.png'); } /* 6 frames across a 600%-wide sheet land on 0/20/40/60/80/100%. */ @keyframes warrior-frames { from { background-position: 0% 0; } to { background-position: 120% 0; } } .sprite--monster { justify-self: end; block-size: calc(var(--sprite-scale, 0.6) * 100%); } /* ---------- action bar ---------- */ .combat__actions { position: relative; z-index: 2; display: flex; gap: var(--ar-space-3); min-block-size: clamp(6.5rem, 11vw, 8.5rem); } .action { position: relative; inline-size: clamp(6.5rem, 11vw, 8.5rem); aspect-ratio: 1; padding: 0; border: 0; background: transparent url('/images/hud/runtime/fight-action-frame-360.png') center / 100% 100% no-repeat; cursor: pointer; } .action__icon, .action__label, .action__key { position: absolute; inset-inline-start: 50%; translate: -50% -50%; } .action__icon { inset-block-start: 32%; inline-size: 34%; border-radius: 50%; opacity: 0.92; } .action__label { inset-block-start: 62%; color: var(--ar-text); font-family: Georgia, 'Times New Roman', serif; font-size: clamp(0.85rem, 1.2vw, 1rem); letter-spacing: 0.03em; white-space: nowrap; } .action__key { inset-block-start: 90%; color: var(--ar-text-muted); font-size: var(--ar-font-sm); font-variant-numeric: tabular-nums; } .action:hover:not(:disabled) .action__label, .action:focus-visible .action__label { color: var(--ar-gold); } .action:focus-visible { outline: 2px solid var(--ar-gold); outline-offset: 3px; } .action:disabled { cursor: progress; opacity: 0.55; } /* ---------- outcome overlay ---------- */ .outcome { position: absolute; z-index: 3; inset-block-start: 50%; inset-inline-start: 50%; display: grid; gap: var(--ar-space-2); justify-items: center; inline-size: min(26rem, 80%); padding: var(--ar-space-5); translate: -50% -50%; border: 1px solid var(--ar-border-highlight); background: rgb(9 11 13 / 0.94); box-shadow: var(--ar-shadow-raised); text-align: center; } .outcome p { margin: 0; color: var(--ar-text-muted); } .outcome__title { margin: 0; font-family: Georgia, 'Times New Roman', serif; font-size: clamp(1.5rem, 3vw, 2rem); font-weight: 400; letter-spacing: 0.12em; text-transform: uppercase; } .outcome--won .outcome__title { color: var(--ar-gold); } .outcome--lost .outcome__title { color: var(--ar-danger); } .outcome__hint { font-size: var(--ar-font-sm); font-style: italic; } .outcome__button, .combat__notice--error button { padding: var(--ar-space-2) var(--ar-space-5); border: 1px solid var(--ar-border-highlight); border-radius: var(--ar-radius-sm); color: var(--ar-text); background: linear-gradient(180deg, #23282c, #14181b); cursor: pointer; font-family: Georgia, 'Times New Roman', serif; letter-spacing: 0.04em; } .outcome__button { margin-block-start: var(--ar-space-2); } .outcome__button:hover, .combat__notice--error button:hover { border-color: var(--ar-gold); color: var(--ar-gold); } /* ---------- combat log ---------- */ .combat__log { display: grid; grid-template-rows: auto minmax(0, 1fr); min-block-size: 0; border: 1px solid var(--ar-border); background: var(--ar-panel-muted); box-shadow: var(--ar-shadow-raised); } .combat__log-title { margin: 0; padding: var(--ar-space-3) var(--ar-space-4); border-block-end: 1px solid var(--ar-border); color: var(--ar-gold); font-family: Georgia, 'Times New Roman', serif; font-size: 1.05rem; font-weight: 400; letter-spacing: 0.1em; text-transform: uppercase; } .combat__log-body { padding: var(--ar-space-3) var(--ar-space-4) var(--ar-space-4); overflow-y: auto; } .combat__log-round { margin: var(--ar-space-4) 0 var(--ar-space-2); color: var(--ar-gold); font-size: var(--ar-font-sm); letter-spacing: 0.1em; text-transform: uppercase; } .combat__log-round:first-child { margin-block-start: 0; } .combat__log-entry { margin: 0 0 var(--ar-space-1); padding-inline-start: var(--ar-space-3); border-inline-start: 2px solid var(--ar-danger); color: var(--ar-text-muted); font-size: var(--ar-font-sm); line-height: 1.45; } .combat__log-entry--player { border-inline-start-color: var(--ar-border-highlight); } /* ---------- notices ---------- */ .combat__notice { grid-column: 1 / -1; padding: var(--ar-space-4); border: 1px solid var(--ar-border); background: var(--ar-panel); box-shadow: var(--ar-shadow-raised); } .combat__notice--error { display: flex; align-items: center; justify-content: space-between; gap: var(--ar-space-4); border-color: var(--ar-danger); } .combat__notice--error button { flex: 0 0 auto; } @media (prefers-reduced-motion: no-preference) { .sprite--attacking, .sprite--hit { animation: warrior-frames 540ms steps(6) 1; } .bar__fill { transition: inline-size var(--ar-motion-base); } .action__label { transition: color var(--ar-motion-fast); } } @media (width < 60rem) { :host, .combat { block-size: auto; } .combat { grid-template-columns: minmax(0, 1fr); } .combat__stage { min-block-size: clamp(24rem, 55vh, 34rem); } .combat__log { max-block-size: 18rem; } } // Below this the three-column status row cannot hold two names and two bars // side by side, so the fighters stack under a centred round marker. @container (width < 38rem) { .combat__status { grid-template-columns: minmax(0, 1fr); gap: var(--ar-space-2); } .combat__round { order: -1; justify-self: center; } .fighter--monster { justify-content: flex-start; } .fighter--monster .fighter__meter { justify-items: start; text-align: start; } .bar--monster .bar__fill { inset-inline-start: 0; inset-inline-end: auto; } .fighter__meter { max-inline-size: none; } }