valtech-components 4.0.443 → 4.0.446

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/esm2022/lib/components/organisms/mini-games/bubble-blitz-game.component.mjs +18 -9
  2. package/esm2022/lib/components/organisms/mini-games/chessimals-engine.mjs +109 -16
  3. package/esm2022/lib/components/organisms/mini-games/chessimals-game.component.mjs +18 -9
  4. package/esm2022/lib/components/organisms/mini-games/christianity-game.component.mjs +1531 -0
  5. package/esm2022/lib/components/organisms/mini-games/memory-game.component.mjs +18 -9
  6. package/esm2022/lib/components/organisms/mini-games/mini-games.i18n.mjs +149 -9
  7. package/esm2022/lib/components/organisms/mini-games/simon-game.component.mjs +18 -9
  8. package/esm2022/lib/components/organisms/mini-games/types.mjs +1 -1
  9. package/esm2022/lib/directives/light-ripple.directive.mjs +57 -0
  10. package/esm2022/lib/version.mjs +2 -2
  11. package/esm2022/mini-games/public-api.mjs +34 -2
  12. package/esm2022/public-api.mjs +3 -1
  13. package/fesm2022/valtech-components-mini-games.mjs +34 -2
  14. package/fesm2022/valtech-components-mini-games.mjs.map +1 -1
  15. package/fesm2022/valtech-components.mjs +1908 -58
  16. package/fesm2022/valtech-components.mjs.map +1 -1
  17. package/lib/components/organisms/mini-games/bubble-blitz-game.component.d.ts +2 -0
  18. package/lib/components/organisms/mini-games/chessimals-game.component.d.ts +3 -1
  19. package/lib/components/organisms/mini-games/christianity-game.component.d.ts +103 -0
  20. package/lib/components/organisms/mini-games/memory-game.component.d.ts +2 -0
  21. package/lib/components/organisms/mini-games/simon-game.component.d.ts +2 -0
  22. package/lib/components/organisms/mini-games/types.d.ts +74 -1
  23. package/lib/directives/light-ripple.directive.d.ts +8 -0
  24. package/lib/version.d.ts +1 -1
  25. package/mini-games/public-api.d.ts +4 -0
  26. package/package.json +2 -1
  27. package/public-api.d.ts +2 -0
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, HostListener, SecurityContext, NgZone, ViewChild, ElementRef, ChangeDetectorRef, output, ContentChild, model, ViewEncapsulation, untracked, viewChild, Injector, isSignal } from '@angular/core';
2
+ import { inject, InjectionToken, makeEnvironmentProviders, APP_INITIALIZER, ErrorHandler, Injectable, DestroyRef, Inject, signal, computed, PLATFORM_ID, isDevMode, Optional, runInInjectionContext, effect, Pipe, TemplateRef, ViewContainerRef, input, Directive, ElementRef, Renderer2, HostListener, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, HostBinding, SecurityContext, NgZone, ViewChild, ChangeDetectorRef, output, ContentChild, model, ViewEncapsulation, untracked, viewChild, Injector, isSignal } from '@angular/core';
3
3
  import { BehaviorSubject, throwError, Subject, map, distinctUntilChanged, filter as filter$1, take as take$1, firstValueFrom, of, from, EMPTY, Observable, interval, defer, timer, merge, concat, debounceTime, switchMap as switchMap$1, catchError as catchError$1, takeUntil, isObservable, forkJoin, race, tap as tap$1, Subscription, shareReplay as shareReplay$1 } from 'rxjs';
4
4
  import { catchError, switchMap, finalize, filter, take, timeout, map as map$1, tap, shareReplay, distinctUntilChanged as distinctUntilChanged$1, retry, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
5
5
  import * as i1$3 from '@angular/common/http';
@@ -49,6 +49,7 @@ import { Capacitor } from '@capacitor/core';
49
49
  import { ImageCropperComponent } from 'ngx-image-cropper';
50
50
  import Compressor from 'compressorjs';
51
51
  import { Calendar } from 'vanilla-calendar-pro';
52
+ import { CdkDrag, CdkDropList } from '@angular/cdk/drag-drop';
52
53
  import 'prismjs/components/prism-scss';
53
54
  import 'prismjs/components/prism-json';
54
55
  import { BrowserMultiFormatReader } from '@zxing/browser';
@@ -58,7 +59,7 @@ import fixWebmDuration from 'fix-webm-duration';
58
59
  * Current version of valtech-components.
59
60
  * This is automatically updated during the publish process.
60
61
  */
61
- const VERSION = '4.0.443';
62
+ const VERSION = '4.0.446';
62
63
 
63
64
  // Control de estado de refresco (singleton a nivel de módulo)
64
65
  let isRefreshing = false;
@@ -10117,6 +10118,61 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
10117
10118
  }]
10118
10119
  }], ctorParameters: () => [] });
10119
10120
 
