vagabond-rpg-foundryvtt/styles/scss/chat/_chat-cards.scss
Cal Corum 7f06ec229a Add Roll Damage button to spell chat cards
Spell damage is now rolled separately via button click instead of
automatically, matching the attack roll behavior. Includes spell chat
card styling fixes for proper header layout and damage display.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 18:14:04 -06:00

859 lines
19 KiB
SCSS

// Vagabond RPG - Chat Card Styles
// ================================
// Uses CSS custom properties for theme support.
// Base chat card
.vagabond.chat-card {
@include panel;
overflow: hidden;
background-color: var(--color-bg-primary);
// Card header
.card-header {
@include flex-between;
padding: $spacing-2 $spacing-3;
background-color: var(--color-bg-secondary);
border-bottom: 1px solid var(--color-border);
.card-title,
h3 {
@include flex-center;
gap: $spacing-2;
font-family: $font-family-header;
font-size: $font-size-base;
font-weight: $font-weight-bold;
margin: 0;
color: var(--color-text-primary);
i {
color: var(--color-accent-primary);
}
}
.card-subtitle {
font-size: $font-size-sm;
color: var(--color-text-muted);
}
.trained-badge {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
background-color: rgba(74, 159, 66, 0.2);
color: var(--color-success);
border-radius: $radius-full;
font-weight: $font-weight-medium;
}
}
// Card content
.card-content {
padding: $spacing-3;
}
// Roll result (large total display)
.roll-result {
@include flex-column;
align-items: center;
gap: $spacing-2;
padding: $spacing-4;
margin: $spacing-3;
background-color: var(--color-bg-secondary);
border-radius: $radius-md;
border: 2px solid var(--color-border);
.roll-total {
font-family: $font-family-header;
font-size: $font-size-4xl;
font-weight: $font-weight-bold;
line-height: 1;
color: var(--color-text-primary);
}
.roll-status {
.status {
display: inline-block;
padding: $spacing-1 $spacing-3;
font-size: $font-size-sm;
font-weight: $font-weight-bold;
text-transform: uppercase;
letter-spacing: 0.1em;
border-radius: $radius-md;
}
.success {
background-color: rgba(74, 159, 66, 0.2);
color: var(--color-success);
}
.failure {
background-color: rgba(201, 68, 68, 0.2);
color: var(--color-danger);
}
.critical {
background-color: rgba(212, 163, 44, 0.3);
color: var(--color-warning);
animation: pulse 1s ease-in-out;
}
.fumble {
background-color: rgba(201, 68, 68, 0.3);
color: var(--color-danger);
animation: shake 0.5s ease-in-out;
}
}
// Conditional styling based on result
&.success {
border-color: var(--color-success);
}
&.failure {
border-color: var(--color-danger);
}
&.critical {
border-color: var(--color-warning);
background-color: rgba(212, 163, 44, 0.1);
}
&.fumble {
border-color: var(--color-danger);
background-color: rgba(201, 68, 68, 0.1);
}
}
// Roll details
.roll-details {
@include flex-column;
gap: $spacing-2;
padding: $spacing-3;
margin: 0 $spacing-3 $spacing-3;
background-color: var(--color-bg-secondary);
border-radius: $radius-md;
font-size: $font-size-sm;
.roll-formula {
@include flex-between;
.label {
color: var(--color-text-muted);
}
.value {
font-family: $font-family-mono;
color: var(--color-text-primary);
}
}
.roll-breakdown {
@include flex-center;
gap: $spacing-3;
padding-top: $spacing-2;
border-top: 1px solid var(--color-border);
span {
@include flex-center;
gap: $spacing-1;
}
.d20-result {
font-family: $font-family-mono;
font-weight: $font-weight-bold;
color: var(--color-text-primary);
}
.favor-die {
font-family: $font-family-mono;
&.favor {
color: var(--color-success);
}
&.hinder {
color: var(--color-danger);
}
}
.modifier {
font-family: $font-family-mono;
color: var(--color-text-secondary);
}
}
}
// Info sections (save-info, skill-info, target-info)
.save-info,
.skill-info,
.target-info {
@include flex-column;
gap: $spacing-1;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2 $spacing-3;
background-color: var(--color-bg-tertiary);
border-radius: $radius-md;
font-size: $font-size-sm;
> div {
@include flex-between;
}
.label {
color: var(--color-text-muted);
}
.value {
font-weight: $font-weight-medium;
color: var(--color-text-primary);
}
.stat-abbr {
font-weight: $font-weight-bold;
color: var(--color-accent-primary);
}
}
// Defense info display
.defense-info-display {
@include flex-center;
gap: $spacing-2;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2 $spacing-3;
background-color: rgba(64, 144, 224, 0.1);
border: 1px solid var(--color-info);
border-radius: $radius-md;
font-size: $font-size-sm;
color: var(--color-info);
i {
font-size: $font-size-base;
}
}
// Defense badge
.defense-badge {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
border-radius: $radius-full;
font-weight: $font-weight-medium;
text-transform: uppercase;
&.block {
background-color: rgba(64, 144, 224, 0.2);
color: var(--color-info);
}
&.dodge {
background-color: rgba(74, 159, 66, 0.2);
color: var(--color-success);
}
}
// Favor/Hinder sources
.favor-sources,
.hinder-sources {
@include flex-center;
gap: $spacing-2;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2;
font-size: $font-size-sm;
border-radius: $radius-md;
}
.favor-sources {
background-color: rgba(74, 159, 66, 0.1);
color: var(--color-success);
}
.hinder-sources {
background-color: rgba(201, 68, 68, 0.1);
color: var(--color-danger);
}
// Result status (legacy)
.result-status {
@include flex-center;
padding: $spacing-2;
font-weight: $font-weight-bold;
text-transform: uppercase;
letter-spacing: 0.1em;
border-radius: $radius-md;
&.success {
background-color: rgba(74, 159, 66, 0.2);
color: var(--color-success);
}
&.failure {
background-color: rgba(201, 68, 68, 0.2);
color: var(--color-danger);
}
&.critical {
background-color: rgba(212, 163, 44, 0.2);
color: var(--color-warning);
animation: pulse 1s ease-in-out;
}
}
// Damage display
.damage-display {
@include flex-center;
gap: $spacing-2;
margin: $spacing-3;
padding: $spacing-2;
background-color: rgba(201, 68, 68, 0.1);
border: 1px solid var(--color-danger);
border-radius: $radius-md;
.damage-label {
font-size: $font-size-sm;
color: var(--color-text-secondary);
}
.damage-value {
font-family: $font-family-header;
font-size: $font-size-xl;
font-weight: $font-weight-bold;
color: var(--color-danger);
}
.damage-type {
font-size: $font-size-sm;
color: var(--color-text-muted);
}
}
// Card buttons (for interactive cards)
.card-buttons {
display: flex;
gap: $spacing-2;
padding: $spacing-3;
border-top: 1px solid var(--color-border);
button {
flex: 1;
}
}
}
// Skill roll card specific
.vagabond.chat-card.skill-roll {
.skill-name {
margin: 0;
}
}
// Save roll card specific
.vagabond.chat-card.save-roll {
.save-name {
margin: 0;
}
}
// Attack roll card specific
.vagabond.chat-card.attack-roll {
.card-header {
display: flex;
align-items: center;
gap: $spacing-3;
.weapon-icon {
width: 32px;
height: 32px;
border-radius: $radius-sm;
border: 1px solid var(--color-border);
}
.header-text {
flex: 1;
.weapon-name {
margin: 0;
font-size: $font-size-base;
color: var(--color-text-primary);
}
.attack-type-badge {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
background-color: rgba(139, 69, 19, 0.2);
color: var(--color-accent-primary);
border-radius: $radius-full;
font-weight: $font-weight-medium;
}
}
}
.damage-section {
margin: $spacing-3;
padding: $spacing-3;
background-color: rgba(201, 68, 68, 0.1);
border: 1px solid rgba(201, 68, 68, 0.3);
border-radius: $radius-md;
&.critical {
background-color: rgba(212, 163, 44, 0.15);
border-color: var(--color-warning);
.damage-total {
color: var(--color-warning);
}
}
.damage-header {
@include flex-center;
gap: $spacing-2;
font-weight: $font-weight-semibold;
margin-bottom: $spacing-2;
color: var(--color-text-primary);
i {
color: var(--color-danger);
}
.crit-label {
color: var(--color-warning);
font-size: $font-size-sm;
}
}
.damage-result {
@include flex-center;
gap: $spacing-2;
.damage-total {
font-family: $font-family-header;
font-size: $font-size-3xl;
font-weight: $font-weight-bold;
color: var(--color-danger);
line-height: 1;
}
.damage-type {
font-size: $font-size-sm;
color: var(--color-text-secondary);
text-transform: capitalize;
}
}
.damage-breakdown {
@include flex-center;
gap: $spacing-2;
margin-top: $spacing-2;
padding-top: $spacing-2;
border-top: 1px solid rgba(201, 68, 68, 0.2);
.damage-die {
@include flex-center;
gap: $spacing-1;
padding: $spacing-1 $spacing-2;
background-color: rgba(201, 68, 68, 0.15);
border-radius: $radius-md;
font-family: $font-family-mono;
font-weight: $font-weight-bold;
color: var(--color-text-primary);
i {
color: var(--color-danger);
font-size: $font-size-sm;
}
}
}
.damage-formula {
@include flex-center;
gap: $spacing-2;
margin-top: $spacing-2;
font-family: $font-family-mono;
font-size: $font-size-sm;
color: var(--color-text-muted);
.grip-indicator {
color: var(--color-text-secondary);
}
}
}
.weapon-properties {
display: flex;
flex-wrap: wrap;
gap: $spacing-1;
margin: $spacing-2 $spacing-3;
padding: $spacing-2;
.property-tag {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
background-color: var(--color-bg-secondary);
border-radius: $radius-full;
color: var(--color-text-secondary);
text-transform: capitalize;
}
}
// Roll Damage button
.card-buttons {
.roll-damage-btn {
@include flex-center;
gap: $spacing-2;
width: 100%;
padding: $spacing-2 $spacing-3;
background-color: rgba(201, 68, 68, 0.2);
border: 1px solid var(--color-danger);
border-radius: $radius-md;
color: var(--color-danger);
font-weight: $font-weight-semibold;
cursor: pointer;
transition: all 0.2s ease;
&:hover:not(:disabled) {
background-color: rgba(201, 68, 68, 0.3);
border-color: var(--color-danger);
}
&:disabled {
opacity: 0.7;
cursor: not-allowed;
}
&.critical {
background-color: rgba(212, 163, 44, 0.2);
border-color: var(--color-warning);
color: var(--color-warning);
&:hover:not(:disabled) {
background-color: rgba(212, 163, 44, 0.3);
}
}
.crit-label {
font-size: $font-size-sm;
color: var(--color-warning);
}
.damage-preview {
font-family: $font-family-mono;
font-size: $font-size-sm;
color: var(--color-text-secondary);
}
}
}
}
// Spell card specific
.vagabond.chat-card.spell-card,
.vagabond.chat-card.spell-cast {
.card-header {
display: flex;
align-items: center;
gap: $spacing-3;
.spell-icon {
width: 32px;
height: 32px;
border-radius: $radius-sm;
border: 1px solid var(--color-border);
object-fit: cover;
}
.header-text {
flex: 1;
min-width: 0; // Prevent flex overflow
.spell-name {
margin: 0;
font-size: $font-size-base;
color: var(--color-text-primary);
}
.casting-skill-badge {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
background-color: rgba(112, 80, 176, 0.2);
color: var(--color-reason);
border-radius: $radius-full;
font-weight: $font-weight-medium;
}
}
.mana-cost-badge {
font-size: $font-size-xs;
padding: $spacing-1 $spacing-2;
background-color: rgba(112, 80, 176, 0.2);
color: var(--color-reason);
border-radius: $radius-full;
font-weight: $font-weight-medium;
i {
margin-right: $spacing-1;
}
}
}
// Cast configuration display (delivery, duration, mana)
.cast-config {
display: flex;
flex-wrap: wrap;
gap: $spacing-2;
margin: $spacing-2 $spacing-3;
padding: $spacing-2;
background-color: var(--color-bg-tertiary);
border-radius: $radius-md;
font-size: $font-size-sm;
.config-item {
display: flex;
gap: $spacing-1;
.label {
color: var(--color-text-muted);
}
.value {
font-weight: $font-weight-medium;
color: var(--color-text-primary);
i {
color: var(--color-warning);
margin-left: $spacing-1;
}
}
}
}
.spell-effect {
padding: $spacing-3;
font-style: italic;
border-left: 3px solid var(--color-accent-primary);
background-color: var(--color-bg-secondary);
margin: $spacing-3;
color: var(--color-text-secondary);
}
// Spell effect section in chat (different from .spell-effect above)
.spell-effect-section {
margin: $spacing-3;
padding: $spacing-3;
background-color: var(--color-bg-secondary);
border-radius: $radius-md;
border-left: 3px solid var(--color-accent-primary);
.effect-header {
@include flex-center;
justify-content: flex-start;
gap: $spacing-2;
margin-bottom: $spacing-2;
font-weight: $font-weight-semibold;
color: var(--color-accent-primary);
}
.effect-text {
font-size: $font-size-sm;
color: var(--color-text-secondary);
font-style: italic;
}
.crit-effect {
margin-top: $spacing-2;
padding-top: $spacing-2;
border-top: 1px solid var(--color-border);
.crit-label {
font-weight: $font-weight-semibold;
color: var(--color-warning);
}
.crit-text {
font-size: $font-size-sm;
color: var(--color-text-secondary);
font-style: italic;
}
}
}
// Damage section (similar to attack-roll)
.damage-section {
margin: $spacing-3;
padding: $spacing-3;
background-color: rgba(201, 68, 68, 0.1);
border: 1px solid rgba(201, 68, 68, 0.3);
border-radius: $radius-md;
&.critical {
background-color: rgba(212, 163, 44, 0.15);
border-color: var(--color-warning);
.damage-total {
color: var(--color-warning);
}
}
.damage-header {
@include flex-center;
gap: $spacing-2;
font-weight: $font-weight-semibold;
margin-bottom: $spacing-2;
color: var(--color-text-primary);
i {
color: var(--color-danger);
}
.crit-label {
color: var(--color-warning);
font-size: $font-size-sm;
}
}
.damage-result {
@include flex-center;
gap: $spacing-2;
.damage-total {
font-family: $font-family-header;
font-size: $font-size-3xl;
font-weight: $font-weight-bold;
color: var(--color-danger);
line-height: 1;
}
.damage-type {
font-size: $font-size-sm;
color: var(--color-text-secondary);
text-transform: capitalize;
}
}
.damage-formula {
@include flex-center;
margin-top: $spacing-2;
font-family: $font-family-mono;
font-size: $font-size-sm;
color: var(--color-text-muted);
}
}
.spell-meta {
@include grid(2, $spacing-2);
margin: 0 $spacing-3 $spacing-3;
font-size: $font-size-sm;
.meta-item {
@include flex-between;
padding: $spacing-1;
.meta-label {
color: var(--color-text-muted);
}
.meta-value {
font-weight: $font-weight-medium;
color: var(--color-text-primary);
}
}
}
// Mana spent display
.mana-spent {
@include flex-center;
gap: $spacing-2;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2;
background-color: rgba(112, 80, 176, 0.1);
border: 1px solid rgba(112, 80, 176, 0.3);
border-radius: $radius-md;
font-size: $font-size-sm;
color: var(--color-reason);
i {
font-size: $font-size-base;
}
}
// Focus indicator
.focus-indicator {
@include flex-center;
gap: $spacing-2;
margin: 0 $spacing-3 $spacing-3;
padding: $spacing-2;
background-color: rgba(212, 163, 44, 0.1);
border: 1px solid var(--color-warning);
border-radius: $radius-md;
font-size: $font-size-sm;
color: var(--color-warning);
}
// Roll Damage button (same style as attack-roll)
.card-buttons {
.roll-damage-btn {
@include flex-center;
gap: $spacing-2;
width: 100%;
padding: $spacing-2 $spacing-3;
background-color: rgba(201, 68, 68, 0.2);
border: 1px solid var(--color-danger);
border-radius: $radius-md;
color: var(--color-danger);
font-weight: $font-weight-semibold;
cursor: pointer;
transition: all 0.2s ease;
&:hover:not(:disabled) {
background-color: rgba(201, 68, 68, 0.3);
border-color: var(--color-danger);
}
&:disabled {
opacity: 0.7;
cursor: not-allowed;
}
&.critical {
background-color: rgba(212, 163, 44, 0.2);
border-color: var(--color-warning);
color: var(--color-warning);
&:hover:not(:disabled) {
background-color: rgba(212, 163, 44, 0.3);
}
}
.crit-label {
font-size: $font-size-sm;
color: var(--color-warning);
}
.damage-preview {
font-family: $font-family-mono;
font-size: $font-size-sm;
color: var(--color-text-secondary);
}
}
}
}
// Animations
@keyframes pulse {
0%,
100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
@keyframes shake {
0%,
100% {
transform: translateX(0);
}
25% {
transform: translateX(-5px);
}
75% {
transform: translateX(5px);
}
}