Improved card design.

This commit is contained in:
Greyson Parrelli
2026-07-25 14:08:59 -04:00
parent 3a7f92b3cb
commit 3598180ff1
2 changed files with 310 additions and 156 deletions
+219 -132
View File
@@ -980,46 +980,36 @@ h3 {
/* Thick printed stock: a warm parchment face, a soft ink border with an inner
keyline, a physical shadow, and a lit sheen along the top. */
/* Cards echo the printed board-game cards: a chunky golden frame around a
landscape illustration up top and a green-framed rule panel below. */
.card {
position: relative;
width: 108px;
height: 148px;
background: linear-gradient(168deg, #fdf6e3, var(--cream) 45%, var(--cream-dark));
border: 2px solid var(--cocoa);
width: 114px;
height: 154px;
background: linear-gradient(165deg, #f8c451, #f0a828 55%, #e2941c);
border-radius: var(--card-radius);
color: var(--ink);
display: flex;
flex-direction: column;
align-items: center;
padding: 7px 6px;
padding: 5px;
gap: 4px;
box-shadow:
inset 0 0 0 1.5px rgba(255, 255, 255, 0.55),
inset 0 -8px 14px rgba(180, 140, 80, 0.22),
inset 0 0 0 1px rgba(255, 255, 255, 0.5),
inset 0 0 0 2.5px rgba(150, 92, 18, 0.55),
var(--shadow-card);
flex-shrink: 0;
transition: transform 130ms cubic-bezier(0.34, 1.4, 0.5, 1), box-shadow 130ms ease;
user-select: none;
}
/* A faint printed sheen sweeping across the top of every card. */
.card::before {
content: '';
position: absolute;
inset: 1.5px 1.5px auto 1.5px;
height: 42%;
border-radius: 11px 11px 40% 40%;
background: linear-gradient(180deg, rgba(255, 255, 255, 0.5), transparent);
pointer-events: none;
}
.card-lg {
width: 132px;
height: 180px;
width: 140px;
height: 190px;
}
.card-sm {
width: 84px;
height: 116px;
width: 88px;
height: 120px;
}
.card.is-clickable {
@@ -1029,8 +1019,8 @@ h3 {
.card.is-clickable:hover {
transform: translateY(-8px) rotate(-1.2deg);
box-shadow:
inset 0 0 0 1.5px rgba(255, 255, 255, 0.6),
inset 0 -8px 14px rgba(180, 140, 80, 0.22),
inset 0 0 0 1px rgba(255, 255, 255, 0.5),
inset 0 0 0 2.5px rgba(150, 92, 18, 0.55),
0 18px 30px -8px rgba(20, 12, 4, 0.6),
0 4px 8px rgba(20, 12, 4, 0.4);
}
@@ -1040,8 +1030,8 @@ h3 {
outline-offset: 1px;
transform: translateY(-8px);
box-shadow:
inset 0 0 0 1.5px rgba(255, 255, 255, 0.6),
0 0 20px rgba(246, 201, 78, 0.45),
inset 0 0 0 2.5px rgba(150, 92, 18, 0.55),
0 0 20px rgba(246, 201, 78, 0.5),
var(--shadow-card);
}
@@ -1053,109 +1043,188 @@ h3 {
filter: grayscale(1);
}
.card-top {
width: 100%;
display: flex;
/* Tier sits at the top-left, suit dot at the top-right. */
justify-content: space-between;
align-items: center;
gap: 5px;
font-size: 0.72rem;
z-index: 1;
min-height: 14px;
}
/* Combat stats (power badge + battle damage marker) get their own centered
row just under the tier/suit line, so they never overlap the art or text. */
.card-combat {
z-index: 2;
/* --- Upper illustration: a stylised landscape --- */
.card-scene {
position: relative;
/* Fixed share of the card so the panel below (and the ability text inside it)
stays height-bounded — that's what lets useFitText shrink long abilities. */
flex: 0 0 58%;
min-height: 0;
border-radius: 7px;
overflow: hidden;
box-shadow: inset 0 0 0 1.5px rgba(90, 55, 15, 0.35);
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
margin: 2px 0 1px;
background:
radial-gradient(120% 70% at 50% -8%, rgba(255, 255, 255, 0.4), transparent 55%),
linear-gradient(
180deg,
#c2e8f8 0%,
#a7dcf0 24%,
#74bf68 44%,
#57a44b 58%,
#e0a751 66%,
#d5942f 86%,
#57a44b 90%,
#4c9640 100%
);
}
.card-tier {
font-family: var(--font-display);
font-size: 0.68rem;
color: rgba(74, 44, 20, 0.5);
}
.card-suit {
font-size: 0.95rem;
}
/* The art sits in a soft printed halo so it reads as the card's hero. */
.card-art {
position: relative;
font-size: 2rem;
line-height: 1;
flex: 0 0 auto;
margin-top: 1px;
z-index: 1;
filter: drop-shadow(0 3px 3px rgba(0, 0, 0, 0.28));
}
.card-art::before {
/* Distant mountain silhouette in the hills band. */
.card-scene::before {
content: '';
position: absolute;
left: 50%;
top: 52%;
width: 2.5em;
height: 2.5em;
transform: translate(-50%, -50%);
border-radius: 50%;
background: radial-gradient(circle, rgba(246, 201, 78, 0.32), transparent 68%);
z-index: -1;
left: -2%;
right: -2%;
top: 24%;
height: 22%;
background: linear-gradient(180deg, #6ea0c6, #5388b2);
clip-path: polygon(
0 100%, 10% 45%, 20% 78%, 34% 22%, 47% 66%, 60% 30%, 73% 72%, 85% 40%, 100% 82%, 100% 100%
);
opacity: 0.9;
}
/* A row of rounded bush tops where the greenery begins. */
.card-scene::after {
content: '';
position: absolute;
left: 0;
right: 0;
top: 40%;
height: 12%;
background: radial-gradient(circle at 50% 100%, #3f8f3a 0 45%, transparent 47%) 0 0 / 21% 100% repeat-x;
opacity: 0.92;
}
/* The pet reads as a die-cut sticker: a white outline hugging the art. */
.card-art {
position: relative;
z-index: 2;
font-size: 2.5rem;
line-height: 1;
transform: translateY(8%);
filter:
drop-shadow(0 0 1.5px #fff) drop-shadow(0 0 1.5px #fff) drop-shadow(0 0 1.5px #fff)
drop-shadow(0 3px 3px rgba(0, 0, 0, 0.35));
}
.card-lg .card-art {
font-size: 2.7rem;
font-size: 3.1rem;
}
.card-sm .card-art {
font-size: 1.9rem;
font-size: 2rem;
}
/* --- Lower rule panel --- */
.card-panel {
flex: 1 1 auto;
min-height: 0;
background: #fbf7ee;
border: 2px solid #4e9a3f;
border-radius: 8px;
padding: 3px 4px 4px;
display: flex;
flex-direction: column;
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.6);
}
/* Small cards (no ability text) get a compact name plate and a taller scene. */
.card-sm .card-scene {
flex: 1 1 auto;
}
.card-sm .card-panel {
flex: 0 0 auto;
}
.card-panel-head {
display: grid;
/* minmax(0, 1fr) lets the name column shrink below its min-content so a long
name wraps instead of shoving the tier die out past the card edge. */
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 4px;
border-bottom: 1.5px solid rgba(78, 154, 63, 0.4);
padding-bottom: 2px;
}
.card-hat {
width: 20px;
height: 13px;
display: block;
}
.card-die {
width: 15px;
height: 15px;
display: block;
justify-self: end;
}
.card-panel-slot {
display: block;
width: 15px;
}
.card-lg .card-hat {
width: 23px;
height: 15px;
}
.card-lg .card-die,
.card-lg .card-panel-slot {
width: 17px;
height: 17px;
}
.card-sm .card-hat {
width: 16px;
height: 10px;
}
.card-sm .card-die,
.card-sm .card-panel-slot {
width: 12px;
height: 12px;
}
.card-name {
font-family: var(--font-display);
font-size: 0.84rem;
font-size: 0.78rem;
line-height: 1.05;
margin-top: 3px;
flex: 0 0 auto;
z-index: 1;
color: var(--cocoa);
/* Always center the name — including when a long name wraps to two lines, so
the second line stays centered instead of drifting off to one side. */
width: 100%;
text-align: center;
min-width: 0;
overflow-wrap: break-word;
/* Cap the name at ~two lines; useFitText shrinks longer names to fit. */
max-height: 2.1em;
overflow: hidden;
}
.card-lg .card-name {
font-size: 0.94rem;
font-size: 0.9rem;
}
.card-sm .card-name {
font-size: 0.66rem;
}
.card-effect {
font-size: 0.55rem;
line-height: 1.2;
font-size: 0.52rem;
line-height: 1.18;
font-weight: 700;
color: var(--ink-soft);
text-align: center;
padding: 2px 3px 0;
z-index: 1;
/* Grow into the space between the name and the power badge and center the
text there, so long effects use the whole middle band instead of being
clipped just under the name. */
padding: 2px 1px 0;
/* Grow to fill the panel and center short abilities; long ones top-align so
the leading words are never the clipped ones. */
flex: 1 1 auto;
display: flex;
/* Stack multiple abilities (e.g. Squirrel's Buy and Sell) vertically rather
than side by side. */
flex-direction: column;
gap: 2px;
/* Center short text in the band, but fall back to top-aligned when the text
is taller than the band, so the leading words are never the ones clipped. */
align-items: safe center;
justify-content: center;
overflow: hidden;
@@ -1167,7 +1236,7 @@ h3 {
}
.card-lg .card-effect {
font-size: 0.63rem;
font-size: 0.6rem;
}
.card-sm .card-effect {
@@ -1200,75 +1269,89 @@ h3 {
background: radial-gradient(circle at 35% 28%, #ffdd6b, #e6ac1f);
}
/* The power badge is a fiery starburst — like a little explosion — carrying the
pet's attack. The spikes are cut with clip-path, so the drop shadow lives on
`filter` (a box-shadow would be clipped away with the corners). */
/* The power badge is a red starburst floating at the top of the illustration,
like a little explosion carrying the pet's attack. The spikes are cut with
clip-path, so the drop shadow lives on `filter`. */
.card-power {
position: absolute;
top: 4%;
left: 50%;
transform: translateX(-50%);
z-index: 3;
font-family: var(--font-display);
background: radial-gradient(circle at 38% 30%, #ffcf6b 4%, var(--coral) 42%, var(--coral-dark));
background: radial-gradient(circle at 40% 30%, #ff8a6b 2%, #e23b28 44%, #bd2716);
color: #fff;
text-shadow: 0 1px 2px rgba(120, 45, 5, 0.7);
width: 32px;
height: 32px;
-webkit-text-stroke: 0.5px rgba(120, 20, 5, 0.85);
text-shadow: 0 1px 1px rgba(120, 20, 5, 0.8);
width: 30px;
height: 30px;
display: grid;
place-items: center;
font-size: 0.9rem;
font-size: 0.92rem;
clip-path: polygon(
50% 0%, 61% 18%, 82% 12%, 78% 34%, 100% 43%, 83% 58%,
93% 79%, 70% 76%, 62% 98%, 50% 82%, 38% 98%, 30% 76%,
7% 79%, 17% 58%, 0% 43%, 22% 34%, 18% 12%, 39% 18%
);
filter: drop-shadow(0 2px 2px rgba(20, 12, 4, 0.5));
filter: drop-shadow(0 1.5px 2px rgba(20, 12, 4, 0.55));
}
.card-power.is-buffed {
background: radial-gradient(circle at 38% 30%, #c9ffd4 4%, #4fd07f 42%, #1f9e55);
text-shadow: 0 1px 2px rgba(15, 60, 30, 0.7);
background: radial-gradient(circle at 40% 30%, #c9ffd4 4%, #4fd07f 42%, #1f9e55);
-webkit-text-stroke: 0.5px rgba(15, 60, 30, 0.85);
text-shadow: 0 1px 1px rgba(15, 60, 30, 0.7);
filter: drop-shadow(0 0 5px rgba(80, 220, 120, 0.75));
}
.card-lg .card-power {
width: 37px;
height: 37px;
width: 35px;
height: 35px;
font-size: 1.02rem;
}
.card-sm .card-power {
width: 27px;
height: 27px;
font-size: 0.76rem;
width: 24px;
height: 24px;
font-size: 0.74rem;
}
.card-damage {
position: absolute;
top: 5%;
right: 5%;
z-index: 3;
font-family: var(--font-display);
color: #fff;
background: linear-gradient(180deg, #e85c49, var(--red));
border: 1.5px solid rgba(120, 20, 10, 0.4);
border-radius: 8px;
padding: 2px 7px;
font-size: 0.8rem;
padding: 1px 6px;
font-size: 0.72rem;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.3);
}
/* Food cards get a rosy stock so they read apart from pets at a glance. */
/* Food cards swap the golden frame for a warm terracotta one, ailments a cold
violet one, so the three kinds read apart at a glance. */
.card-food {
background: linear-gradient(168deg, #fff0ea, #ffe0d1 55%, #ffceba);
background: linear-gradient(165deg, #f3a67a, #e07f4f 55%, #cf6a3a);
}
.card-food::before {
background: linear-gradient(180deg, rgba(255, 255, 255, 0.6), transparent);
}
.card-food .card-effect {
color: #8a3320;
.card-food .card-panel {
border-color: #c96a3a;
}
.card-food .card-effect,
.card-food .card-name {
color: #8a3320;
}
.card-food .card-art::before {
background: radial-gradient(circle, rgba(255, 140, 100, 0.28), transparent 68%);
.card-ailment .card-panel {
border-color: #6f57b0;
}
.card-ailment .card-effect,
.card-ailment .card-name {
color: #45308a;
}
.card-check {
@@ -1402,13 +1485,10 @@ h3 {
width: fit-content;
}
/* Unicorn ailment cards: a cold, spectral palette distinct from foods/pets. */
/* Unicorn ailment cards: a cold violet frame (panel + text colours are set
with the other card-kind overrides above). */
.card-ailment {
background: linear-gradient(168deg, #e9e6f7, #cfc7ec 55%, #b3a8dd);
}
.card-ailment .card-effect,
.card-ailment .card-name {
color: #45308a;
background: linear-gradient(165deg, #b9a6e6, #9a83d9 55%, #7d64c6);
}
/* Ailment badges pinned to a battle unit. */
@@ -2161,7 +2241,7 @@ h3 {
shrinking the decorative art; useFitText then keeps the text at a larger
size before it has to shrink to fit. */
.battle-unit .card-art {
font-size: 1.5rem;
font-size: 1.95rem;
}
/* A pet flips face-up off its deck: it starts over the stack (outer edge) still
@@ -2666,6 +2746,13 @@ h3 {
padding-bottom: 10px;
}
/* Keep the illustration a healthy size while the panel grows to fit the full,
unclipped ability text. */
.card-magnify .card-scene {
flex: 0 0 auto;
height: 104px;
}
.card-magnify .card-effect {
flex: 0 0 auto;
overflow: visible;