10121
+ class LightRippleDirective {
10122
+ constructor() {
10123
+ this.host = inject(ElementRef);
10124
+ this.renderer = inject(Renderer2);
10125
+ }
10126
+ createRipple(event) {
10127
+ const element = this.host.nativeElement;
10128
+ const rect = element.getBoundingClientRect();
10129
+ const size = Math.max(rect.width, rect.height) * 1.55;
10130
+ const ripple = this.renderer.createElement('span');
10131
+ const x = event.clientX - rect.left - size / 2;
10132
+ const y = event.clientY - rect.top - size / 2;
10133
+ if (getComputedStyle(element).position === 'static') {
10134
+ this.renderer.setStyle(element, 'position', 'relative');
10135
+ }
10136
+ this.renderer.setStyle(element, 'overflow', 'hidden');
10137
+ this.renderer.setStyle(element, 'isolation', 'isolate');
10138
+ this.renderer.setStyle(element, 'touch-action', 'manipulation');
10139
+ this.renderer.setStyle(ripple, 'position', 'absolute');
10140
+ this.renderer.setStyle(ripple, 'left', `${x}px`);
10141
+ this.renderer.setStyle(ripple, 'top', `${y}px`);
10142
+ this.renderer.setStyle(ripple, 'width', `${size}px`);
10143
+ this.renderer.setStyle(ripple, 'height', `${size}px`);
10144
+ this.renderer.setStyle(ripple, 'border-radius', '999px');
10145
+ this.renderer.setStyle(ripple, 'pointer-events', 'none');
10146
+ this.renderer.setStyle(ripple, 'z-index', '1');
10147
+ this.renderer.setStyle(ripple, 'background', 'radial-gradient(circle, rgba(255,255,255,0.98) 0 0.16rem, rgba(191,219,254,0.9) 0.18rem 0.34rem, rgba(96,165,250,0.46) 0.36rem 23%, rgba(96,165,250,0.18) 38%, transparent 70%)');
10148
+ this.renderer.setStyle(ripple, 'box-shadow', '0 0 0.75rem rgba(255,255,255,0.85), 0 0 1.8rem rgba(96,165,250,0.52)');
10149
+ this.renderer.appendChild(element, ripple);
10150
+ ripple
10151
+ .animate([
10152
+ { opacity: 0.88, transform: 'scale(0.08)' },
10153
+ { opacity: 0.48, transform: 'scale(0.48)' },
10154
+ { opacity: 0, transform: 'scale(1)' },
10155
+ ], { duration: 680, easing: 'cubic-bezier(0.16, 0.84, 0.24, 1)' })
10156
+ .finished.finally(() => {
10157
+ if (ripple.parentNode === element) {
10158
+ this.renderer.removeChild(element, ripple);
10159
+ }
10160
+ });
10161
+ }
10162
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LightRippleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
10163
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: LightRippleDirective, isStandalone: true, selector: "[valLightRipple]", host: { listeners: { "pointerdown": "createRipple($event)" } }, ngImport: i0 }); }
10164
+ }
10165
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LightRippleDirective, decorators: [{
10166
+ type: Directive,
10167
+ args: [{
10168
+ selector: '[valLightRipple]',
10169
+ standalone: true,
10170
+ }]
10171
+ }], propDecorators: { createRipple: [{
10172
+ type: HostListener,
10173
+ args: ['pointerdown', ['$event']]
10174
+ }] } });
10175
+
10120
10176
  /**
10121
10177
  * Presets de botón por defecto provistos por la librería.
10122
10178
  *
@@ -61031,18 +61087,66 @@ const CHESSIMALS_BOT_PROFILES = [
61031
61087
  labelKey: 'chessimalsBotSentinel',
61032
61088
  descriptionKey: 'chessimalsBotSentinelBody',
61033
61089
  },
61090
+ {
61091
+ id: 'oracle',
61092
+ difficulty: 'hard',
61093
+ avatar: '🔮',
61094
+ labelKey: 'chessimalsBotOracle',
61095
+ descriptionKey: 'chessimalsBotOracleBody',
61096
+ },
61097
+ {
61098
+ id: 'ambusher',
61099
+ difficulty: 'hard',
61100
+ avatar: '🪤',
61101
+ labelKey: 'chessimalsBotAmbusher',
61102
+ descriptionKey: 'chessimalsBotAmbusherBody',
61103
+ },
61104
+ {
61105
+ id: 'locksmith',
61106
+ difficulty: 'hard',
61107
+ avatar: '🔐',
61108
+ labelKey: 'chessimalsBotLocksmith',
61109
+ descriptionKey: 'chessimalsBotLocksmithBody',
61110
+ },
61111
+ {
61112
+ id: 'storm',
61113
+ difficulty: 'hard',
61114
+ avatar: '🌩️',
61115
+ labelKey: 'chessimalsBotStorm',
61116
+ descriptionKey: 'chessimalsBotStormBody',
61117
+ },
61118
+ {
61119
+ id: 'matriarch',
61120
+ difficulty: 'hard',
61121
+ avatar: '👑',
61122
+ labelKey: 'chessimalsBotMatriarch',
61123
+ descriptionKey: 'chessimalsBotMatriarchBody',
61124
+ },
61125
+ {
61126
+ id: 'endgame',
61127
+ difficulty: 'hard',
61128
+ avatar: '⌛',
61129
+ labelKey: 'chessimalsBotEndgame',
61130
+ descriptionKey: 'chessimalsBotEndgameBody',
61131
+ },
61034
61132
  ];
61035
61133
  const BOT_STYLES = {
61036
- explorer: { advancement: 1.05, capture: 0.82, safety: 0.62, power: 0.8, center: 1.15, unlock: 1.05, reply: 0.7, randomness: 260, spread: 0.68 },
61037
- impulsive: { advancement: 0.9, capture: 1.45, safety: 0.48, power: 1.15, center: 0.8, unlock: 0.9, reply: 0.55, randomness: 290, spread: 0.62 },
61038
- runner: { advancement: 1.55, capture: 0.78, safety: 0.5, power: 0.95, center: 0.7, unlock: 1.1, reply: 0.55, randomness: 250, spread: 0.6 },
61039
- hunter: { advancement: 0.95, capture: 1.45, safety: 0.9, power: 1.05, center: 0.95, unlock: 0.95, reply: 1, randomness: 90, spread: 0.3 },
61040
- guardian: { advancement: 0.88, capture: 1, safety: 1.45, power: 0.85, center: 1.05, unlock: 1, reply: 1.15, randomness: 70, spread: 0.26 },
61041
- jumper: { advancement: 1.12, capture: 1, safety: 0.92, power: 1.42, center: 1.18, unlock: 1.08, reply: 0.95, randomness: 95, spread: 0.32 },
61042
- strategist: { advancement: 1.05, capture: 1.08, safety: 1.22, power: 1.08, center: 1.16, unlock: 1.1, reply: 1.25, randomness: 22, spread: 0.14 },
61043
- predator: { advancement: 0.98, capture: 1.68, safety: 1.02, power: 1.34, center: 1, unlock: 1, reply: 1.12, randomness: 28, spread: 0.16 },
61044
- sprinter: { advancement: 1.72, capture: 0.9, safety: 0.95, power: 1.08, center: 0.86, unlock: 1.18, reply: 1, randomness: 26, spread: 0.15 },
61045
- sentinel: { advancement: 0.9, capture: 1.12, safety: 1.72, power: 0.95, center: 1.28, unlock: 1.05, reply: 1.38, randomness: 18, spread: 0.12 },
61134
+ explorer: { advancement: 1.05, capture: 0.82, safety: 0.62, power: 0.8, center: 1.15, unlock: 1.05, reply: 0.7, randomness: 260, spread: 0.68, mobility: 0.75, trap: 0.5, endgame: 0.55 },
61135
+ impulsive: { advancement: 0.9, capture: 1.45, safety: 0.48, power: 1.15, center: 0.8, unlock: 0.9, reply: 0.55, randomness: 290, spread: 0.62, mobility: 0.85, trap: 0.62, endgame: 0.5 },
61136
+ runner: { advancement: 1.55, capture: 0.78, safety: 0.5, power: 0.95, center: 0.7, unlock: 1.1, reply: 0.55, randomness: 250, spread: 0.6, mobility: 0.72, trap: 0.45, endgame: 1.1 },
61137
+ hunter: { advancement: 0.95, capture: 1.45, safety: 0.9, power: 1.05, center: 0.95, unlock: 0.95, reply: 1, randomness: 90, spread: 0.3, mobility: 0.95, trap: 0.82, endgame: 0.76 },
61138
+ guardian: { advancement: 0.88, capture: 1, safety: 1.45, power: 0.85, center: 1.05, unlock: 1, reply: 1.15, randomness: 70, spread: 0.26, mobility: 0.82, trap: 0.72, endgame: 0.72 },
61139
+ jumper: { advancement: 1.12, capture: 1, safety: 0.92, power: 1.42, center: 1.18, unlock: 1.08, reply: 0.95, randomness: 95, spread: 0.32, mobility: 1.15, trap: 0.9, endgame: 0.82 },
61140
+ strategist: { advancement: 1.05, capture: 1.08, safety: 1.22, power: 1.08, center: 1.16, unlock: 1.1, reply: 1.25, randomness: 22, spread: 0.14, mobility: 1.08, trap: 1.06, endgame: 1 },
61141
+ predator: { advancement: 0.98, capture: 1.68, safety: 1.02, power: 1.34, center: 1, unlock: 1, reply: 1.12, randomness: 28, spread: 0.16, mobility: 1.02, trap: 1.18, endgame: 0.82 },
61142
+ sprinter: { advancement: 1.72, capture: 0.9, safety: 0.95, power: 1.08, center: 0.86, unlock: 1.18, reply: 1, randomness: 26, spread: 0.15, mobility: 0.95, trap: 0.78, endgame: 1.42 },
61143
+ sentinel: { advancement: 0.9, capture: 1.12, safety: 1.72, power: 0.95, center: 1.28, unlock: 1.05, reply: 1.38, randomness: 18, spread: 0.12, mobility: 0.86, trap: 1.04, endgame: 0.84 },
61144
+ oracle: { advancement: 1, capture: 1.12, safety: 1.42, power: 1.1, center: 1.18, unlock: 1.08, reply: 1.8, randomness: 8, spread: 0.08, mobility: 1.06, trap: 1.22, endgame: 1.08 },
61145
+ ambusher: { advancement: 0.9, capture: 1.48, safety: 1.08, power: 1.46, center: 1.05, unlock: 1.02, reply: 1.32, randomness: 14, spread: 0.1, mobility: 1.12, trap: 1.72, endgame: 0.92 },
61146
+ locksmith: { advancement: 0.88, capture: 1.04, safety: 1.55, power: 1.02, center: 1.48, unlock: 1.12, reply: 1.52, randomness: 12, spread: 0.1, mobility: 1.58, trap: 1.24, endgame: 0.86 },
61147
+ storm: { advancement: 1.18, capture: 1.38, safety: 0.98, power: 1.62, center: 1.08, unlock: 1.18, reply: 1.22, randomness: 18, spread: 0.13, mobility: 1.36, trap: 1.28, endgame: 1.02 },
61148
+ matriarch: { advancement: 0.96, capture: 1.18, safety: 1.64, power: 1.18, center: 1.22, unlock: 1.08, reply: 1.66, randomness: 10, spread: 0.08, mobility: 1.02, trap: 1.36, endgame: 1 },
61149
+ endgame: { advancement: 1.46, capture: 1, safety: 1.28, power: 1.04, center: 0.94, unlock: 1.08, reply: 1.44, randomness: 10, spread: 0.09, mobility: 0.98, trap: 1.02, endgame: 1.86 },
61046
61150
  };
61047
61151
  const DEFAULT_BOT_PROFILE_BY_DIFFICULTY = {
61048
61152
  easy: 'explorer',
@@ -61128,8 +61232,17 @@ function chooseChessimalsBotMove(state, difficulty = 'normal', profileId = DEFAU
61128
61232
  if (moves.length === 0)
61129
61233
  return undefined;
61130
61234
  const style = BOT_STYLES[profileId] ?? BOT_STYLES[DEFAULT_BOT_PROFILE_BY_DIFFICULTY[difficulty]];
61131
- const scored = moves
61132
- .map((move) => ({ move, score: scoreBotMoveWithLookahead(state, move, difficulty, style) }))
61235
+ const quickScored = moves
61236
+ .map((move) => ({ move, score: scoreBotMove(state, move, difficulty, style) }))
61237
+ .sort((a, b) => b.score - a.score);
61238
+ const lookaheadLimit = difficulty === 'hard' ? 32 : difficulty === 'normal' ? 24 : 0;
61239
+ const scored = quickScored
61240
+ .map((item, index) => ({
61241
+ move: item.move,
61242
+ score: index < lookaheadLimit
61243
+ ? scoreBotMoveWithLookahead(state, item.move, difficulty, style)
61244
+ : item.score,
61245
+ }))
61133
61246
  .sort((a, b) => b.score - a.score);
61134
61247
  if (difficulty === 'easy') {
61135
61248
  const playable = scored.filter((item) => item.score > -3000);
@@ -61327,7 +61440,7 @@ function getPowerMoves(state, piece, animal) {
61327
61440
  const directions = getPowerDirections(animal);
61328
61441
  const moves = [];
61329
61442
  for (const direction of directions) {
61330
- for (let distance = 1; distance <= 3; distance += 1) {
61443
+ for (let distance = 1; distance < state.boardSize; distance += 1) {
61331
61444
  const target = {
61332
61445
  row: piece.position.row + direction.row * distance,
61333
61446
  col: piece.position.col + direction.col * distance,
@@ -61388,7 +61501,7 @@ function getKangarooMoves(state, piece) {
61388
61501
  }
61389
61502
  return moves;
61390
61503
  }
61391
- function scoreBotMove(state, move, difficulty, style) {
61504
+ function scoreBotMove(state, move, difficulty, style, includeTacticalPressure = true) {
61392
61505
  const color = state.currentTurn;
61393
61506
  const targetPiece = move.capturesPieceId
61394
61507
  ? activePieces(state).find((piece) => piece.id === move.capturesPieceId)
@@ -61414,6 +61527,14 @@ function scoreBotMove(state, move, difficulty, style) {
61414
61527
  score += 14 * style.power;
61415
61528
  if (wouldUnlockPower(state, color, move.to))
61416
61529
  score += 90 * style.unlock;
61530
+ if (includeTacticalPressure && state.boardSize <= 6) {
61531
+ score += countPowerReachAfterMove(state, move, color) * (difficulty === 'hard' ? 8 : 4) * style.mobility;
61532
+ score += countProtectedThreatsAfterMove(state, move, color) * (difficulty === 'hard' ? 36 : 18) * style.trap;
61533
+ score += scoreEndgamePressure(state, move, color) * style.endgame;
61534
+ }
61535
+ else {
61536
+ score += scoreEndgamePressure(state, move, color) * style.endgame;
61537
+ }
61417
61538
  if (difficulty === 'hard' && isSquareVulnerableAfterMove(state, move)) {
61418
61539
  score -= (targetPiece ? 80 : 140) * style.safety;
61419
61540
  }
@@ -61444,7 +61565,7 @@ function scoreBotMoveWithLookahead(state, move, difficulty, style) {
61444
61565
  score += centerControl * (difficulty === 'hard' ? 18 : 10) * style.center;
61445
61566
  }
61446
61567
  const opponentBestReply = opponentMoves
61447
- .map((opponentMove) => scoreBotMove(afterMove, opponentMove, difficulty, style))
61568
+ .map((opponentMove) => scoreBotMove(afterMove, opponentMove, difficulty, style, false))
61448
61569
  .sort((a, b) => b - a)[0];
61449
61570
  if (opponentBestReply) {
61450
61571
  const replyWeight = difficulty === 'easy' ? 0.12 : difficulty === 'normal' ? 0.32 : 0.48;
@@ -61456,6 +61577,34 @@ function scoreBotMoveWithLookahead(state, move, difficulty, style) {
61456
61577
  }
61457
61578
  return score;
61458
61579
  }
61580
+ function countPowerReachAfterMove(state, move, color) {
61581
+ try {
61582
+ const afterMove = applyChessimalsMove(state, move);
61583
+ const evaluationState = { ...afterMove, currentTurn: color };
61584
+ return getChessimalsAllLegalMoves(evaluationState, color).filter((nextMove) => nextMove.kind === 'power').length;
61585
+ }
61586
+ catch {
61587
+ return 0;
61588
+ }
61589
+ }
61590
+ function countProtectedThreatsAfterMove(state, move, color) {
61591
+ try {
61592
+ const afterMove = applyChessimalsMove(state, move);
61593
+ const evaluationState = { ...afterMove, currentTurn: color };
61594
+ const ourMoves = getChessimalsAllLegalMoves(evaluationState, color);
61595
+ const enemyPieces = activePieces(afterMove).filter((piece) => piece.color !== color && !piece.captured);
61596
+ return enemyPieces.filter((piece) => ourMoves.some((nextMove) => nextMove.capturesPieceId === piece.id)).length;
61597
+ }
61598
+ catch {
61599
+ return 0;
61600
+ }
61601
+ }
61602
+ function scoreEndgamePressure(state, move, color) {
61603
+ const remainingEnemyPieces = activePieces(state).filter((piece) => piece.color !== color && !piece.captured).length;
61604
+ const urgency = remainingEnemyPieces <= Math.max(2, Math.floor(state.boardSize / 2)) ? 1.6 : 1;
61605
+ const distanceToPromotion = color === 'white' ? move.to.row : state.boardSize - 1 - move.to.row;
61606
+ return Math.max(0, state.boardSize - distanceToPromotion) * 14 * urgency;
61607
+ }
61459
61608
  function pickNoisyBotMove(scored, spread) {
61460
61609
  if (scored.length === 0)
61461
61610
  return undefined;
@@ -62503,6 +62652,58 @@ const MINI_GAMES_I18N = {
62503
62652
  bubbleDescription: 'Revienta grupos de burbujas, encadena combos y sube tu puntaje.',
62504
62653
  chessimalsTitle: 'Chessimals',
62505
62654
  chessimalsDescription: 'Una carrera de peones con cartas de animales y poderes tácticos.',
62655
+ christianityTitle: 'Christianity',
62656
+ christianityDescription: 'Un juego de cartas familiar con líderes, ofrendas y decisiones tácticas.',
62657
+ christianityEyebrow: 'MVP de mesa',
62658
+ christianityTable: 'Mesa de Christianity',
62659
+ christianityTurn: 'Turno',
62660
+ christianityOfferings: 'Ofrendas',
62661
+ christianityHand: 'Mano',
62662
+ christianityOpponentBattle: 'Zona de batalla rival',
62663
+ christianityYourBattle: 'Tu zona de batalla',
62664
+ christianityOpponentHand: 'Mano rival',
62665
+ christianitySharedZone: 'Zona compartida',
62666
+ christianityMatch: 'Match',
62667
+ christianityMatchScore: 'Marcador de match',
62668
+ christianityHistory: 'Historia',
62669
+ christianityDeck: 'Mazo',
62670
+ christianityPlace: 'Lugar',
62671
+ christianityEmpty: 'Vacío',
62672
+ christianityYourHand: 'Tu mano',
62673
+ christianityCost: 'Coste',
62674
+ christianityOfferingCard: 'Ofrenda',
62675
+ christianityCharacterCard: 'Personaje',
62676
+ christianityLeaderCard: 'Líder',
62677
+ christianityHiddenCard: 'Carta oculta',
62678
+ christianityPreviewCard: 'Ver carta',
62679
+ christianityEndTurn: 'Terminar turno',
62680
+ christianityPlayCard: 'Jugar carta',
62681
+ christianityPlayOffering: 'Jugar ofrenda',
62682
+ christianityPlayHere: 'Jugar aquí',
62683
+ christianityReset: 'Reiniciar mock',
62684
+ christianityWaitTurn: 'Espera el turno rival.',
62685
+ christianityChooseTarget: 'Elige un objetivo para atacar.',
62686
+ christianityChooseCharacterTarget: 'El rival tiene personajes: debes atacarlos antes que al líder.',
62687
+ christianityReadyToPlay: 'Puedes jugar esta carta.',
62688
+ christianityChooseSlot: 'Elige una casilla disponible para jugar esta carta.',
62689
+ christianityPlaceOffering: 'Puedes jugar esta ofrenda con el botón de acción.',
62690
+ christianityNeedOfferings: 'Necesitas más ofrendas para jugar esa carta.',
62691
+ christianityChooseCard: 'Elige una carta o un personaje listo para actuar.',
62692
+ christianityLeaderProtected: 'No puedes atacar directamente al líder mientras tenga personajes en batalla.',
62693
+ christianityLeaderBody: 'Si su vida llega a 0, la partida termina.',
62694
+ christianityOfferingReady: 'Lista',
62695
+ christianityOfferingExhausted: 'Agotada',
62696
+ christianityOfferingBody: 'Se agota para pagar costes y vuelve a estar lista al comenzar tu turno.',
62697
+ christianityOfferingNoAbility: 'Esta ofrenda no tiene habilidad activable.',
62698
+ christianityUseAbility: 'Usar',
62699
+ christianityCloseOfferings: 'Cerrar ofrendas',
62700
+ christianityCharacterBody: 'Entra a batalla y debe esperar un turno para atacar.',
62701
+ christianityCharacterReady: 'Listo para atacar.',
62702
+ christianityCharacterExhausted: 'No puede atacar todavía.',
62703
+ christianityDeckBody: 'La primera carta de esta pila se roba automaticamente al comenzar cada turno.',
62704
+ christianityClosePreview: 'Cerrar previsualizacion de carta',
62705
+ christianityCloseHistory: 'Cerrar historia',
62706
+ christianityHistoryEmpty: 'Todavía no hay cartas en historia.',
62506
62707
  soonTitle: 'Próximamente',
62507
62708
  openGame: 'Jugar',
62508
62709
  close: 'Cerrar',
@@ -62627,10 +62828,10 @@ const MINI_GAMES_I18N = {
62627
62828
  chessimalsRulePowersTitle: 'Cuándo se activan los poderes',
62628
62829
  chessimalsRulePowersBody: 'Tus cartas se desbloquean cuando uno de tus peones cruza la línea central o cuando un peón rival entra en tu mitad del tablero.',
62629
62830
  chessimalsRuleCardsTitle: 'Cartas de animales',
62630
- chessimalsRuleEagle: 'Águila: se mueve hasta 3 casillas en diagonal, hacia adelante o atrás.',
62631
- chessimalsRuleBull: 'Toro: se mueve hasta 3 casillas en línea recta, incluso hacia los lados.',
62831
+ chessimalsRuleEagle: 'Águila: se mueve en diagonal por todo el tablero, hacia adelante o atrás, sin entrar a la última fila.',
62832
+ chessimalsRuleBull: 'Toro: se mueve en línea recta por todo el tablero, incluso hacia los lados, sin entrar a la última fila.',
62632
62833
  chessimalsRuleKangaroo: 'Canguro: salta en L, como el caballo del ajedrez. Puede saltar por encima de piezas y caer libre o capturar una pieza rival.',
62633
- chessimalsRuleLion: 'León: se mueve hasta 3 casillas en cualquier dirección.',
62834
+ chessimalsRuleLion: 'León: se mueve en cualquier dirección por todo el tablero, sin entrar a la última fila.',
62634
62835
  chessimalsRuleLimitsTitle: 'Reglas de equilibrio',
62635
62836
  chessimalsRuleLimitsBody: 'Cada carta se usa una sola vez por partida. Ningún poder puede entrar directamente a la última fila: el paso final para ganar siempre debe ser un avance normal.',
62636
62837
  chessimalsBoardSize: 'Tamaño del tablero',
@@ -62743,6 +62944,18 @@ const MINI_GAMES_I18N = {
62743
62944
  chessimalsBotSprinterBody: 'Optimiza rutas de promoción.',
62744
62945
  chessimalsBotSentinel: 'Centinela',
62745
62946
  chessimalsBotSentinelBody: 'Defiende sólido y castiga errores.',
62947
+ chessimalsBotOracle: 'Oráculo',
62948
+ chessimalsBotOracleBody: 'Lee respuestas y evita trampas profundas.',
62949
+ chessimalsBotAmbusher: 'Emboscador',
62950
+ chessimalsBotAmbusherBody: 'Prepara capturas dobles con poderes largos.',
62951
+ chessimalsBotLocksmith: 'Cerrajero',
62952
+ chessimalsBotLocksmithBody: 'Cierra el centro y reduce tus rutas.',
62953
+ chessimalsBotStorm: 'Tormenta',
62954
+ chessimalsBotStormBody: 'Usa poderes largos para presionar todo el tablero.',
62955
+ chessimalsBotMatriarch: 'Matriarca',
62956
+ chessimalsBotMatriarchBody: 'Protege su estructura y gana por desgaste.',
62957
+ chessimalsBotEndgame: 'Finalista',
62958
+ chessimalsBotEndgameBody: 'Convierte ventajas pequeñas en promoción.',
62746
62959
  chessimalsBotExplorerTendency: 'Tiende a variar rutas, probar el centro y cometer errores suaves.',
62747
62960
  chessimalsBotImpulsiveTendency: 'Tiende a capturar rápido, incluso cuando puede quedar expuesto.',
62748
62961
  chessimalsBotRunnerTendency: 'Tiende a avanzar hacia la promoción antes que defender.',
@@ -62753,6 +62966,12 @@ const MINI_GAMES_I18N = {
62753
62966
  chessimalsBotPredatorTendency: 'Tiende a forzar capturas y usar poderes agresivos.',
62754
62967
  chessimalsBotSprinterTendency: 'Tiende a encontrar caminos rápidos de promoción.',
62755
62968
  chessimalsBotSentinelTendency: 'Tiende a defender sólido y castigar errores.',
62969
+ chessimalsBotOracleTendency: 'Tiende a anticipar respuestas y elegir jugadas difíciles de refutar.',
62970
+ chessimalsBotAmbusherTendency: 'Tiende a dejar piezas bajo amenaza múltiple antes de capturar.',
62971
+ chessimalsBotLocksmithTendency: 'Tiende a cortar rutas por el centro y dejarte sin buenas casillas.',
62972
+ chessimalsBotStormTendency: 'Tiende a convertir poderes largos en presión desde varios ángulos.',
62973
+ chessimalsBotMatriarchTendency: 'Tiende a conservar piezas y cambiar solo cuando queda mejor.',
62974
+ chessimalsBotEndgameTendency: 'Tiende a simplificar y correr hacia la promoción cuando ve ventaja.',
62756
62975
  chessimalsBotReportTitle: 'Reporte del bot',
62757
62976
  chessimalsBotReportVs: 'Contra {bot}',
62758
62977
  chessimalsBotReportBody: '{outcome}. Hizo {captures} capturas y usó {powers} poderes. {style}',
@@ -62840,7 +63059,7 @@ const MINI_GAMES_I18N = {
62840
63059
  chessimalsTutorialStep4Title: 'Devuelve el turno',
62841
63060
  chessimalsTutorialStep4Body: 'Mueve el peón negro de la columna F una casilla hacia abajo para continuar.',
62842
63061
  chessimalsTutorialStep5Title: 'Usa el poder Canguro',
62843
- chessimalsTutorialStep5Body: 'Selecciona la carta Canguro y salta en L para capturar el peón negro.',
63062
+ chessimalsTutorialStep5Body: 'Selecciona la carta Canguro y salta en L para capturar el peón negro. Las otras cartas pueden cruzar todo el tablero, pero ningún poder puede entrar a la última fila.',
62844
63063
  chessimalsTutorialStep6Title: 'Prepara la llegada',
62845
63064
  chessimalsTutorialStep6Body: 'Mueve el último peón negro hacia abajo. Después tendrás camino para ganar.',
62846
63065
  chessimalsTutorialStep7Title: 'Llega a la última fila',
@@ -62904,6 +63123,58 @@ const MINI_GAMES_I18N = {
62904
63123
  bubbleDescription: 'Pop bubble groups, chain combos, and push your score higher.',
62905
63124
  chessimalsTitle: 'Chessimals',
62906
63125
  chessimalsDescription: 'A pawn race with animal cards and tactical powers.',
63126
+ christianityTitle: 'Christianity',
63127
+ christianityDescription: 'A family card game with leaders, offerings, and tactical choices.',
63128
+ christianityEyebrow: 'Table MVP',
63129
+ christianityTable: 'Christianity table',
63130
+ christianityTurn: 'Turn',
63131
+ christianityOfferings: 'Offerings',
63132
+ christianityHand: 'Hand',
63133
+ christianityOpponentBattle: 'Opponent battle zone',
63134
+ christianityYourBattle: 'Your battle zone',
63135
+ christianityOpponentHand: 'Opponent hand',
63136
+ christianitySharedZone: 'Shared zone',
63137
+ christianityMatch: 'Match',
63138
+ christianityMatchScore: 'Match score',
63139
+ christianityHistory: 'History',
63140
+ christianityDeck: 'Deck',
63141
+ christianityPlace: 'Place',
63142
+ christianityEmpty: 'Empty',
63143
+ christianityYourHand: 'Your hand',
63144
+ christianityCost: 'Cost',
63145
+ christianityOfferingCard: 'Offering',
63146
+ christianityCharacterCard: 'Character',
63147
+ christianityLeaderCard: 'Leader',
63148
+ christianityHiddenCard: 'Hidden card',
63149
+ christianityPreviewCard: 'Preview card',
63150
+ christianityEndTurn: 'End turn',
63151
+ christianityPlayCard: 'Play card',
63152
+ christianityPlayOffering: 'Play offering',
63153
+ christianityPlayHere: 'Play here',
63154
+ christianityReset: 'Reset mock',
63155
+ christianityWaitTurn: 'Wait for the opponent turn.',
63156
+ christianityChooseTarget: 'Choose a target to attack.',
63157
+ christianityChooseCharacterTarget: 'The opponent has characters: attack them before the leader.',
63158
+ christianityReadyToPlay: 'You can play this card.',
63159
+ christianityChooseSlot: 'Choose an available slot to play this card.',
63160
+ christianityPlaceOffering: 'You can play this offering with the action button.',
63161
+ christianityNeedOfferings: 'You need more offerings to play that card.',
63162
+ christianityChooseCard: 'Choose a card or a ready character.',
63163
+ christianityLeaderProtected: 'You cannot attack the leader directly while they have characters in battle.',
63164
+ christianityLeaderBody: 'If this leader reaches 0 life, the game ends.',
63165
+ christianityOfferingReady: 'Ready',
63166
+ christianityOfferingExhausted: 'Exhausted',
63167
+ christianityOfferingBody: 'Exhaust it to pay costs. It readies again at the start of your turn.',
63168
+ christianityOfferingNoAbility: 'This offering has no active ability.',
63169
+ christianityUseAbility: 'Use',
63170
+ christianityCloseOfferings: 'Close offerings',
63171
+ christianityCharacterBody: 'Enters battle and must wait one turn before attacking.',
63172
+ christianityCharacterReady: 'Ready to attack.',
63173
+ christianityCharacterExhausted: 'Cannot attack yet.',
63174
+ christianityDeckBody: 'The top card in this pile is drawn automatically at the start of each turn.',
63175
+ christianityClosePreview: 'Close card preview',
63176
+ christianityCloseHistory: 'Close history',
63177
+ christianityHistoryEmpty: 'There are no cards in history yet.',
62907
63178
  soonTitle: 'Coming soon',
62908
63179
  openGame: 'Play',
62909
63180
  close: 'Close',
@@ -63028,10 +63299,10 @@ const MINI_GAMES_I18N = {
63028
63299
  chessimalsRulePowersTitle: 'When powers unlock',
63029
63300
  chessimalsRulePowersBody: 'Your cards unlock when one of your pawns crosses the center line, or when a rival pawn enters your half of the board.',
63030
63301
  chessimalsRuleCardsTitle: 'Animal cards',
63031
- chessimalsRuleEagle: 'Eagle: moves up to 3 squares diagonally, forward or backward.',
63032
- chessimalsRuleBull: 'Bull: moves up to 3 squares in a straight line, including sideways.',
63302
+ chessimalsRuleEagle: 'Eagle: moves diagonally across the whole board, forward or backward, without entering the final row.',
63303
+ chessimalsRuleBull: 'Bull: moves in a straight line across the whole board, including sideways, without entering the final row.',
63033
63304
  chessimalsRuleKangaroo: 'Kangaroo: jumps in an L shape, like a chess knight. It can jump over pieces and land on an empty square or capture a rival piece.',
63034
- chessimalsRuleLion: 'Lion: moves up to 3 squares in any direction.',
63305
+ chessimalsRuleLion: 'Lion: moves in any direction across the whole board, without entering the final row.',
63035
63306
  chessimalsRuleLimitsTitle: 'Balance rules',
63036
63307
  chessimalsRuleLimitsBody: 'Each card can be used once per game. No power can land directly on the final row: the winning step must always be a normal forward move.',
63037
63308
  chessimalsBoardSize: 'Board size',
@@ -63144,6 +63415,18 @@ const MINI_GAMES_I18N = {
63144
63415
  chessimalsBotSprinterBody: 'Optimizes promotion routes.',
63145
63416
  chessimalsBotSentinel: 'Sentinel',
63146
63417
  chessimalsBotSentinelBody: 'Defends solidly and punishes mistakes.',
63418
+ chessimalsBotOracle: 'Oracle',
63419
+ chessimalsBotOracleBody: 'Reads replies and avoids deep traps.',
63420
+ chessimalsBotAmbusher: 'Ambusher',
63421
+ chessimalsBotAmbusherBody: 'Sets up double captures with long powers.',
63422
+ chessimalsBotLocksmith: 'Locksmith',
63423
+ chessimalsBotLocksmithBody: 'Closes the center and reduces your routes.',
63424
+ chessimalsBotStorm: 'Storm',
63425
+ chessimalsBotStormBody: 'Uses long powers to pressure the whole board.',
63426
+ chessimalsBotMatriarch: 'Matriarch',
63427
+ chessimalsBotMatriarchBody: 'Protects structure and wins by attrition.',
63428
+ chessimalsBotEndgame: 'Endgame',
63429
+ chessimalsBotEndgameBody: 'Turns small edges into promotion.',
63147
63430
  chessimalsBotExplorerTendency: 'Tends to vary routes, test the center, and make soft mistakes.',
63148
63431
  chessimalsBotImpulsiveTendency: 'Tends to capture quickly, even when it can become exposed.',
63149
63432
  chessimalsBotRunnerTendency: 'Tends to push toward promotion before defending.',
@@ -63154,6 +63437,12 @@ const MINI_GAMES_I18N = {
63154
63437
  chessimalsBotPredatorTendency: 'Tends to force captures and use aggressive powers.',
63155
63438
  chessimalsBotSprinterTendency: 'Tends to find fast promotion paths.',
63156
63439
  chessimalsBotSentinelTendency: 'Tends to defend solidly and punish mistakes.',
63440
+ chessimalsBotOracleTendency: 'Tends to anticipate replies and choose hard-to-refute moves.',
63441
+ chessimalsBotAmbusherTendency: 'Tends to leave pieces under multiple threats before capturing.',
63442
+ chessimalsBotLocksmithTendency: 'Tends to close central routes and leave you without good squares.',
63443
+ chessimalsBotStormTendency: 'Tends to turn long powers into pressure from several angles.',
63444
+ chessimalsBotMatriarchTendency: 'Tends to preserve pieces and trade only when it improves.',
63445
+ chessimalsBotEndgameTendency: 'Tends to simplify and race toward promotion when ahead.',
63157
63446
  chessimalsBotReportTitle: 'Bot report',
63158
63447
  chessimalsBotReportVs: 'Against {bot}',
63159
63448
  chessimalsBotReportBody: '{outcome}. It made {captures} captures and used {powers} powers. {style}',
@@ -63241,7 +63530,7 @@ const MINI_GAMES_I18N = {
63241
63530
  chessimalsTutorialStep4Title: 'Return the turn',
63242
63531
  chessimalsTutorialStep4Body: 'Move the black pawn on file F one square downward to continue.',
63243
63532
  chessimalsTutorialStep5Title: 'Use the Kangaroo power',
63244
- chessimalsTutorialStep5Body: 'Select the Kangaroo card and jump in an L shape to capture the black pawn.',
63533
+ chessimalsTutorialStep5Body: 'Select the Kangaroo card and jump in an L shape to capture the black pawn. The other cards can cross the whole board, but no power can enter the final row.',
63245
63534
  chessimalsTutorialStep6Title: 'Prepare the finish',
63246
63535
  chessimalsTutorialStep6Body: 'Move the last black pawn downward. Then your path to win is open.',
63247
63536
  chessimalsTutorialStep7Title: 'Reach the last row',
@@ -64423,6 +64712,7 @@ class ChessimalsGameComponent {
64423
64712
  });
64424
64713
  this.botThinking = signal(false);
64425
64714
  this.confirmAction = signal(undefined);
64715
+ this.confirmedAction = signal(undefined);
64426
64716
  this.onlineJoinCode = signal('');
64427
64717
  this.onlineLoading = signal(false);
64428
64718
  this.onlineAction = signal(undefined);
@@ -65367,13 +65657,12 @@ class ChessimalsGameComponent {
65367
65657
  closeConfirmModal() {
65368
65658
  this.confirmAction.set(undefined);
65369
65659
  }
65370
- confirmPendingAction(token) {
65371
- if (token !== 'confirm') {
65372
- this.closeConfirmModal();
65373
- return;
65374
- }
65375
- const action = this.confirmAction();
65660
+ handleConfirmModalDismissed() {
65376
65661
  this.confirmAction.set(undefined);
65662
+ const action = this.confirmedAction();
65663
+ this.confirmedAction.set(undefined);
65664
+ if (!action)
65665
+ return;
65377
65666
  if (action === 'restart') {
65378
65667
  this.restartGame();
65379
65668
  return;
@@ -65390,6 +65679,15 @@ class ChessimalsGameComponent {
65390
65679
  this.resignGame();
65391
65680
  }
65392
65681
  }
65682
+ confirmPendingAction(token) {
65683
+ if (token !== 'confirm') {
65684
+ this.closeConfirmModal();
65685
+ return;
65686
+ }
65687
+ const action = this.confirmAction();
65688
+ this.confirmedAction.set(action);
65689
+ this.confirmAction.set(undefined);
65690
+ }
65393
65691
  resignGame() {
65394
65692
  const game = this.game();
65395
65693
  if (game.status === 'finished')
@@ -67460,7 +67758,7 @@ class ChessimalsGameComponent {
67460
67758
  <ion-modal
67461
67759
  [isOpen]="!!confirmAction()"
67462
67760
  cssClass="val-modal-adaptive"
67463
- (didDismiss)="closeConfirmModal()"
67761
+ (didDismiss)="handleConfirmModalDismissed()"
67464
67762
  >
67465
67763
  <ng-template>
67466
67764
  <val-modal-layout
@@ -68414,7 +68712,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
68414
68712
  <ion-modal
68415
68713
  [isOpen]="!!confirmAction()"
68416
68714
  cssClass="val-modal-adaptive"
68417
- (didDismiss)="closeConfirmModal()"
68715
+ (didDismiss)="handleConfirmModalDismissed()"
68418
68716
  >
68419
68717
  <ng-template>
68420
68718
  <val-modal-layout
@@ -68440,6 +68738,1531 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
68440
68738
  type: Input
68441
68739
  }] } });
68442
68740
 
68741
+ const STARTER_CARDS = {
68742
+ o_simple: {
68743
+ id: 'o_simple',
68744
+ name: 'Ofrenda simple',
68745
+ type: 'offering',
68746
+ cost: 0,
68747
+ attack: 0,
68748
+ life: 1,
68749
+ verseText: 'Una ofrenda sencilla queda lista para sostener tus siguientes jugadas.',
68750
+ scripture: 'Genesis 4:4',
68751
+ edition: 'GEN',
68752
+ collectorNumber: '001/020',
68753
+ year: '2026',
68754
+ author: 'MVP',
68755
+ rarity: 'normal',
68756
+ },
68757
+ o_forbidden: {
68758
+ id: 'o_forbidden',
68759
+ name: 'El fruto prohibido',
68760
+ type: 'offering',
68761
+ cost: 0,
68762
+ attack: 0,
68763
+ life: 2,
68764
+ abilityName: 'Conocimiento del bien y del mal',
68765
+ abilityText: 'Al usarla, disminuye en 1 los puntos de vida de tu Líder.',
68766
+ abilityCost: 0,
68767
+ verseText: 'Dios el Señor puso al hombre en el jardín de Edén para que lo labrara y lo cuidara.',
68768
+ scripture: 'Genesis 2:17 NBV',
68769
+ edition: 'GEN',
68770
+ collectorNumber: '012/180',
68771
+ year: '2026',
68772
+ author: 'MVP',
68773
+ rarity: 'uncommon',
68774
+ },
68775
+ p_scout: {
68776
+ id: 'p_scout',
68777
+ name: 'Scout',
68778
+ type: 'character',
68779
+ cost: 1,
68780
+ attack: 1,
68781
+ life: 1,
68782
+ verseText: 'Un explorador humilde abre camino antes de que llegue la batalla.',
68783
+ scripture: 'Genesis 13:17',
68784
+ edition: 'GEN',
68785
+ collectorNumber: '002/020',
68786
+ year: '2026',
68787
+ author: 'MVP',
68788
+ rarity: 'normal',
68789
+ },
68790
+ p_guard: { id: 'p_guard', name: 'Guard', type: 'character', cost: 2, attack: 1, life: 3, edition: 'GEN', collectorNumber: '003/020', year: '2026', author: 'MVP', rarity: 'normal' },
68791
+ p_warrior: { id: 'p_warrior', name: 'Warrior', type: 'character', cost: 2, attack: 2, life: 2, edition: 'GEN', collectorNumber: '004/020', year: '2026', author: 'MVP', rarity: 'normal' },
68792
+ p_elder: { id: 'p_elder', name: 'Elder', type: 'character', cost: 3, attack: 2, life: 4, edition: 'GEN', collectorNumber: '005/020', year: '2026', author: 'MVP', rarity: 'uncommon' },
68793
+ p_champion: { id: 'p_champion', name: 'Champion', type: 'character', cost: 4, attack: 4, life: 4, edition: 'GEN', collectorNumber: '006/020', year: '2026', author: 'MVP', rarity: 'rare' },
68794
+ };
68795
+ const STARTING_SHARED_DECK = [
68796
+ 'o_simple',
68797
+ 'p_scout',
68798
+ 'o_forbidden',
68799
+ 'o_simple',
68800
+ 'p_guard',
68801
+ 'p_warrior',
68802
+ 'o_simple',
68803
+ 'p_elder',
68804
+ 'p_scout',
68805
+ 'o_simple',
68806
+ 'p_champion',
68807
+ 'p_guard',
68808
+ 'o_simple',
68809
+ 'p_warrior',
68810
+ 'p_scout',
68811
+ 'o_simple',
68812
+ 'p_elder',
68813
+ 'p_guard',
68814
+ 'o_simple',
68815
+ ];
68816
+ const STARTING_GAME = {
68817
+ gameId: 'mock-christianity',
68818
+ status: 'in_progress',
68819
+ mode: 'local_pass',
68820
+ turnOwner: 'P1',
68821
+ revision: 0,
68822
+ turnCount: 1,
68823
+ matchScore: { P1: 1, P2: 0 },
68824
+ sharedDeck: STARTING_SHARED_DECK,
68825
+ historyZone: [],
68826
+ players: {
68827
+ P1: {
68828
+ seat: 'P1',
68829
+ displayName: 'Jugador',
68830
+ avatar: 'J',
68831
+ avatarColor: '#2563eb',
68832
+ leaderName: 'Adam',
68833
+ leaderHp: 15,
68834
+ leaderMaxHp: 15,
68835
+ offerings: [
68836
+ { instanceId: 'p1_offering_001', cardId: 'o_simple', name: 'Ofrenda simple', owner: 'P1', ready: true, value: 1 },
68837
+ {
68838
+ instanceId: 'p1_offering_002',
68839
+ cardId: 'o_forbidden',
68840
+ name: 'El fruto prohibido',
68841
+ owner: 'P1',
68842
+ ready: true,
68843
+ value: 2,
68844
+ abilityName: 'Conocimiento del bien y del mal',
68845
+ abilityText: 'Al usarla, disminuye en 1 los puntos de vida de tu Lider.',
68846
+ abilityCost: 0,
68847
+ },
68848
+ ],
68849
+ offeringPlayedThisTurn: false,
68850
+ hand: ['o_simple', 'p_scout', 'p_warrior', 'p_guard'],
68851
+ battleZone: [],
68852
+ },
68853
+ P2: {
68854
+ seat: 'P2',
68855
+ displayName: 'Rival',
68856
+ avatar: 'R',
68857
+ avatarColor: '#b45309',
68858
+ leaderName: 'Noah',
68859
+ leaderHp: 15,
68860
+ leaderMaxHp: 15,
68861
+ offerings: [{ instanceId: 'p2_offering_001', cardId: 'o_simple', name: 'Ofrenda simple', owner: 'P2', ready: true, value: 1 }],
68862
+ offeringPlayedThisTurn: false,
68863
+ handCount: 4,
68864
+ battleZone: [
68865
+ {
68866
+ instanceId: 'opp_001',
68867
+ cardId: 'p_scout',
68868
+ name: 'Scout',
68869
+ owner: 'P2',
68870
+ controller: 'P2',
68871
+ attack: 1,
68872
+ currentHp: 1,
68873
+ maxHp: 1,
68874
+ canAttack: false,
68875
+ },
68876
+ ],
68877
+ },
68878
+ },
68879
+ log: ['Partida iniciada.'],
68880
+ };
68881
+ class ChristianityGameComponent {
68882
+ constructor() {
68883
+ this.i18n = inject(I18nService);
68884
+ this.game = signal(structuredClone(STARTING_GAME));
68885
+ this.selectedHandCard = signal(null);
68886
+ this.selectedAttacker = signal(null);
68887
+ this.selectedPreview = signal(null);
68888
+ this.previewTilt = signal({ rotateX: 5, rotateY: -5, shiftX: 0, shiftY: 0 });
68889
+ this.hoveredHandIndex = signal(null);
68890
+ this.draggingCardId = signal(null);
68891
+ this.showHistory = signal(false);
68892
+ this.offeringsSeat = signal(null);
68893
+ this.canDropOnBattleSlot = (drag) => {
68894
+ const card = this.cardDefinition(drag.data);
68895
+ return card.type === 'character' && this.canPlay(card);
68896
+ };
68897
+ this.canDropOnOfferings = (drag) => {
68898
+ const card = this.cardDefinition(drag.data);
68899
+ return card.type === 'offering' && this.canPlay(card);
68900
+ };
68901
+ this.player = computed(() => this.game().players.P1);
68902
+ this.opponent = computed(() => this.game().players.P2);
68903
+ this.currentPlayer = computed(() => this.game().players[this.game().turnOwner]);
68904
+ this.isOwnTurn = computed(() => this.game().turnOwner === 'P1');
68905
+ this.hasOpponentGuards = computed(() => this.opponent().battleZone.length > 0);
68906
+ this.opponentHandCount = computed(() => this.opponent().handCount ?? this.opponent().hand?.length ?? 0);
68907
+ this.selectedCardDefinition = computed(() => {
68908
+ const selected = this.selectedHandCard();
68909
+ return selected ? this.cardDefinition(selected) : null;
68910
+ });
68911
+ this.selectedPreviewCard = computed(() => {
68912
+ const cardId = this.selectedPreview()?.cardId;
68913
+ return cardId ? this.cardDefinition(cardId) : null;
68914
+ });
68915
+ this.statusText = computed(() => {
68916
+ const attacker = this.selectedAttacker();
68917
+ const handCard = this.selectedCardDefinition();
68918
+ if (!this.isOwnTurn()) {
68919
+ return this.t('christianityWaitTurn');
68920
+ }
68921
+ if (attacker) {
68922
+ return this.hasOpponentGuards() ? this.t('christianityChooseCharacterTarget') : this.t('christianityChooseTarget');
68923
+ }
68924
+ if (handCard) {
68925
+ if (!this.canPlay(handCard)) {
68926
+ return this.t('christianityNeedOfferings');
68927
+ }
68928
+ return handCard.type === 'offering' ? this.t('christianityPlaceOffering') : this.t('christianityChooseSlot');
68929
+ }
68930
+ return this.t('christianityChooseCard');
68931
+ });
68932
+ this.i18n.registerDefaults('MiniGames', MINI_GAMES_I18N);
68933
+ }
68934
+ t(key) {
68935
+ this.i18n.lang();
68936
+ return this.i18n.t(key, 'MiniGames');
68937
+ }
68938
+ cardDefinition(cardId) {
68939
+ return STARTER_CARDS[cardId] ?? STARTER_CARDS['p_scout'];
68940
+ }
68941
+ cardTypeLabel(card) {
68942
+ return card.type === 'offering' ? this.t('christianityOfferingCard') : this.t('christianityCharacterCard');
68943
+ }
68944
+ battleSlots(seat) {
68945
+ const cards = this.game().players[seat].battleZone;
68946
+ return Array.from({ length: 4 }, (_, index) => ({
68947
+ trackId: cards[index]?.instanceId ?? `${seat}-empty-${index}`,
68948
+ card: cards[index],
68949
+ }));
68950
+ }
68951
+ battleSlotDropId(index) {
68952
+ return `christianity-battle-slot-${index}`;
68953
+ }
68954
+ dropTargetIds() {
68955
+ return ['christianity-offerings-drop', ...this.battleSlots('P1').map((_, index) => this.battleSlotDropId(index))];
68956
+ }
68957
+ hiddenHandCards(count) {
68958
+ return Array.from({ length: count });
68959
+ }
68960
+ fanTransform(index, total, opponent) {
68961
+ if (total <= 1)
68962
+ return 'none';
68963
+ const center = (total - 1) / 2;
68964
+ const offset = index - center;
68965
+ const rotate = offset * (opponent ? 8 : 5);
68966
+ const lift = Math.abs(offset) * 0.25;
68967
+ const hoverLift = opponent ? 0 : this.handWaveLift(index);
68968
+ const scale = opponent ? 1 : this.handWaveScale(index);
68969
+ const fanLift = opponent ? Math.abs(offset) * 0.34 : lift + hoverLift;
68970
+ const fanSpread = opponent ? offset * 0.08 : 0;
68971
+ return `translate(${fanSpread}rem, ${fanLift}rem) rotate(${rotate}deg) scale(${scale})`;
68972
+ }
68973
+ handCardZIndex(index) {
68974
+ const hovered = this.hoveredHandIndex();
68975
+ if (hovered === null)
68976
+ return 2;
68977
+ const distance = Math.abs(index - hovered);
68978
+ return Math.max(2, 8 - distance);
68979
+ }
68980
+ setHoveredHandIndex(index) {
68981
+ this.hoveredHandIndex.set(index);
68982
+ }
68983
+ clearHoveredHandIndex() {
68984
+ this.hoveredHandIndex.set(null);
68985
+ }
68986
+ releaseHoveredHand(event) {
68987
+ if (event.pointerType !== 'mouse') {
68988
+ window.setTimeout(() => this.clearHoveredHandIndex(), 180);
68989
+ }
68990
+ }
68991
+ handWaveLift(index) {
68992
+ const hovered = this.hoveredHandIndex();
68993
+ if (hovered === null)
68994
+ return 0;
68995
+ const distance = Math.abs(index - hovered);
68996
+ if (distance === 0)
68997
+ return -1.15;
68998
+ if (distance === 1)
68999
+ return -0.58;
69000
+ if (distance === 2)
69001
+ return -0.22;
69002
+ return 0;
69003
+ }
69004
+ handWaveScale(index) {
69005
+ const hovered = this.hoveredHandIndex();
69006
+ if (hovered === null)
69007
+ return 1;
69008
+ const distance = Math.abs(index - hovered);
69009
+ if (distance === 0)
69010
+ return 1.06;
69011
+ if (distance === 1)
69012
+ return 1.03;
69013
+ return 1;
69014
+ }
69015
+ readyOfferings(player) {
69016
+ return player.offerings.reduce((total, offering) => total + (offering.ready ? offering.value : 0), 0);
69017
+ }
69018
+ totalOfferings(player) {
69019
+ return player.offerings.reduce((total, offering) => total + offering.value, 0);
69020
+ }
69021
+ canPlay(card) {
69022
+ if (!this.isOwnTurn())
69023
+ return false;
69024
+ if (card.type === 'offering')
69025
+ return !this.player().offeringPlayedThisTurn;
69026
+ return this.readyOfferings(this.player()) >= card.cost && this.player().battleZone.length < 4;
69027
+ }
69028
+ canPlaySelected() {
69029
+ const selected = this.selectedHandCard();
69030
+ return !!selected && this.canPlay(this.cardDefinition(selected));
69031
+ }
69032
+ selectedActionLabel() {
69033
+ const selected = this.selectedCardDefinition();
69034
+ if (!selected)
69035
+ return this.t('christianityPlayCard');
69036
+ return selected.type === 'offering' ? this.t('christianityPlayOffering') : this.t('christianityPlayCard');
69037
+ }
69038
+ selectedActionDisabled() {
69039
+ const selected = this.selectedCardDefinition();
69040
+ if (!selected || !this.canPlay(selected))
69041
+ return true;
69042
+ return selected.type === 'character';
69043
+ }
69044
+ previewActionDisabled() {
69045
+ const preview = this.selectedPreview();
69046
+ if (preview?.source !== 'hand' || !preview.cardId)
69047
+ return true;
69048
+ return !this.canPlay(this.cardDefinition(preview.cardId));
69049
+ }
69050
+ canPlaceSelectedCharacter() {
69051
+ const selected = this.selectedCardDefinition();
69052
+ return !!selected && selected.type === 'character' && this.canPlay(selected);
69053
+ }
69054
+ canPlaceSelectedOffering() {
69055
+ const selected = this.selectedCardDefinition();
69056
+ return !!selected && selected.type === 'offering' && this.canPlay(selected);
69057
+ }
69058
+ isDraggingCharacter() {
69059
+ const cardId = this.draggingCardId();
69060
+ if (!cardId)
69061
+ return false;
69062
+ const card = this.cardDefinition(cardId);
69063
+ return card.type === 'character' && this.canPlay(card);
69064
+ }
69065
+ isDraggingOffering() {
69066
+ const cardId = this.draggingCardId();
69067
+ if (!cardId)
69068
+ return false;
69069
+ const card = this.cardDefinition(cardId);
69070
+ return card.type === 'offering' && this.canPlay(card);
69071
+ }
69072
+ startDraggingCard(cardId) {
69073
+ this.selectedAttacker.set(null);
69074
+ this.selectedHandCard.set(cardId);
69075
+ this.draggingCardId.set(cardId);
69076
+ this.closePreview();
69077
+ }
69078
+ endDraggingCard() {
69079
+ this.draggingCardId.set(null);
69080
+ }
69081
+ dropOnBattleSlot(event, slotIndex) {
69082
+ const card = this.cardDefinition(event.item.data);
69083
+ if (card.type !== 'character')
69084
+ return;
69085
+ this.playCardFromHand(event.item.data, slotIndex);
69086
+ }
69087
+ dropOnOfferings(event) {
69088
+ const card = this.cardDefinition(event.item.data);
69089
+ if (card.type !== 'offering')
69090
+ return;
69091
+ this.playCardFromHand(event.item.data);
69092
+ }
69093
+ selectHandCard(cardId) {
69094
+ const wasSelected = this.selectedHandCard() === cardId;
69095
+ this.selectedAttacker.set(null);
69096
+ this.selectedHandCard.set(wasSelected ? null : cardId);
69097
+ this.closePreview();
69098
+ }
69099
+ playSelectedCard(slotIndex) {
69100
+ const cardId = this.selectedHandCard();
69101
+ if (!cardId)
69102
+ return;
69103
+ this.playCardFromHand(cardId, slotIndex);
69104
+ }
69105
+ playCardFromHand(cardId, slotIndex) {
69106
+ const card = this.cardDefinition(cardId);
69107
+ if (!this.canPlay(card))
69108
+ return;
69109
+ this.game.update(game => {
69110
+ const next = structuredClone(game);
69111
+ const player = next.players.P1;
69112
+ const handIndex = player.hand?.indexOf(cardId) ?? -1;
69113
+ if (handIndex < 0 || !player.hand)
69114
+ return game;
69115
+ player.hand.splice(handIndex, 1);
69116
+ if (card.type === 'offering') {
69117
+ player.offerings.push({
69118
+ instanceId: `p1_offering_${next.revision + 1}`,
69119
+ cardId: card.id,
69120
+ name: card.name,
69121
+ owner: 'P1',
69122
+ ready: true,
69123
+ value: card.life,
69124
+ abilityName: card.abilityName,
69125
+ abilityText: card.abilityText,
69126
+ abilityCost: card.abilityCost,
69127
+ });
69128
+ player.offeringPlayedThisTurn = true;
69129
+ }
69130
+ else {
69131
+ this.spendOfferings(player, card.cost);
69132
+ const insertIndex = Math.min(slotIndex ?? player.battleZone.length, player.battleZone.length);
69133
+ player.battleZone.splice(insertIndex, 0, {
69134
+ instanceId: `p1_${next.revision + 1}_${player.battleZone.length}`,
69135
+ cardId: card.id,
69136
+ name: card.name,
69137
+ owner: 'P1',
69138
+ controller: 'P1',
69139
+ attack: card.attack,
69140
+ currentHp: card.life,
69141
+ maxHp: card.life,
69142
+ canAttack: false,
69143
+ });
69144
+ }
69145
+ next.revision++;
69146
+ next.log = [
69147
+ card.type === 'offering' ? `${card.name} queda lista como ofrenda.` : `${card.name} entra en batalla.`,
69148
+ ...next.log,
69149
+ ].slice(0, 4);
69150
+ return next;
69151
+ });
69152
+ this.selectedHandCard.set(null);
69153
+ this.draggingCardId.set(null);
69154
+ this.closePreview();
69155
+ }
69156
+ playPreviewCard() {
69157
+ const preview = this.selectedPreview();
69158
+ if (preview?.source !== 'hand' || !preview.cardId)
69159
+ return;
69160
+ const card = this.cardDefinition(preview.cardId);
69161
+ if (!this.canPlay(card))
69162
+ return;
69163
+ this.selectedHandCard.set(preview.cardId);
69164
+ if (card.type === 'character') {
69165
+ this.closePreview();
69166
+ return;
69167
+ }
69168
+ this.playSelectedCard();
69169
+ }
69170
+ handleOfferingPile(seat) {
69171
+ this.openOfferings(seat);
69172
+ }
69173
+ selectAttacker(card) {
69174
+ this.selectedHandCard.set(null);
69175
+ this.inspectCharacter(card);
69176
+ if (!this.isOwnTurn() || !card.canAttack)
69177
+ return;
69178
+ this.selectedAttacker.set(this.selectedAttacker()?.instanceId === card.instanceId ? null : card);
69179
+ }
69180
+ handleOpponentCharacter(card) {
69181
+ this.inspectCharacter(card);
69182
+ if (this.selectedAttacker()) {
69183
+ this.attackCharacter(card);
69184
+ }
69185
+ }
69186
+ handleOpponentLeader() {
69187
+ this.inspectLeader('P2');
69188
+ if (this.selectedAttacker() && !this.hasOpponentGuards()) {
69189
+ this.attackLeader();
69190
+ }
69191
+ }
69192
+ attackLeader() {
69193
+ const attacker = this.selectedAttacker();
69194
+ if (!attacker)
69195
+ return;
69196
+ if (this.hasOpponentGuards()) {
69197
+ this.selectedPreview.set({
69198
+ title: this.opponent().leaderName,
69199
+ eyebrow: this.t('christianityLeaderCard'),
69200
+ meta: `${this.opponent().leaderHp}/${this.opponent().leaderMaxHp}`,
69201
+ body: this.t('christianityLeaderProtected'),
69202
+ });
69203
+ return;
69204
+ }
69205
+ this.game.update(game => {
69206
+ const next = structuredClone(game);
69207
+ const liveAttacker = next.players.P1.battleZone.find(card => card.instanceId === attacker.instanceId);
69208
+ if (!liveAttacker || !liveAttacker.canAttack)
69209
+ return game;
69210
+ next.players.P2.leaderHp = Math.max(0, next.players.P2.leaderHp - liveAttacker.attack);
69211
+ liveAttacker.canAttack = false;
69212
+ next.revision++;
69213
+ next.log = [`${liveAttacker.name} ataca al lider rival.`, ...next.log].slice(0, 4);
69214
+ return next;
69215
+ });
69216
+ this.selectedAttacker.set(null);
69217
+ }
69218
+ attackCharacter(target) {
69219
+ const attacker = this.selectedAttacker();
69220
+ if (!attacker)
69221
+ return;
69222
+ this.game.update(game => {
69223
+ const next = structuredClone(game);
69224
+ const liveAttacker = next.players.P1.battleZone.find(card => card.instanceId === attacker.instanceId);
69225
+ const liveTarget = next.players.P2.battleZone.find(card => card.instanceId === target.instanceId);
69226
+ if (!liveAttacker || !liveTarget || !liveAttacker.canAttack)
69227
+ return game;
69228
+ liveTarget.currentHp -= liveAttacker.attack;
69229
+ liveAttacker.currentHp -= liveTarget.attack;
69230
+ liveAttacker.canAttack = false;
69231
+ this.cleanupDestroyed(next.players.P1, next);
69232
+ this.cleanupDestroyed(next.players.P2, next);
69233
+ next.revision++;
69234
+ next.log = [`${liveAttacker.name} combate contra ${liveTarget.name}.`, ...next.log].slice(0, 4);
69235
+ return next;
69236
+ });
69237
+ this.selectedAttacker.set(null);
69238
+ }
69239
+ endTurn() {
69240
+ this.selectedHandCard.set(null);
69241
+ this.selectedAttacker.set(null);
69242
+ this.selectedPreview.set(null);
69243
+ this.game.update(game => {
69244
+ const next = structuredClone(game);
69245
+ next.turnOwner = next.turnOwner === 'P1' ? 'P2' : 'P1';
69246
+ next.turnCount++;
69247
+ const current = next.players[next.turnOwner];
69248
+ current.offeringPlayedThisTurn = false;
69249
+ current.offerings = current.offerings.map(offering => ({ ...offering, ready: true }));
69250
+ current.battleZone = current.battleZone.map(card => ({ ...card, canAttack: true }));
69251
+ const drawnCard = next.sharedDeck.shift();
69252
+ if (drawnCard) {
69253
+ if (current.hand) {
69254
+ current.hand.push(drawnCard);
69255
+ }
69256
+ else {
69257
+ current.handCount = (current.handCount ?? 0) + 1;
69258
+ }
69259
+ }
69260
+ next.revision++;
69261
+ next.log = [
69262
+ drawnCard ? `${current.displayName} roba una carta.` : `El mazo esta vacio.`,
69263
+ `Turno de ${current.displayName}.`,
69264
+ ...next.log,
69265
+ ].slice(0, 4);
69266
+ return next;
69267
+ });
69268
+ }
69269
+ resetMock() {
69270
+ this.game.set(structuredClone(STARTING_GAME));
69271
+ this.selectedHandCard.set(null);
69272
+ this.selectedAttacker.set(null);
69273
+ this.selectedPreview.set(null);
69274
+ this.showHistory.set(false);
69275
+ this.offeringsSeat.set(null);
69276
+ }
69277
+ closePreview() {
69278
+ this.selectedPreview.set(null);
69279
+ this.resetPreviewTilt();
69280
+ }
69281
+ openOfferings(seat) {
69282
+ this.selectedPreview.set(null);
69283
+ this.showHistory.set(false);
69284
+ this.offeringsSeat.set(seat);
69285
+ }
69286
+ closeOfferings() {
69287
+ this.offeringsSeat.set(null);
69288
+ }
69289
+ tiltPreview(event) {
69290
+ const bounds = event.currentTarget.getBoundingClientRect();
69291
+ const x = (event.clientX - bounds.left) / bounds.width - 0.5;
69292
+ const y = (event.clientY - bounds.top) / bounds.height - 0.5;
69293
+ this.previewTilt.set({
69294
+ rotateX: 5 - y * 18,
69295
+ rotateY: -5 + x * 18,
69296
+ shiftX: x * 10,
69297
+ shiftY: y * 10,
69298
+ });
69299
+ }
69300
+ resetPreviewTilt() {
69301
+ this.previewTilt.set({ rotateX: 5, rotateY: -5, shiftX: 0, shiftY: 0 });
69302
+ }
69303
+ cleanupDestroyed(player, game) {
69304
+ const destroyed = player.battleZone.filter(card => card.currentHp <= 0);
69305
+ if (!destroyed.length)
69306
+ return;
69307
+ game.historyZone.push(...destroyed.map(card => card.cardId));
69308
+ player.battleZone = player.battleZone.filter(card => card.currentHp > 0);
69309
+ }
69310
+ inspectLeader(seat) {
69311
+ const player = this.game().players[seat];
69312
+ this.selectedPreview.set({
69313
+ title: player.leaderName,
69314
+ eyebrow: this.t('christianityLeaderCard'),
69315
+ meta: `${player.leaderHp}/${player.leaderMaxHp}`,
69316
+ body: seat === 'P2' && this.hasOpponentGuards() ? this.t('christianityLeaderProtected') : this.t('christianityLeaderBody'),
69317
+ });
69318
+ }
69319
+ inspectOffering(offering) {
69320
+ this.selectedPreview.set({
69321
+ title: offering.name,
69322
+ eyebrow: this.t('christianityOfferingCard'),
69323
+ meta: offering.ready ? this.t('christianityOfferingReady') : this.t('christianityOfferingExhausted'),
69324
+ body: offering.abilityText || this.t('christianityOfferingBody'),
69325
+ });
69326
+ }
69327
+ canUseOfferingAbility(offering, seat) {
69328
+ if (seat !== 'P1' || !this.isOwnTurn())
69329
+ return false;
69330
+ if (!offering.ready || !offering.abilityName)
69331
+ return false;
69332
+ return this.readyOfferings(this.game().players[seat]) >= (offering.abilityCost ?? 0);
69333
+ }
69334
+ useOfferingAbility(offering, seat) {
69335
+ if (!this.canUseOfferingAbility(offering, seat))
69336
+ return;
69337
+ this.game.update(game => {
69338
+ const next = structuredClone(game);
69339
+ const player = next.players[seat];
69340
+ const liveOffering = player.offerings.find(card => card.instanceId === offering.instanceId);
69341
+ if (!liveOffering || !liveOffering.ready)
69342
+ return game;
69343
+ const offeringId = liveOffering.instanceId;
69344
+ this.spendOfferings(player, liveOffering.abilityCost ?? 0);
69345
+ player.offerings = player.offerings.map(card => (card.instanceId === offeringId ? { ...card, ready: false } : card));
69346
+ player.leaderHp = Math.max(0, player.leaderHp - 1);
69347
+ next.revision++;
69348
+ next.log = [`${liveOffering.name}: ${liveOffering.abilityName}.`, ...next.log].slice(0, 4);
69349
+ return next;
69350
+ });
69351
+ }
69352
+ inspectDeck() {
69353
+ this.selectedPreview.set({
69354
+ title: this.t('christianityDeck'),
69355
+ eyebrow: this.t('christianitySharedZone'),
69356
+ meta: `${this.game().sharedDeck.length}`,
69357
+ body: this.t('christianityDeckBody'),
69358
+ });
69359
+ }
69360
+ inspectHandCard(cardId, fromHand = false) {
69361
+ const card = this.cardDefinition(cardId);
69362
+ if (fromHand) {
69363
+ this.selectedAttacker.set(null);
69364
+ this.selectedHandCard.set(cardId);
69365
+ }
69366
+ this.selectedPreview.set({
69367
+ title: card.name,
69368
+ eyebrow: card.type === 'offering' ? this.t('christianityOfferingCard') : this.t('christianityCharacterCard'),
69369
+ meta: card.type === 'offering' ? `+${card.life}` : `${this.t('christianityCost')} ${card.cost} · ${card.attack}/${card.life}`,
69370
+ body: card.type === 'offering' ? this.t('christianityOfferingBody') : this.t('christianityCharacterBody'),
69371
+ cardId,
69372
+ source: fromHand ? 'hand' : 'pile',
69373
+ });
69374
+ }
69375
+ inspectHistoryCard(cardId) {
69376
+ this.showHistory.set(false);
69377
+ this.inspectHandCard(cardId);
69378
+ }
69379
+ inspectCharacter(card) {
69380
+ this.selectedPreview.set({
69381
+ title: card.name,
69382
+ eyebrow: this.t('christianityCharacterCard'),
69383
+ meta: `${card.attack}/${card.currentHp}`,
69384
+ body: card.canAttack ? this.t('christianityCharacterReady') : this.t('christianityCharacterExhausted'),
69385
+ });
69386
+ }
69387
+ spendOfferings(player, cost) {
69388
+ let remaining = cost;
69389
+ player.offerings = player.offerings.map(offering => {
69390
+ if (remaining <= 0 || !offering.ready)
69391
+ return offering;
69392
+ remaining -= offering.value;
69393
+ return { ...offering, ready: false };
69394
+ });
69395
+ }
69396
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChristianityGameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
69397
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: ChristianityGameComponent, isStandalone: true, selector: "val-christianity-game", ngImport: i0, template: `
69398
+ <main class="christianity-shell">
69399
+ <section class="christianity-header">
69400
+ <div>
69401
+ <p>{{ t('christianityEyebrow') }}</p>
69402
+ <h1>{{ t('christianityTitle') }}</h1>
69403
+ </div>
69404
+ <div class="christianity-turn" [class.is-own-turn]="isOwnTurn()">
69405
+ <span>{{ t('christianityTurn') }}</span>
69406
+ <strong>{{ currentPlayer().displayName }}</strong>
69407
+ </div>
69408
+ </section>
69409
+
69410
+ <section class="christianity-match-strip" [attr.aria-label]="t('christianityMatchScore')">
69411
+ <article class="christianity-match-player">
69412
+ <span class="christianity-avatar" [style.background]="player().avatarColor">{{ player().avatar }}</span>
69413
+ <div>
69414
+ <strong>{{ player().displayName }}</strong>
69415
+ <small>{{ player().leaderName }} · {{ player().leaderHp }}/{{ player().leaderMaxHp }}</small>
69416
+ </div>
69417
+ </article>
69418
+ <div class="christianity-scoreboard">
69419
+ <span>{{ t('christianityMatch') }}</span>
69420
+ <strong>{{ game().matchScore.P1 }}-{{ game().matchScore.P2 }}</strong>
69421
+ </div>
69422
+ <article class="christianity-match-player christianity-match-player--opponent">
69423
+ <span class="christianity-avatar" [style.background]="opponent().avatarColor">{{ opponent().avatar }}</span>
69424
+ <div>
69425
+ <strong>{{ opponent().displayName }}</strong>
69426
+ <small>{{ opponent().leaderName }} · {{ opponent().leaderHp }}/{{ opponent().leaderMaxHp }}</small>
69427
+ </div>
69428
+ </article>
69429
+ </section>
69430
+
69431
+ <section class="christianity-hand-shelf christianity-hand-shelf--opponent">
69432
+ <div class="christianity-hand-meter christianity-hand-meter--opponent">
69433
+ <span>{{ t('christianityHand') }}</span>
69434
+ <strong>{{ opponentHandCount() }}</strong>
69435
+ </div>
69436
+ <section class="christianity-hand-fan christianity-hand-fan--opponent" [attr.aria-label]="t('christianityOpponentHand')">
69437
+ @for (_ of hiddenHandCards(opponentHandCount()); track $index) {
69438
+ <button
69439
+ type="button"
69440
+ class="christianity-card-preview-card christianity-card-preview-card--back"
69441
+ valLightRipple
69442
+ [style.transform]="fanTransform($index, opponentHandCount(), true)"
69443
+ [attr.aria-label]="t('christianityHiddenCard')"
69444
+ ></button>
69445
+ }
69446
+ </section>
69447
+ </section>
69448
+
69449
+ <section class="christianity-table" [attr.aria-label]="t('christianityTable')">
69450
+ <section class="christianity-player-side christianity-player-side--opponent">
69451
+ <section class="christianity-player-rack christianity-player-rack--opponent">
69452
+ <div class="christianity-offerings-zone">
69453
+ <button type="button" class="christianity-offering-pile" valLightRipple (click)="openOfferings('P2')">
69454
+ <i aria-hidden="true"></i>
69455
+ <i aria-hidden="true"></i>
69456
+ <i aria-hidden="true"></i>
69457
+ <span>{{ t('christianityOfferings') }}</span>
69458
+ <strong>{{ readyOfferings(opponent()) }}/{{ totalOfferings(opponent()) }}</strong>
69459
+ </button>
69460
+ </div>
69461
+ <button type="button" class="christianity-leader-card" valLightRipple [class.is-target]="selectedAttacker() && !hasOpponentGuards()" (click)="handleOpponentLeader()">
69462
+ <span>{{ opponent().leaderName }}</span>
69463
+ <strong>{{ opponent().leaderHp }}/{{ opponent().leaderMaxHp }}</strong>
69464
+ </button>
69465
+ <span class="christianity-rack-spacer" aria-hidden="true"></span>
69466
+ </section>
69467
+
69468
+ <section class="christianity-battle-zone christianity-battle-zone--opponent" [attr.aria-label]="t('christianityOpponentBattle')">
69469
+ @for (slot of battleSlots('P2'); track slot.trackId) {
69470
+ @if (slot.card) {
69471
+ <button
69472
+ type="button"
69473
+ class="christianity-card-preview-card christianity-card-preview-card--battle"
69474
+ valLightRipple
69475
+ [class.is-target]="selectedAttacker()"
69476
+ (click)="handleOpponentCharacter(slot.card)"
69477
+ >
69478
+ <span>{{ slot.card.name }}</span>
69479
+ <strong>{{ slot.card.attack }} / {{ slot.card.currentHp }}</strong>
69480
+ </button>
69481
+ } @else {
69482
+ <span class="christianity-slot"></span>
69483
+ }
69484
+ }
69485
+ </section>
69486
+ </section>
69487
+
69488
+ <section class="christianity-shared-zone" [attr.aria-label]="t('christianitySharedZone')">
69489
+ <button type="button" class="christianity-zone-pile christianity-zone-pile--history" valLightRipple (click)="showHistory.set(true)">
69490
+ <i aria-hidden="true"></i>
69491
+ <i aria-hidden="true"></i>
69492
+ <i aria-hidden="true"></i>
69493
+ <span>{{ t('christianityHistory') }}</span>
69494
+ <strong>{{ game().historyZone.length }}</strong>
69495
+ </button>
69496
+ <button type="button" class="christianity-zone-pile christianity-zone-pile--deck" valLightRipple aria-live="polite" (click)="inspectDeck()">
69497
+ <i aria-hidden="true"></i>
69498
+ <i aria-hidden="true"></i>
69499
+ <i aria-hidden="true"></i>
69500
+ <span>{{ t('christianityDeck') }}</span>
69501
+ <strong>{{ game().sharedDeck.length }}</strong>
69502
+ </button>
69503
+ <div class="christianity-zone-card">
69504
+ <span>{{ t('christianityPlace') }}</span>
69505
+ <strong>{{ t('christianityEmpty') }}</strong>
69506
+ </div>
69507
+ </section>
69508
+
69509
+ <section class="christianity-player-side">
69510
+ <section class="christianity-battle-zone" [class.is-placing-card]="canPlaceSelectedCharacter() || isDraggingCharacter()" [attr.aria-label]="t('christianityYourBattle')">
69511
+ @for (slot of battleSlots('P1'); track slot.trackId) {
69512
+ @if (slot.card) {
69513
+ <button
69514
+ type="button"
69515
+ class="christianity-card-preview-card christianity-card-preview-card--battle"
69516
+ valLightRipple
69517
+ [class.is-selected]="selectedAttacker()?.instanceId === slot.card.instanceId"
69518
+ [class.is-exhausted]="!slot.card.canAttack"
69519
+ (click)="selectAttacker(slot.card)"
69520
+ >
69521
+ <span>{{ slot.card.name }}</span>
69522
+ <strong>{{ slot.card.attack }} / {{ slot.card.currentHp }}</strong>
69523
+ </button>
69524
+ } @else {
69525
+ <button
69526
+ type="button"
69527
+ class="christianity-slot"
69528
+ cdkDropList
69529
+ [id]="battleSlotDropId($index)"
69530
+ [cdkDropListData]="$index"
69531
+ [cdkDropListConnectedTo]="['christianity-hand-source']"
69532
+ [cdkDropListEnterPredicate]="canDropOnBattleSlot"
69533
+ [class.christianity-slot--play-target]="canPlaceSelectedCharacter() || isDraggingCharacter()"
69534
+ valLightRipple
69535
+ (cdkDropListDropped)="dropOnBattleSlot($event, $index)"
69536
+ (click)="playSelectedCard($index)"
69537
+ >
69538
+ @if (canPlaceSelectedCharacter() || isDraggingCharacter()) {
69539
+ <span>{{ t('christianityPlayHere') }}</span>
69540
+ }
69541
+ </button>
69542
+ }
69543
+ }
69544
+ </section>
69545
+
69546
+ <section class="christianity-player-rack">
69547
+ <div class="christianity-offerings-zone">
69548
+ <button
69549
+ type="button"
69550
+ class="christianity-offering-pile"
69551
+ cdkDropList
69552
+ id="christianity-offerings-drop"
69553
+ valLightRipple
69554
+ [cdkDropListConnectedTo]="['christianity-hand-source']"
69555
+ [class.is-play-target]="canPlaceSelectedOffering() || isDraggingOffering()"
69556
+ [cdkDropListEnterPredicate]="canDropOnOfferings"
69557
+ (cdkDropListDropped)="dropOnOfferings($event)"
69558
+ (click)="handleOfferingPile('P1')"
69559
+ >
69560
+ <i aria-hidden="true"></i>
69561
+ <i aria-hidden="true"></i>
69562
+ <i aria-hidden="true"></i>
69563
+ <span>{{ t('christianityOfferings') }}</span>
69564
+ <strong>{{ readyOfferings(player()) }}/{{ totalOfferings(player()) }}</strong>
69565
+ </button>
69566
+ </div>
69567
+ <button type="button" class="christianity-leader-card" valLightRipple (click)="inspectLeader('P1')">
69568
+ <span>{{ player().leaderName }}</span>
69569
+ <strong>{{ player().leaderHp }}/{{ player().leaderMaxHp }}</strong>
69570
+ </button>
69571
+ <div class="christianity-player-command">
69572
+ <div class="christianity-player-badge">
69573
+ <span class="christianity-avatar" [style.background]="player().avatarColor">{{ player().avatar }}</span>
69574
+ <strong>{{ player().displayName }}</strong>
69575
+ </div>
69576
+ <button
69577
+ type="button"
69578
+ class="christianity-end-turn"
69579
+ (click)="endTurn()"
69580
+ >
69581
+ {{ t('christianityEndTurn') }}
69582
+ </button>
69583
+ </div>
69584
+ </section>
69585
+ </section>
69586
+ </section>
69587
+
69588
+ <section class="christianity-hand-shelf">
69589
+ <div class="christianity-hand-meter">
69590
+ <span>{{ t('christianityHand') }}</span>
69591
+ <strong>{{ player().hand?.length ?? 0 }}</strong>
69592
+ </div>
69593
+ <section
69594
+ class="christianity-hand-fan"
69595
+ cdkDropList
69596
+ id="christianity-hand-source"
69597
+ [cdkDropListConnectedTo]="dropTargetIds()"
69598
+ [attr.aria-label]="t('christianityYourHand')"
69599
+ (pointerleave)="clearHoveredHandIndex()"
69600
+ >
69601
+ @for (cardId of player().hand ?? []; track cardId + $index) {
69602
+ @let card = cardDefinition(cardId);
69603
+ <div
69604
+ class="christianity-hand-card-wrap"
69605
+ [class.is-selected]="selectedHandCard() === cardId"
69606
+ [class.is-dragging]="draggingCardId() === cardId"
69607
+ [style.z-index]="handCardZIndex($index)"
69608
+ [style.transform]="fanTransform($index, player().hand?.length ?? 0, false)"
69609
+ (pointerenter)="setHoveredHandIndex($index)"
69610
+ (pointerdown)="setHoveredHandIndex($index)"
69611
+ (pointerup)="releaseHoveredHand($event)"
69612
+ >
69613
+ <button
69614
+ type="button"
69615
+ class="christianity-card-preview-card christianity-card-preview-card--hand"
69616
+ cdkDrag
69617
+ valLightRipple
69618
+ [cdkDragData]="cardId"
69619
+ [cdkDragDisabled]="!canPlay(card)"
69620
+ [class.is-selected]="selectedHandCard() === cardId"
69621
+ [class.is-disabled]="!canPlay(card)"
69622
+ (cdkDragStarted)="startDraggingCard(cardId)"
69623
+ (cdkDragEnded)="endDraggingCard()"
69624
+ (click)="selectHandCard(cardId)"
69625
+ >
69626
+ <small>
69627
+ @if (card.type === 'offering') {
69628
+ {{ t('christianityOfferingCard') }}
69629
+ } @else {
69630
+ {{ t('christianityCost') }} {{ card.cost }}
69631
+ }
69632
+ </small>
69633
+ <span>{{ card.name }}</span>
69634
+ <strong>
69635
+ @if (card.type === 'offering') {
69636
+ +{{ card.life }}
69637
+ } @else {
69638
+ {{ card.attack }} / {{ card.life }}
69639
+ }
69640
+ </strong>
69641
+ </button>
69642
+ <button
69643
+ type="button"
69644
+ class="christianity-card-eye"
69645
+ [attr.aria-label]="t('christianityPreviewCard')"
69646
+ (click)="inspectHandCard(cardId, true); $event.stopPropagation()"
69647
+ ></button>
69648
+ </div>
69649
+ }
69650
+ </section>
69651
+ </section>
69652
+
69653
+ @if (selectedPreview()) {
69654
+ <button type="button" class="christianity-preview-backdrop" [attr.aria-label]="t('christianityClosePreview')" (click)="closePreview()"></button>
69655
+ <aside
69656
+ class="christianity-floating-card-shell"
69657
+ aria-live="polite"
69658
+ >
69659
+ <button type="button" class="christianity-floating-card-close" (click)="closePreview()">
69660
+ {{ t('close') }}
69661
+ </button>
69662
+ <div
69663
+ class="christianity-floating-card"
69664
+ [style.--preview-rotate-x]="previewTilt().rotateX + 'deg'"
69665
+ [style.--preview-rotate-y]="previewTilt().rotateY + 'deg'"
69666
+ [style.--preview-shift-x]="previewTilt().shiftX + 'px'"
69667
+ [style.--preview-shift-y]="previewTilt().shiftY + 'px'"
69668
+ (pointermove)="tiltPreview($event)"
69669
+ (pointerleave)="resetPreviewTilt()"
69670
+ >
69671
+ @if (selectedPreviewCard(); as previewCard) {
69672
+ <header class="christianity-full-card-header">
69673
+ <span class="christianity-full-card-type-icon" aria-hidden="true"></span>
69674
+ <strong>{{ previewCard.name }}</strong>
69675
+ <span class="christianity-full-card-cost">{{ previewCard.type === 'offering' ? '+' + previewCard.life : previewCard.cost }}</span>
69676
+ </header>
69677
+ <section class="christianity-full-card-art" [class.has-image]="previewCard.imageUrl">
69678
+ @if (previewCard.imageUrl) {
69679
+ <img [src]="previewCard.imageUrl" [alt]="previewCard.name" />
69680
+ } @else {
69681
+ <span>{{ previewCard.name }}</span>
69682
+ }
69683
+ <small>{{ cardTypeLabel(previewCard) }}</small>
69684
+ </section>
69685
+ <section class="christianity-full-card-verse">
69686
+ <p>{{ previewCard.verseText ?? selectedPreview()?.body }}</p>
69687
+ @if (previewCard.scripture) {
69688
+ <strong>{{ previewCard.scripture }}</strong>
69689
+ }
69690
+ </section>
69691
+ <section class="christianity-full-card-effect">
69692
+ <div class="christianity-full-card-stats">
69693
+ @if (previewCard.type === 'character') {
69694
+ <strong>{{ previewCard.attack }}</strong>
69695
+ <strong>{{ previewCard.life }}</strong>
69696
+ } @else {
69697
+ <strong>+{{ previewCard.life }}</strong>
69698
+ }
69699
+ </div>
69700
+ <div>
69701
+ @if (previewCard.abilityName) {
69702
+ <strong>{{ previewCard.abilityName }}</strong>
69703
+ }
69704
+ <p>{{ previewCard.abilityText ?? selectedPreview()?.body }}</p>
69705
+ </div>
69706
+ <span
69707
+ class="christianity-full-card-rarity"
69708
+ [class.is-normal]="!previewCard.rarity || previewCard.rarity === 'normal'"
69709
+ [class.is-uncommon]="previewCard.rarity === 'uncommon'"
69710
+ [class.is-rare]="previewCard.rarity === 'rare'"
69711
+ [class.is-legendary]="previewCard.rarity === 'legendary'"
69712
+ aria-hidden="true"
69713
+ ></span>
69714
+ </section>
69715
+ <footer class="christianity-full-card-footer">
69716
+ <span>{{ previewCard.edition ?? 'MVP' }}</span>
69717
+ <span>{{ previewCard.collectorNumber ?? previewCard.id }}</span>
69718
+ <span>{{ previewCard.year ?? '2026' }} CHRISTIANITY</span>
69719
+ <span>{{ previewCard.author ?? 'MVP' }}</span>
69720
+ </footer>
69721
+ } @else {
69722
+ <small>{{ selectedPreview()?.eyebrow }}</small>
69723
+ <strong>{{ selectedPreview()?.title }}</strong>
69724
+ <span>{{ selectedPreview()?.meta }}</span>
69725
+ <p>{{ selectedPreview()?.body }}</p>
69726
+ }
69727
+ </div>
69728
+ @if (selectedPreview()?.source === 'hand') {
69729
+ <div class="christianity-floating-card-actions">
69730
+ <button type="button" [disabled]="previewActionDisabled()" (click)="playPreviewCard()">
69731
+ {{ selectedActionLabel() }}
69732
+ </button>
69733
+ </div>
69734
+ }
69735
+ </aside>
69736
+ }
69737
+
69738
+ <section class="christianity-actions" aria-live="polite">
69739
+ <p>{{ statusText() }}</p>
69740
+ <div>
69741
+ <button type="button" [disabled]="selectedActionDisabled()" (click)="playSelectedCard()">
69742
+ {{ selectedActionLabel() }}
69743
+ </button>
69744
+ <button type="button" (click)="resetMock()">
69745
+ {{ t('christianityReset') }}
69746
+ </button>
69747
+ </div>
69748
+ </section>
69749
+
69750
+ @if (showHistory()) {
69751
+ <button type="button" class="christianity-history-backdrop" [attr.aria-label]="t('christianityCloseHistory')" (click)="showHistory.set(false)"></button>
69752
+ <section class="christianity-history-drawer">
69753
+ <header>
69754
+ <h2>{{ t('christianityHistory') }}</h2>
69755
+ <div class="christianity-dialog-actions">
69756
+ <span>{{ game().historyZone.length }}</span>
69757
+ <button type="button" class="christianity-dialog-close" (click)="showHistory.set(false)">
69758
+ {{ t('close') }}
69759
+ </button>
69760
+ </div>
69761
+ </header>
69762
+ @if (game().historyZone.length) {
69763
+ <div class="christianity-history-grid">
69764
+ @for (cardId of game().historyZone; track cardId + $index) {
69765
+ @let card = cardDefinition(cardId);
69766
+ <button type="button" class="christianity-card-preview-card" valLightRipple (click)="inspectHistoryCard(cardId)">
69767
+ <small>{{ card.type === 'offering' ? t('christianityOfferingCard') : t('christianityCharacterCard') }}</small>
69768
+ <span>{{ card.name }}</span>
69769
+ <strong>
69770
+ @if (card.type === 'offering') {
69771
+ +{{ card.life }}
69772
+ } @else {
69773
+ {{ card.attack }} / {{ card.life }}
69774
+ }
69775
+ </strong>
69776
+ </button>
69777
+ }
69778
+ </div>
69779
+ } @else {
69780
+ <p>{{ t('christianityHistoryEmpty') }}</p>
69781
+ }
69782
+ </section>
69783
+ }
69784
+
69785
+ @if (offeringsSeat()) {
69786
+ @let offeringPlayer = game().players[offeringsSeat()!];
69787
+ <button type="button" class="christianity-history-backdrop" [attr.aria-label]="t('christianityCloseOfferings')" (click)="closeOfferings()"></button>
69788
+ <section class="christianity-history-drawer christianity-offerings-drawer">
69789
+ <header>
69790
+ <h2>{{ t('christianityOfferings') }}</h2>
69791
+ <div class="christianity-dialog-actions">
69792
+ <span>{{ readyOfferings(offeringPlayer) }}/{{ totalOfferings(offeringPlayer) }}</span>
69793
+ <button type="button" class="christianity-dialog-close" (click)="closeOfferings()">
69794
+ {{ t('close') }}
69795
+ </button>
69796
+ </div>
69797
+ </header>
69798
+ <div class="christianity-offering-list">
69799
+ @for (offering of offeringPlayer.offerings; track offering.instanceId) {
69800
+ <article class="christianity-offering-row" [class.is-exhausted]="!offering.ready">
69801
+ <button type="button" class="christianity-offering-card" valLightRipple (click)="inspectOffering(offering)">
69802
+ <small>{{ t('christianityOfferingCard') }}</small>
69803
+ <span>{{ offering.name }}</span>
69804
+ <strong>+{{ offering.value }}</strong>
69805
+ @if (offering.abilityName) {
69806
+ <p>{{ offering.abilityName }}</p>
69807
+ }
69808
+ </button>
69809
+ <div>
69810
+ <strong>{{ offering.ready ? t('christianityOfferingReady') : t('christianityOfferingExhausted') }}</strong>
69811
+ <p>{{ offering.abilityText || t('christianityOfferingNoAbility') }}</p>
69812
+ @if (offering.abilityName) {
69813
+ <button
69814
+ type="button"
69815
+ [disabled]="!canUseOfferingAbility(offering, offeringsSeat()!)"
69816
+ (click)="useOfferingAbility(offering, offeringsSeat()!)"
69817
+ >
69818
+ {{ t('christianityUseAbility') }}
69819
+ </button>
69820
+ }
69821
+ </div>
69822
+ </article>
69823
+ }
69824
+ </div>
69825
+ </section>
69826
+ }
69827
+ </main>
69828
+ `, isInline: true, styles: [":host{--christianity-theme-ink: var(--val-text-color, #1f2933);--christianity-theme-surface: #ffffff;--christianity-theme-parchment: #fffaf0;--christianity-theme-olive: #5f6f2a;--christianity-theme-gold: #d6a21d;--christianity-theme-gold-soft: rgba(214, 162, 29, .18);--christianity-theme-gold-ring: rgba(214, 162, 29, .48);--christianity-theme-glow: rgba(245, 199, 85, .32);--christianity-theme-focus: #2563eb;--christianity-theme-shadow: rgba(82, 64, 28, .18);--christianity-theme-shadow-strong: rgba(82, 64, 28, .3);display:block;color:var(--christianity-theme-ink)}.christianity-shell{display:grid;gap:.65rem;padding:.75rem .25rem;border:1px solid rgba(36,48,68,.12);border-radius:.75rem;background:#f6f8fb;overflow:visible}.christianity-header,.christianity-match-strip,.christianity-player__summary,.christianity-shared-zone,.christianity-actions{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.christianity-header h1,.christianity-header p,.christianity-match-player strong,.christianity-match-player small,.christianity-scoreboard span,.christianity-history h2,.christianity-actions p{margin:0}.christianity-header h1{font-size:1.35rem;line-height:1.1}.christianity-header p,.christianity-turn span,.christianity-offerings span,.christianity-hidden-hand span,.christianity-deck span,.christianity-place span,.christianity-pile span,.christianity-leader span{color:#1f2933a3;font-size:.75rem}.christianity-turn,.christianity-leader,.christianity-offerings,.christianity-hidden-hand,.christianity-pile,.christianity-deck,.christianity-place{display:grid;gap:.15rem;min-width:5.25rem;padding:.55rem .65rem;border:1px solid rgba(36,48,68,.12);border-radius:.5rem;background:#fff}.christianity-turn.is-own-turn{border-color:#12806c59;background:#ecfdf5}.christianity-match-strip{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);padding:.45rem;border:1px solid rgba(36,48,68,.1);border-radius:.75rem;background:#fff}.christianity-match-player{display:grid;grid-template-columns:auto minmax(0,1fr);gap:.5rem;align-items:center;min-width:0}.christianity-match-player--opponent{direction:rtl}.christianity-match-player--opponent div{direction:ltr;text-align:right}.christianity-match-player div{display:grid;min-width:0}.christianity-match-player strong,.christianity-match-player small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.christianity-match-player small,.christianity-scoreboard span{color:#1f293394;font-size:.72rem}.christianity-scoreboard{display:grid;justify-items:center;min-width:4.2rem;padding:0 .55rem;border-right:1px solid rgba(36,48,68,.1);border-left:1px solid rgba(36,48,68,.1)}.christianity-scoreboard strong{font-size:1.2rem;line-height:1}.christianity-table{display:grid;gap:.45rem;padding:.45rem .35rem;border-radius:.75rem;background:#dceafb;overflow:visible}.christianity-player-side{display:grid;gap:.35rem;padding:.35rem .3rem;border-radius:.7rem;background:#ffffff57;grid-template-rows:minmax(7rem,1fr) auto;min-height:13.75rem}.christianity-player-side--opponent{grid-template-rows:auto minmax(7rem,1fr)}.christianity-player{display:grid;gap:.65rem}.christianity-battle-zone{--christianity-battle-card-width: clamp(4.8rem, 15vw, 6.6rem);display:grid;grid-template-columns:repeat(4,var(--christianity-battle-card-width));gap:.5rem;align-items:center;justify-content:center;min-height:clamp(7.8rem,25vw,9.6rem);padding:.55rem .4rem;border-radius:.75rem;background:#ffffffc2;transition:background .16s ease,box-shadow .16s ease}.christianity-battle-zone.is-placing-card{background:linear-gradient(180deg,#fffaf0f5,#ffffffd6),#ffffffc2;box-shadow:inset 0 0 0 .14rem var(--christianity-theme-gold-soft),0 .8rem 1.7rem #5f6f2a1f}.christianity-shared-zone{padding:.55rem .4rem;border-radius:.75rem;background:#ffffffe6}.christianity-card,.christianity-end-turn,.christianity-actions button,.christianity-pile,.christianity-leader--target{border:1px solid rgba(36,48,68,.16);border-radius:.5rem;background:#fff;color:inherit;font:inherit}.christianity-card{display:grid;align-content:space-between;min-height:5.8rem;padding:.5rem;text-align:left;box-shadow:0 .5rem 1.25rem #24304414}.christianity-card span{font-weight:700}.christianity-card strong{justify-self:end;padding:.15rem .35rem;border-radius:999px;background:#edf2f7;font-size:.8rem}.christianity-card.is-selected{border-color:var(--christianity-theme-gold);box-shadow:0 0 0 .18rem var(--christianity-theme-gold-soft),0 .85rem 1.4rem var(--christianity-theme-shadow)}.christianity-card.is-disabled,.christianity-card.is-exhausted{opacity:.55}.christianity-card.is-target{border-color:#dc2626}.christianity-offering-cards{display:grid;grid-auto-flow:column;grid-auto-columns:.7rem;gap:.16rem;align-items:end;min-height:1.05rem}.christianity-offering-cards i{display:block;width:.65rem;height:.95rem;border:1px solid rgba(16,42,67,.22);border-radius:.18rem;background:#f8fafc}.christianity-offering-cards i.is-used{background:#cbd5e1;transform:rotate(90deg);transform-origin:center}.christianity-slot{display:grid;place-items:center;justify-self:center;width:var(--christianity-battle-card-width);height:clamp(6.8rem,21vw,8.4rem);min-height:0;aspect-ratio:5 / 7;border:1px dashed rgba(36,48,68,.22);border-radius:.5rem;background:#ffffff73;color:inherit;font:inherit}.christianity-slot--play-target{position:relative;border-color:var(--christianity-theme-gold-ring);background:linear-gradient(180deg,#fffaf0eb,#f8fafcd1),#ffffffb3;color:#5d4305;font-weight:800;overflow:hidden;box-shadow:inset 0 0 0 .12rem #d6a21d33,0 .7rem 1.25rem var(--christianity-theme-shadow);animation:christianity-target-pulse 1.45s ease-in-out infinite}.christianity-slot--play-target:before{content:\"\";position:absolute;inset:.35rem;border:1px solid rgba(214,162,29,.22);border-radius:.4rem;background:linear-gradient(135deg,rgba(214,162,29,.1),transparent 46%),radial-gradient(circle at 50% 42%,var(--christianity-theme-glow),transparent 58%)}.christianity-slot--play-target span{position:relative;z-index:2;padding:.16rem .44rem;border-radius:999px;background:#ffffffc7;font-size:.78rem}@keyframes christianity-target-pulse{0%,to{box-shadow:inset 0 0 0 .12rem #d6a21d33,0 .7rem 1.25rem var(--christianity-theme-shadow)}50%{box-shadow:inset 0 0 0 .16rem #d6a21d57,0 .9rem 1.65rem var(--christianity-theme-shadow-strong)}}.christianity-hand{display:grid;grid-auto-columns:minmax(6rem,8rem);grid-auto-flow:column;gap:.55rem;overflow-x:auto;padding-bottom:.25rem}.christianity-actions{align-items:flex-start;padding:.75rem;border-radius:.75rem;background:#fff}.christianity-actions div{display:flex;flex-wrap:wrap;gap:.5rem;justify-content:flex-end}.christianity-actions button,.christianity-end-turn{min-height:2.4rem;padding:0 .75rem;font-weight:700}.christianity-actions button:not(:disabled),.christianity-end-turn{background:#102a43;color:#fff}.christianity-history{padding:.75rem;border-radius:.75rem;background:#fff}.christianity-hand-fan{position:relative;display:flex;justify-content:center;min-height:10.8rem;padding:.25rem .25rem 2.1rem;isolation:isolate;overflow:visible}.christianity-hand-shelf{position:relative;display:grid;z-index:12;min-height:12rem;margin-top:-1.15rem;padding:1.45rem .25rem 1rem;overflow:visible}.christianity-hand-shelf--opponent{z-index:8;min-height:6.85rem;margin-top:0;margin-bottom:0;padding:.45rem .25rem .85rem}.christianity-hand-fan--opponent{min-height:5.9rem;padding-bottom:.75rem;align-items:start}.christianity-card-preview-card,.christianity-card-mini,.christianity-offering-pile,.christianity-offering-card,.christianity-leader-card,.christianity-zone-card,.christianity-zone-pile,.christianity-end-turn{border:1px solid rgba(36,48,68,.16);border-radius:.5rem;background:#fff;color:inherit;font:inherit}.christianity-card-preview-card{display:grid;align-content:space-between;width:clamp(4.9rem,17vw,7.1rem);min-height:clamp(6.6rem,22vw,8.8rem);padding:.48rem;text-align:left;transform-origin:50% 115%;transition:transform .16s ease,box-shadow .16s ease,border-color .16s ease;box-shadow:0 .5rem 1.25rem #2430441a}.christianity-hand-card-wrap{position:relative;display:grid;justify-items:center;margin-inline:-.42rem;padding-bottom:2rem;transform-origin:50% 115%;transition:transform .16s ease,filter .16s ease}.christianity-hand-card-wrap:hover,.christianity-hand-card-wrap.is-selected,.christianity-hand-card-wrap.is-dragging{z-index:3}.christianity-hand-card-wrap:hover .christianity-card-preview-card--hand,.christianity-hand-card-wrap.is-selected .christianity-card-preview-card--hand,.christianity-hand-card-wrap.is-dragging .christianity-card-preview-card--hand{border-color:var(--christianity-theme-gold);box-shadow:0 0 0 .12rem var(--christianity-theme-gold-soft),0 1rem 2rem var(--christianity-theme-shadow)}.christianity-card-preview-card--hand{touch-action:none}.christianity-card-preview-card--hand.cdk-drag-disabled{cursor:not-allowed}.christianity-card-preview-card.cdk-drag-preview{border:1px solid var(--christianity-theme-gold-ring);box-shadow:0 0 0 .16rem #fff4c2ad,0 1.5rem 3rem var(--christianity-theme-shadow-strong);transform:rotate(2deg) scale(1.03)}.christianity-card-preview-card.cdk-drag-placeholder{opacity:.22}.christianity-slot.cdk-drop-list-dragging,.christianity-offering-pile.cdk-drop-list-dragging{border-color:var(--christianity-theme-gold-ring)}.christianity-slot.cdk-drop-list-receiving,.christianity-offering-pile.cdk-drop-list-receiving{box-shadow:inset 0 0 0 .18rem #d6a21d57,0 1rem 1.9rem var(--christianity-theme-shadow-strong)}.christianity-card-eye{position:absolute;right:50%;bottom:.38rem;width:2.15rem;height:1.55rem;border:1px solid rgba(214,162,29,.34);border-radius:999px;background:#fffffff0;box-shadow:0 .55rem 1.1rem #102a4324;opacity:0;transform:translate(50%,-.2rem) scale(.92);transition:opacity .14s ease,transform .14s ease,border-color .14s ease}.christianity-card-eye:before{content:\"\";position:absolute;top:50%;left:50%;width:1.1rem;height:1.1rem;border:.12rem solid var(--christianity-theme-olive);border-radius:82% 0;background:#fffaf0eb;transform:translate(-50%,-50%) rotate(45deg)}.christianity-card-eye:after{content:\"\";position:absolute;top:50%;left:50%;width:.42rem;height:.42rem;border:.09rem solid rgba(255,250,240,.95);border-radius:999px;background:radial-gradient(circle at 35% 32%,#ffffff 0 .06rem,transparent .07rem),var(--christianity-theme-gold);transform:translate(-50%,-50%)}.christianity-hand-card-wrap:hover .christianity-card-eye,.christianity-hand-card-wrap.is-selected .christianity-card-eye,.christianity-card-eye:focus-visible{opacity:1;transform:translate(50%) scale(1)}.christianity-offering-pile.is-play-target{border-color:var(--christianity-theme-gold-ring);background:linear-gradient(180deg,#fffaf0f5,#fffffff0),radial-gradient(circle at 82% 14%,rgba(250,204,21,.28) 0 .7rem,transparent .72rem);box-shadow:inset 0 0 0 .12rem #d6a21d3d,0 .8rem 1.55rem var(--christianity-theme-shadow);animation:christianity-target-pulse 1.45s ease-in-out infinite}.christianity-card-preview-card--back{width:clamp(4rem,14vw,5.7rem);min-height:clamp(5rem,16vw,6.6rem);box-shadow:0 .8rem 1.55rem #24304424;transform-origin:50% -18%;background:linear-gradient(135deg,#102a431f,#102a4305),repeating-linear-gradient(45deg,#e2e8f0 0 .35rem,#f8fafc .35rem .7rem)}.christianity-card-preview-card--battle{justify-self:center;width:var(--christianity-battle-card-width);min-width:0;height:clamp(6.8rem,21vw,8.4rem);min-height:0;aspect-ratio:5 / 7;margin-inline:0}.christianity-card-preview-card span,.christianity-card-mini span,.christianity-offering-pile span,.christianity-offering-card span,.christianity-leader-card span,.christianity-zone-card span,.christianity-zone-pile span{position:relative;z-index:2;font-weight:700}.christianity-card-preview-card strong,.christianity-card-mini strong,.christianity-offering-pile strong,.christianity-offering-card strong,.christianity-leader-card strong,.christianity-zone-card strong,.christianity-zone-pile strong{position:relative;z-index:3;justify-self:end;padding:.15rem .35rem;border-radius:999px;background:#edf2f7;font-size:.8rem}.christianity-player-rack{display:grid;grid-template-columns:minmax(5.9rem,7rem) minmax(5rem,1fr) minmax(4.2rem,7rem);gap:.45rem;align-items:end;justify-items:stretch}.christianity-player-rack--opponent{align-items:start}.christianity-hand-meter{position:absolute;top:0;right:.35rem;z-index:4;display:inline-grid;grid-auto-flow:column;gap:.25rem;align-items:center;min-height:1.7rem;padding:.18rem .46rem;border:1px solid rgba(36,48,68,.12);border-radius:999px;background:#ffffffe6;box-shadow:0 .35rem .8rem #102a4314}.christianity-hand-meter--opponent{top:.15rem}.christianity-hand-meter span{color:#1f293394;font-size:.68rem}.christianity-hand-meter strong{font-size:.86rem}.christianity-player-badge,.christianity-player-command{display:grid;gap:.35rem;justify-items:center;min-width:0}.christianity-player-badge{align-content:start;color:#1f2933c2;font-size:.74rem}.christianity-player-badge--opponent{justify-self:center;grid-auto-flow:column;align-items:center;justify-content:center}.christianity-player-badge strong{max-width:6.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.christianity-avatar{display:grid;place-items:center;width:1.85rem;height:1.85rem;border-radius:999px;color:#fff;font-size:.76rem;font-weight:800;box-shadow:0 .35rem .9rem #102a4329}.christianity-offerings-zone{display:flex;flex-wrap:wrap;gap:.25rem;justify-content:flex-start;justify-self:start;width:100%}.christianity-card-mini,.christianity-offering-pile,.christianity-offering-card,.christianity-leader-card,.christianity-zone-card,.christianity-zone-pile{display:grid;align-content:space-between;min-height:4.9rem;padding:.48rem;text-align:left}.christianity-card-mini{width:3.5rem}.christianity-offering-pile{position:relative;isolation:isolate;overflow:hidden;justify-self:start;width:min(100%,5.9rem);min-height:7.1rem;padding:.95rem .52rem .6rem;background:linear-gradient(180deg,#fff,#f8fafc),linear-gradient(135deg,rgba(250,204,21,.18),transparent 42%)}.christianity-offering-pile i{position:absolute;inset:auto auto 1.05rem .72rem;z-index:-1;width:2.55rem;height:3.55rem;border:1px solid rgba(16,42,67,.18);border-radius:.35rem;background:linear-gradient(180deg,#ffffffeb,#f1f5f9eb),radial-gradient(circle at 78% 18%,#facc15 0 .38rem,transparent .4rem);box-shadow:0 .35rem .85rem #102a431a;transform:rotate(-5deg)}.christianity-offering-pile i:nth-child(2){transform:translate(.28rem,.08rem) rotate(3deg)}.christianity-offering-pile i:nth-child(3){transform:translate(.55rem,.18rem) rotate(-1deg)}.christianity-leader-card{align-self:center;justify-self:center;width:clamp(4.75rem,17vw,6rem);min-height:clamp(6.6rem,22vw,8.4rem)}.christianity-rack-spacer{display:block;min-height:1px}.christianity-battle-zone{grid-template-columns:repeat(4,var(--christianity-battle-card-width))}.christianity-shared-zone{display:grid;grid-template-columns:repeat(3,minmax(4.3rem,1fr));align-items:stretch}.christianity-zone-card,.christianity-zone-pile{min-height:6.45rem;padding:.7rem .52rem .55rem}.christianity-zone-pile{position:relative;isolation:isolate;overflow:hidden;box-shadow:inset 0 0 0 999px #ffffff1f}.christianity-zone-pile i{position:absolute;inset:auto .72rem 1.02rem auto;z-index:-1;width:2.7rem;height:3.7rem;border:1px solid rgba(16,42,67,.18);border-radius:.35rem;background:#f8fafc;box-shadow:0 .35rem .85rem #102a431c;transform:rotate(4deg)}.christianity-zone-pile i:nth-child(2){transform:translate(-.28rem,.12rem) rotate(-3deg)}.christianity-zone-pile i:nth-child(3){background:linear-gradient(135deg,#102a4329,#102a4308),repeating-linear-gradient(45deg,#dbeafe 0 .33rem,#fff .33rem .66rem);transform:translate(-.54rem,.24rem) rotate(2deg)}.christianity-floating-card-shell{position:fixed;top:50%;left:50%;z-index:61;display:grid;gap:.75rem;width:min(26rem,calc(100vw - 1.25rem));transform:translate(-50%,-50%)}.christianity-floating-card{display:grid;grid-template-rows:auto minmax(9rem,1.25fr) auto minmax(7rem,.9fr) auto;gap:.58rem;width:100%;min-height:min(29rem,calc(100vh - 3.5rem));padding:.72rem;border:1px solid rgba(36,48,68,.18);border-radius:.75rem;background:linear-gradient(180deg,#fffffff5,#f8fafcf5),radial-gradient(circle at 20% 0%,var(--christianity-theme-gold-soft),transparent 45%);box-shadow:0 0 0 .18rem #fff4c294,0 0 2.2rem var(--christianity-theme-glow),0 2.4rem 5rem #102a4357,inset 0 0 0 .35rem #ffffff8c;touch-action:none;transform:translate(var(--preview-shift-x, 0px),var(--preview-shift-y, 0px)) perspective(48rem) rotateX(var(--preview-rotate-x, 5deg)) rotateY(var(--preview-rotate-y, -5deg));transition:transform 90ms ease-out}.christianity-full-card-header{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:.42rem;align-items:center}.christianity-full-card-header strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:clamp(1.25rem,5vw,1.85rem);line-height:1.04}.christianity-full-card-type-icon,.christianity-full-card-cost{display:grid;place-items:center;border-radius:999px}.christianity-full-card-type-icon{width:1.6rem;height:1.6rem;background:radial-gradient(circle at 50% 50%,rgba(95,111,42,.72) 0 .22rem,transparent .24rem),#2430441a}.christianity-full-card-cost{width:2.1rem;height:2.1rem;background:#ffd91a;color:#243044;font-size:1.35rem;font-weight:900;box-shadow:inset 0 -.12rem #52401c2e}.christianity-full-card-art{position:relative;display:grid;place-items:center;min-height:9rem;overflow:hidden;border-radius:.48rem;background:linear-gradient(135deg,#5f6f2a33,#d6a21d29),radial-gradient(circle at 50% 25%,rgba(255,255,255,.76),transparent 42%),#dbe7ef;box-shadow:inset 0 0 0 1px #24304414}.christianity-full-card-art img{width:100%;height:100%;object-fit:cover}.christianity-full-card-art>span{max-width:80%;color:#24304494;font-size:clamp(1.1rem,5vw,1.8rem);font-weight:900;line-height:1.05;text-align:center}.christianity-full-card-art small{position:absolute;right:0;bottom:.55rem;min-width:5rem;padding:.16rem .48rem;border-radius:999px 0 0 999px;background:#ffffffe6;box-shadow:0 .3rem .8rem #102a431f;color:#1f2933bd;font-size:.68rem;font-style:italic;font-weight:900;text-align:center;text-transform:uppercase}.christianity-full-card-verse,.christianity-full-card-effect{display:grid;gap:.32rem}.christianity-full-card-verse p,.christianity-full-card-effect p{margin:0;line-height:1.25}.christianity-full-card-verse{color:#171923;font-family:Georgia,Times New Roman,serif;font-size:clamp(.72rem,2.7vw,.86rem)}.christianity-full-card-verse strong{font-family:inherit;font-size:.78rem;font-weight:900}.christianity-full-card-effect{position:relative;align-content:start;min-height:7rem;padding:.6rem .7rem;overflow:hidden;border-radius:.45rem;background:radial-gradient(circle at 50% 72%,rgba(36,48,68,.07),transparent 34%),#ffffffdb}.christianity-full-card-stats{display:flex;gap:1rem;min-height:1.35rem}.christianity-full-card-stats strong{font-size:1rem;line-height:1}.christianity-full-card-effect>div:last-of-type{display:grid;gap:.12rem}.christianity-full-card-effect>div:last-of-type strong{font-size:.82rem}.christianity-full-card-effect p{font-size:clamp(.78rem,2.9vw,.92rem)}.christianity-full-card-rarity{position:absolute;top:.62rem;right:.62rem;width:.46rem;height:.46rem;border-radius:.12rem;transform:rotate(45deg)}.christianity-full-card-rarity.is-normal{background:#d1d5db}.christianity-full-card-rarity.is-uncommon{background:#22c55e}.christianity-full-card-rarity.is-rare{background:#3b82f6}.christianity-full-card-rarity.is-legendary{background:#eab308}.christianity-full-card-footer{display:grid;grid-template-columns:auto auto minmax(0,1fr) auto;gap:.34rem;align-items:center;color:#1f2933ad;font-size:.58rem;line-height:1;text-transform:uppercase}.christianity-full-card-footer span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.christianity-floating-card-close{position:absolute;top:.65rem;right:.65rem;z-index:62;min-height:2rem;padding:0 .6rem;border:1px solid rgba(36,48,68,.14);border-radius:999px;background:#ffffffe6;color:#1f2933c7;font:inherit;font-size:.76rem;font-weight:800;box-shadow:0 .45rem 1rem #102a431a}.christianity-preview-backdrop,.christianity-history-backdrop{position:fixed;inset:0;border:0;border-radius:0;background:#0f172a75}.christianity-preview-backdrop{z-index:60}.christianity-floating-card>small,.christianity-floating-card>span{color:#1f2933a3}.christianity-floating-card>strong{font-size:clamp(1.55rem,8vw,2.35rem);line-height:1.05}.christianity-floating-card>p{margin:0;align-self:end;font-size:.95rem;line-height:1.35}.christianity-floating-card-actions{display:flex;justify-content:center;padding:0 .35rem}.christianity-floating-card-actions button{min-height:2.35rem;padding:0 1rem;border:0;border-radius:999px;background:#102a43;color:#fff;font:inherit;font-size:.9rem;font-weight:800;box-shadow:0 .65rem 1.3rem #102a432e}.christianity-floating-card-actions button:disabled{cursor:not-allowed;opacity:.45}@media (min-width: 52rem){.christianity-floating-card-shell{width:min(29rem,calc(100vw - 3rem))}.christianity-floating-card{min-height:min(35rem,calc(100vh - 4rem));padding:1.35rem}}.christianity-history-backdrop{z-index:40}.christianity-history-drawer{position:fixed;right:auto;bottom:max(.5rem,env(safe-area-inset-bottom));left:50%;z-index:41;display:grid;grid-template-rows:auto minmax(0,1fr);gap:.75rem;width:min(calc(100vw - 1rem),44rem);min-height:min(18rem,calc(100dvh - 1rem));max-height:min(32rem,calc(100dvh - 2rem));padding:.8rem;border:1px solid rgba(36,48,68,.16);border-radius:.75rem;background:#fffffffa;box-shadow:0 1.5rem 4rem #102a4347;transform:translate(-50%)}.christianity-history-drawer header{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.christianity-history-drawer h2,.christianity-history-drawer p{margin:0}.christianity-history-drawer header span{display:grid;place-items:center;min-width:1.85rem;height:1.85rem;border-radius:999px;background:#edf2f7;font-weight:800}.christianity-dialog-actions{display:flex;align-items:center;gap:.45rem}.christianity-dialog-close{min-height:1.85rem;padding:0 .62rem;border:1px solid rgba(36,48,68,.14);border-radius:999px;background:#fff;color:#1f2933c7;font:inherit;font-size:.76rem;font-weight:800;box-shadow:0 .35rem .8rem #102a4314}.christianity-history-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(5.4rem,1fr));gap:.55rem;min-height:0;overflow-y:scroll;scrollbar-color:rgba(36,48,68,.32) rgba(226,232,240,.72);scrollbar-gutter:stable;padding:.1rem .1rem .25rem}.christianity-history-grid::-webkit-scrollbar,.christianity-offering-list::-webkit-scrollbar{width:.65rem}.christianity-history-grid::-webkit-scrollbar-track,.christianity-offering-list::-webkit-scrollbar-track{border-radius:999px;background:#e2e8f0b8}.christianity-history-grid::-webkit-scrollbar-thumb,.christianity-offering-list::-webkit-scrollbar-thumb{border:.14rem solid rgba(226,232,240,.72);border-radius:999px;background:#24304452}.christianity-offerings-drawer{width:min(calc(100vw - 1rem),48rem);min-height:min(20rem,calc(100dvh - 1rem));max-height:min(34rem,calc(100dvh - 2rem))}.christianity-offering-list{display:grid;gap:.6rem;min-height:0;overflow-y:scroll;scrollbar-color:rgba(36,48,68,.32) rgba(226,232,240,.72);scrollbar-gutter:stable;padding:.1rem}.christianity-offering-row{display:grid;grid-template-columns:minmax(4.9rem,6.2rem) minmax(0,1fr);gap:.65rem;align-items:stretch;padding:.45rem;border:1px solid rgba(36,48,68,.12);border-radius:.65rem;background:#fff}.christianity-offering-row.is-exhausted{opacity:.68}.christianity-offering-card{min-height:7.4rem;background:linear-gradient(180deg,#fffffff5,#f8fafcf5),radial-gradient(circle at 82% 14%,#facc15 0 .48rem,transparent .5rem);box-shadow:0 .45rem 1rem #102a431a}.christianity-offering-card small{color:#1f293394;font-size:.66rem;text-transform:uppercase}.christianity-offering-card p,.christianity-offering-row p{margin:0}.christianity-offering-card p{align-self:end;color:#1f2933a3;font-size:.72rem;line-height:1.2}.christianity-offering-row>div{display:grid;gap:.35rem;align-content:center;min-width:0}.christianity-offering-row>div p{color:#1f2933b8;font-size:.85rem;line-height:1.3}.christianity-offering-row>div button{justify-self:start;min-height:2.2rem;padding:0 .7rem;border:1px solid rgba(16,42,67,.16);border-radius:.5rem;background:#102a43;color:#fff;font:inherit;font-weight:800}.christianity-offering-row>div button:disabled{background:#e2e8f0;color:#1f293394}button{cursor:pointer}button:disabled{cursor:not-allowed;opacity:.55}button:focus-visible{outline:.1875rem solid color-mix(in srgb,var(--christianity-theme-focus) 24%,transparent);outline-offset:.125rem}@media (max-width: 720px){.christianity-shell{padding:.55rem 0;border-right:0;border-left:0;border-radius:0}.christianity-header,.christianity-player__summary,.christianity-shared-zone,.christianity-actions{align-items:stretch;flex-direction:column}.christianity-match-strip{grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.35rem;padding:.35rem}.christianity-match-player{gap:.35rem}.christianity-match-player small{display:none}.christianity-scoreboard{min-width:3.65rem;padding:0 .35rem}.christianity-scoreboard strong{font-size:1.05rem}.christianity-table{gap:.35rem}.christianity-player-side{padding:.3rem .25rem}.christianity-battle-zone{--christianity-battle-card-width: clamp(4.4rem, 20vw, 5.8rem);grid-template-columns:repeat(4,var(--christianity-battle-card-width));justify-content:center;overflow-x:auto}.christianity-hand-fan{min-height:10.55rem;padding-bottom:2rem;overflow:visible}.christianity-hand-shelf{min-height:11.75rem;margin-top:-1rem;padding-top:1.35rem;padding-bottom:.9rem}.christianity-hand-shelf--opponent{min-height:6.65rem;margin-top:0;margin-bottom:0;padding-top:.4rem;padding-bottom:.85rem}.christianity-player-rack{grid-template-columns:minmax(4.7rem,5.9rem) minmax(4.8rem,1fr) minmax(3.7rem,5rem)}.christianity-shared-zone{grid-template-columns:repeat(3,minmax(3.7rem,1fr))}.christianity-zone-card,.christianity-zone-pile{min-height:6.15rem;padding:.58rem .46rem .5rem}.christianity-offering-pile{min-height:6.85rem;padding:.88rem .46rem .55rem}.christianity-card-preview-card{width:clamp(4.2rem,20vw,5.7rem);min-height:clamp(5.8rem,26vw,7.4rem)}.christianity-leader-card{width:clamp(4.55rem,20vw,5.7rem);min-height:clamp(6.15rem,27vw,7.6rem)}.christianity-offering-row{grid-template-columns:minmax(4.5rem,5.5rem) minmax(0,1fr);gap:.5rem}.christianity-hand-fan--opponent{min-height:5.75rem;padding-bottom:.7rem}}\n"], dependencies: [{ kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: LightRippleDirective, selector: "[valLightRipple]" }] }); }
69829
+ }
69830
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ChristianityGameComponent, decorators: [{
69831
+ type: Component,
69832
+ args: [{ selector: 'val-christianity-game', standalone: true, imports: [CdkDrag, CdkDropList, LightRippleDirective], template: `
69833
+ <main class="christianity-shell">
69834
+ <section class="christianity-header">
69835
+ <div>
69836
+ <p>{{ t('christianityEyebrow') }}</p>
69837
+ <h1>{{ t('christianityTitle') }}</h1>
69838
+ </div>
69839
+ <div class="christianity-turn" [class.is-own-turn]="isOwnTurn()">
69840
+ <span>{{ t('christianityTurn') }}</span>
69841
+ <strong>{{ currentPlayer().displayName }}</strong>
69842
+ </div>
69843
+ </section>
69844
+
69845
+ <section class="christianity-match-strip" [attr.aria-label]="t('christianityMatchScore')">
69846
+ <article class="christianity-match-player">
69847
+ <span class="christianity-avatar" [style.background]="player().avatarColor">{{ player().avatar }}</span>
69848
+ <div>
69849
+ <strong>{{ player().displayName }}</strong>
69850
+ <small>{{ player().leaderName }} · {{ player().leaderHp }}/{{ player().leaderMaxHp }}</small>
69851
+ </div>
69852
+ </article>
69853
+ <div class="christianity-scoreboard">
69854
+ <span>{{ t('christianityMatch') }}</span>
69855
+ <strong>{{ game().matchScore.P1 }}-{{ game().matchScore.P2 }}</strong>
69856
+ </div>
69857
+ <article class="christianity-match-player christianity-match-player--opponent">
69858
+ <span class="christianity-avatar" [style.background]="opponent().avatarColor">{{ opponent().avatar }}</span>
69859
+ <div>
69860
+ <strong>{{ opponent().displayName }}</strong>
69861
+ <small>{{ opponent().leaderName }} · {{ opponent().leaderHp }}/{{ opponent().leaderMaxHp }}</small>
69862
+ </div>
69863
+ </article>
69864
+ </section>
69865
+
69866
+ <section class="christianity-hand-shelf christianity-hand-shelf--opponent">
69867
+ <div class="christianity-hand-meter christianity-hand-meter--opponent">
69868
+ <span>{{ t('christianityHand') }}</span>
69869
+ <strong>{{ opponentHandCount() }}</strong>
69870
+ </div>
69871
+ <section class="christianity-hand-fan christianity-hand-fan--opponent" [attr.aria-label]="t('christianityOpponentHand')">
69872
+ @for (_ of hiddenHandCards(opponentHandCount()); track $index) {
69873
+ <button
69874
+ type="button"
69875
+ class="christianity-card-preview-card christianity-card-preview-card--back"
69876
+ valLightRipple
69877
+ [style.transform]="fanTransform($index, opponentHandCount(), true)"
69878
+ [attr.aria-label]="t('christianityHiddenCard')"
69879
+ ></button>
69880
+ }
69881
+ </section>
69882
+ </section>
69883
+
69884
+ <section class="christianity-table" [attr.aria-label]="t('christianityTable')">
69885
+ <section class="christianity-player-side christianity-player-side--opponent">
69886
+ <section class="christianity-player-rack christianity-player-rack--opponent">
69887
+ <div class="christianity-offerings-zone">
69888
+ <button type="button" class="christianity-offering-pile" valLightRipple (click)="openOfferings('P2')">
69889
+ <i aria-hidden="true"></i>
69890
+ <i aria-hidden="true"></i>
69891
+ <i aria-hidden="true"></i>
69892
+ <span>{{ t('christianityOfferings') }}</span>
69893
+ <strong>{{ readyOfferings(opponent()) }}/{{ totalOfferings(opponent()) }}</strong>
69894
+ </button>
69895
+ </div>
69896
+ <button type="button" class="christianity-leader-card" valLightRipple [class.is-target]="selectedAttacker() && !hasOpponentGuards()" (click)="handleOpponentLeader()">
69897
+ <span>{{ opponent().leaderName }}</span>
69898
+ <strong>{{ opponent().leaderHp }}/{{ opponent().leaderMaxHp }}</strong>
69899
+ </button>
69900
+ <span class="christianity-rack-spacer" aria-hidden="true"></span>
69901
+ </section>
69902
+
69903
+ <section class="christianity-battle-zone christianity-battle-zone--opponent" [attr.aria-label]="t('christianityOpponentBattle')">
69904
+ @for (slot of battleSlots('P2'); track slot.trackId) {
69905
+ @if (slot.card) {
69906
+ <button
69907
+ type="button"
69908
+ class="christianity-card-preview-card christianity-card-preview-card--battle"
69909
+ valLightRipple
69910
+ [class.is-target]="selectedAttacker()"
69911
+ (click)="handleOpponentCharacter(slot.card)"
69912
+ >
69913
+ <span>{{ slot.card.name }}</span>
69914
+ <strong>{{ slot.card.attack }} / {{ slot.card.currentHp }}</strong>
69915
+ </button>
69916
+ } @else {
69917
+ <span class="christianity-slot"></span>
69918
+ }
69919
+ }
69920
+ </section>
69921
+ </section>
69922
+
69923
+ <section class="christianity-shared-zone" [attr.aria-label]="t('christianitySharedZone')">
69924
+ <button type="button" class="christianity-zone-pile christianity-zone-pile--history" valLightRipple (click)="showHistory.set(true)">
69925
+ <i aria-hidden="true"></i>
69926
+ <i aria-hidden="true"></i>
69927
+ <i aria-hidden="true"></i>
69928
+ <span>{{ t('christianityHistory') }}</span>
69929
+ <strong>{{ game().historyZone.length }}</strong>
69930
+ </button>
69931
+ <button type="button" class="christianity-zone-pile christianity-zone-pile--deck" valLightRipple aria-live="polite" (click)="inspectDeck()">
69932
+ <i aria-hidden="true"></i>
69933
+ <i aria-hidden="true"></i>
69934
+ <i aria-hidden="true"></i>
69935
+ <span>{{ t('christianityDeck') }}</span>
69936
+ <strong>{{ game().sharedDeck.length }}</strong>
69937
+ </button>
69938
+ <div class="christianity-zone-card">
69939
+ <span>{{ t('christianityPlace') }}</span>
69940
+ <strong>{{ t('christianityEmpty') }}</strong>
69941
+ </div>
69942
+ </section>
69943
+
69944
+ <section class="christianity-player-side">
69945
+ <section class="christianity-battle-zone" [class.is-placing-card]="canPlaceSelectedCharacter() || isDraggingCharacter()" [attr.aria-label]="t('christianityYourBattle')">
69946
+ @for (slot of battleSlots('P1'); track slot.trackId) {
69947
+ @if (slot.card) {
69948
+ <button
69949
+ type="button"
69950
+ class="christianity-card-preview-card christianity-card-preview-card--battle"
69951
+ valLightRipple
69952
+ [class.is-selected]="selectedAttacker()?.instanceId === slot.card.instanceId"
69953
+ [class.is-exhausted]="!slot.card.canAttack"
69954
+ (click)="selectAttacker(slot.card)"
69955
+ >
69956
+ <span>{{ slot.card.name }}</span>
69957
+ <strong>{{ slot.card.attack }} / {{ slot.card.currentHp }}</strong>
69958
+ </button>
69959
+ } @else {
69960
+ <button
69961
+ type="button"
69962
+ class="christianity-slot"
69963
+ cdkDropList
69964
+ [id]="battleSlotDropId($index)"
69965
+ [cdkDropListData]="$index"
69966
+ [cdkDropListConnectedTo]="['christianity-hand-source']"
69967
+ [cdkDropListEnterPredicate]="canDropOnBattleSlot"
69968
+ [class.christianity-slot--play-target]="canPlaceSelectedCharacter() || isDraggingCharacter()"
69969
+ valLightRipple
69970
+ (cdkDropListDropped)="dropOnBattleSlot($event, $index)"
69971
+ (click)="playSelectedCard($index)"
69972
+ >
69973
+ @if (canPlaceSelectedCharacter() || isDraggingCharacter()) {
69974
+ <span>{{ t('christianityPlayHere') }}</span>
69975
+ }
69976
+ </button>
69977
+ }
69978
+ }
69979
+ </section>
69980
+
69981
+ <section class="christianity-player-rack">
69982
+ <div class="christianity-offerings-zone">
69983
+ <button
69984
+ type="button"
69985
+ class="christianity-offering-pile"
69986
+ cdkDropList
69987
+ id="christianity-offerings-drop"
69988
+ valLightRipple
69989
+ [cdkDropListConnectedTo]="['christianity-hand-source']"
69990
+ [class.is-play-target]="canPlaceSelectedOffering() || isDraggingOffering()"
69991
+ [cdkDropListEnterPredicate]="canDropOnOfferings"
69992
+ (cdkDropListDropped)="dropOnOfferings($event)"
69993
+ (click)="handleOfferingPile('P1')"
69994
+ >
69995
+ <i aria-hidden="true"></i>
69996
+ <i aria-hidden="true"></i>
69997
+ <i aria-hidden="true"></i>
69998
+ <span>{{ t('christianityOfferings') }}</span>
69999
+ <strong>{{ readyOfferings(player()) }}/{{ totalOfferings(player()) }}</strong>
70000
+ </button>
70001
+ </div>
70002
+ <button type="button" class="christianity-leader-card" valLightRipple (click)="inspectLeader('P1')">
70003
+ <span>{{ player().leaderName }}</span>
70004
+ <strong>{{ player().leaderHp }}/{{ player().leaderMaxHp }}</strong>
70005
+ </button>
70006
+ <div class="christianity-player-command">
70007
+ <div class="christianity-player-badge">
70008
+ <span class="christianity-avatar" [style.background]="player().avatarColor">{{ player().avatar }}</span>
70009
+ <strong>{{ player().displayName }}</strong>
70010
+ </div>
70011
+ <button
70012
+ type="button"
70013
+ class="christianity-end-turn"
70014
+ (click)="endTurn()"
70015
+ >
70016
+ {{ t('christianityEndTurn') }}
70017
+ </button>
70018
+ </div>
70019
+ </section>
70020
+ </section>
70021
+ </section>
70022
+
70023
+ <section class="christianity-hand-shelf">
70024
+ <div class="christianity-hand-meter">
70025
+ <span>{{ t('christianityHand') }}</span>
70026
+ <strong>{{ player().hand?.length ?? 0 }}</strong>
70027
+ </div>
70028
+ <section
70029
+ class="christianity-hand-fan"
70030
+ cdkDropList
70031
+ id="christianity-hand-source"
70032
+ [cdkDropListConnectedTo]="dropTargetIds()"
70033
+ [attr.aria-label]="t('christianityYourHand')"
70034
+ (pointerleave)="clearHoveredHandIndex()"
70035
+ >
70036
+ @for (cardId of player().hand ?? []; track cardId + $index) {
70037
+ @let card = cardDefinition(cardId);
70038
+ <div
70039
+ class="christianity-hand-card-wrap"
70040
+ [class.is-selected]="selectedHandCard() === cardId"
70041
+ [class.is-dragging]="draggingCardId() === cardId"
70042
+ [style.z-index]="handCardZIndex($index)"
70043
+ [style.transform]="fanTransform($index, player().hand?.length ?? 0, false)"
70044
+ (pointerenter)="setHoveredHandIndex($index)"
70045
+ (pointerdown)="setHoveredHandIndex($index)"
70046
+ (pointerup)="releaseHoveredHand($event)"
70047
+ >
70048
+ <button
70049
+ type="button"
70050
+ class="christianity-card-preview-card christianity-card-preview-card--hand"
70051
+ cdkDrag
70052
+ valLightRipple
70053
+ [cdkDragData]="cardId"
70054
+ [cdkDragDisabled]="!canPlay(card)"
70055
+ [class.is-selected]="selectedHandCard() === cardId"
70056
+ [class.is-disabled]="!canPlay(card)"
70057
+ (cdkDragStarted)="startDraggingCard(cardId)"
70058
+ (cdkDragEnded)="endDraggingCard()"
70059
+ (click)="selectHandCard(cardId)"
70060
+ >
70061
+ <small>
70062
+ @if (card.type === 'offering') {
70063
+ {{ t('christianityOfferingCard') }}
70064
+ } @else {
70065
+ {{ t('christianityCost') }} {{ card.cost }}
70066
+ }
70067
+ </small>
70068
+ <span>{{ card.name }}</span>
70069
+ <strong>
70070
+ @if (card.type === 'offering') {
70071
+ +{{ card.life }}
70072
+ } @else {
70073
+ {{ card.attack }} / {{ card.life }}
70074
+ }
70075
+ </strong>
70076
+ </button>
70077
+ <button
70078
+ type="button"
70079
+ class="christianity-card-eye"
70080
+ [attr.aria-label]="t('christianityPreviewCard')"
70081
+ (click)="inspectHandCard(cardId, true); $event.stopPropagation()"
70082
+ ></button>
70083
+ </div>
70084
+ }
70085
+ </section>
70086
+ </section>
70087
+
70088
+ @if (selectedPreview()) {
70089
+ <button type="button" class="christianity-preview-backdrop" [attr.aria-label]="t('christianityClosePreview')" (click)="closePreview()"></button>
70090
+ <aside
70091
+ class="christianity-floating-card-shell"
70092
+ aria-live="polite"
70093
+ >
70094
+ <button type="button" class="christianity-floating-card-close" (click)="closePreview()">
70095
+ {{ t('close') }}
70096
+ </button>
70097
+ <div
70098
+ class="christianity-floating-card"
70099
+ [style.--preview-rotate-x]="previewTilt().rotateX + 'deg'"
70100
+ [style.--preview-rotate-y]="previewTilt().rotateY + 'deg'"
70101
+ [style.--preview-shift-x]="previewTilt().shiftX + 'px'"
70102
+ [style.--preview-shift-y]="previewTilt().shiftY + 'px'"
70103
+ (pointermove)="tiltPreview($event)"
70104
+ (pointerleave)="resetPreviewTilt()"
70105
+ >
70106
+ @if (selectedPreviewCard(); as previewCard) {
70107
+ <header class="christianity-full-card-header">
70108
+ <span class="christianity-full-card-type-icon" aria-hidden="true"></span>
70109
+ <strong>{{ previewCard.name }}</strong>
70110
+ <span class="christianity-full-card-cost">{{ previewCard.type === 'offering' ? '+' + previewCard.life : previewCard.cost }}</span>
70111
+ </header>
70112
+ <section class="christianity-full-card-art" [class.has-image]="previewCard.imageUrl">
70113
+ @if (previewCard.imageUrl) {
70114
+ <img [src]="previewCard.imageUrl" [alt]="previewCard.name" />
70115
+ } @else {
70116
+ <span>{{ previewCard.name }}</span>
70117
+ }
70118
+ <small>{{ cardTypeLabel(previewCard) }}</small>
70119
+ </section>
70120
+ <section class="christianity-full-card-verse">
70121
+ <p>{{ previewCard.verseText ?? selectedPreview()?.body }}</p>
70122
+ @if (previewCard.scripture) {
70123
+ <strong>{{ previewCard.scripture }}</strong>
70124
+ }
70125
+ </section>
70126
+ <section class="christianity-full-card-effect">
70127
+ <div class="christianity-full-card-stats">
70128
+ @if (previewCard.type === 'character') {
70129
+ <strong>{{ previewCard.attack }}</strong>
70130
+ <strong>{{ previewCard.life }}</strong>
70131
+ } @else {
70132
+ <strong>+{{ previewCard.life }}</strong>
70133
+ }
70134
+ </div>
70135
+ <div>
70136
+ @if (previewCard.abilityName) {
70137
+ <strong>{{ previewCard.abilityName }}</strong>
70138
+ }
70139
+ <p>{{ previewCard.abilityText ?? selectedPreview()?.body }}</p>
70140
+ </div>
70141
+ <span
70142
+ class="christianity-full-card-rarity"
70143
+ [class.is-normal]="!previewCard.rarity || previewCard.rarity === 'normal'"
70144
+ [class.is-uncommon]="previewCard.rarity === 'uncommon'"
70145
+ [class.is-rare]="previewCard.rarity === 'rare'"
70146
+ [class.is-legendary]="previewCard.rarity === 'legendary'"
70147
+ aria-hidden="true"
70148
+ ></span>
70149
+ </section>
70150
+ <footer class="christianity-full-card-footer">
70151
+ <span>{{ previewCard.edition ?? 'MVP' }}</span>
70152
+ <span>{{ previewCard.collectorNumber ?? previewCard.id }}</span>
70153
+ <span>{{ previewCard.year ?? '2026' }} CHRISTIANITY</span>
70154
+ <span>{{ previewCard.author ?? 'MVP' }}</span>
70155
+ </footer>
70156
+ } @else {
70157
+ <small>{{ selectedPreview()?.eyebrow }}</small>
70158
+ <strong>{{ selectedPreview()?.title }}</strong>
70159
+ <span>{{ selectedPreview()?.meta }}</span>
70160
+ <p>{{ selectedPreview()?.body }}</p>
70161
+ }
70162
+ </div>
70163
+ @if (selectedPreview()?.source === 'hand') {
70164
+ <div class="christianity-floating-card-actions">
70165
+ <button type="button" [disabled]="previewActionDisabled()" (click)="playPreviewCard()">
70166
+ {{ selectedActionLabel() }}
70167
+ </button>
70168
+ </div>
70169
+ }
70170
+ </aside>
70171
+ }
70172
+
70173
+ <section class="christianity-actions" aria-live="polite">
70174
+ <p>{{ statusText() }}</p>
70175
+ <div>
70176
+ <button type="button" [disabled]="selectedActionDisabled()" (click)="playSelectedCard()">
70177
+ {{ selectedActionLabel() }}
70178
+ </button>
70179
+ <button type="button" (click)="resetMock()">
70180
+ {{ t('christianityReset') }}
70181
+ </button>
70182
+ </div>
70183
+ </section>
70184
+
70185
+ @if (showHistory()) {
70186
+ <button type="button" class="christianity-history-backdrop" [attr.aria-label]="t('christianityCloseHistory')" (click)="showHistory.set(false)"></button>
70187
+ <section class="christianity-history-drawer">
70188
+ <header>
70189
+ <h2>{{ t('christianityHistory') }}</h2>
70190
+ <div class="christianity-dialog-actions">
70191
+ <span>{{ game().historyZone.length }}</span>
70192
+ <button type="button" class="christianity-dialog-close" (click)="showHistory.set(false)">
70193
+ {{ t('close') }}
70194
+ </button>
70195
+ </div>
70196
+ </header>
70197
+ @if (game().historyZone.length) {
70198
+ <div class="christianity-history-grid">
70199
+ @for (cardId of game().historyZone; track cardId + $index) {
70200
+ @let card = cardDefinition(cardId);
70201
+ <button type="button" class="christianity-card-preview-card" valLightRipple (click)="inspectHistoryCard(cardId)">
70202
+ <small>{{ card.type === 'offering' ? t('christianityOfferingCard') : t('christianityCharacterCard') }}</small>
70203
+ <span>{{ card.name }}</span>
70204
+ <strong>
70205
+ @if (card.type === 'offering') {
70206
+ +{{ card.life }}
70207
+ } @else {
70208
+ {{ card.attack }} / {{ card.life }}
70209
+ }
70210
+ </strong>
70211
+ </button>
70212
+ }
70213
+ </div>
70214
+ } @else {
70215
+ <p>{{ t('christianityHistoryEmpty') }}</p>
70216
+ }
70217
+ </section>
70218
+ }
70219
+
70220
+ @if (offeringsSeat()) {
70221
+ @let offeringPlayer = game().players[offeringsSeat()!];
70222
+ <button type="button" class="christianity-history-backdrop" [attr.aria-label]="t('christianityCloseOfferings')" (click)="closeOfferings()"></button>
70223
+ <section class="christianity-history-drawer christianity-offerings-drawer">
70224
+ <header>
70225
+ <h2>{{ t('christianityOfferings') }}</h2>
70226
+ <div class="christianity-dialog-actions">
70227
+ <span>{{ readyOfferings(offeringPlayer) }}/{{ totalOfferings(offeringPlayer) }}</span>
70228
+ <button type="button" class="christianity-dialog-close" (click)="closeOfferings()">
70229
+ {{ t('close') }}
70230
+ </button>
70231
+ </div>
70232
+ </header>
70233
+ <div class="christianity-offering-list">
70234
+ @for (offering of offeringPlayer.offerings; track offering.instanceId) {
70235
+ <article class="christianity-offering-row" [class.is-exhausted]="!offering.ready">
70236
+ <button type="button" class="christianity-offering-card" valLightRipple (click)="inspectOffering(offering)">
70237
+ <small>{{ t('christianityOfferingCard') }}</small>
70238
+ <span>{{ offering.name }}</span>
70239
+ <strong>+{{ offering.value }}</strong>
70240
+ @if (offering.abilityName) {
70241
+ <p>{{ offering.abilityName }}</p>
70242
+ }
70243
+ </button>
70244
+ <div>
70245
+ <strong>{{ offering.ready ? t('christianityOfferingReady') : t('christianityOfferingExhausted') }}</strong>
70246
+ <p>{{ offering.abilityText || t('christianityOfferingNoAbility') }}</p>
70247
+ @if (offering.abilityName) {
70248
+ <button
70249
+ type="button"
70250
+ [disabled]="!canUseOfferingAbility(offering, offeringsSeat()!)"
70251
+ (click)="useOfferingAbility(offering, offeringsSeat()!)"
70252
+ >
70253
+ {{ t('christianityUseAbility') }}
70254
+ </button>
70255
+ }
70256
+ </div>
70257
+ </article>
70258
+ }
70259
+ </div>
70260
+ </section>
70261
+ }
70262
+ </main>
70263
+ `, styles: [":host{--christianity-theme-ink: var(--val-text-color, #1f2933);--christianity-theme-surface: #ffffff;--christianity-theme-parchment: #fffaf0;--christianity-theme-olive: #5f6f2a;--christianity-theme-gold: #d6a21d;--christianity-theme-gold-soft: rgba(214, 162, 29, .18);--christianity-theme-gold-ring: rgba(214, 162, 29, .48);--christianity-theme-glow: rgba(245, 199, 85, .32);--christianity-theme-focus: #2563eb;--christianity-theme-shadow: rgba(82, 64, 28, .18);--christianity-theme-shadow-strong: rgba(82, 64, 28, .3);display:block;color:var(--christianity-theme-ink)}.christianity-shell{display:grid;gap:.65rem;padding:.75rem .25rem;border:1px solid rgba(36,48,68,.12);border-radius:.75rem;background:#f6f8fb;overflow:visible}.christianity-header,.christianity-match-strip,.christianity-player__summary,.christianity-shared-zone,.christianity-actions{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.christianity-header h1,.christianity-header p,.christianity-match-player strong,.christianity-match-player small,.christianity-scoreboard span,.christianity-history h2,.christianity-actions p{margin:0}.christianity-header h1{font-size:1.35rem;line-height:1.1}.christianity-header p,.christianity-turn span,.christianity-offerings span,.christianity-hidden-hand span,.christianity-deck span,.christianity-place span,.christianity-pile span,.christianity-leader span{color:#1f2933a3;font-size:.75rem}.christianity-turn,.christianity-leader,.christianity-offerings,.christianity-hidden-hand,.christianity-pile,.christianity-deck,.christianity-place{display:grid;gap:.15rem;min-width:5.25rem;padding:.55rem .65rem;border:1px solid rgba(36,48,68,.12);border-radius:.5rem;background:#fff}.christianity-turn.is-own-turn{border-color:#12806c59;background:#ecfdf5}.christianity-match-strip{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);padding:.45rem;border:1px solid rgba(36,48,68,.1);border-radius:.75rem;background:#fff}.christianity-match-player{display:grid;grid-template-columns:auto minmax(0,1fr);gap:.5rem;align-items:center;min-width:0}.christianity-match-player--opponent{direction:rtl}.christianity-match-player--opponent div{direction:ltr;text-align:right}.christianity-match-player div{display:grid;min-width:0}.christianity-match-player strong,.christianity-match-player small{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.christianity-match-player small,.christianity-scoreboard span{color:#1f293394;font-size:.72rem}.christianity-scoreboard{display:grid;justify-items:center;min-width:4.2rem;padding:0 .55rem;border-right:1px solid rgba(36,48,68,.1);border-left:1px solid rgba(36,48,68,.1)}.christianity-scoreboard strong{font-size:1.2rem;line-height:1}.christianity-table{display:grid;gap:.45rem;padding:.45rem .35rem;border-radius:.75rem;background:#dceafb;overflow:visible}.christianity-player-side{display:grid;gap:.35rem;padding:.35rem .3rem;border-radius:.7rem;background:#ffffff57;grid-template-rows:minmax(7rem,1fr) auto;min-height:13.75rem}.christianity-player-side--opponent{grid-template-rows:auto minmax(7rem,1fr)}.christianity-player{display:grid;gap:.65rem}.christianity-battle-zone{--christianity-battle-card-width: clamp(4.8rem, 15vw, 6.6rem);display:grid;grid-template-columns:repeat(4,var(--christianity-battle-card-width));gap:.5rem;align-items:center;justify-content:center;min-height:clamp(7.8rem,25vw,9.6rem);padding:.55rem .4rem;border-radius:.75rem;background:#ffffffc2;transition:background .16s ease,box-shadow .16s ease}.christianity-battle-zone.is-placing-card{background:linear-gradient(180deg,#fffaf0f5,#ffffffd6),#ffffffc2;box-shadow:inset 0 0 0 .14rem var(--christianity-theme-gold-soft),0 .8rem 1.7rem #5f6f2a1f}.christianity-shared-zone{padding:.55rem .4rem;border-radius:.75rem;background:#ffffffe6}.christianity-card,.christianity-end-turn,.christianity-actions button,.christianity-pile,.christianity-leader--target{border:1px solid rgba(36,48,68,.16);border-radius:.5rem;background:#fff;color:inherit;font:inherit}.christianity-card{display:grid;align-content:space-between;min-height:5.8rem;padding:.5rem;text-align:left;box-shadow:0 .5rem 1.25rem #24304414}.christianity-card span{font-weight:700}.christianity-card strong{justify-self:end;padding:.15rem .35rem;border-radius:999px;background:#edf2f7;font-size:.8rem}.christianity-card.is-selected{border-color:var(--christianity-theme-gold);box-shadow:0 0 0 .18rem var(--christianity-theme-gold-soft),0 .85rem 1.4rem var(--christianity-theme-shadow)}.christianity-card.is-disabled,.christianity-card.is-exhausted{opacity:.55}.christianity-card.is-target{border-color:#dc2626}.christianity-offering-cards{display:grid;grid-auto-flow:column;grid-auto-columns:.7rem;gap:.16rem;align-items:end;min-height:1.05rem}.christianity-offering-cards i{display:block;width:.65rem;height:.95rem;border:1px solid rgba(16,42,67,.22);border-radius:.18rem;background:#f8fafc}.christianity-offering-cards i.is-used{background:#cbd5e1;transform:rotate(90deg);transform-origin:center}.christianity-slot{display:grid;place-items:center;justify-self:center;width:var(--christianity-battle-card-width);height:clamp(6.8rem,21vw,8.4rem);min-height:0;aspect-ratio:5 / 7;border:1px dashed rgba(36,48,68,.22);border-radius:.5rem;background:#ffffff73;color:inherit;font:inherit}.christianity-slot--play-target{position:relative;border-color:var(--christianity-theme-gold-ring);background:linear-gradient(180deg,#fffaf0eb,#f8fafcd1),#ffffffb3;color:#5d4305;font-weight:800;overflow:hidden;box-shadow:inset 0 0 0 .12rem #d6a21d33,0 .7rem 1.25rem var(--christianity-theme-shadow);animation:christianity-target-pulse 1.45s ease-in-out infinite}.christianity-slot--play-target:before{content:\"\";position:absolute;inset:.35rem;border:1px solid rgba(214,162,29,.22);border-radius:.4rem;background:linear-gradient(135deg,rgba(214,162,29,.1),transparent 46%),radial-gradient(circle at 50% 42%,var(--christianity-theme-glow),transparent 58%)}.christianity-slot--play-target span{position:relative;z-index:2;padding:.16rem .44rem;border-radius:999px;background:#ffffffc7;font-size:.78rem}@keyframes christianity-target-pulse{0%,to{box-shadow:inset 0 0 0 .12rem #d6a21d33,0 .7rem 1.25rem var(--christianity-theme-shadow)}50%{box-shadow:inset 0 0 0 .16rem #d6a21d57,0 .9rem 1.65rem var(--christianity-theme-shadow-strong)}}.christianity-hand{display:grid;grid-auto-columns:minmax(6rem,8rem);grid-auto-flow:column;gap:.55rem;overflow-x:auto;padding-bottom:.25rem}.christianity-actions{align-items:flex-start;padding:.75rem;border-radius:.75rem;background:#fff}.christianity-actions div{display:flex;flex-wrap:wrap;gap:.5rem;justify-content:flex-end}.christianity-actions button,.christianity-end-turn{min-height:2.4rem;padding:0 .75rem;font-weight:700}.christianity-actions button:not(:disabled),.christianity-end-turn{background:#102a43;color:#fff}.christianity-history{padding:.75rem;border-radius:.75rem;background:#fff}.christianity-hand-fan{position:relative;display:flex;justify-content:center;min-height:10.8rem;padding:.25rem .25rem 2.1rem;isolation:isolate;overflow:visible}.christianity-hand-shelf{position:relative;display:grid;z-index:12;min-height:12rem;margin-top:-1.15rem;padding:1.45rem .25rem 1rem;overflow:visible}.christianity-hand-shelf--opponent{z-index:8;min-height:6.85rem;margin-top:0;margin-bottom:0;padding:.45rem .25rem .85rem}.christianity-hand-fan--opponent{min-height:5.9rem;padding-bottom:.75rem;align-items:start}.christianity-card-preview-card,.christianity-card-mini,.christianity-offering-pile,.christianity-offering-card,.christianity-leader-card,.christianity-zone-card,.christianity-zone-pile,.christianity-end-turn{border:1px solid rgba(36,48,68,.16);border-radius:.5rem;background:#fff;color:inherit;font:inherit}.christianity-card-preview-card{display:grid;align-content:space-between;width:clamp(4.9rem,17vw,7.1rem);min-height:clamp(6.6rem,22vw,8.8rem);padding:.48rem;text-align:left;transform-origin:50% 115%;transition:transform .16s ease,box-shadow .16s ease,border-color .16s ease;box-shadow:0 .5rem 1.25rem #2430441a}.christianity-hand-card-wrap{position:relative;display:grid;justify-items:center;margin-inline:-.42rem;padding-bottom:2rem;transform-origin:50% 115%;transition:transform .16s ease,filter .16s ease}.christianity-hand-card-wrap:hover,.christianity-hand-card-wrap.is-selected,.christianity-hand-card-wrap.is-dragging{z-index:3}.christianity-hand-card-wrap:hover .christianity-card-preview-card--hand,.christianity-hand-card-wrap.is-selected .christianity-card-preview-card--hand,.christianity-hand-card-wrap.is-dragging .christianity-card-preview-card--hand{border-color:var(--christianity-theme-gold);box-shadow:0 0 0 .12rem var(--christianity-theme-gold-soft),0 1rem 2rem var(--christianity-theme-shadow)}.christianity-card-preview-card--hand{touch-action:none}.christianity-card-preview-card--hand.cdk-drag-disabled{cursor:not-allowed}.christianity-card-preview-card.cdk-drag-preview{border:1px solid var(--christianity-theme-gold-ring);box-shadow:0 0 0 .16rem #fff4c2ad,0 1.5rem 3rem var(--christianity-theme-shadow-strong);transform:rotate(2deg) scale(1.03)}.christianity-card-preview-card.cdk-drag-placeholder{opacity:.22}.christianity-slot.cdk-drop-list-dragging,.christianity-offering-pile.cdk-drop-list-dragging{border-color:var(--christianity-theme-gold-ring)}.christianity-slot.cdk-drop-list-receiving,.christianity-offering-pile.cdk-drop-list-receiving{box-shadow:inset 0 0 0 .18rem #d6a21d57,0 1rem 1.9rem var(--christianity-theme-shadow-strong)}.christianity-card-eye{position:absolute;right:50%;bottom:.38rem;width:2.15rem;height:1.55rem;border:1px solid rgba(214,162,29,.34);border-radius:999px;background:#fffffff0;box-shadow:0 .55rem 1.1rem #102a4324;opacity:0;transform:translate(50%,-.2rem) scale(.92);transition:opacity .14s ease,transform .14s ease,border-color .14s ease}.christianity-card-eye:before{content:\"\";position:absolute;top:50%;left:50%;width:1.1rem;height:1.1rem;border:.12rem solid var(--christianity-theme-olive);border-radius:82% 0;background:#fffaf0eb;transform:translate(-50%,-50%) rotate(45deg)}.christianity-card-eye:after{content:\"\";position:absolute;top:50%;left:50%;width:.42rem;height:.42rem;border:.09rem solid rgba(255,250,240,.95);border-radius:999px;background:radial-gradient(circle at 35% 32%,#ffffff 0 .06rem,transparent .07rem),var(--christianity-theme-gold);transform:translate(-50%,-50%)}.christianity-hand-card-wrap:hover .christianity-card-eye,.christianity-hand-card-wrap.is-selected .christianity-card-eye,.christianity-card-eye:focus-visible{opacity:1;transform:translate(50%) scale(1)}.christianity-offering-pile.is-play-target{border-color:var(--christianity-theme-gold-ring);background:linear-gradient(180deg,#fffaf0f5,#fffffff0),radial-gradient(circle at 82% 14%,rgba(250,204,21,.28) 0 .7rem,transparent .72rem);box-shadow:inset 0 0 0 .12rem #d6a21d3d,0 .8rem 1.55rem var(--christianity-theme-shadow);animation:christianity-target-pulse 1.45s ease-in-out infinite}.christianity-card-preview-card--back{width:clamp(4rem,14vw,5.7rem);min-height:clamp(5rem,16vw,6.6rem);box-shadow:0 .8rem 1.55rem #24304424;transform-origin:50% -18%;background:linear-gradient(135deg,#102a431f,#102a4305),repeating-linear-gradient(45deg,#e2e8f0 0 .35rem,#f8fafc .35rem .7rem)}.christianity-card-preview-card--battle{justify-self:center;width:var(--christianity-battle-card-width);min-width:0;height:clamp(6.8rem,21vw,8.4rem);min-height:0;aspect-ratio:5 / 7;margin-inline:0}.christianity-card-preview-card span,.christianity-card-mini span,.christianity-offering-pile span,.christianity-offering-card span,.christianity-leader-card span,.christianity-zone-card span,.christianity-zone-pile span{position:relative;z-index:2;font-weight:700}.christianity-card-preview-card strong,.christianity-card-mini strong,.christianity-offering-pile strong,.christianity-offering-card strong,.christianity-leader-card strong,.christianity-zone-card strong,.christianity-zone-pile strong{position:relative;z-index:3;justify-self:end;padding:.15rem .35rem;border-radius:999px;background:#edf2f7;font-size:.8rem}.christianity-player-rack{display:grid;grid-template-columns:minmax(5.9rem,7rem) minmax(5rem,1fr) minmax(4.2rem,7rem);gap:.45rem;align-items:end;justify-items:stretch}.christianity-player-rack--opponent{align-items:start}.christianity-hand-meter{position:absolute;top:0;right:.35rem;z-index:4;display:inline-grid;grid-auto-flow:column;gap:.25rem;align-items:center;min-height:1.7rem;padding:.18rem .46rem;border:1px solid rgba(36,48,68,.12);border-radius:999px;background:#ffffffe6;box-shadow:0 .35rem .8rem #102a4314}.christianity-hand-meter--opponent{top:.15rem}.christianity-hand-meter span{color:#1f293394;font-size:.68rem}.christianity-hand-meter strong{font-size:.86rem}.christianity-player-badge,.christianity-player-command{display:grid;gap:.35rem;justify-items:center;min-width:0}.christianity-player-badge{align-content:start;color:#1f2933c2;font-size:.74rem}.christianity-player-badge--opponent{justify-self:center;grid-auto-flow:column;align-items:center;justify-content:center}.christianity-player-badge strong{max-width:6.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.christianity-avatar{display:grid;place-items:center;width:1.85rem;height:1.85rem;border-radius:999px;color:#fff;font-size:.76rem;font-weight:800;box-shadow:0 .35rem .9rem #102a4329}.christianity-offerings-zone{display:flex;flex-wrap:wrap;gap:.25rem;justify-content:flex-start;justify-self:start;width:100%}.christianity-card-mini,.christianity-offering-pile,.christianity-offering-card,.christianity-leader-card,.christianity-zone-card,.christianity-zone-pile{display:grid;align-content:space-between;min-height:4.9rem;padding:.48rem;text-align:left}.christianity-card-mini{width:3.5rem}.christianity-offering-pile{position:relative;isolation:isolate;overflow:hidden;justify-self:start;width:min(100%,5.9rem);min-height:7.1rem;padding:.95rem .52rem .6rem;background:linear-gradient(180deg,#fff,#f8fafc),linear-gradient(135deg,rgba(250,204,21,.18),transparent 42%)}.christianity-offering-pile i{position:absolute;inset:auto auto 1.05rem .72rem;z-index:-1;width:2.55rem;height:3.55rem;border:1px solid rgba(16,42,67,.18);border-radius:.35rem;background:linear-gradient(180deg,#ffffffeb,#f1f5f9eb),radial-gradient(circle at 78% 18%,#facc15 0 .38rem,transparent .4rem);box-shadow:0 .35rem .85rem #102a431a;transform:rotate(-5deg)}.christianity-offering-pile i:nth-child(2){transform:translate(.28rem,.08rem) rotate(3deg)}.christianity-offering-pile i:nth-child(3){transform:translate(.55rem,.18rem) rotate(-1deg)}.christianity-leader-card{align-self:center;justify-self:center;width:clamp(4.75rem,17vw,6rem);min-height:clamp(6.6rem,22vw,8.4rem)}.christianity-rack-spacer{display:block;min-height:1px}.christianity-battle-zone{grid-template-columns:repeat(4,var(--christianity-battle-card-width))}.christianity-shared-zone{display:grid;grid-template-columns:repeat(3,minmax(4.3rem,1fr));align-items:stretch}.christianity-zone-card,.christianity-zone-pile{min-height:6.45rem;padding:.7rem .52rem .55rem}.christianity-zone-pile{position:relative;isolation:isolate;overflow:hidden;box-shadow:inset 0 0 0 999px #ffffff1f}.christianity-zone-pile i{position:absolute;inset:auto .72rem 1.02rem auto;z-index:-1;width:2.7rem;height:3.7rem;border:1px solid rgba(16,42,67,.18);border-radius:.35rem;background:#f8fafc;box-shadow:0 .35rem .85rem #102a431c;transform:rotate(4deg)}.christianity-zone-pile i:nth-child(2){transform:translate(-.28rem,.12rem) rotate(-3deg)}.christianity-zone-pile i:nth-child(3){background:linear-gradient(135deg,#102a4329,#102a4308),repeating-linear-gradient(45deg,#dbeafe 0 .33rem,#fff .33rem .66rem);transform:translate(-.54rem,.24rem) rotate(2deg)}.christianity-floating-card-shell{position:fixed;top:50%;left:50%;z-index:61;display:grid;gap:.75rem;width:min(26rem,calc(100vw - 1.25rem));transform:translate(-50%,-50%)}.christianity-floating-card{display:grid;grid-template-rows:auto minmax(9rem,1.25fr) auto minmax(7rem,.9fr) auto;gap:.58rem;width:100%;min-height:min(29rem,calc(100vh - 3.5rem));padding:.72rem;border:1px solid rgba(36,48,68,.18);border-radius:.75rem;background:linear-gradient(180deg,#fffffff5,#f8fafcf5),radial-gradient(circle at 20% 0%,var(--christianity-theme-gold-soft),transparent 45%);box-shadow:0 0 0 .18rem #fff4c294,0 0 2.2rem var(--christianity-theme-glow),0 2.4rem 5rem #102a4357,inset 0 0 0 .35rem #ffffff8c;touch-action:none;transform:translate(var(--preview-shift-x, 0px),var(--preview-shift-y, 0px)) perspective(48rem) rotateX(var(--preview-rotate-x, 5deg)) rotateY(var(--preview-rotate-y, -5deg));transition:transform 90ms ease-out}.christianity-full-card-header{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:.42rem;align-items:center}.christianity-full-card-header strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:clamp(1.25rem,5vw,1.85rem);line-height:1.04}.christianity-full-card-type-icon,.christianity-full-card-cost{display:grid;place-items:center;border-radius:999px}.christianity-full-card-type-icon{width:1.6rem;height:1.6rem;background:radial-gradient(circle at 50% 50%,rgba(95,111,42,.72) 0 .22rem,transparent .24rem),#2430441a}.christianity-full-card-cost{width:2.1rem;height:2.1rem;background:#ffd91a;color:#243044;font-size:1.35rem;font-weight:900;box-shadow:inset 0 -.12rem #52401c2e}.christianity-full-card-art{position:relative;display:grid;place-items:center;min-height:9rem;overflow:hidden;border-radius:.48rem;background:linear-gradient(135deg,#5f6f2a33,#d6a21d29),radial-gradient(circle at 50% 25%,rgba(255,255,255,.76),transparent 42%),#dbe7ef;box-shadow:inset 0 0 0 1px #24304414}.christianity-full-card-art img{width:100%;height:100%;object-fit:cover}.christianity-full-card-art>span{max-width:80%;color:#24304494;font-size:clamp(1.1rem,5vw,1.8rem);font-weight:900;line-height:1.05;text-align:center}.christianity-full-card-art small{position:absolute;right:0;bottom:.55rem;min-width:5rem;padding:.16rem .48rem;border-radius:999px 0 0 999px;background:#ffffffe6;box-shadow:0 .3rem .8rem #102a431f;color:#1f2933bd;font-size:.68rem;font-style:italic;font-weight:900;text-align:center;text-transform:uppercase}.christianity-full-card-verse,.christianity-full-card-effect{display:grid;gap:.32rem}.christianity-full-card-verse p,.christianity-full-card-effect p{margin:0;line-height:1.25}.christianity-full-card-verse{color:#171923;font-family:Georgia,Times New Roman,serif;font-size:clamp(.72rem,2.7vw,.86rem)}.christianity-full-card-verse strong{font-family:inherit;font-size:.78rem;font-weight:900}.christianity-full-card-effect{position:relative;align-content:start;min-height:7rem;padding:.6rem .7rem;overflow:hidden;border-radius:.45rem;background:radial-gradient(circle at 50% 72%,rgba(36,48,68,.07),transparent 34%),#ffffffdb}.christianity-full-card-stats{display:flex;gap:1rem;min-height:1.35rem}.christianity-full-card-stats strong{font-size:1rem;line-height:1}.christianity-full-card-effect>div:last-of-type{display:grid;gap:.12rem}.christianity-full-card-effect>div:last-of-type strong{font-size:.82rem}.christianity-full-card-effect p{font-size:clamp(.78rem,2.9vw,.92rem)}.christianity-full-card-rarity{position:absolute;top:.62rem;right:.62rem;width:.46rem;height:.46rem;border-radius:.12rem;transform:rotate(45deg)}.christianity-full-card-rarity.is-normal{background:#d1d5db}.christianity-full-card-rarity.is-uncommon{background:#22c55e}.christianity-full-card-rarity.is-rare{background:#3b82f6}.christianity-full-card-rarity.is-legendary{background:#eab308}.christianity-full-card-footer{display:grid;grid-template-columns:auto auto minmax(0,1fr) auto;gap:.34rem;align-items:center;color:#1f2933ad;font-size:.58rem;line-height:1;text-transform:uppercase}.christianity-full-card-footer span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.christianity-floating-card-close{position:absolute;top:.65rem;right:.65rem;z-index:62;min-height:2rem;padding:0 .6rem;border:1px solid rgba(36,48,68,.14);border-radius:999px;background:#ffffffe6;color:#1f2933c7;font:inherit;font-size:.76rem;font-weight:800;box-shadow:0 .45rem 1rem #102a431a}.christianity-preview-backdrop,.christianity-history-backdrop{position:fixed;inset:0;border:0;border-radius:0;background:#0f172a75}.christianity-preview-backdrop{z-index:60}.christianity-floating-card>small,.christianity-floating-card>span{color:#1f2933a3}.christianity-floating-card>strong{font-size:clamp(1.55rem,8vw,2.35rem);line-height:1.05}.christianity-floating-card>p{margin:0;align-self:end;font-size:.95rem;line-height:1.35}.christianity-floating-card-actions{display:flex;justify-content:center;padding:0 .35rem}.christianity-floating-card-actions button{min-height:2.35rem;padding:0 1rem;border:0;border-radius:999px;background:#102a43;color:#fff;font:inherit;font-size:.9rem;font-weight:800;box-shadow:0 .65rem 1.3rem #102a432e}.christianity-floating-card-actions button:disabled{cursor:not-allowed;opacity:.45}@media (min-width: 52rem){.christianity-floating-card-shell{width:min(29rem,calc(100vw - 3rem))}.christianity-floating-card{min-height:min(35rem,calc(100vh - 4rem));padding:1.35rem}}.christianity-history-backdrop{z-index:40}.christianity-history-drawer{position:fixed;right:auto;bottom:max(.5rem,env(safe-area-inset-bottom));left:50%;z-index:41;display:grid;grid-template-rows:auto minmax(0,1fr);gap:.75rem;width:min(calc(100vw - 1rem),44rem);min-height:min(18rem,calc(100dvh - 1rem));max-height:min(32rem,calc(100dvh - 2rem));padding:.8rem;border:1px solid rgba(36,48,68,.16);border-radius:.75rem;background:#fffffffa;box-shadow:0 1.5rem 4rem #102a4347;transform:translate(-50%)}.christianity-history-drawer header{display:flex;align-items:center;justify-content:space-between;gap:.75rem}.christianity-history-drawer h2,.christianity-history-drawer p{margin:0}.christianity-history-drawer header span{display:grid;place-items:center;min-width:1.85rem;height:1.85rem;border-radius:999px;background:#edf2f7;font-weight:800}.christianity-dialog-actions{display:flex;align-items:center;gap:.45rem}.christianity-dialog-close{min-height:1.85rem;padding:0 .62rem;border:1px solid rgba(36,48,68,.14);border-radius:999px;background:#fff;color:#1f2933c7;font:inherit;font-size:.76rem;font-weight:800;box-shadow:0 .35rem .8rem #102a4314}.christianity-history-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(5.4rem,1fr));gap:.55rem;min-height:0;overflow-y:scroll;scrollbar-color:rgba(36,48,68,.32) rgba(226,232,240,.72);scrollbar-gutter:stable;padding:.1rem .1rem .25rem}.christianity-history-grid::-webkit-scrollbar,.christianity-offering-list::-webkit-scrollbar{width:.65rem}.christianity-history-grid::-webkit-scrollbar-track,.christianity-offering-list::-webkit-scrollbar-track{border-radius:999px;background:#e2e8f0b8}.christianity-history-grid::-webkit-scrollbar-thumb,.christianity-offering-list::-webkit-scrollbar-thumb{border:.14rem solid rgba(226,232,240,.72);border-radius:999px;background:#24304452}.christianity-offerings-drawer{width:min(calc(100vw - 1rem),48rem);min-height:min(20rem,calc(100dvh - 1rem));max-height:min(34rem,calc(100dvh - 2rem))}.christianity-offering-list{display:grid;gap:.6rem;min-height:0;overflow-y:scroll;scrollbar-color:rgba(36,48,68,.32) rgba(226,232,240,.72);scrollbar-gutter:stable;padding:.1rem}.christianity-offering-row{display:grid;grid-template-columns:minmax(4.9rem,6.2rem) minmax(0,1fr);gap:.65rem;align-items:stretch;padding:.45rem;border:1px solid rgba(36,48,68,.12);border-radius:.65rem;background:#fff}.christianity-offering-row.is-exhausted{opacity:.68}.christianity-offering-card{min-height:7.4rem;background:linear-gradient(180deg,#fffffff5,#f8fafcf5),radial-gradient(circle at 82% 14%,#facc15 0 .48rem,transparent .5rem);box-shadow:0 .45rem 1rem #102a431a}.christianity-offering-card small{color:#1f293394;font-size:.66rem;text-transform:uppercase}.christianity-offering-card p,.christianity-offering-row p{margin:0}.christianity-offering-card p{align-self:end;color:#1f2933a3;font-size:.72rem;line-height:1.2}.christianity-offering-row>div{display:grid;gap:.35rem;align-content:center;min-width:0}.christianity-offering-row>div p{color:#1f2933b8;font-size:.85rem;line-height:1.3}.christianity-offering-row>div button{justify-self:start;min-height:2.2rem;padding:0 .7rem;border:1px solid rgba(16,42,67,.16);border-radius:.5rem;background:#102a43;color:#fff;font:inherit;font-weight:800}.christianity-offering-row>div button:disabled{background:#e2e8f0;color:#1f293394}button{cursor:pointer}button:disabled{cursor:not-allowed;opacity:.55}button:focus-visible{outline:.1875rem solid color-mix(in srgb,var(--christianity-theme-focus) 24%,transparent);outline-offset:.125rem}@media (max-width: 720px){.christianity-shell{padding:.55rem 0;border-right:0;border-left:0;border-radius:0}.christianity-header,.christianity-player__summary,.christianity-shared-zone,.christianity-actions{align-items:stretch;flex-direction:column}.christianity-match-strip{grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);gap:.35rem;padding:.35rem}.christianity-match-player{gap:.35rem}.christianity-match-player small{display:none}.christianity-scoreboard{min-width:3.65rem;padding:0 .35rem}.christianity-scoreboard strong{font-size:1.05rem}.christianity-table{gap:.35rem}.christianity-player-side{padding:.3rem .25rem}.christianity-battle-zone{--christianity-battle-card-width: clamp(4.4rem, 20vw, 5.8rem);grid-template-columns:repeat(4,var(--christianity-battle-card-width));justify-content:center;overflow-x:auto}.christianity-hand-fan{min-height:10.55rem;padding-bottom:2rem;overflow:visible}.christianity-hand-shelf{min-height:11.75rem;margin-top:-1rem;padding-top:1.35rem;padding-bottom:.9rem}.christianity-hand-shelf--opponent{min-height:6.65rem;margin-top:0;margin-bottom:0;padding-top:.4rem;padding-bottom:.85rem}.christianity-player-rack{grid-template-columns:minmax(4.7rem,5.9rem) minmax(4.8rem,1fr) minmax(3.7rem,5rem)}.christianity-shared-zone{grid-template-columns:repeat(3,minmax(3.7rem,1fr))}.christianity-zone-card,.christianity-zone-pile{min-height:6.15rem;padding:.58rem .46rem .5rem}.christianity-offering-pile{min-height:6.85rem;padding:.88rem .46rem .55rem}.christianity-card-preview-card{width:clamp(4.2rem,20vw,5.7rem);min-height:clamp(5.8rem,26vw,7.4rem)}.christianity-leader-card{width:clamp(4.55rem,20vw,5.7rem);min-height:clamp(6.15rem,27vw,7.6rem)}.christianity-offering-row{grid-template-columns:minmax(4.5rem,5.5rem) minmax(0,1fr);gap:.5rem}.christianity-hand-fan--opponent{min-height:5.75rem;padding-bottom:.7rem}}\n"] }]
70264
+ }], ctorParameters: () => [] });
70265
+
68443
70266
  addIcons({ refreshOutline, sparklesOutline, trophyOutline });
68444
70267
  const BUBBLE_COLORS = {
68445
70268
  rose: '#ff4f9f',
@@ -68496,6 +70319,7 @@ class BubbleBlitzGameComponent {
68496
70319
  this.animating = signal(false);
68497
70320
  this.leaderboard = signal(this.readLeaderboard());
68498
70321
  this.confirmAction = signal(undefined);
70322
+ this.confirmedAction = signal(undefined);
68499
70323
  this.config = computed(() => MODE_CONFIG[this.mode()]);
68500
70324
  this.feverReady = computed(() => this.fever() >= this.config().feverTarget);
68501
70325
  this.feverProgress = computed(() => Math.min(100, Math.round((this.fever() / this.config().feverTarget) * 100)));
@@ -68675,13 +70499,12 @@ class BubbleBlitzGameComponent {
68675
70499
  closeConfirmModal() {
68676
70500
  this.confirmAction.set(undefined);
68677
70501
  }
68678
- confirmPendingAction(token) {
68679
- if (token !== 'confirm') {
68680
- this.closeConfirmModal();
68681
- return;
68682
- }
68683
- const action = this.confirmAction();
70502
+ handleConfirmModalDismissed() {
68684
70503
  this.confirmAction.set(undefined);
70504
+ const action = this.confirmedAction();
70505
+ this.confirmedAction.set(undefined);
70506
+ if (!action)
70507
+ return;
68685
70508
  if (action === 'restart') {
68686
70509
  this.start();
68687
70510
  return;
@@ -68694,6 +70517,15 @@ class BubbleBlitzGameComponent {
68694
70517
  this.resetToGamesMenu();
68695
70518
  }
68696
70519
  }
70520
+ confirmPendingAction(token) {
70521
+ if (token !== 'confirm') {
70522
+ this.closeConfirmModal();
70523
+ return;
70524
+ }
70525
+ const action = this.confirmAction();
70526
+ this.confirmedAction.set(action);
70527
+ this.confirmAction.set(undefined);
70528
+ }
68697
70529
  startTimer() {
68698
70530
  this.stopTimer();
68699
70531
  this.timer = window.setInterval(() => {
@@ -68997,7 +70829,7 @@ class BubbleBlitzGameComponent {
68997
70829
  <ion-modal
68998
70830
  [isOpen]="!!confirmAction()"
68999
70831
  cssClass="val-modal-adaptive"
69000
- (didDismiss)="closeConfirmModal()"
70832
+ (didDismiss)="handleConfirmModalDismissed()"
69001
70833
  >
69002
70834
  <ng-template>
69003
70835
  <val-modal-layout
@@ -69147,7 +70979,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
69147
70979
  <ion-modal
69148
70980
  [isOpen]="!!confirmAction()"
69149
70981
  cssClass="val-modal-adaptive"
69150
- (didDismiss)="closeConfirmModal()"
70982
+ (didDismiss)="handleConfirmModalDismissed()"
69151
70983
  >
69152
70984
  <ng-template>
69153
70985
  <val-modal-layout
@@ -69211,6 +71043,7 @@ class MemoryGameComponent {
69211
71043
  this.lockBoard = signal(false);
69212
71044
  this.leaderboard = signal(this.readLeaderboard());
69213
71045
  this.confirmAction = signal(undefined);
71046
+ this.confirmedAction = signal(undefined);
69214
71047
  this.profileConfig = computed(() => PROFILE_CONFIG[this.profile()]);
69215
71048
  this.pairCount = computed(() => this.profileConfig().pairs);
69216
71049
  this.boardClass = computed(() => `memory-board ${this.profileConfig().boardClass}`);
@@ -69348,13 +71181,12 @@ class MemoryGameComponent {
69348
71181
  closeConfirmModal() {
69349
71182
  this.confirmAction.set(undefined);
69350
71183
  }
69351
- confirmPendingAction(token) {
69352
- if (token !== 'confirm') {
69353
- this.closeConfirmModal();
69354
- return;
69355
- }
69356
- const action = this.confirmAction();
71184
+ handleConfirmModalDismissed() {
69357
71185
  this.confirmAction.set(undefined);
71186
+ const action = this.confirmedAction();
71187
+ this.confirmedAction.set(undefined);
71188
+ if (!action)
71189
+ return;
69358
71190
  if (action === 'restart') {
69359
71191
  this.start();
69360
71192
  return;
@@ -69367,6 +71199,15 @@ class MemoryGameComponent {
69367
71199
  this.resetToGamesMenu();
69368
71200
  }
69369
71201
  }
71202
+ confirmPendingAction(token) {
71203
+ if (token !== 'confirm') {
71204
+ this.closeConfirmModal();
71205
+ return;
71206
+ }
71207
+ const action = this.confirmAction();
71208
+ this.confirmedAction.set(action);
71209
+ this.confirmAction.set(undefined);
71210
+ }
69370
71211
  flip(card) {
69371
71212
  if (this.lockBoard() || card.flipped || card.matched || this.won() || this.failed())
69372
71213
  return;
@@ -69681,7 +71522,7 @@ class MemoryGameComponent {
69681
71522
  <ion-modal
69682
71523
  [isOpen]="!!confirmAction()"
69683
71524
  cssClass="val-modal-adaptive"
69684
- (didDismiss)="closeConfirmModal()"
71525
+ (didDismiss)="handleConfirmModalDismissed()"
69685
71526
  >
69686
71527
  <ng-template>
69687
71528
  <val-modal-layout
@@ -69839,7 +71680,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
69839
71680
  <ion-modal
69840
71681
  [isOpen]="!!confirmAction()"
69841
71682
  cssClass="val-modal-adaptive"
69842
- (didDismiss)="closeConfirmModal()"
71683
+ (didDismiss)="handleConfirmModalDismissed()"
69843
71684
  >
69844
71685
  <ng-template>
69845
71686
  <val-modal-layout
@@ -70185,6 +72026,7 @@ class SimonGameComponent {
70185
72026
  this.activePad = signal(undefined);
70186
72027
  this.leaderboard = signal(this.readLeaderboard());
70187
72028
  this.confirmAction = signal(undefined);
72029
+ this.confirmedAction = signal(undefined);
70188
72030
  this.modeConfig = computed(() => SIMON_MODES[this.mode()]);
70189
72031
  this.bestRound = computed(() => this.modeLeaderboard()[0]?.round ?? 0);
70190
72032
  this.modeLeaderboard = computed(() => this.leaderboard()
@@ -70284,13 +72126,12 @@ class SimonGameComponent {
70284
72126
  closeConfirmModal() {
70285
72127
  this.confirmAction.set(undefined);
70286
72128
  }
70287
- confirmPendingAction(token) {
70288
- if (token !== 'confirm') {
70289
- this.closeConfirmModal();
70290
- return;
70291
- }
70292
- const action = this.confirmAction();
72129
+ handleConfirmModalDismissed() {
70293
72130
  this.confirmAction.set(undefined);
72131
+ const action = this.confirmedAction();
72132
+ this.confirmedAction.set(undefined);
72133
+ if (!action)
72134
+ return;
70294
72135
  if (action === 'restart') {
70295
72136
  this.start();
70296
72137
  return;
@@ -70303,6 +72144,15 @@ class SimonGameComponent {
70303
72144
  this.resetToGamesMenu();
70304
72145
  }
70305
72146
  }
72147
+ confirmPendingAction(token) {
72148
+ if (token !== 'confirm') {
72149
+ this.closeConfirmModal();
72150
+ return;
72151
+ }
72152
+ const action = this.confirmAction();
72153
+ this.confirmedAction.set(action);
72154
+ this.confirmAction.set(undefined);
72155
+ }
70306
72156
  tap(pad) {
70307
72157
  if (this.phase() !== 'waiting' || !this.acceptingInput)
70308
72158
  return;
@@ -70546,7 +72396,7 @@ class SimonGameComponent {
70546
72396
  <ion-modal
70547
72397
  [isOpen]="!!confirmAction()"
70548
72398
  cssClass="val-modal-adaptive"
70549
- (didDismiss)="closeConfirmModal()"
72399
+ (didDismiss)="handleConfirmModalDismissed()"
70550
72400
  >
70551
72401
  <ng-template>
70552
72402
  <val-modal-layout
@@ -70676,7 +72526,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
70676
72526
  <ion-modal
70677
72527
  [isOpen]="!!confirmAction()"
70678
72528
  cssClass="val-modal-adaptive"
70679
- (didDismiss)="closeConfirmModal()"
72529
+ (didDismiss)="handleConfirmModalDismissed()"
70680
72530
  >
70681
72531
  <ng-template>
70682
72532
  <val-modal-layout
@@ -85992,5 +87842,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
85992
87842
  * Generated bundle index. Do not edit.
85993
87843
  */
