MTG_Life/style.css
2025-09-09 17:56:44 -04:00

547 lines
19 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. 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 wooden (or black) bowl
- no duplicate rules / cleaned media queries
*/
/* ===== Base / Resets =================================================== */
*,
*::before,
*::after { box-sizing: border-box; }
html, body { height: 100%; }
html { min-height: 100%; margin: 0; }
body {
background: radial-gradient(circle at 50% 40%, #792f22 0%, #4f644f 47%, #6c7f83 100%);
margin: 0;
color: #333;
user-select: none;
font-family: 'Lucida Grande','Lucida Sans Unicode','Lucida Sans',Geneva,Verdana,sans-serif;
}
/* 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; /* change to slow/fast the roll */
--die-size: 96px; /* change to scale die & bowl together */
/* cards */
--card-border: hsl(0 0% 100% / 0.16);
--ring-thickness: 10px;
/* bowl (wood theme) */
--wood-h: 30; /* hue 2040 = warm brown */
--wood-s: 55%; /* saturation 4070% */
--wood-l: 35%; /* lightness 3045% */
--wood-sheen: .05; /* tiny linear grain */
--wood-rim: .18; /* rim highlight strength */
}
/* ===== Main Layout ===================================================== */
main{
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: center;
width: 100vw;
min-height: 100vh;
padding-top: 100px; /* space for toolbar */
gap: clamp(18px, 4vw, 44px); /* gap between cards */
}
/* ===== Toolbar ========================================================= */
#buttonWrapper{
position: fixed;
top: 10px;
left: 50%;
transform: translateX(-50%);
width: min(92%, 760px);
display: flex;
justify-content: space-evenly;
align-items: center;
padding: 6px;
border-radius: 20px;
background: #eee;
opacity: .9;
box-shadow: 0 4px 8px rgba(0,0,0,.2);
z-index: 10;
}
.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); }
/* ===== Dice slot + bowl =============================================== */
/* Dice hitbox no visual box */
.dice{
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: var(--bowl-size);
height: var(--bowl-size);
background: none !important;
border: none !important;
box-shadow: none !important;
}
/* 3D canvas for die (sized by --die-size) */
.dice .content{
position: relative;
width: var(--die-size);
height: var(--die-size);
perspective: calc(var(--die-size) * 15);
}
/* --- Wooden bowl (default) --- */
.dice .content::before{
content:"";
position: absolute; inset: 6px; border-radius: 50%;
z-index: 0;
background:
/* concentric rings */
repeating-conic-gradient(
at 50% 52%,
hsl(var(--wood-h) var(--wood-s) calc(var(--wood-l) + 7%)) 0deg 5deg,
hsl(var(--wood-h) var(--wood-s) calc(var(--wood-l) - 7%)) 5deg 10deg
),
/* subtle straight grain */
repeating-linear-gradient(
14deg,
rgba(255,255,255,var(--wood-sheen)) 0 2px,
rgba(0,0,0,var(--wood-sheen)) 2px 4px
),
/* concave shading */
radial-gradient(120% 120% at 50% 42%,
rgba(255,255,255,.18) 0%,
rgba(255,255,255,.10) 30%,
rgba(0,0,0,.22) 70%,
rgba(0,0,0,.34) 100%);
background-blend-mode: multiply, overlay, normal;
box-shadow:
inset 0 12px 26px rgba(0,0,0,.45),
inset 0 -8px 18px rgba(255,255,255,.08),
0 2px 8px rgba(0,0,0,.28);
}
/* rim highlight */
.dice .content::after{
content:"";
position: absolute; inset: 0; border-radius: 50%;
z-index: 0; pointer-events: none;
background:
radial-gradient(80% 80% at 50% 25%,
rgba(255,255,255,var(--wood-rim)) 0%,
rgba(255,255,255,0) 60%);
box-shadow:
0 0 0 2px hsl(var(--wood-h) var(--wood-s) calc(var(--wood-l) - 4%) / .45),
inset 0 0 18px rgba(255,255,255,.08);
}
/* --- Black bowl variant (add class .bowl--black to .dice) --- */
.content::before{
content:"";
position:absolute; inset:6px; / inner lip */
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);
}
/* Subtle rim highlight */
.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 2px rgba(255,255,255,.08),
inset 0 0 20px rgba(0,0,0,.6);
pointer-events:none;
}
/* ===== Die (D20) ====================================================== */
/* wrapper that owns the animation */
.roller{
position: absolute;
inset: 0;
transform-style: preserve-3d;
z-index: 1; /* above bowl */
}
/* 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;
/* FIX: reset a local counter so numbering starts at 1 here */
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: rotateX(11deg) rotateY(-540deg); }
.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(94,134,91,0.9);
width: 0; height: 0;
transform-style: preserve-3d;
backface-visibility: hidden;
/* FIX: unique counter to avoid clashes (was steps) */
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); /* avoid z-fighting */
}
/* 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); }
}