MTG_Life/style.css
2025-09-10 09:24:49 -04:00

922 lines
19 KiB
CSS
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
  MTG Life Counter — Full CSS
  - modern player cards with depleting ring
  - contained die slot with black bowl
  - no duplicate rules / cleaned media queries
*/
/* Put a solid fallback on the root */
html { background-color: #6c7f83; } /* match your gradient's far color */
/* Let body grow; don't paint the bg here */
body {
min-height: 100%;
background: transparent;
position: relative;
}
/* Fixed, full-viewport gradient layer to kill seams */
body::before{
content: "";
position: fixed;
inset: 0;
z-index: -1;
pointer-events: none;
background: radial-gradient(circle at 50% 40%, #792f22 0%, #4f644f 47%, #6c7f83 100%);
transform: translateZ(0); /* GPU promote to avoid subpixel gaps */
}
/* Animatable property for the ring sweep */
@property --life-deg {
syntax: '<angle>';
inherits: true;
initial-value: 360deg;
}
/* ===== Theme Variables ================================================= */
:root {
/* layout */
--border-radius: 30px;
/* dice / animation */
--roll-ms: 1500ms;
--die-base: 96; /* px, the geometry was authored at this size */
--bowl-ratio: 1.55; /* bowl diameter ÷ die size */
--die-size: clamp(70px, 32svmin, 200px) !important;
--bowl-size: calc(var(--die-size) * var(--bowl-ratio));
/* cards */
--card-border: hsl(0 0% 100% / 0.16);
--ring-thickness: 10px;
}
/* Tiny phones: a slightly tighter bowl so the rim never touches edges */
@media (max-width: 420px) {
:root {
--bowl-ratio: 1.48;
}
}
/* ===== Main Layout ===================================================== */
main {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: center;
width: 100vw;
min-height: 100vh;
padding-top: 100px;
gap: clamp(18px, 4vw, 44px);
}
/* ===== Toolbar ========================================================= */
#buttonWrapper {
position: fixed;
top: 10px;
left: 50%;
transform: translateX(-50%);
width: min(92%, 760px);
display: flex;
align-items: center;
justify-content: space-evenly;
gap: 10px;
padding: 6px;
border-radius: 20px;
background: #eee;
opacity: .9;
box-shadow: 0 4px 8px rgba(0, 0, 0, .2);
overflow: hidden;
z-index: 10;
}
#buttonWrapper > * {
flex: 0 0 auto;
}
#buttonWrapper .dice {
min-width: 0;
}
.icons {
font-size: clamp(18px, 1.6vw, 26px);
padding: 10px;
color: #697069;
cursor: pointer;
transition: color .2s, transform .2s;
}
.icons:hover {
color: #333;
transform: scale(1.08);
}
.icons:active {
transform: scale(0.94);
}
/* ===== Die Roller Modal ================================================ */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 100; /* Sit on top */
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
justify-content: center;
align-items: center;
}
.modal-content {
background: linear-gradient(180deg, hsl(0 0% 100% / .10), hsl(0 0% 100% / .05));
border: 1px solid hsl(0 0% 100% / .16);
padding: 20px;
border-radius: 20px;
position: relative;
width: 90%;
max-width: 400px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4);
}
.close-button {
color: #fff;
float: right;
font-size: 36px;
font-weight: bold;
cursor: pointer;
position: absolute;
top: 10px;
right: 20px;
z-index: 101;
}
.close-button:hover {
color: #ccc;
}
.die-container {
display: flex;
justify-content: center;
align-items: center;
height: 300px;
width: 100%;
}
.die-container .content {
width: 200px;
height: 200px;
perspective: 2000px;
}
/* ===== Die (D20) ====================================================== */
.die-container .content > .track {
position: absolute;
inset: 0;
z-index: 1;
transform: scale(calc(var(--die-size) / (var(--die-base) * 1px)));
transform-origin: 50% 50%;
will-change: transform;
}
.die-container .content > .track > .roller {
position: absolute;
inset: 0;
}
/* Bowl background */
.die-container .content::before {
content: "";
position: absolute;
inset: clamp(3px, calc(var(--die-size) * .065), 12px);
border-radius: 50%;
z-index: 0;
background: radial-gradient(circle at 50% 45%, #4a4a4a 0%, #2a2a2a 62%, #111 80%, #000 100%);
box-shadow:
inset 0 10px 24px rgba(255, 255, 255, .08),
inset 0 -12px 24px rgba(0, 0, 0, .65),
0 2px 10px rgba(0, 0, 0, .55);
}
/* Bowl rim highlight */
.die-container .content::after {
content: "";
position: absolute;
inset: 0;
border-radius: 50%;
z-index: 0;
background: radial-gradient(circle at 50% 30%, rgba(255, 255, 255, .14) 0%, rgba(0, 0, 0, 0) 60%);
box-shadow:
0 0 0 calc(var(--die-size) * .018) rgba(255, 255, 255, .08),
inset 0 0 calc(var(--die-size) * .20) rgba(0, 0, 0, .6);
pointer-events: none;
}
/* wrapper that owns the animation */
.roller {
position: absolute;
inset: 0;
transform-style: preserve-3d;
z-index: 1;
}
/* elliptical path that eases back to center */
@keyframes orbit-wobble {
0% {
transform: translate3d(0, 0, 2px) rotateZ(0deg);
}
15% {
transform: translate3d(16px, 10px, -4px) rotateZ(.6deg);
}
35% {
transform: translate3d(-14px, 12px, -2px) rotateZ(-.7deg);
}
55% {
transform: translate3d(12px, -10px, 1px) rotateZ(.5deg);
}
75% {
transform: translate3d(-6px, 4px, 0) rotateZ(-.25deg);
}
100% {
transform: translate3d(0, 0, 0) rotateZ(0deg);
}
}
/* clean 0→100% spin */
@keyframes roll {
0% {
transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);
}
25% {
transform: rotateX(180deg) rotateY(360deg) rotateZ(0deg);
}
50% {
transform: rotateX(360deg) rotateY(720deg) rotateZ(0deg);
}
75% {
transform: rotateX(540deg) rotateY(1080deg) rotateZ(0deg);
}
100% {
transform: rotateX(720deg) rotateY(1440deg) rotateZ(0deg);
}
}
/* run both animations together */
.roller.rolling {
animation:
orbit-wobble var(--roll-ms) ease-in-out,
roll var(--roll-ms) linear;
}
.die {
position: absolute;
inset: 0;
transform-style: preserve-3d;
transition: transform .5s ease-out;
transform-origin: 50% 50% 10px;
cursor: pointer;
counter-reset: d20num 0;
}
.die:not([data-face]) {
transform: rotateX(-53deg) rotateY(0deg);
}
.die[data-face="1"] {
transform: rotateX(-53deg) rotateY(0deg);
}
.die[data-face="2"] {
transform: rotateX(-53deg) rotateY(72deg);
}
.die[data-face="3"] {
transform: rotateX(-53deg) rotateY(144deg);
}
.die[data-face="4"] {
transform: rotateX(-53deg) rotateY(216deg);
}
.die[data-face="5"] {
transform: rotateX(-53deg) rotateY(288deg);
}
.die[data-face="16"] {
transform: rotateX(127deg) rotateY(-72deg);
}
.die[data-face="17"] {
transform: rotateX(127deg) rotateY(-144deg);
}
.die[data-face="18"] {
transform: rotateX(127deg) rotateY(-216deg);
}
.die[data-face="19"] {
transform: rotateX(127deg) rotateY(-288deg);
}
.die[data-face="20"] {
transform: rotateX(127deg) rotateY(-360deg);
}
.die[data-face="6"] {
transform: rotateX(11deg) rotateZ(180deg) rotateY(0deg);
}
.die[data-face="7"] {
transform: rotateX(11deg) rotateZ(180deg) rotateY(72deg);
}
.die[data-face="8"] {
transform: rotateX(11deg) rotateZ(180deg) rotateY(144deg);
}
.die[data-face="9"] {
transform: rotateX(11deg) rotateZ(180deg) rotateY(216deg);
}
.die[data-face="10"] {
transform: rotateX(11deg) rotateZ(180deg) rotateY(288deg);
}
.die[data-face="11"] {
transform: rotateX(11deg) rotateY(-252deg);
}
.die[data-face="12"] {
transform: rotateX(11deg) rotateY(-324deg);
}
.die[data-face="13"] {
transform: rotateX(11deg) rotateY(-396deg);
}
.die[data-face="14"] {
transform: rotateX(11deg) rotateY(-468deg);
}
.die[data-face="15"] {
transform: rotateY(540deg) translateZ(18.75px) translateY(13.545px) rotateX(-11deg);
}
.die .face {
position: absolute;
left: 50%;
top: 0;
margin: 0 -12.5px;
border-left: 12.5px solid transparent;
border-right: 12.5px solid transparent;
border-bottom: 21.5px solid rgba(106, 67, 151, 0.9);
width: 0;
height: 0;
transform-style: preserve-3d;
backface-visibility: hidden;
counter-increment: d20num 1;
}
.die .face::before {
content: counter(d20num);
position: absolute;
top: 5.375px;
left: -25px;
width: 50px;
height: 21.5px;
color: #fff;
text-shadow: 1px 1px 3px #000;
font-size: 10.75px;
text-align: center;
line-height: 19.35px;
transform: translateZ(0.1px);
}
/* Face placement */
.die .face:nth-child(1) {
transform: rotateY(0deg) translateZ(8.375px) translateY(-3.225px) rotateX(53deg);
}
.die .face:nth-child(2) {
transform: rotateY(-72deg) translateZ(8.375px) translateY(-3.225px) rotateX(53deg);
}
.die .face:nth-child(3) {
transform: rotateY(-144deg) translateZ(8.375px) translateY(-3.225px) rotateX(53deg);
}
.die .face:nth-child(4) {
transform: rotateY(-216deg) translateZ(8.375px) translateY(-3.225px) rotateX(53deg);
}
.die .face:nth-child(5) {
transform: rotateY(-288deg) translateZ(8.375px) translateY(-3.225px) rotateX(53deg);
}
.die .face:nth-child(16) {
transform: rotateY(-108deg) translateZ(8.375px) translateY(30.315px) rotateZ(180deg) rotateX(53deg);
}
.die .face:nth-child(17) {
transform: rotateY(-36deg) translateZ(8.375px) translateY(30.315px) rotateZ(180deg) rotateX(53deg);
}
.die .face:nth-child(18) {
transform: rotateY(36deg) translateZ(8.375px) translateY(30.315px) rotateZ(180deg) rotateX(53deg);
}
.die .face:nth-child(19) {
transform: rotateY(108deg) translateZ(8.375px) translateY(30.315px) rotateZ(180deg) rotateX(53deg);
}
.die .face:nth-child(20) {
transform: rotateY(180deg) translateZ(8.375px) translateY(30.315px) rotateZ(180deg) rotateX(53deg);
}
.die .face:nth-child(6) {
transform: rotateY(360deg) translateZ(18.75px) translateY(13.545px) rotateZ(180deg) rotateX(-11deg);
}
.die .face:nth-child(7) {
transform: rotateY(288deg) translateZ(18.75px) translateY(13.545px) rotateZ(180deg) rotateX(-11deg);
}
.die .face:nth-child(8) {
transform: rotateY(216deg) translateZ(18.75px) translateY(13.545px) rotateZ(180deg) rotateX(-11deg);
}
.die .face:nth-child(9) {
transform: rotateY(144deg) translateZ(18.75px) translateY(13.545px) rotateZ(180deg) rotateX(-11deg);
}
.die .face:nth-child(10) {
transform: rotateY(72deg) translateZ(18.75px) translateY(13.545px) rotateZ(180deg) rotateX(-11deg);
}
.die .face:nth-child(11) {
transform: rotateY(252deg) translateZ(18.75px) translateY(13.545px) rotateX(-11deg);
}
.die .face:nth-child(12) {
transform: rotateY(324deg) translateZ(18.75px) translateY(13.545px) rotateX(-11deg);
}
.die .face:nth-child(13) {
transform: rotateY(396deg) translateZ(18.75px) translateY(13.545px) rotateX(-11deg);
}
.die .face:nth-child(14) {
transform: rotateY(468deg) translateZ(18.75px) translateY(13.545px) rotateX(-11deg);
}
.die .face:nth-child(15) {
transform: rotateY(540deg) translateZ(18.75px) translateY(13.545px) rotateX(-11deg);
}
/* Optional micro-alignment of face 1 (tweak if needed) */
:root {
--face1-ry: 0deg;
--face1-dy: 32px;
--face1-rz: .6deg;
}
.die .face:nth-child(1) {
transform:
rotateY(calc(0deg + var(--face1-ry)))
translateZ(8.375px)
translateY(calc(-3.225px + var(--face1-dy)))
rotateX(53deg)
rotateZ(var(--face1-rz));
}
/* ===== Player Cards ==================================================== */
/* varied accents */
main .player:nth-child(6n+1) {
--accent: hsl(200 100% 65%);
}
main .player:nth-child(6n+2) {
--accent: hsl(280 100% 70%);
}
main .player:nth-child(6n+3) {
--accent: hsl(150 95% 54%);
}
main .player:nth-child(6n+4) {
--accent: hsl(20 100% 65%);
}
main .player:nth-child(6n+5) {
--accent: hsl(45 100% 62%);
}
main .player:nth-child(6n+6) {
--accent: hsl(325 100% 68%);
}
/* 2-player: distinct */
body.is-two-player-mode main .player:nth-child(1) {
--accent: #45c5ff;
}
body.is-two-player-mode main .player:nth-child(2) {
--accent: #b86bff;
}
.player {
position: relative;
display: flex;
flex-direction: column;
gap: 14px;
padding: 18px 18px 16px;
border-radius: 20px;
background: linear-gradient(180deg, hsl(0 0% 100% / .10), hsl(0 0% 100% / .05)) border-box;
border: 1px solid var(--card-border);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
box-shadow: 0 10px 30px hsl(0 0% 0% / .25), inset 0 1px 0 hsl(0 0% 100% / .15);
transition: transform .18s, box-shadow .18s;
max-width: clamp(540px, 46vw, 960px);
}
.player:hover {
transform: translateY(-2px);
box-shadow: 0 16px 40px hsl(0 0% 0% / .33), inset 0 1px 0 hsl(0 0% 100% / .18);
}
/* accent edge glow */
.player::after {
content: "";
position: absolute;
inset: -1px;
border-radius: 20px;
pointer-events: none;
background: linear-gradient(135deg, transparent 20%, color-mix(in oklab, var(--accent), white 25%) 50%, transparent 80%);
opacity: .25;
}
/* name pill */
.name {
width: 100%;
max-width: 360px;
padding: 10px 16px;
border-radius: 14px;
background: hsl(0 0% 100% / .08);
border: 1px solid hsl(0 0% 100% / .18);
color: #fff;
text-align: center;
font-size: clamp(16px, 2.2vw, 20px);
outline: none;
caret-color: var(--accent);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: box-shadow .18s, border-color .18s, background .18s;
}
.name:focus {
background: hsl(0 0% 100% / .12);
border-color: color-mix(in oklab, var(--accent), white 30%);
box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent), transparent 80%);
}
/* life area */
.life {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 12px;
background: transparent;
border: 0;
padding: 6px 0;
}
.vert {
display: flex;
flex-direction: column;
gap: 8px;
align-items: center;
}
/* ringed number */
.life-count {
position: relative;
width: clamp(96px, 14vw, 142px);
height: clamp(96px, 14vw, 142px);
border-radius: 50%;
display: grid;
place-items: center;
color: #fff;
font-weight: 800;
text-shadow: 0 1px 0 hsl(0 0% 0% / .35);
font-size: clamp(36px, 8vh, 64px);
isolation: isolate;
transition: --life-deg 280ms linear;
}
.life-count::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
z-index: -2;
background: conic-gradient(from -90deg, var(--accent) 0 var(--life-deg, calc(var(--life-pct, 1)*1turn)), hsl(0 0% 100% / .10) 0 360deg);
filter: drop-shadow(0 4px 10px color-mix(in oklab, var(--accent), black 70%));
}
.life-count::after {
content: "";
position: absolute;
inset: var(--ring-thickness);
border-radius: inherit;
z-index: -1;
background: hsl(0 0% 100% / .06);
border: 1px solid hsl(0 0% 100% / .12);
}
/* life buttons */
.life-btn {
width: 44px;
height: 44px;
border-radius: 50%;
display: grid;
place-items: center;
color: #fff;
font-size: 20px;
cursor: pointer;
background: linear-gradient(180deg, hsl(0 0% 100% / .18), hsl(0 0% 100% / .06));
border: 1px solid hsl(0 0% 100% / .18);
box-shadow: 0 6px 16px hsl(0 0% 0% / .25), inset 0 1px 0 hsl(0 0% 100% / .25);
transition: transform .12s, box-shadow .12s, background .12s;
}
.life-btn:hover {
transform: translateY(-1px);
box-shadow: 0 10px 20px hsl(0 0% 0% / .35), inset 0 1px 0 hsl(0 0% 100% / .30);
}
.life-btn:active {
transform: translateY(0) scale(.97);
}
.life-up-1,
.life-up-5 {
color: color-mix(in oklab, var(--accent), white 10%);
}
.life-down-1,
.life-down-5 {
color: hsl(0 90% 60%);
}
/* special counters */
.special-counters {
width: 100%;
max-width: 520px;
padding-top: 10px;
background: none;
gap: 10px;
}
.poison-counter,
.commander-damage-counter {
display: flex;
align-items: center;
gap: 10px;
background: hsl(0 0% 100% / .07);
border: 1px solid hsl(0 0% 100% / .14);
border-radius: 12px;
padding: 8px 10px;
color: #fff;
font-size: clamp(12px, 1.6vw, 16px);
}
.commander-name {
flex: 1 1 auto;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
opacity: .9;
}
.commander-controls {
display: inline-flex;
align-items: center;
gap: 6px;
}
.poison-btn,
.commander-btn {
width: 28px;
height: 28px;
min-width: 28px;
min-height: 28px;
display: grid;
place-items: center;
font-size: 14px;
line-height: 1;
padding: 0;
border-radius: 8px;
color: #fff;
cursor: pointer;
background: hsl(0 0% 100% / .12);
border: 1px solid hsl(0 0% 100% / .18);
transition: transform .1s, background .1s;
}
.poison-btn:hover,
.commander-btn:hover {
transform: translateY(-1px);
}
.poison-value,
.commander-value {
min-width: 1.8ch;
text-align: center;
color: #fff;
}
/* poison: label left, controls dock right */
.poison-counter .counter-label {
margin-right: 8px;
}
.poison-counter .poison-down {
margin-left: auto;
}
.poison-counter .poison-value {
min-width: 2ch;
}
/* commander panel show/hide */
body.is-commander-mode .commander-damage {
display: block;
}
.commander-damage {
display: none;
}
/* zero-life style */
.player[data-life-zero="true"] .life-count {
color: hsl(0 100% 70%);
filter: drop-shadow(0 0 18px hsl(0 100% 60% / .45));
}
.player[data-life-zero="true"] .life-count::before {
background: conic-gradient(hsl(0 100% 62%) 360deg, transparent 0);
}
/* ===== Responsive ====================================================== */
@media (orientation: landscape) and (max-height: 500px) {
.player {
padding: 20px;
}
.life {
gap: 12px;
}
.life-count {
width: 150px;
height: 150px;
font-size: clamp(44px, 5vw, 78px);
--ring-thickness: 12px;
}
.life-btn {
width: 52px;
height: 52px;
font-size: 24px;
}
.name {
font-size: clamp(16px, 2.4vw, 22px);
}
}
@media (min-width: 768px) {
.player {
padding: 22px;
border-radius: 22px;
}
.life {
gap: 14px;
}
.life-count {
width: 180px;
height: 180px;
font-size: clamp(52px, 4.6vw, 86px);
--ring-thickness: 14px;
}
.life-btn {
width: 58px;
height: 58px;
font-size: 26px;
}
.special-counters {
max-width: 640px;
}
.poison-counter,
.commander-damage-counter {
font-size: 16px;
}
.poison-btn,
.commander-btn {
width: 32px;
height: 32px;
font-size: 16px;
}
}
@media (min-width: 1200px) {
.life-count {
width: 220px;
height: 220px;
font-size: clamp(64px, 3.6vw, 96px);
--ring-thickness: 16px;
}
.life-btn {
width: 64px;
height: 64px;
font-size: 30px;
}
}
@media (min-width: 1600px) {
.life-count {
width: 260px;
height: 260px;
font-size: clamp(72px, 3vw, 112px);
--ring-thickness: 18px;
}
.life-btn {
width: 70px;
height: 70px;
font-size: 32px;
}
}
/* ===== Infect Mode (secret) ===== */
body.infect-mode {
filter: hue-rotate(-25deg) saturate(1.25);
}
body.infect-mode .life-count::before {
background: conic-gradient(from -90deg, #35ff96 0 var(--life-deg, calc(var(--life-pct, 1)*1turn)), rgba(255, 255, 255, 0.10) 0 360deg);
filter: drop-shadow(0 6px 16px rgba(11, 232, 129, 0.55));
}
body.infect-mode .poison-counter {
border-color: rgba(53, 255, 150, 0.35);
box-shadow: 0 0 12px rgba(53, 255, 150, 0.25) inset;
}
body.infect-mode .poison-btn {
background: linear-gradient(180deg, rgba(53, 255, 150, .22), rgba(53, 255, 150, .12));
border-color: rgba(53, 255, 150, .45);
}
/* Skull hint while holding */
#poison-toggle.egg-hold {
animation: skull-hold 1.2s linear;
filter: drop-shadow(0 0 10px rgba(53, 255, 150, .45));
}
@keyframes skull-hold {
0% {
transform: scale(1);
}
90% {
transform: scale(1.12);
}
100% {
transform: scale(1.08);
}
}