Move the UI to be vertical.
This commit is contained in:
+216
-172
@@ -531,10 +531,13 @@ h3 {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* A centred portrait column — the app is laid out for a tall, narrow play
|
||||
field, so it stays compact even on a wide desktop (the event log docks
|
||||
alongside it). */
|
||||
.table-main {
|
||||
flex: 1;
|
||||
padding: 26px 20px 48px;
|
||||
max-width: 1100px;
|
||||
padding: 22px 16px 48px;
|
||||
max-width: 620px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -668,24 +671,94 @@ h3 {
|
||||
box-shadow: inset 0 0 0 1px rgba(246, 201, 78, 0.45);
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.table-body {
|
||||
flex-direction: column;
|
||||
/* On wide screens the dock wrapper is transparent to layout, so the log docks
|
||||
as a right column exactly as its own rules describe. */
|
||||
.event-log-dock {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
/* The floating log button and drawer backdrop only exist on narrow screens. */
|
||||
.log-fab,
|
||||
.log-backdrop {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Narrow screens: the event log becomes a drawer that slides in from the right
|
||||
over the play field, opened by a floating button. */
|
||||
@media (max-width: 1000px) {
|
||||
.event-log-dock {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: min(340px, 88vw);
|
||||
z-index: 80;
|
||||
transform: translateX(100%);
|
||||
transition: transform 240ms ease;
|
||||
box-shadow: -8px 0 24px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.event-log {
|
||||
|
||||
.event-log-dock.is-open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
.event-log-dock .event-log {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: none;
|
||||
position: static;
|
||||
max-height: 220px;
|
||||
border-left: none;
|
||||
border-top: 3px solid rgba(0, 0, 0, 0.35);
|
||||
border-left: 1px solid rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
.event-log.is-collapsed {
|
||||
|
||||
.event-log-dock .event-log.is-collapsed {
|
||||
width: 100%;
|
||||
}
|
||||
.event-log.is-collapsed .event-log-head {
|
||||
|
||||
.event-log-dock .event-log.is-collapsed .event-log-head {
|
||||
writing-mode: horizontal-tb;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.log-backdrop {
|
||||
display: block;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 75;
|
||||
background: rgba(10, 20, 14, 0.5);
|
||||
backdrop-filter: blur(1.5px);
|
||||
animation: result-in 200ms ease;
|
||||
}
|
||||
|
||||
.log-fab {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
position: fixed;
|
||||
right: 14px;
|
||||
bottom: 14px;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
padding: 0;
|
||||
border-radius: 50%;
|
||||
z-index: 70;
|
||||
font-size: 1.4rem;
|
||||
background: linear-gradient(180deg, var(--wood-light), var(--wood));
|
||||
color: var(--cream);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.22),
|
||||
0 4px 0 var(--wood-dark),
|
||||
0 6px 14px rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
|
||||
.log-fab:active {
|
||||
transform: translateY(3px);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.18),
|
||||
0 1px 0 var(--wood-dark),
|
||||
0 2px 6px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- lobby ---------- */
|
||||
@@ -1567,79 +1640,42 @@ h3 {
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.arrange-row {
|
||||
/* A vertical battle line laid into a felt tray: card 0 (fights first) sits at
|
||||
the top and later pets flow downward. */
|
||||
.arrange-col {
|
||||
position: relative;
|
||||
display: flex;
|
||||
/* Battle line reads right-to-left, wrapping downward: card 0 (fights first)
|
||||
sits top-right and later pets flow left, then onto rows below. The wide
|
||||
row-gap leaves a band for the wrap-around connector arrows. */
|
||||
direction: rtl;
|
||||
column-gap: 14px;
|
||||
row-gap: 56px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
justify-content: flex-start;
|
||||
gap: 12px;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 120% at 50% 0%, rgba(255, 255, 255, 0.04), transparent 70%),
|
||||
radial-gradient(ellipse 120% 80% at 50% 0%, rgba(255, 255, 255, 0.04), transparent 70%),
|
||||
rgba(0, 0, 0, 0.24);
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
border-radius: 18px;
|
||||
/* Extra right padding reserves the strip the "first" marker sits in, so its
|
||||
width doesn't shove the top row left of the wrapped rows below it. */
|
||||
padding: 20px 52px 20px 18px;
|
||||
padding: 16px 18px 20px;
|
||||
min-height: 224px;
|
||||
box-shadow: var(--tray-inset);
|
||||
}
|
||||
|
||||
/* Pinned out of flow to the reserved strip beside the first (rightmost) card,
|
||||
vertically centred on the top row, so it never affects card alignment. */
|
||||
/* The "first to fight" label sits at the top of the column, above the first
|
||||
card. It's a static first child (no data-flip-key), so the FLIP animator
|
||||
ignores it. */
|
||||
.arrange-marker {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 16px;
|
||||
height: 148px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
z-index: 2;
|
||||
direction: ltr;
|
||||
font-family: var(--font-display);
|
||||
color: var(--gold);
|
||||
writing-mode: vertical-rl;
|
||||
transform: rotate(180deg);
|
||||
font-size: 0.95rem;
|
||||
letter-spacing: 0.04em;
|
||||
opacity: 0.85;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
/* SVG overlay for the wrap-around connector arrows. Absolute so it sits out of
|
||||
the flex flow; pointer-events off so it never blocks dragging. overflow is
|
||||
visible because the curve control points can bow just past the tray edge. */
|
||||
.arrange-connectors {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 3;
|
||||
overflow: visible;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.arrange-connector {
|
||||
fill: none;
|
||||
stroke: rgba(190, 194, 200, 0.55);
|
||||
stroke-width: 2.5;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.arrange-arrowhead-shape {
|
||||
fill: rgba(190, 194, 200, 0.55);
|
||||
}
|
||||
|
||||
/* Each row: reorder arrows on the left, the card on the right. */
|
||||
.arrange-card {
|
||||
direction: ltr;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
gap: 12px;
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
@@ -1649,7 +1685,8 @@ h3 {
|
||||
|
||||
.arrange-arrows {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* ---------- battle ---------- */
|
||||
@@ -1710,18 +1747,19 @@ h3 {
|
||||
.battlefield {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
gap: 6px;
|
||||
background:
|
||||
radial-gradient(ellipse 55% 80% at center, rgba(246, 201, 78, 0.12), transparent 66%),
|
||||
radial-gradient(ellipse 80% 55% at center, rgba(246, 201, 78, 0.12), transparent 66%),
|
||||
linear-gradient(180deg, rgba(0, 0, 0, 0.28), rgba(0, 0, 0, 0.18));
|
||||
border: 1px solid rgba(0, 0, 0, 0.3);
|
||||
border-radius: 20px;
|
||||
/* Roomy top/bottom padding: pets keep their central row while set-aside
|
||||
cards fan above and attached foods fan below. The bottom needs plenty of
|
||||
room since a pet can carry a big stack of apples (Manatee, Fire Ant, …). */
|
||||
padding: 132px 14px 268px;
|
||||
/* Side padding leaves room for set-aside pets (left) and attached foods
|
||||
(right) to fan out beside each pet; a big apple stack (Manatee, Fire Ant)
|
||||
scrolls horizontally rather than clipping. */
|
||||
padding: 18px 14px;
|
||||
min-height: 150px;
|
||||
overflow-x: auto;
|
||||
box-shadow:
|
||||
@@ -1735,18 +1773,17 @@ h3 {
|
||||
flex-shrink: 0;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
min-width: 2.4rem;
|
||||
align-self: stretch;
|
||||
min-height: 2.4rem;
|
||||
}
|
||||
|
||||
/* A soft seam down the middle of the arena. */
|
||||
/* A soft seam across the middle of the arena, where the two sides clash. */
|
||||
.battle-center::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 8%;
|
||||
bottom: 8%;
|
||||
width: 2px;
|
||||
background: linear-gradient(180deg, transparent, rgba(246, 201, 78, 0.25), transparent);
|
||||
left: 8%;
|
||||
right: 8%;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, rgba(246, 201, 78, 0.25), transparent);
|
||||
}
|
||||
|
||||
.battle-center-bolt {
|
||||
@@ -1754,12 +1791,20 @@ h3 {
|
||||
filter: drop-shadow(0 0 8px rgba(246, 201, 78, 0.5));
|
||||
}
|
||||
|
||||
/* One player's half. The opponent (top) stacks deck-over-pet; you (bottom)
|
||||
stack pet-over-deck, so both decks sit on the outer edge and the two pets
|
||||
meet at the centre seam. */
|
||||
.battle-side {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
/* Centres the deck stack under (you) / over (opponent) the pet. */
|
||||
.battle-deck {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@@ -1838,53 +1883,57 @@ h3 {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Spawn arcs out from the pet (inner edge) onto the deck. The pet sits to the
|
||||
right of the deck on the left side and to the left on the right side, so
|
||||
each side pulls its spawn in from the opposite direction. */
|
||||
@keyframes summon-from-right {
|
||||
/* Spawn arcs out from the pet onto the deck. The pet sits toward the centre
|
||||
seam — above your deck (bottom half) and below the opponent's (top half) — so
|
||||
each spawn is pulled in from its own pet's side. */
|
||||
@keyframes summon-to-bottom {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate(120px, 8px) scale(0.5) rotate(10deg);
|
||||
transform: translateY(-70px) scale(0.5);
|
||||
}
|
||||
25% {
|
||||
opacity: 1;
|
||||
transform: translate(64px, -22px) scale(1.05) rotate(5deg);
|
||||
transform: translateY(-30px) scale(1.05);
|
||||
}
|
||||
70% {
|
||||
opacity: 1;
|
||||
transform: translate(0, -12px) scale(1) rotate(0);
|
||||
transform: translateY(4px) scale(1);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate(0, 2px) scale(0.72);
|
||||
transform: translateY(14px) scale(0.72);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes summon-from-left {
|
||||
@keyframes summon-to-top {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translate(-120px, 8px) scale(0.5) rotate(-10deg);
|
||||
transform: translateY(70px) scale(0.5);
|
||||
}
|
||||
25% {
|
||||
opacity: 1;
|
||||
transform: translate(-64px, -22px) scale(1.05) rotate(-5deg);
|
||||
transform: translateY(30px) scale(1.05);
|
||||
}
|
||||
70% {
|
||||
opacity: 1;
|
||||
transform: translate(0, -12px) scale(1) rotate(0);
|
||||
transform: translateY(-4px) scale(1);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translate(0, 2px) scale(0.72);
|
||||
transform: translateY(-14px) scale(0.72);
|
||||
}
|
||||
}
|
||||
|
||||
.summon-pop.summon-from-right {
|
||||
animation-name: summon-from-right;
|
||||
/* You throw from the bottom (deck below the pet); the opponent from the top. */
|
||||
.summon-pop.summon-to-bottom {
|
||||
top: auto;
|
||||
bottom: calc(100% - 24px);
|
||||
animation-name: summon-to-bottom;
|
||||
}
|
||||
|
||||
.summon-pop.summon-from-left {
|
||||
animation-name: summon-from-left;
|
||||
.summon-pop.summon-to-top {
|
||||
top: calc(100% - 24px);
|
||||
animation-name: summon-to-top;
|
||||
}
|
||||
|
||||
/* Apple/bee spawned in the shop, flying out from the creature that made it. */
|
||||
@@ -1948,27 +1997,27 @@ h3 {
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
/* Set-aside pets (Blowfish, Badger, …) laid out in a row above the active
|
||||
pet, kept until their pending effect resolves. */
|
||||
/* Set-aside pets (Blowfish, Badger, …) laid out in a row to the left of the
|
||||
active pet, kept until their pending effect resolves. */
|
||||
.setaside-row {
|
||||
position: absolute;
|
||||
bottom: calc(100% + 6px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
right: calc(100% + 6px);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
/* Attached (or pending) foods fanned below the pet: a vertical stack that
|
||||
overlaps ~¾ so only each card's top edge shows, last card fully on top. */
|
||||
/* Attached (or pending) foods fanned to the right of the pet: a horizontal row
|
||||
that overlaps ~¾ so only each card's left edge shows, last card fully on top. */
|
||||
.food-fan {
|
||||
position: absolute;
|
||||
top: calc(100% - 6px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
left: calc(100% - 6px);
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
z-index: 4;
|
||||
}
|
||||
@@ -1978,8 +2027,8 @@ h3 {
|
||||
}
|
||||
|
||||
.food-fan-card:not(:first-child) {
|
||||
/* Slightly tighter overlap so a tall apple stack fits the play area. */
|
||||
margin-top: -92px;
|
||||
/* Overlap so a tall apple stack stays compact beside the pet. */
|
||||
margin-left: -64px;
|
||||
}
|
||||
|
||||
/* Released cards (a spent set-aside pet, or a used-up food perk) shrink and
|
||||
@@ -1998,13 +2047,13 @@ h3 {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* A freshly dealt food (apple) sails in from the deck — up and toward the outer
|
||||
edge — and settles onto the fan, rather than blinking into place. Direction
|
||||
follows the side the deck sits on (see food-in-left / food-in-right). */
|
||||
@keyframes food-in-left {
|
||||
/* A freshly dealt food (apple) sails in from the deck and settles onto the fan,
|
||||
rather than blinking into place. The deck sits below the pet on your side and
|
||||
above it on the opponent's, so the apple flies up (bottom) or down (top). */
|
||||
@keyframes food-in-bottom {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-64px, -52px) rotate(-14deg) scale(0.6);
|
||||
transform: translate(-30px, 70px) rotate(-12deg) scale(0.6);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
@@ -2012,10 +2061,10 @@ h3 {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes food-in-right {
|
||||
@keyframes food-in-top {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(64px, -52px) rotate(14deg) scale(0.6);
|
||||
transform: translate(-30px, -70px) rotate(12deg) scale(0.6);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
@@ -2023,27 +2072,27 @@ h3 {
|
||||
}
|
||||
}
|
||||
|
||||
.food-fan-card.food-in-left {
|
||||
animation: food-in-left 440ms cubic-bezier(0.2, 0.8, 0.3, 1) backwards;
|
||||
.food-fan-card.food-in-bottom {
|
||||
animation: food-in-bottom 440ms cubic-bezier(0.2, 0.8, 0.3, 1) backwards;
|
||||
}
|
||||
|
||||
.food-fan-card.food-in-right {
|
||||
animation: food-in-right 440ms cubic-bezier(0.2, 0.8, 0.3, 1) backwards;
|
||||
.food-fan-card.food-in-top {
|
||||
animation: food-in-top 440ms cubic-bezier(0.2, 0.8, 0.3, 1) backwards;
|
||||
}
|
||||
|
||||
/* A pet that faints with a pending effect rises up out of the arena into the
|
||||
set-aside row, shrinking from its arena size to the smaller set-aside size. */
|
||||
/* A pet that faints with a pending effect slides out of the arena into the
|
||||
set-aside row on its left, shrinking to the smaller set-aside size. */
|
||||
@keyframes setaside-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(150px) scale(1.2);
|
||||
transform: translateX(120px) scale(1.2);
|
||||
}
|
||||
55% {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
transform: translateX(0) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2071,61 +2120,68 @@ h3 {
|
||||
}
|
||||
|
||||
/* A pet flips face-up off its deck: it starts over the stack (outer edge) still
|
||||
turned edge-on, then slides in toward its arena slot while turning to face us.
|
||||
The deck sits to the outer side of each unit, so each side pulls the reveal in
|
||||
from its own edge. */
|
||||
@keyframes unit-reveal-left {
|
||||
turned edge-on, then rises in toward its arena slot while turning to face us.
|
||||
The deck sits below your pet and above the opponent's, so each side pulls the
|
||||
reveal in from its own edge. */
|
||||
@keyframes unit-reveal-bottom {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-108px) perspective(760px) rotateY(-92deg) scale(0.92);
|
||||
transform: translateY(108px) perspective(760px) rotateX(-92deg) scale(0.92);
|
||||
}
|
||||
45% {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0) perspective(760px) rotateY(0deg) scale(1);
|
||||
transform: translateY(0) perspective(760px) rotateX(0deg) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes unit-reveal-right {
|
||||
@keyframes unit-reveal-top {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(108px) perspective(760px) rotateY(92deg) scale(0.92);
|
||||
transform: translateY(-108px) perspective(760px) rotateX(92deg) scale(0.92);
|
||||
}
|
||||
45% {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0) perspective(760px) rotateY(0deg) scale(1);
|
||||
transform: translateY(0) perspective(760px) rotateX(0deg) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.battle-unit.unit-reveal-left {
|
||||
transform-origin: left center;
|
||||
animation: unit-reveal-left 520ms cubic-bezier(0.2, 0.8, 0.3, 1);
|
||||
.battle-unit.unit-reveal-bottom {
|
||||
transform-origin: center bottom;
|
||||
animation: unit-reveal-bottom 520ms cubic-bezier(0.2, 0.8, 0.3, 1);
|
||||
}
|
||||
|
||||
.battle-unit.unit-reveal-right {
|
||||
transform-origin: right center;
|
||||
animation: unit-reveal-right 520ms cubic-bezier(0.2, 0.8, 0.3, 1);
|
||||
.battle-unit.unit-reveal-top {
|
||||
transform-origin: center top;
|
||||
animation: unit-reveal-top 520ms cubic-bezier(0.2, 0.8, 0.3, 1);
|
||||
}
|
||||
|
||||
/* --- rock dice --- */
|
||||
|
||||
/* A little tray of dice, drawn just below the throwing side's deck (see
|
||||
.stack-dice). Fixed slots: the dice scramble in place, then settle showing
|
||||
the rolled rock faces. */
|
||||
/* A little tray of dice, drawn beside the throwing side's deck on the side that
|
||||
faces the centre seam — above your deck, below the opponent's. Fixed slots:
|
||||
the dice scramble in place, then settle showing the rolled rock faces. */
|
||||
.stack-dice {
|
||||
position: absolute;
|
||||
top: calc(100% + 8px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 8;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.battle-deck-bottom .stack-dice {
|
||||
bottom: calc(100% + 8px);
|
||||
}
|
||||
|
||||
.battle-deck-top .stack-dice {
|
||||
top: calc(100% + 8px);
|
||||
}
|
||||
|
||||
.dice-roll {
|
||||
display: flex;
|
||||
gap: 7px;
|
||||
@@ -2247,42 +2303,43 @@ h3 {
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
@keyframes clash-left {
|
||||
/* You (bottom) lunge up into the seam; the opponent (top) lunges down. */
|
||||
@keyframes clash-bottom {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
35% {
|
||||
transform: translateX(26px) rotate(4deg);
|
||||
transform: translateY(-26px) rotate(2deg);
|
||||
}
|
||||
60% {
|
||||
transform: translateX(-6px);
|
||||
transform: translateY(6px);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes clash-right {
|
||||
@keyframes clash-top {
|
||||
0% {
|
||||
transform: translateX(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
35% {
|
||||
transform: translateX(-26px) rotate(-4deg);
|
||||
transform: translateY(26px) rotate(-2deg);
|
||||
}
|
||||
60% {
|
||||
transform: translateX(6px);
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(0);
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.battle-unit.clash-left {
|
||||
animation: clash-left 500ms ease;
|
||||
.battle-unit.clash-bottom {
|
||||
animation: clash-bottom 500ms ease;
|
||||
}
|
||||
|
||||
.battle-unit.clash-right {
|
||||
animation: clash-right 500ms ease;
|
||||
.battle-unit.clash-top {
|
||||
animation: clash-top 500ms ease;
|
||||
}
|
||||
|
||||
@keyframes dying {
|
||||
@@ -2462,9 +2519,6 @@ h3 {
|
||||
width: 92px;
|
||||
height: 128px;
|
||||
}
|
||||
.arrange-marker {
|
||||
height: 128px;
|
||||
}
|
||||
.card-lg {
|
||||
width: 104px;
|
||||
height: 146px;
|
||||
@@ -2624,22 +2678,12 @@ h3 {
|
||||
max-width: min(60vw, 560px);
|
||||
}
|
||||
|
||||
/* first-right: the first pet sits on the right (matches your own arrangement).
|
||||
first-left: the first pet sits on the left (a rival, who faces you from the
|
||||
right of the board). The "⚔️ first" marker is the first DOM child, so it
|
||||
lands next to the first card at whichever end. */
|
||||
.deck-peek-cards.first-right {
|
||||
direction: rtl;
|
||||
}
|
||||
/* first-left: the lineup runs first-to-last, left to right, with the "⚔️ first"
|
||||
marker as the first DOM child so it lands next to the first card. */
|
||||
.deck-peek-cards.first-left {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
/* Keep each card's own contents left-to-right regardless of row direction. */
|
||||
.deck-peek-cards > * {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
/* Compact echo of the arrangement phase's "⚔️ first" indicator. */
|
||||
.deck-peek-first {
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user