/*   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: ''; 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); } }