85994
87844
 
85995
- export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, BubbleBlitzGameComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHESSIMALS_BOT_PROFILES, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, ChatComposerComponent, ChatInputComponent, ChatWindowComponent, CheckInputComponent, CheckboxRadioInputComponent, ChessimalsGameComponent, ChessimalsOnlineService, ChipGroupComponent, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentReactionModalComponent, ContentService, ContentTransformer, ConversationListItemComponent, ConversationService, CookieBannerComponent, CookieSettingsComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_POST_UPDATE_GRACE_MS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DatasetPaginationService, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmptyStateComponent, EntityCardComponent, EntityFeedService, ExpandableTextComponent, ExternalBrowserService, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSchemaBuilderService, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HapticsService, HasPermissionDirective, HeaderActionsService, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, HtmlViewerModalComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, KNOWN_ROUTES, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, LayeredCardComponent, LegalContentService, LegalLinkService, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LiveReadFallbackService, LoadMoreComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, META_SCHEMA_VERSION, METRIC_CARD_DEFAULTS, MINI_GAME_PLAYER_AVATARS, MINI_GAME_PLAYER_COLORS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MediaViewerModalComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MemoryGameComponent, MenuComponent, MessageBubbleComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, MiniGamePlayerProfileService, MiniGamesMenuComponent, ModalLayoutComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OperationReferenceComponent, OptionCardsComponent, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, POST_UPDATE_TS_KEY, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PdfService, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PhoneDisplayComponent, PhoneFormatService, PhoneInputComponent, PickerV2Component, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PricingTableComponent, ProcessLinksPipe, ProfileContentComponent, ProfileModalComponent, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, ReactionBarComponent, ReactionsService, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, RequestService, RetroAudioService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SessionTransitionOverlayComponent, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimonGameComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, ThreadPanelComponent, TicketCardComponent, TicketCardImageService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, TypingIndicatorComponent, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UsageMetersComponent, UsageService, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_CHAT_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_REACTIONS_CONFIG, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VALTECH_WHATSAPP_CONFIG, VERSION, ValtechErrorService, VerifyViewComponent, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, WorkflowService, applyChessimalsMove, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, button, canSubmitRequestType, chooseChessimalsBotMove, collections, connectPageRefresh, createChessimalsGame, createChessimalsReviewState, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialDatasetState, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, datasetPageFromLegacyCursor, docs, errorLoggingInterceptor, extractPathParams, formatClockTime, formatDateSeparator, formatRelativeTime, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getChessimalsAllLegalMoves, getChessimalsLegalMoves, getChessimalsPieceAt, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isKnownRoute, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, positionKey, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechChat, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationClickActions, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechReactions, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, query, rbacGuard, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resignChessimalsGame, resolveColor, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, selectableRequestTypes, storagePaths, superAdminGuard, toArticle, validateRoutes };
87845
+ export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, APP_VERSION_PLATFORM_PLUGIN, APP_VERSION_REMOTE_PLUGIN, ARTICLE_CARD_DEFAULTS, ARTICLE_SPACING, ARTICLE_STRIP_DEFAULTS, AUTH_CTA_DEFAULTS, AVATAR_UPLOAD_DEFAULTS, AboutViewComponent, AccordionComponent, AccountViewComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AnimatedTerminalComponent, ApiKeyCreateModalComponent, ApiKeyService, ApiKeysModalComponent, ApiKeysViewComponent, AppConfigService, AppVersionService, ArticleBuilder, ArticleCardComponent, ArticleComponent, ArticleStripComponent, AttachmentUploaderComponent, AuthBackgroundComponent, AuthCtaComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, BubbleBlitzGameComponent, ButtonComponent, ButtonGroupComponent, CALLOUT_LABELS, CHESSIMALS_BOT_PROFILES, CHEV_KEYS, CIRCLE_KEYS, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CORNER_KEYS, CTA_CARD_DEFAULTS, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, ChangeEmailModalComponent, ChangePasswordModalComponent, ChatComposerComponent, ChatInputComponent, ChatWindowComponent, CheckInputComponent, CheckboxRadioInputComponent, ChessimalsGameComponent, ChessimalsOnlineService, ChipGroupComponent, ChristianityGameComponent, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentReactionModalComponent, ContentService, ContentTransformer, ConversationListItemComponent, ConversationService, CookieBannerComponent, CookieSettingsComponent, CountdownComponent, CreateOrgModalComponent, CtaCardComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_APP_VERSION_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_BUTTON_PRESETS, DEFAULT_CANCEL_BUTTON, DEFAULT_CHECK_INTERVAL_MS, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_DEBUG_CONSOLE_CONFIG, DEFAULT_DONATION_CONFIG, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_LOGIN_LOGO, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_POST_UPDATE_GRACE_MS, DEFAULT_PRESETS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DEFAULT_SPLASH_SCREEN_CONFIG, DataTableComponent, DatasetPaginationService, DateInputComponent, DatePickerComponent, DateRangeInputComponent, DebugConsoleComponent, DeleteAccountModalComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DonationService, DownloadService, EditOrgModalComponent, EmptyStateComponent, EntityCardComponent, EntityFeedService, ExpandableTextComponent, ExternalBrowserService, FEATURES_LIST_DEFAULTS, FUN_MODAL_DEFAULTS, FabComponent, FaqComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FieldListComponent, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FontSizeOption, FontSizeSelectorComponent, FontSizeService, FooterComponent, FooterLinksComponent, FormComponent, FormFieldComponent, FormSchemaBuilderService, FormSkeletonComponent, FunHeaderComponent, FunModalComponent, GlassComponent, GlowCardComponent, GlowComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HapticsService, HasPermissionDirective, HeaderActionsService, HeaderComponent, HintComponent, HorizontalScrollComponent, HrefComponent, HtmlViewerModalComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, INVITATION_CARD_DEFAULTS, IONIC_COLORS$5 as IONIC_COLORS, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, InvitationCardComponent, InviteMemberModalComponent, ItemListComponent, KNOWN_ROUTES, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LEGAL_CONTENT_CONFIG, LOGGED_IN_HINT_COOKIE, LOGIN_DEFAULTS, LandingSplitComponent, LandingStepsComponent, LanguageSelectorComponent, LanguageSelectorV2Component, LayeredCardComponent, LegalContentService, LegalLinkService, LightRippleDirective, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LiveReadFallbackService, LoadMoreComponent, LoadingDirective, LocalStorageService, LocaleService, LoginAttemptModalComponent, LoginComponent, MEDIA_OBJECT_DEFAULTS, MEMBER_CARD_DEFAULTS, META_SCHEMA_VERSION, METRIC_CARD_DEFAULTS, MINI_GAME_PLAYER_AVATARS, MINI_GAME_PLAYER_COLORS, MODAL_SIZES, MOTIF_KEYS, MOTION, MaintenancePageComponent, MarkdownArticleParserService, MediaObjectComponent, MediaViewerModalComponent, MemberCardComponent, MemberDetailModalComponent, MemberImportModalComponent, MemoryGameComponent, MenuComponent, MessageBubbleComponent, MessagingService, MetaService, MetricCardComponent, MfaModalComponent, MiniGamePlayerProfileService, MiniGamesMenuComponent, ModalLayoutComponent, ModalService, ModalShellComponent, MultiSelectSearchComponent, NUM_KEYS, NavigationService, NetworkBannerComponent, NetworkStatusService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationPreferencesViewComponent, NotificationsService, NotificationsViewComponent, NumberFromToComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OperationReferenceComponent, OptionCardsComponent, OrgInfoSheetComponent, OrgService, OrgSwitchService, OrganizationViewComponent, PATTERN_MOTIFS, PATTERN_PALETTES, PATTERN_STYLE_CONFIGS, PLATFORM_CONFIGS, POST_UPDATE_TS_KEY, PageContentComponent, PageLinksComponent, PageRefreshService, PageTemplateComponent, PageWavesComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PatternComponent, PdfService, PermissionCatalogService, PermissionSelectorComponent, PermissionsModalComponent, PermissionsViewComponent, PhoneDisplayComponent, PhoneFormatService, PhoneInputComponent, PickerV2Component, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PreferencesService, PreferencesViewComponent, PresetService, PriceTagComponent, PricingTableComponent, ProcessLinksPipe, ProfileContentComponent, ProfileModalComponent, ProfileSkeletonComponent, ProfileViewComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QrScannerComponent, QueryBuilder, QuoteBoxComponent, REQUEST_STATUSES, RadioInputComponent, RangeInputComponent, RatingComponent, ReactionBarComponent, ReactionsService, RefresherComponent, RequestFirestoreService, RequestFormBuilderService, RequestFormComponent, RequestModalComponent, RequestService, RetroAudioService, RightsFooterComponent, RotatingTextComponent, SEARCH_HEADER_DEFAULTS, SETTINGS_SECTIONS_CATALOG, SHAPE_KEYS, SHARE_PROFILE_MODAL_DEFAULTS, SKELETON_LAYOUT_DEFAULT_ROWS, SKELETON_PRESETS, SOLID_KEYS, STATS_BAR_DEFAULTS, STROKE_KEYS, SearchHeaderComponent, SearchSelectorComponent, SearchbarComponent, SectionHeaderComponent, SecurityViewComponent, SegmentControlComponent, SelectSearchComponent, SessionListModalComponent, SessionService, SessionTransitionOverlayComponent, SettingsHubComponent, ShareButtonsComponent, ShareProfileModalComponent, SimonGameComponent, SimpleComponent, SkeletonComponent, SkeletonLayoutComponent, SkeletonService, SplashComponent, SplashScreenService, StatsBarComponent, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, SwitchOrgModalComponent, TRI_KEYS, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, ThreadPanelComponent, TicketCardComponent, TicketCardImageService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TransferOwnershipModalComponent, TranslatePipe, TypedCollection, TypingIndicatorComponent, UPDATE_BANNER_DEFAULT_CONTENT, UPDATE_BANNER_I18N_NAMESPACE, UpdateBannerComponent, UsageMetersComponent, UsageService, UserAvatarComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_APP_VERSION, VALTECH_AUTH_CONFIG, VALTECH_CHAT_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_CONTENT_CONFIG, VALTECH_DEBUG_CONSOLE, VALTECH_DEFAULT_CONTENT, VALTECH_DONATION_CONFIG, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_LEGAL_CONFIG, VALTECH_NETWORK_ERROR_KEY, VALTECH_REACTIONS_CONFIG, VALTECH_SETTINGS_MENU_LINKS, VALTECH_SITE_PATHS, VALTECH_SOCIAL_LINKS, VALTECH_SPLASH_SCREEN, VALTECH_WEB_BASE_URLS, VALTECH_WHATSAPP_CONFIG, VERSION, ValtechErrorService, VerifyViewComponent, WhatsappFabComponent, WhatsappService, WizardComponent, WizardFooterComponent, WorkflowService, applyChessimalsMove, applyDefaultValueToControl, authGuard, authInterceptor, authPasswordValidator, beautifyLegalArticle, blogPost, buildCompanyFooterProps, buildFooterLinks, buildLegalLinkResolver, buildPath, buildSettingsCards, button, canSubmitRequestType, chooseChessimalsBotMove, collections, connectPageRefresh, createChessimalsGame, createChessimalsReviewState, createErrorStateProps, createFirebaseConfig, createGlowCardProps, createInitialDatasetState, createInitialPaginationState, createNumberFromToField, createPageState, createPermissionLabeler, createRefreshableStream, createTitleProps, datasetPageFromLegacyCursor, docs, errorLoggingInterceptor, extractPathParams, formatClockTime, formatDateSeparator, formatRelativeTime, generatePatternTiles, generateRandomTile, getAppInfo, getAppVersion, getChessimalsAllLegalMoves, getChessimalsLegalMoves, getChessimalsPieceAt, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, groupPermissionsByScope, guestGuard, hasEmulators, iconButton, interpretError, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isIonicColor, isKnownRoute, isValidPath, joinPath, maxLength, mulberry32, news, parseMarkdownArticle, permissionGuard, permissionGuardFromRoute, positionKey, provideLegalContent, provideSplashScreen, provideValtechAboutRoutes, provideValtechAccountRoutes, provideValtechAds, provideValtechApiKeysRoutes, provideValtechAppConfig, provideValtechAppVersion, provideValtechAppVersionHttp, provideValtechAuth, provideValtechAuthInterceptor, provideValtechChat, provideValtechContent, provideValtechDebugConsole, provideValtechDonations, provideValtechErrorHandling, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechLegal, provideValtechNotificationClickActions, provideValtechNotificationPreferencesRoutes, provideValtechNotificationsRoutes, provideValtechOrganizationRoutes, provideValtechPermissionsRoutes, provideValtechPreferencesRoutes, provideValtechPresets, provideValtechProfileRoutes, provideValtechReactions, provideValtechSecurityRoutes, provideValtechSettingsRoutes, provideValtechSite, provideValtechSkeleton, provideValtechWhatsapp, query, rbacGuard, renderPatternSvgInner, replaceSpecialChars, requestSubmitMode, resignChessimalsGame, resolveColor, resolveInputDefaultValue, resolveIonicColor, resolveWebBaseUrl, roleGuard, selectableRequestTypes, storagePaths, superAdminGuard, toArticle, validateRoutes };
85996
87846
  //# sourceMappingURL=valtech-components.mjs.map