blacktrigram 0.7.68 → 0.7.70

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 (219) hide show
  1. package/lib/App2.js.map +1 -1
  2. package/lib/assets/index.css +987 -987
  3. package/lib/audio/AudioAssetLoader.js.map +1 -1
  4. package/lib/audio/AudioAssetRegistry.js +2 -2
  5. package/lib/audio/AudioAssetRegistry.js.map +1 -1
  6. package/lib/audio/AudioCache.js.map +1 -1
  7. package/lib/audio/AudioManager.js +1 -1
  8. package/lib/audio/AudioManager.js.map +1 -1
  9. package/lib/audio/AudioMonitor.js.map +1 -1
  10. package/lib/audio/AudioPool.js.map +1 -1
  11. package/lib/audio/AudioProvider.js.map +1 -1
  12. package/lib/audio/AudioUtils.js.map +1 -1
  13. package/lib/audio/BoneImpactAudioMap.js.map +1 -1
  14. package/lib/components/screens/combat/CombatScreen3D.js +3 -3
  15. package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
  16. package/lib/components/screens/combat/components/controls/CombatControlsPanel.js.map +1 -1
  17. package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
  18. package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
  19. package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
  20. package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
  21. package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
  22. package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
  23. package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
  24. package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
  25. package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
  26. package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
  27. package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
  28. package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
  29. package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
  30. package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
  31. package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
  32. package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
  33. package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
  34. package/lib/components/screens/intro/IntroScreen3D.js +1 -1
  35. package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
  36. package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
  37. package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
  38. package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
  39. package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
  40. package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
  41. package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
  42. package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
  43. package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
  44. package/lib/components/screens/training/TrainingScreen3D.js +1 -1
  45. package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
  46. package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
  47. package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
  48. package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
  49. package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
  50. package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
  51. package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
  52. package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
  53. package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
  54. package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
  55. package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
  56. package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
  57. package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
  58. package/lib/components/shared/mobile/HapticController.js.map +1 -1
  59. package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
  60. package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
  61. package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
  62. package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
  63. package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
  64. package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
  65. package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
  66. package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
  67. package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
  68. package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
  69. package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
  70. package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
  71. package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
  72. package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
  73. package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
  74. package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
  75. package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
  76. package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
  77. package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
  78. package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
  79. package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
  80. package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
  81. package/lib/components/shared/ui/SplashScreen.js +2 -2
  82. package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
  83. package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
  84. package/lib/data/techniques.js.map +1 -1
  85. package/lib/hooks/useCombatTimer.js.map +1 -1
  86. package/lib/hooks/useKeyboardControls.js.map +1 -1
  87. package/lib/hooks/useSkeletalAnimation.js +2 -2
  88. package/lib/hooks/useSkeletalAnimation.js.map +1 -1
  89. package/lib/hooks/useTechniqueSelection.js.map +1 -1
  90. package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
  91. package/lib/index.js +2 -2
  92. package/lib/systems/CombatSystem.js.map +1 -1
  93. package/lib/systems/EffectCalculator.js.map +1 -1
  94. package/lib/systems/ResponsiveScaling.js.map +1 -1
  95. package/lib/systems/TrigramSystem.js.map +1 -1
  96. package/lib/systems/ai/AIPersonality.js.map +1 -1
  97. package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
  98. package/lib/systems/ai/DecisionTree.js.map +1 -1
  99. package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
  100. package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
  101. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
  102. package/lib/systems/animation/builders/SkeletonRig.js +1 -1
  103. package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
  104. package/lib/systems/animation/catalogs/AttackAnimations.js +1 -1
  105. package/lib/systems/animation/catalogs/AttackAnimations.js.map +1 -1
  106. package/lib/systems/animation/catalogs/BasicAnimations.js +1 -1
  107. package/lib/systems/animation/catalogs/BasicAnimations.js.map +1 -1
  108. package/lib/systems/animation/catalogs/ComboAnimations.js +1 -1
  109. package/lib/systems/animation/catalogs/ComboAnimations.js.map +1 -1
  110. package/lib/systems/animation/catalogs/DarkOpsAnimations.js +1 -1
  111. package/lib/systems/animation/catalogs/DarkOpsAnimations.js.map +1 -1
  112. package/lib/systems/animation/catalogs/DefensiveAnimations.js +2 -11
  113. package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
  114. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js +1 -1
  115. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js.map +1 -1
  116. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js +1 -1
  117. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
  118. package/lib/systems/animation/catalogs/GamRedirectionAnimations.js.map +1 -1
  119. package/lib/systems/animation/catalogs/GamStanceAnimations.js.map +1 -1
  120. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js.map +1 -1
  121. package/lib/systems/animation/catalogs/GanStanceAnimations.js +1 -1
  122. package/lib/systems/animation/catalogs/GanStanceAnimations.js.map +1 -1
  123. package/lib/systems/animation/catalogs/GanTechniqueAnimations.js +1 -1
  124. package/lib/systems/animation/catalogs/GanTechniqueAnimations.js.map +1 -1
  125. package/lib/systems/animation/catalogs/GeonStanceAnimations.js +1 -1
  126. package/lib/systems/animation/catalogs/GeonStanceAnimations.js.map +1 -1
  127. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js +1 -1
  128. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js.map +1 -1
  129. package/lib/systems/animation/catalogs/GrapplingAnimations.js +1 -1
  130. package/lib/systems/animation/catalogs/GrapplingAnimations.js.map +1 -1
  131. package/lib/systems/animation/catalogs/JinStanceAnimations.js +1 -1
  132. package/lib/systems/animation/catalogs/JinStanceAnimations.js.map +1 -1
  133. package/lib/systems/animation/catalogs/JinTechniqueAnimations.js +1 -1
  134. package/lib/systems/animation/catalogs/JinTechniqueAnimations.js.map +1 -1
  135. package/lib/systems/animation/catalogs/KickAnimations.js +1 -1
  136. package/lib/systems/animation/catalogs/KickAnimations.js.map +1 -1
  137. package/lib/systems/animation/catalogs/LiStanceAnimations.js +1 -1
  138. package/lib/systems/animation/catalogs/LiStanceAnimations.js.map +1 -1
  139. package/lib/systems/animation/catalogs/LiTechniqueAnimations.js.map +1 -1
  140. package/lib/systems/animation/catalogs/MovementAnimations.js +1 -1
  141. package/lib/systems/animation/catalogs/MovementAnimations.js.map +1 -1
  142. package/lib/systems/animation/catalogs/PunchAnimations.js +1 -1
  143. package/lib/systems/animation/catalogs/PunchAnimations.js.map +1 -1
  144. package/lib/systems/animation/catalogs/SonStanceAnimations.js +1 -1
  145. package/lib/systems/animation/catalogs/SonStanceAnimations.js.map +1 -1
  146. package/lib/systems/animation/catalogs/SonTechniqueAnimations.js +1 -1
  147. package/lib/systems/animation/catalogs/SonTechniqueAnimations.js.map +1 -1
  148. package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js +1 -1
  149. package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js.map +1 -1
  150. package/lib/systems/animation/catalogs/StanceAnimations.js +1 -1
  151. package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
  152. package/lib/systems/animation/catalogs/StanceAttackAnimations.js +215 -272
  153. package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
  154. package/lib/systems/animation/catalogs/StanceIdleAnimations.js +2 -11
  155. package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
  156. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js +2 -2
  157. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
  158. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js +1 -1
  159. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
  160. package/lib/systems/animation/catalogs/TaeJointLockAnimations.js.map +1 -1
  161. package/lib/systems/animation/catalogs/TaeStanceAnimations.js +1 -1
  162. package/lib/systems/animation/catalogs/TaeStanceAnimations.js.map +1 -1
  163. package/lib/systems/animation/core/AnimationOptimizations.js +1 -1
  164. package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
  165. package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
  166. package/lib/systems/animation/core/AnimationRegistry.js +11 -209
  167. package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
  168. package/lib/systems/animation/core/AnimationStateMachine.js +2 -2
  169. package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
  170. package/lib/systems/animation/core/TechniqueAnimationMapper.js +1 -1
  171. package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
  172. package/lib/systems/animation/core/TechniqueAnimationMapping.js +1 -1
  173. package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
  174. package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
  175. package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
  176. package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
  177. package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
  178. package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
  179. package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
  180. package/lib/systems/combat/BalanceSystem.js.map +1 -1
  181. package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
  182. package/lib/systems/combat/CombatStateSystem.js.map +1 -1
  183. package/lib/systems/combat/GrappleSystem.js.map +1 -1
  184. package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
  185. package/lib/systems/combat/typeGuards.js.map +1 -1
  186. package/lib/systems/index.js +2 -2
  187. package/lib/systems/movement/integration.js.map +1 -1
  188. package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
  189. package/lib/systems/physics/CollisionDetection.js +1 -1
  190. package/lib/systems/physics/CollisionDetection.js.map +1 -1
  191. package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
  192. package/lib/systems/physics/MovementPhysics.js.map +1 -1
  193. package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
  194. package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
  195. package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
  196. package/lib/systems/trigram/StanceManager.js.map +1 -1
  197. package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
  198. package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
  199. package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
  200. package/lib/systems/trigram/techniques/index.js.map +1 -1
  201. package/lib/systems/trigram/types.js.map +1 -1
  202. package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
  203. package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
  204. package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
  205. package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
  206. package/lib/types/constants/designSystem.js.map +1 -1
  207. package/lib/utils/colorHelpers.js.map +1 -1
  208. package/lib/utils/colorUtils.js.map +1 -1
  209. package/lib/utils/controlMapping.js.map +1 -1
  210. package/lib/utils/deviceDetection.js.map +1 -1
  211. package/lib/utils/effectUtils.js.map +1 -1
  212. package/lib/utils/fabricTextures.js.map +1 -1
  213. package/lib/utils/htmlOverlayHelpers.js.map +1 -1
  214. package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
  215. package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
  216. package/lib/utils/safeAreaUtils.js.map +1 -1
  217. package/lib/utils/stanceHelpers.js.map +1 -1
  218. package/lib/utils/visualEffects.js.map +1 -1
  219. package/package.json +11 -11
@@ -1,1154 +1,1154 @@
1
- @import url("https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap");@import url("https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&display=swap");
2
-
3
-
1
+ @import url("https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap");@import url("https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&display=swap");/**
2
+ * BreathingIndicator Component Styles
3
+ *
4
+ * Defines keyframe animation for the pulsing breathing difficulty indicator
5
+ */
4
6
 
5
- /* Black Trigram - Korean Cyberpunk Martial Arts Styling */
6
- /* Note: CSS variables are now centralized in index.css */
7
- * {
8
- margin: 0;
9
- padding: 0;
10
- box-sizing: border-box;
11
- }
12
- body {
13
- font-family: var(--font-korean);
14
- background: linear-gradient(
15
- 135deg,
16
- var(--color-bg-dark) 0%,
17
- var(--color-bg-medium) 100%
18
- );
19
- color: var(--color-text-primary);
20
- overflow: hidden;
21
- user-select: none;
22
- }
23
- #root {
24
- width: 100vw;
25
- height: 100vh;
26
- display: flex;
27
- justify-content: center;
28
- align-items: center;
29
- background: radial-gradient(
30
- ellipse at center,
31
- var(--color-bg-medium) 0%,
32
- var(--color-bg-dark) 100%
33
- );
34
- }
35
- /* Korean Text Enhancement */
36
- .korean-text {
37
- font-family: var(--font-korean);
38
- font-weight: 400;
39
- text-shadow: 0 0 8px var(--color-korean-east);
40
- letter-spacing: 0.02em;
41
- }
42
- .korean-title {
43
- font-family: var(--font-korean);
44
- font-weight: 700;
45
- font-size: 3rem;
46
- background: linear-gradient(
47
- 45deg,
48
- var(--color-accent-cyan),
49
- var(--color-warning)
50
- );
51
- -webkit-background-clip: text;
52
- -webkit-text-fill-color: transparent;
53
- background-clip: text;
54
- text-shadow: 0 0 20px var(--color-accent-cyan);
55
- }
56
- .cyber-text {
57
- font-family: var(--font-cyber);
58
- color: var(--color-accent-cyan);
59
- text-transform: uppercase;
60
- letter-spacing: 0.1em;
61
- text-shadow: 0 0 10px currentColor;
62
- }
63
- /* Cyberpunk UI Elements */
64
- .cyberpunk-border {
65
- border: 2px solid var(--color-accent-cyan);
66
- border-image: linear-gradient(
67
- 45deg,
68
- var(--color-accent-cyan),
69
- var(--color-warning),
70
- var(--color-accent-cyan)
71
- )
72
- 1;
73
- box-shadow: 0 0 10px var(--color-accent-cyan),
74
- inset 0 0 10px color-mix(in srgb, var(--color-accent-cyan) 10%, transparent);
75
- }
76
- .cyberpunk-button {
77
- background: linear-gradient(
78
- 135deg,
79
- color-mix(in srgb, var(--color-accent-cyan) 10%, transparent),
80
- color-mix(in srgb, var(--color-warning) 10%, transparent)
81
- );
82
- border: 1px solid var(--color-accent-cyan);
83
- color: var(--color-text-primary);
84
- padding: 0.8rem 1.5rem;
85
- cursor: pointer;
86
- transition: all 0.3s ease;
87
- font-family: var(--font-korean);
88
- font-weight: 500;
89
- position: relative;
90
- overflow: hidden;
91
- }
92
- .cyberpunk-button:hover {
93
- background: linear-gradient(
94
- 135deg,
95
- color-mix(in srgb, var(--color-accent-cyan) 20%, transparent),
96
- color-mix(in srgb, var(--color-warning) 20%, transparent)
97
- );
98
- box-shadow: 0 0 20px var(--color-accent-cyan);
99
- transform: translateY(-2px);
100
- }
101
- .cyberpunk-button:before {
102
- content: "";
103
- position: absolute;
104
- top: 0;
105
- left: -100%;
106
- width: 100%;
107
- height: 100%;
108
- background: linear-gradient(
109
- 90deg,
110
- transparent,
111
- color-mix(in srgb, var(--color-text-primary) 20%, transparent),
112
- transparent
113
- );
114
- transition: left 0.5s;
115
- }
116
- .cyberpunk-button:hover:before {
117
- left: 100%;
118
- }
119
- /* Combat HUD Styling */
120
- .combat-hud {
121
- position: absolute;
122
- top: 0;
123
- left: 0;
124
- right: 0;
125
- background: linear-gradient(
126
- 180deg,
127
- color-mix(in srgb, var(--color-bg-dark) 90%, transparent) 0%,
128
- transparent 100%
129
- );
130
- padding: 1rem;
131
- border-bottom: 1px solid var(--color-accent-cyan);
132
- }
133
- .health-bar {
134
- background: var(--color-bg-dark);
135
- border: 1px solid var(--color-accent-cyan);
136
- height: 8px;
137
- border-radius: 4px;
138
- overflow: hidden;
139
- position: relative;
140
- }
141
- .health-bar-fill {
142
- background: linear-gradient(
143
- 90deg,
144
- var(--color-danger) 0%,
145
- var(--color-warning) 50%,
146
- var(--color-korean-east) 100%
147
- );
148
- height: 100%;
149
- transition: width 0.3s ease;
150
- box-shadow: 0 0 10px currentColor;
151
- }
152
- /* Animation Effects */
153
- @keyframes korean-glow {
154
- 0%,
155
- 100% {
156
- text-shadow: 0 0 5px var(--color-korean-east);
7
+ @keyframes breathing-pulse {
8
+ 0%, 100% {
9
+ opacity: 1;
157
10
  }
158
- 50% {
159
- text-shadow: 0 0 20px var(--color-korean-east);
11
+ 50% {
12
+ opacity: 0.7;
160
13
  }
161
14
  }
162
- .animate-glow {
163
- animation: korean-glow 2s ease-in-out infinite;
164
- }
165
- @keyframes combat-flash {
166
- 0% {
167
- background-color: color-mix(in srgb, var(--color-danger) 10%, transparent);
15
+ /**
16
+ * HUD Animations - Centralized keyframe animations for all HUD components
17
+ *
18
+ * Performance-optimized animations for 60fps gameplay
19
+ * Korean cyberpunk themed with glow effects
20
+ *
21
+ * @category UI Animations
22
+ * @korean HUD 애니메이션
23
+ */
24
+
25
+ /* Health Bar Pulse - Critical health warning */
26
+ @keyframes healthPulse {
27
+ 0%, 100% {
28
+ opacity: 1;
29
+ filter: brightness(1) drop-shadow(0 0 8px rgba(255, 68, 68, 0.6));
168
30
  }
169
31
  50% {
170
- background-color: color-mix(in srgb, var(--color-danger) 30%, transparent);
171
- }
172
- 100% {
173
- background-color: color-mix(in srgb, var(--color-danger) 10%, transparent);
32
+ opacity: 0.85;
33
+ filter: brightness(1.2) drop-shadow(0 0 12px rgba(255, 68, 68, 0.9));
174
34
  }
175
35
  }
176
- .combat-flash {
177
- animation: combat-flash 0.2s ease-in-out;
178
- }
179
- /* Responsive Design */
180
- @media (max-width: 768px) {
181
- .korean-title {
182
- font-size: 2rem;
183
- }
184
36
 
185
- .cyberpunk-button {
186
- padding: 0.6rem 1.2rem;
187
- font-size: 0.9rem;
37
+ /* Stamina Bar Pulse - Low stamina warning */
38
+ @keyframes staminaPulse {
39
+ 0%, 100% {
40
+ opacity: 1;
41
+ filter: brightness(1) drop-shadow(0 0 6px rgba(0, 136, 255, 0.6));
188
42
  }
189
-
190
- /* Enhanced responsive design for Korean martial arts game */
191
- .app-container {
192
- position: relative;
193
- width: 100vw;
194
- height: 100vh;
195
- overflow: hidden;
196
- background: #000000;
197
- display: flex;
198
- align-items: center;
199
- justify-content: center;
43
+ 50% {
44
+ opacity: 0.85;
45
+ filter: brightness(1.2) drop-shadow(0 0 10px rgba(0, 136, 255, 0.9));
200
46
  }
47
+ }
201
48
 
202
- /* Better mobile canvas handling */
203
- .app-container canvas {
204
- width: 100vw !important;
205
- height: 100vh !important;
206
- position: relative !important;
49
+ /* Technique Card Glow - Available technique */
50
+ @keyframes techniqueGlow {
51
+ 0%, 100% {
52
+ box-shadow: 0 0 10px rgba(0, 255, 255, 0.3),
53
+ 0 0 20px rgba(0, 255, 255, 0.2),
54
+ inset 0 0 10px rgba(0, 255, 255, 0.1);
207
55
  }
208
-
209
- /* Improve mobile UI overlay positioning */
210
- .test-overlay {
211
- position: fixed;
212
- top: 0;
213
- left: 0;
214
- width: 100vw;
215
- height: 100vh;
216
- z-index: 500;
56
+ 50% {
57
+ box-shadow: 0 0 15px rgba(0, 255, 255, 0.5),
58
+ 0 0 30px rgba(0, 255, 255, 0.3),
59
+ inset 0 0 15px rgba(0, 255, 255, 0.2);
217
60
  }
218
61
  }
219
- /* Tablet optimizations */
220
- @media (min-width: 768px) and (max-width: 1024px) {
221
- .app-container canvas {
222
- width: 100vw !important;
223
- height: 100vh !important;
62
+
63
+ /* Technique Card Pulse - Selected technique */
64
+ @keyframes techniqueSelected {
65
+ 0%, 100% {
66
+ transform: scale(1);
67
+ box-shadow: 0 0 15px rgba(255, 170, 0, 0.6),
68
+ 0 0 25px rgba(255, 170, 0, 0.4),
69
+ inset 0 0 15px rgba(255, 170, 0, 0.2);
224
70
  }
225
- }
226
- /* Desktop optimizations */
227
- @media (min-width: 1024px) {
228
- .app-container {
229
- justify-content: center;
230
- align-items: center;
71
+ 50% {
72
+ transform: scale(1.05);
73
+ box-shadow: 0 0 20px rgba(255, 170, 0, 0.8),
74
+ 0 0 35px rgba(255, 170, 0, 0.5),
75
+ inset 0 0 20px rgba(255, 170, 0, 0.3);
231
76
  }
232
77
  }
233
- /* Loading and Error States */
234
- .loading-spinner {
235
- border: 2px solid var(--color-bg-medium);
236
- border-top: 2px solid var(--color-accent-cyan);
237
- border-radius: 50%;
238
- width: 40px;
239
- height: 40px;
240
- animation: spin 1s linear infinite;
241
- margin: 0 auto;
242
- }
243
- @keyframes spin {
244
- 0% {
245
- transform: rotate(0deg);
78
+
79
+ /* HUD Panel Fade In - Smooth entry */
80
+ @keyframes hudFadeIn {
81
+ from {
82
+ opacity: 0;
83
+ transform: translateY(-10px);
246
84
  }
247
- 100% {
248
- transform: rotate(360deg);
85
+ to {
86
+ opacity: 1;
87
+ transform: translateY(0);
249
88
  }
250
89
  }
251
- .error-message {
252
- color: var(--color-danger);
253
- background: color-mix(in srgb, var(--color-danger) 10%, transparent);
254
- border: 1px solid var(--color-danger);
255
- padding: 1rem;
256
- border-radius: 4px;
257
- margin: 1rem 0;
258
- font-family: var(--font-korean);
259
- }
260
- /* Accessibility */
261
- .sr-only {
262
- position: absolute;
263
- width: 1px;
264
- height: 1px;
265
- padding: 0;
266
- margin: -1px;
267
- overflow: hidden;
268
- clip: rect(0, 0, 0, 0);
269
- white-space: nowrap;
270
- border: 0;
271
- }
272
- /* High contrast mode support - Comprehensive accessibility */
273
- @media (prefers-contrast: high) {
274
- :root {
275
- /* High contrast colors for better visibility */
276
- --color-primary-cyan: #ffffff;
277
- --color-primary-gold: #ffffff;
278
- --color-text-primary: #ffffff;
279
- --color-text-secondary: #ffffff;
280
- --color-text-tertiary: #cccccc;
281
- --color-bg-dark: #000000;
282
- --color-bg-medium: #000000;
283
- --color-bg-light: #1a1a1a;
284
-
285
- /* Ensure sufficient contrast for UI elements */
286
- --color-danger: #ff0000;
287
- --color-success: #00ff00;
288
- --color-warning: #ffff00;
289
- }
290
-
291
- /* Increase border visibility in high contrast mode */
292
- button,
293
- .error-boundary__container,
294
- .loading-state__progress {
295
- border-width: 3px;
90
+
91
+ /* Combat Readiness Pulse - Ready to attack */
92
+ @keyframes readinessPulse {
93
+ 0%, 100% {
94
+ filter: brightness(1) drop-shadow(0 0 8px rgba(0, 255, 136, 0.5));
296
95
  }
297
- }
298
- /* Reduced motion support */
299
- @media (prefers-reduced-motion: reduce) {
300
- *,
301
- *::before,
302
- *::after {
303
- animation-duration: 0.01ms !important;
304
- animation-iteration-count: 1 !important;
305
- transition-duration: 0.01ms !important;
96
+ 50% {
97
+ filter: brightness(1.3) drop-shadow(0 0 15px rgba(0, 255, 136, 0.8));
306
98
  }
307
99
  }
308
- /* Reset default Vite styles */
309
- #root {
310
- width: 100vw;
311
- height: 100vh;
312
- margin: 0;
313
- padding: 0;
314
- overflow: hidden;
315
- }
316
- /* Full-screen game container */
317
- .app-container {
318
- position: fixed;
319
- top: 0;
320
- left: 0;
321
- width: 100vw;
322
- height: 100vh;
323
- margin: 0;
324
- padding: 0;
325
- overflow: hidden;
326
- background: #000000;
327
- display: flex;
328
- align-items: center;
329
- justify-content: center;
330
- font-family: "Noto Sans KR", sans-serif;
331
100
 
332
- /* Prevent text selection during game */
333
- user-select: none;
334
- -webkit-user-select: none;
335
- -moz-user-select: none;
336
- -ms-user-select: none;
337
-
338
- /* Disable touch callouts on mobile */
339
- -webkit-touch-callout: none;
340
-
341
- /* Optimize for game rendering */
342
- will-change: transform;
343
- transform: translateZ(0);
344
- backface-visibility: hidden;
345
- }
346
- /* Hide any old game elements */
347
- .app-container h1,
348
- .app-container .instructions {
349
- display: none !important;
350
- }
351
- /* Korean typography support */
352
- /* NOTE: overflow: hidden on body prevents the page itself from scrolling.
353
- * This is intentional for a full-screen game. Individual screens that need
354
- * scrollable content (Philosophy, Controls) use internal scrollable containers
355
- * with overflowY: "auto" on their content areas, which works correctly
356
- * because the content div has a fixed height within the viewport. */
357
- body {
358
- font-family: "Noto Sans KR", sans-serif;
359
- margin: 0;
360
- padding: 0;
361
- overflow: hidden;
362
- background: #000000;
363
- width: 100vw;
364
- height: 100vh;
365
- }
366
- /* Traditional Korean color scheme enhancements */
367
- .app-container::before {
368
- content: "";
369
- position: absolute;
370
- top: 0;
371
- left: 0;
372
- right: 0;
373
- bottom: 0;
374
- background: radial-gradient(
375
- circle at center,
376
- color-mix(in srgb, var(--color-korean-south) 10%, transparent) 0%,
377
- var(--color-primary-black) 70%
378
- );
379
- pointer-events: none;
380
- z-index: -1;
101
+ /* Speed Indicator Glow - High speed movement */
102
+ @keyframes speedGlow {
103
+ 0%, 100% {
104
+ text-shadow: 0 0 8px rgba(0, 255, 255, 0.6),
105
+ 0 0 16px rgba(0, 255, 255, 0.4);
106
+ }
107
+ 50% {
108
+ text-shadow: 0 0 12px rgba(0, 255, 255, 0.8),
109
+ 0 0 24px rgba(0, 255, 255, 0.6);
110
+ }
381
111
  }
382
- /* Performance optimizations for WebGL */
383
- .app-container canvas {
384
- will-change: transform;
385
- transform: translateZ(0);
386
- backface-visibility: hidden;
112
+
113
+ /* Timer Flash - Final seconds warning */
114
+ @keyframes timerFlash {
115
+ 0%, 100% {
116
+ color: var(--color-korean-south);
117
+ text-shadow: 0 0 10px color-mix(in srgb, var(--color-korean-south) 80%, transparent),
118
+ 0 0 20px color-mix(in srgb, var(--color-korean-south) 50%, transparent);
119
+ }
120
+ 50% {
121
+ color: var(--color-korean-center);
122
+ text-shadow: 0 0 15px var(--color-korean-center),
123
+ 0 0 30px color-mix(in srgb, var(--color-korean-center) 70%, transparent);
124
+ }
387
125
  }
388
- /* Responsive adjustments for different screen sizes */
389
- @media (max-width: 768px) {
390
- .app-container {
391
- width: 100vw !important;
392
- height: 100vh !important;
126
+
127
+ /* Round Display Pulse - Round transition */
128
+ @keyframes roundPulse {
129
+ 0% {
130
+ transform: scale(0.9);
131
+ opacity: 0;
132
+ }
133
+ 50% {
134
+ transform: scale(1.05);
135
+ opacity: 1;
136
+ }
137
+ 100% {
138
+ transform: scale(1);
139
+ opacity: 1;
393
140
  }
141
+ }
394
142
 
395
- .app-container canvas {
396
- width: 100vw !important;
397
- height: 100vh !important;
143
+ /* Combo Counter Flash - Combo milestone */
144
+ @keyframes comboFlash {
145
+ 0%, 100% {
146
+ transform: scale(1);
147
+ filter: brightness(1);
148
+ }
149
+ 25% {
150
+ transform: scale(1.2);
151
+ filter: brightness(1.5) drop-shadow(0 0 20px rgba(255, 170, 0, 1));
152
+ }
153
+ 50% {
154
+ transform: scale(1.1);
155
+ filter: brightness(1.3) drop-shadow(0 0 15px rgba(255, 170, 0, 0.8));
156
+ }
157
+ 75% {
158
+ transform: scale(1.15);
159
+ filter: brightness(1.4) drop-shadow(0 0 18px rgba(255, 170, 0, 0.9));
398
160
  }
399
161
  }
400
- @media (max-width: 375px) {
401
- .app-container {
402
- width: 100vw !important;
403
- height: 100vh !important;
162
+
163
+ /* Body Part Critical - Body part near failure */
164
+ @keyframes bodyPartCritical {
165
+ 0%, 100% {
166
+ border-color: rgba(255, 68, 68, 0.8);
167
+ box-shadow: 0 0 8px rgba(255, 68, 68, 0.5),
168
+ inset 0 0 8px rgba(255, 68, 68, 0.3);
169
+ }
170
+ 50% {
171
+ border-color: rgba(255, 68, 68, 1);
172
+ box-shadow: 0 0 15px rgba(255, 68, 68, 0.8),
173
+ inset 0 0 12px rgba(255, 68, 68, 0.5);
404
174
  }
175
+ }
405
176
 
406
- .app-container canvas {
407
- width: 100vw !important;
408
- height: 100vh !important;
177
+ /* Guard Indicator Active - Guard stance active */
178
+ @keyframes guardActive {
179
+ 0%, 100% {
180
+ box-shadow: 0 0 12px rgba(0, 255, 136, 0.6),
181
+ 0 0 24px rgba(0, 255, 136, 0.4);
182
+ }
183
+ 50% {
184
+ box-shadow: 0 0 18px rgba(0, 255, 136, 0.9),
185
+ 0 0 36px rgba(0, 255, 136, 0.6);
409
186
  }
410
187
  }
411
- /* Remove any legacy Vite template styles that might interfere */
412
- .logo {
413
- display: none !important;
188
+
189
+ /* Stance Change Flash - Stance transition effect */
190
+ @keyframes stanceChange {
191
+ 0% {
192
+ opacity: 0;
193
+ transform: scale(0.8) rotate(-5deg);
194
+ }
195
+ 50% {
196
+ opacity: 1;
197
+ transform: scale(1.1) rotate(2deg);
198
+ }
199
+ 100% {
200
+ opacity: 1;
201
+ transform: scale(1) rotate(0deg);
202
+ }
414
203
  }
415
- .card {
416
- display: none !important;
204
+
205
+ /* Training Mode Active - Training session indicator */
206
+ @keyframes trainingActive {
207
+ 0%, 100% {
208
+ border-color: rgba(0, 255, 136, 0.8);
209
+ filter: brightness(1);
210
+ }
211
+ 50% {
212
+ border-color: rgba(0, 255, 136, 1);
213
+ filter: brightness(1.2) drop-shadow(0 0 10px rgba(0, 255, 136, 0.7));
214
+ }
417
215
  }
418
- .read-the-docs {
419
- display: none !important;
216
+
217
+ /* Vital Point Hover - Targeting assistance */
218
+ @keyframes vitalPointHover {
219
+ 0%, 100% {
220
+ transform: scale(1);
221
+ filter: brightness(1);
222
+ }
223
+ 50% {
224
+ transform: scale(1.15);
225
+ filter: brightness(1.4) drop-shadow(0 0 12px rgba(255, 170, 0, 0.9));
226
+ }
420
227
  }
421
- /* Note: Theme variables are now centralized in index.css */
422
- /* Performance optimizations for mobile */
423
- @media (max-width: 768px) {
424
- .app-container {
425
- /* Prevent iOS zoom on double-tap */
426
- touch-action: manipulation;
427
228
 
428
- /* Lock viewport to prevent scrolling */
429
- position: fixed;
430
- overflow: hidden;
229
+ /* Message Slide In - Combat log messages */
230
+ @keyframes messageSlideIn {
231
+ from {
232
+ opacity: 0;
233
+ transform: translateX(-20px);
234
+ }
235
+ to {
236
+ opacity: 1;
237
+ transform: translateX(0);
431
238
  }
432
239
  }
433
- /* High DPI display support */
434
- @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
435
- .app-container canvas {
436
- image-rendering: -webkit-optimize-contrast;
437
- image-rendering: crisp-edges;
240
+
241
+ /* Archetype Badge Glow - Player archetype indicator */
242
+ @keyframes archetypeGlow {
243
+ 0%, 100% {
244
+ box-shadow: 0 0 10px rgba(0, 255, 255, 0.4),
245
+ inset 0 0 10px rgba(0, 255, 255, 0.2);
246
+ }
247
+ 50% {
248
+ box-shadow: 0 0 15px rgba(0, 255, 255, 0.6),
249
+ inset 0 0 15px rgba(0, 255, 255, 0.3);
438
250
  }
439
251
  }
440
- .app {
441
- width: 100vw;
442
- height: 100vh;
443
- display: flex;
444
- flex-direction: column;
445
- background: linear-gradient(135deg, #000a12 0%, #001a25 100%);
446
- color: #ffffff;
447
- font-family: "Noto Sans KR", Arial, sans-serif;
448
- overflow: hidden;
449
- /* Remove focus outline when the app container is focused via tabIndex.
450
- * The game container is made focusable for keyboard input capture. */
451
- outline: none;
252
+
253
+ /* Performance Optimizations */
254
+ /* Use will-change sparingly for GPU-friendly properties */
255
+ .hud-animated {
256
+ /* Limit will-change to widely used, GPU-accelerated properties */
257
+ /* Overuse of will-change can degrade performance */
258
+ will-change: transform, opacity;
452
259
  }
453
- .app-header {
454
- padding: 1rem 2rem;
455
- background: color-mix(in srgb, var(--color-bg-dark) 90%, transparent);
456
- border-bottom: 2px solid var(--color-primary-gold);
260
+
261
+ /* Hardware acceleration hints */
262
+ .hud-transform {
263
+ transform: translateZ(0);
264
+ backface-visibility: hidden;
265
+ }
266
+
267
+ /* Reduce motion for accessibility */
268
+ /* Following WCAG 2.1 - Success Criterion 2.3.3: reduce motion, not eliminate it */
269
+ @media (prefers-reduced-motion: reduce) {
270
+ /* Target HUD animations specifically - most specific rule wins */
271
+ .hud-animated {
272
+ animation: none !important;
273
+ transition-duration: 0.1s !important;
274
+ }
275
+ }
276
+ /**
277
+ * Training component styles
278
+ * CSS classes for Html overlay components to avoid inline style manipulation
279
+ */
280
+
281
+ /* Training Controls Button */
282
+ .training-button {
283
+ width: 100%;
284
+ height: 40px;
285
+ border: 2px solid color-mix(in srgb, var(--color-text-primary) 80%, transparent);
286
+ border-radius: 8px;
287
+ color: var(--color-text-primary);
288
+ font-weight: bold;
289
+ cursor: pointer;
457
290
  display: flex;
458
- justify-content: space-between;
459
291
  align-items: center;
460
- box-shadow: 0 2px 10px color-mix(in srgb, var(--color-primary-gold) 30%, transparent);
292
+ justify-content: center;
293
+ gap: 8px;
294
+ transition: all 0.2s ease;
461
295
  }
462
- .app-title {
463
- margin: 0;
464
- display: flex;
465
- flex-direction: column;
466
- gap: 0.25rem;
296
+
297
+ .training-button-start {
298
+ background: var(--color-success);
467
299
  }
468
- .korean-title {
469
- font-size: 1.8rem;
470
- font-weight: bold;
471
- color: var(--color-primary-gold);
472
- text-shadow: 2px 2px 4px color-mix(in srgb, var(--color-primary-black) 80%, transparent);
300
+
301
+ .training-button-stop {
302
+ background: var(--color-korean-south);
303
+ }
304
+
305
+ .training-button:hover {
306
+ transform: scale(1.05);
307
+ box-shadow: 0 0 15px currentColor;
308
+ }
309
+
310
+ /* Training Mode Selector */
311
+ .mode-button {
312
+ background: color-mix(in srgb, var(--color-bg-light) 50%, transparent);
313
+ border: 2px solid color-mix(in srgb, var(--color-primary-cyan) 40%, transparent);
314
+ border-radius: 8px;
315
+ padding: 10px;
316
+ cursor: pointer;
317
+ text-align: left;
318
+ color: var(--color-text-primary);
319
+ transition: all 0.2s ease;
473
320
  }
474
- .english-title {
475
- font-size: 1rem;
476
- color: var(--color-info);
477
- font-style: italic;
478
- text-shadow: 1px 1px 2px color-mix(in srgb, var(--color-primary-black) 60%, transparent);
321
+
322
+ .mode-button.selected {
323
+ background: color-mix(in srgb, var(--color-primary-cyan) 25%, transparent);
324
+ border-color: var(--color-primary-cyan);
325
+ box-shadow: 0 0 12px color-mix(in srgb, var(--color-primary-cyan) 50%, transparent);
479
326
  }
480
- .app-status {
481
- display: flex;
482
- flex-direction: column;
483
- gap: 0.5rem;
484
- text-align: right;
327
+
328
+ .mode-button:not(.selected):hover {
329
+ background: color-mix(in srgb, var(--color-gray-300) 70%, transparent);
330
+ border-color: var(--color-primary-cyan);
331
+ transform: scale(1.02);
485
332
  }
486
- .phase-indicator,
487
- .time-indicator {
488
- padding: 0.25rem 0.75rem;
489
- border-radius: 4px;
490
- font-size: 0.9rem;
491
- font-weight: bold;
333
+
334
+ .mode-button:focus-visible {
335
+ outline: 2px solid var(--color-primary-cyan);
336
+ outline-offset: 2px;
337
+ box-shadow: 0 0 12px color-mix(in srgb, var(--color-primary-cyan) 80%, transparent);
492
338
  }
493
- .phase-indicator {
494
- background: color-mix(in srgb, var(--color-primary-gold) 20%, transparent);
495
- color: var(--color-primary-gold);
496
- border: 1px solid var(--color-primary-gold);
339
+
340
+ /* Vital Point Button */
341
+ .vital-point-button {
342
+ background: color-mix(in srgb, var(--color-bg-light) 50%, transparent);
343
+ border: 2px solid color-mix(in srgb, var(--color-korean-center) 50%, transparent);
344
+ border-radius: 8px;
345
+ padding: 8px;
346
+ cursor: pointer;
347
+ text-align: left;
348
+ color: var(--color-text-primary);
349
+ transition: all 0.2s ease;
497
350
  }
498
- .time-indicator {
499
- background: color-mix(in srgb, var(--color-info) 20%, transparent);
500
- color: var(--color-info);
501
- border: 1px solid var(--color-info);
351
+
352
+ .vital-point-button.selected {
353
+ background: color-mix(in srgb, var(--color-korean-center) 30%, transparent);
502
354
  }
503
- .app-main {
504
- flex: 1;
505
- display: flex;
506
- justify-content: center;
507
- align-items: center;
508
- overflow: hidden;
355
+
356
+ .vital-point-button:not(.selected):hover {
357
+ background: color-mix(in srgb, var(--color-gray-300) 70%, transparent);
509
358
  }
510
- .app-debug {
511
- background: color-mix(in srgb, var(--color-primary-black) 80%, transparent);
512
- color: #00ff00;
513
- font-family: "Courier New", monospace;
514
- font-size: 0.8rem;
515
- max-height: 200px;
516
- overflow-y: auto;
359
+
360
+ /* Training Feedback Animation - Fast and snappy */
361
+ @keyframes feedbackPulse {
362
+ 0% {
363
+ transform: scale(0.9);
364
+ opacity: 0;
365
+ }
366
+ 40% {
367
+ transform: scale(1.05);
368
+ }
369
+ 100% {
370
+ transform: scale(1);
371
+ opacity: 1;
372
+ }
517
373
  }
518
- .app-debug summary {
519
- padding: 0.5rem;
520
- cursor: pointer;
521
- background: color-mix(in srgb, var(--color-success) 10%, transparent);
522
- border-bottom: 1px solid #00ff00;
374
+
375
+ .training-feedback {
376
+ background: color-mix(in srgb, var(--color-primary-black) 90%, transparent);
377
+ border: 3px solid var(--color-primary-gold);
378
+ border-radius: 16px;
379
+ color: var(--color-primary-gold);
380
+ text-align: center;
381
+ box-shadow: 0 0 30px color-mix(in srgb, var(--color-primary-gold) 50%, transparent);
382
+ animation: feedbackPulse 0.4s ease-out;
383
+ min-width: 200px;
523
384
  }
524
- .app-debug pre {
525
- padding: 1rem;
526
- margin: 0;
527
- white-space: pre-wrap;
528
- word-wrap: break-word;
385
+
386
+ .training-feedback.mobile {
387
+ padding: 15px 25px;
388
+ font-size: 18px;
529
389
  }
530
- /* Responsive design */
531
- @media (max-width: 768px) {
532
- .app-header {
533
- padding: 0.5rem 1rem;
534
- flex-direction: column;
535
- gap: 0.5rem;
536
- }
537
390
 
538
- .korean-title {
539
- font-size: 1.4rem;
540
- }
391
+ .training-feedback.desktop {
392
+ padding: 20px 40px;
393
+ font-size: 24px;
394
+ }
541
395
 
542
- .english-title {
543
- font-size: 0.9rem;
396
+ /* Pulsing Status Indicator (replaces requestAnimationFrame) */
397
+ @keyframes statusPulse {
398
+ 0%, 100% {
399
+ opacity: 0.6;
400
+ box-shadow: 0 0 8px currentColor;
544
401
  }
545
-
546
- .app-status {
547
- flex-direction: row;
548
- gap: 1rem;
402
+ 50% {
403
+ opacity: 1;
404
+ box-shadow: 0 0 16px currentColor;
549
405
  }
550
406
  }
551
- /* Korean traditional design elements */
552
- .app::before {
553
- content: "";
554
- position: fixed;
555
- top: 0;
556
- left: 0;
557
- right: 0;
558
- bottom: 0;
559
- background-image: radial-gradient(
560
- circle at 20% 20%,
561
- color-mix(in srgb, var(--color-primary-gold) 5%, transparent) 0%,
562
- transparent 50%
563
- ),
564
- radial-gradient(
565
- circle at 80% 80%,
566
- color-mix(in srgb, var(--color-info) 5%, transparent) 0%,
567
- transparent 50%
568
- );
569
- pointer-events: none;
570
- z-index: -1;
571
- }
572
- /* Loading screen styles */
573
- .loading-screen {
574
- display: flex;
575
- justify-content: center;
576
- align-items: center;
577
- min-height: 100vh;
578
- background: linear-gradient(135deg, #000000 0%, #1a1a2e 50%, #16213e 100%);
579
- color: #ffffff;
580
- font-family: "Noto Sans KR", Arial, sans-serif;
407
+
408
+ .status-indicator {
409
+ width: 12px;
410
+ height: 12px;
411
+ border-radius: 50%;
412
+ background: var(--color-success);
581
413
  }
582
- .loading-content {
583
- text-align: center;
584
- animation: pulse 2s ease-in-out infinite;
414
+
415
+ .status-indicator.active {
416
+ animation: statusPulse 1s ease-in-out infinite;
585
417
  }
586
- .korean-title {
587
- font-size: 2.5rem;
588
- font-weight: 700;
589
- color: #ffd700;
590
- margin-bottom: 1rem;
591
- text-shadow: 0 0 20px color-mix(in srgb, var(--color-primary-gold) 50%, transparent);
418
+
419
+ .status-indicator.inactive {
420
+ background: var(--color-gray-500);
592
421
  }
593
- .english-subtitle {
594
- font-size: 1.2rem;
595
- font-weight: 300;
596
- color: #00ffff;
422
+
423
+
424
+
425
+
426
+ /* Black Trigram - Korean Cyberpunk Martial Arts Styling */
427
+ /* Note: CSS variables are now centralized in index.css */
428
+ * {
597
429
  margin: 0;
430
+ padding: 0;
431
+ box-sizing: border-box;
598
432
  }
599
- /* Error state styles */
600
- .error-state {
433
+ body {
434
+ font-family: var(--font-korean);
435
+ background: linear-gradient(
436
+ 135deg,
437
+ var(--color-bg-dark) 0%,
438
+ var(--color-bg-medium) 100%
439
+ );
440
+ color: var(--color-text-primary);
441
+ overflow: hidden;
442
+ user-select: none;
443
+ }
444
+ #root {
445
+ width: 100vw;
446
+ height: 100vh;
601
447
  display: flex;
602
- flex-direction: column;
603
448
  justify-content: center;
604
449
  align-items: center;
605
- min-height: 100vh;
606
- background: linear-gradient(135deg, #8b0000 0%, #4b0000 100%);
607
- color: #ffffff;
608
- font-family: "Noto Sans KR", Arial, sans-serif;
609
- text-align: center;
450
+ background: radial-gradient(
451
+ ellipse at center,
452
+ var(--color-bg-medium) 0%,
453
+ var(--color-bg-dark) 100%
454
+ );
610
455
  }
611
- .error-state h1 {
612
- color: #ff4444;
613
- margin-bottom: 2rem;
456
+ /* Korean Text Enhancement */
457
+ .korean-text {
458
+ font-family: var(--font-korean);
459
+ font-weight: 400;
460
+ text-shadow: 0 0 8px var(--color-korean-east);
461
+ letter-spacing: 0.02em;
614
462
  }
615
- .error-state button {
616
- padding: 1rem 2rem;
617
- background: #ffd700;
618
- color: #000000;
619
- border: none;
620
- border-radius: 4px;
621
- font-weight: bold;
622
- cursor: pointer;
623
- transition: background-color 0.3s ease;
463
+ .korean-title {
464
+ font-family: var(--font-korean);
465
+ font-weight: 700;
466
+ font-size: 3rem;
467
+ background: linear-gradient(
468
+ 45deg,
469
+ var(--color-accent-cyan),
470
+ var(--color-warning)
471
+ );
472
+ -webkit-background-clip: text;
473
+ -webkit-text-fill-color: transparent;
474
+ background-clip: text;
475
+ text-shadow: 0 0 20px var(--color-accent-cyan);
624
476
  }
625
- .error-state button:hover {
626
- background: #ffed4e;
477
+ .cyber-text {
478
+ font-family: var(--font-cyber);
479
+ color: var(--color-accent-cyan);
480
+ text-transform: uppercase;
481
+ letter-spacing: 0.1em;
482
+ text-shadow: 0 0 10px currentColor;
627
483
  }
628
- @keyframes pulse {
629
- 0%,
630
- 100% {
631
- opacity: 1;
632
- }
633
- 50% {
634
- opacity: 0.7;
635
- }
484
+ /* Cyberpunk UI Elements */
485
+ .cyberpunk-border {
486
+ border: 2px solid var(--color-accent-cyan);
487
+ border-image: linear-gradient(
488
+ 45deg,
489
+ var(--color-accent-cyan),
490
+ var(--color-warning),
491
+ var(--color-accent-cyan)
492
+ )
493
+ 1;
494
+ box-shadow: 0 0 10px var(--color-accent-cyan),
495
+ inset 0 0 10px color-mix(in srgb, var(--color-accent-cyan) 10%, transparent);
636
496
  }
637
- /* App-specific styles for Black Trigram */
638
- .app-container {
639
- width: 100%;
640
- height: 100%;
497
+ .cyberpunk-button {
498
+ background: linear-gradient(
499
+ 135deg,
500
+ color-mix(in srgb, var(--color-accent-cyan) 10%, transparent),
501
+ color-mix(in srgb, var(--color-warning) 10%, transparent)
502
+ );
503
+ border: 1px solid var(--color-accent-cyan);
504
+ color: var(--color-text-primary);
505
+ padding: 0.8rem 1.5rem;
506
+ cursor: pointer;
507
+ transition: all 0.3s ease;
508
+ font-family: var(--font-korean);
509
+ font-weight: 500;
641
510
  position: relative;
642
- background: linear-gradient(45deg, #0a0a0a, #1a1a1e);
643
- }
644
- .game-canvas {
645
- width: 100%;
646
- height: 100%;
647
- display: block;
511
+ overflow: hidden;
648
512
  }
649
- .loading-screen {
650
- position: absolute;
651
- top: 50%;
652
- left: 50%;
653
- transform: translate(-50%, -50%);
654
- text-align: center;
655
- color: var(--color-primary-cyan);
513
+ .cyberpunk-button:hover {
514
+ background: linear-gradient(
515
+ 135deg,
516
+ color-mix(in srgb, var(--color-accent-cyan) 20%, transparent),
517
+ color-mix(in srgb, var(--color-warning) 20%, transparent)
518
+ );
519
+ box-shadow: 0 0 20px var(--color-accent-cyan);
520
+ transform: translateY(-2px);
656
521
  }
657
- .error-screen {
522
+ .cyberpunk-button:before {
523
+ content: "";
658
524
  position: absolute;
659
- top: 50%;
660
- left: 50%;
661
- transform: translate(-50%, -50%);
662
- text-align: center;
663
- color: #ff4136;
664
- padding: 2rem;
665
- border: 1px solid #ff4136;
666
- background: color-mix(in srgb, var(--color-danger) 10%, transparent);
667
- }
668
- /* Fix UI overlay positioning to not interfere with canvas visibility */
669
- .test-overlay {
670
- pointer-events: none;
671
- position: absolute !important; /* Changed from fixed */
672
525
  top: 0;
673
- left: 0;
526
+ left: -100%;
674
527
  width: 100%;
675
528
  height: 100%;
676
- z-index: 100; /* Reduced from 500 to ensure canvas visibility */
677
- background: transparent;
678
- }
679
- /* Fix button z-index to be lower than canvas but still interactive */
680
- .test-overlay button {
681
- z-index: 50 !important; /* Reduced from 400 */
682
- pointer-events: auto;
683
- position: absolute;
529
+ background: linear-gradient(
530
+ 90deg,
531
+ transparent,
532
+ color-mix(in srgb, var(--color-text-primary) 20%, transparent),
533
+ transparent
534
+ );
535
+ transition: left 0.5s;
684
536
  }
685
- /* Ensure buttons don't cover the center of the canvas */
686
- .training-button {
687
- top: 60% !important; /* Move down from 50% */
688
- left: 5% !important;
689
- right: auto !important;
690
- width: auto !important;
691
- max-width: 200px !important;
537
+ .cyberpunk-button:hover:before {
538
+ left: 100%;
692
539
  }
693
- .combat-button {
694
- top: 70% !important; /* Move down from 60% */
695
- left: 5% !important;
696
- right: auto !important;
697
- width: auto !important;
698
- max-width: 200px !important;
540
+ /* Combat HUD Styling */
541
+ .combat-hud {
542
+ position: absolute;
543
+ top: 0;
544
+ left: 0;
545
+ right: 0;
546
+ background: linear-gradient(
547
+ 180deg,
548
+ color-mix(in srgb, var(--color-bg-dark) 90%, transparent) 0%,
549
+ transparent 100%
550
+ );
551
+ padding: 1rem;
552
+ border-bottom: 1px solid var(--color-accent-cyan);
699
553
  }
700
- /* Mobile specific adjustments */
701
- @media (max-width: 768px) {
702
- .training-button {
703
- top: 65% !important;
704
- left: 5% !important;
705
- right: 5% !important;
706
- width: auto !important;
707
- font-size: 14px;
708
- padding: 10px 16px;
709
- }
710
-
711
- .combat-button {
712
- top: 75% !important;
713
- left: 5% !important;
714
- right: 5% !important;
715
- width: auto !important;
716
- font-size: 14px;
717
- padding: 10px 16px;
718
- }
554
+ .health-bar {
555
+ background: var(--color-bg-dark);
556
+ border: 1px solid var(--color-accent-cyan);
557
+ height: 8px;
558
+ border-radius: 4px;
559
+ overflow: hidden;
560
+ position: relative;
719
561
  }
720
- @media (max-width: 375px) {
721
- .training-button {
722
- top: 70% !important;
723
- font-size: 12px;
724
- padding: 8px 12px;
725
- }
726
-
727
- .combat-button {
728
- top: 80% !important;
729
- font-size: 12px;
730
- padding: 8px 12px;
731
- }
562
+ .health-bar-fill {
563
+ background: linear-gradient(
564
+ 90deg,
565
+ var(--color-danger) 0%,
566
+ var(--color-warning) 50%,
567
+ var(--color-korean-east) 100%
568
+ );
569
+ height: 100%;
570
+ transition: width 0.3s ease;
571
+ box-shadow: 0 0 10px currentColor;
732
572
  }
733
- /**
734
- * HUD Animations - Centralized keyframe animations for all HUD components
735
- *
736
- * Performance-optimized animations for 60fps gameplay
737
- * Korean cyberpunk themed with glow effects
738
- *
739
- * @category UI Animations
740
- * @korean HUD 애니메이션
741
- */
742
-
743
- /* Health Bar Pulse - Critical health warning */
744
- @keyframes healthPulse {
745
- 0%, 100% {
746
- opacity: 1;
747
- filter: brightness(1) drop-shadow(0 0 8px rgba(255, 68, 68, 0.6));
573
+ /* Animation Effects */
574
+ @keyframes korean-glow {
575
+ 0%,
576
+ 100% {
577
+ text-shadow: 0 0 5px var(--color-korean-east);
748
578
  }
749
579
  50% {
750
- opacity: 0.85;
751
- filter: brightness(1.2) drop-shadow(0 0 12px rgba(255, 68, 68, 0.9));
580
+ text-shadow: 0 0 20px var(--color-korean-east);
752
581
  }
753
582
  }
754
-
755
- /* Stamina Bar Pulse - Low stamina warning */
756
- @keyframes staminaPulse {
757
- 0%, 100% {
758
- opacity: 1;
759
- filter: brightness(1) drop-shadow(0 0 6px rgba(0, 136, 255, 0.6));
760
- }
761
- 50% {
762
- opacity: 0.85;
763
- filter: brightness(1.2) drop-shadow(0 0 10px rgba(0, 136, 255, 0.9));
764
- }
583
+ .animate-glow {
584
+ animation: korean-glow 2s ease-in-out infinite;
765
585
  }
766
-
767
- /* Technique Card Glow - Available technique */
768
- @keyframes techniqueGlow {
769
- 0%, 100% {
770
- box-shadow: 0 0 10px rgba(0, 255, 255, 0.3),
771
- 0 0 20px rgba(0, 255, 255, 0.2),
772
- inset 0 0 10px rgba(0, 255, 255, 0.1);
586
+ @keyframes combat-flash {
587
+ 0% {
588
+ background-color: color-mix(in srgb, var(--color-danger) 10%, transparent);
773
589
  }
774
590
  50% {
775
- box-shadow: 0 0 15px rgba(0, 255, 255, 0.5),
776
- 0 0 30px rgba(0, 255, 255, 0.3),
777
- inset 0 0 15px rgba(0, 255, 255, 0.2);
778
- }
779
- }
780
-
781
- /* Technique Card Pulse - Selected technique */
782
- @keyframes techniqueSelected {
783
- 0%, 100% {
784
- transform: scale(1);
785
- box-shadow: 0 0 15px rgba(255, 170, 0, 0.6),
786
- 0 0 25px rgba(255, 170, 0, 0.4),
787
- inset 0 0 15px rgba(255, 170, 0, 0.2);
591
+ background-color: color-mix(in srgb, var(--color-danger) 30%, transparent);
788
592
  }
789
- 50% {
790
- transform: scale(1.05);
791
- box-shadow: 0 0 20px rgba(255, 170, 0, 0.8),
792
- 0 0 35px rgba(255, 170, 0, 0.5),
793
- inset 0 0 20px rgba(255, 170, 0, 0.3);
593
+ 100% {
594
+ background-color: color-mix(in srgb, var(--color-danger) 10%, transparent);
794
595
  }
795
596
  }
796
-
797
- /* HUD Panel Fade In - Smooth entry */
798
- @keyframes hudFadeIn {
799
- from {
800
- opacity: 0;
801
- transform: translateY(-10px);
802
- }
803
- to {
804
- opacity: 1;
805
- transform: translateY(0);
806
- }
597
+ .combat-flash {
598
+ animation: combat-flash 0.2s ease-in-out;
807
599
  }
600
+ /* Responsive Design */
601
+ @media (max-width: 768px) {
602
+ .korean-title {
603
+ font-size: 2rem;
604
+ }
808
605
 
809
- /* Combat Readiness Pulse - Ready to attack */
810
- @keyframes readinessPulse {
811
- 0%, 100% {
812
- filter: brightness(1) drop-shadow(0 0 8px rgba(0, 255, 136, 0.5));
606
+ .cyberpunk-button {
607
+ padding: 0.6rem 1.2rem;
608
+ font-size: 0.9rem;
813
609
  }
814
- 50% {
815
- filter: brightness(1.3) drop-shadow(0 0 15px rgba(0, 255, 136, 0.8));
610
+
611
+ /* Enhanced responsive design for Korean martial arts game */
612
+ .app-container {
613
+ position: relative;
614
+ width: 100vw;
615
+ height: 100vh;
616
+ overflow: hidden;
617
+ background: #000000;
618
+ display: flex;
619
+ align-items: center;
620
+ justify-content: center;
816
621
  }
817
- }
818
622
 
819
- /* Speed Indicator Glow - High speed movement */
820
- @keyframes speedGlow {
821
- 0%, 100% {
822
- text-shadow: 0 0 8px rgba(0, 255, 255, 0.6),
823
- 0 0 16px rgba(0, 255, 255, 0.4);
623
+ /* Better mobile canvas handling */
624
+ .app-container canvas {
625
+ width: 100vw !important;
626
+ height: 100vh !important;
627
+ position: relative !important;
824
628
  }
825
- 50% {
826
- text-shadow: 0 0 12px rgba(0, 255, 255, 0.8),
827
- 0 0 24px rgba(0, 255, 255, 0.6);
629
+
630
+ /* Improve mobile UI overlay positioning */
631
+ .test-overlay {
632
+ position: fixed;
633
+ top: 0;
634
+ left: 0;
635
+ width: 100vw;
636
+ height: 100vh;
637
+ z-index: 500;
828
638
  }
829
639
  }
830
-
831
- /* Timer Flash - Final seconds warning */
832
- @keyframes timerFlash {
833
- 0%, 100% {
834
- color: var(--color-korean-south);
835
- text-shadow: 0 0 10px color-mix(in srgb, var(--color-korean-south) 80%, transparent),
836
- 0 0 20px color-mix(in srgb, var(--color-korean-south) 50%, transparent);
640
+ /* Tablet optimizations */
641
+ @media (min-width: 768px) and (max-width: 1024px) {
642
+ .app-container canvas {
643
+ width: 100vw !important;
644
+ height: 100vh !important;
837
645
  }
838
- 50% {
839
- color: var(--color-korean-center);
840
- text-shadow: 0 0 15px var(--color-korean-center),
841
- 0 0 30px color-mix(in srgb, var(--color-korean-center) 70%, transparent);
646
+ }
647
+ /* Desktop optimizations */
648
+ @media (min-width: 1024px) {
649
+ .app-container {
650
+ justify-content: center;
651
+ align-items: center;
842
652
  }
843
653
  }
844
-
845
- /* Round Display Pulse - Round transition */
846
- @keyframes roundPulse {
654
+ /* Loading and Error States */
655
+ .loading-spinner {
656
+ border: 2px solid var(--color-bg-medium);
657
+ border-top: 2px solid var(--color-accent-cyan);
658
+ border-radius: 50%;
659
+ width: 40px;
660
+ height: 40px;
661
+ animation: spin 1s linear infinite;
662
+ margin: 0 auto;
663
+ }
664
+ @keyframes spin {
847
665
  0% {
848
- transform: scale(0.9);
849
- opacity: 0;
850
- }
851
- 50% {
852
- transform: scale(1.05);
853
- opacity: 1;
666
+ transform: rotate(0deg);
854
667
  }
855
668
  100% {
856
- transform: scale(1);
857
- opacity: 1;
669
+ transform: rotate(360deg);
858
670
  }
859
671
  }
860
-
861
- /* Combo Counter Flash - Combo milestone */
862
- @keyframes comboFlash {
863
- 0%, 100% {
864
- transform: scale(1);
865
- filter: brightness(1);
866
- }
867
- 25% {
868
- transform: scale(1.2);
869
- filter: brightness(1.5) drop-shadow(0 0 20px rgba(255, 170, 0, 1));
672
+ .error-message {
673
+ color: var(--color-danger);
674
+ background: color-mix(in srgb, var(--color-danger) 10%, transparent);
675
+ border: 1px solid var(--color-danger);
676
+ padding: 1rem;
677
+ border-radius: 4px;
678
+ margin: 1rem 0;
679
+ font-family: var(--font-korean);
680
+ }
681
+ /* Accessibility */
682
+ .sr-only {
683
+ position: absolute;
684
+ width: 1px;
685
+ height: 1px;
686
+ padding: 0;
687
+ margin: -1px;
688
+ overflow: hidden;
689
+ clip: rect(0, 0, 0, 0);
690
+ white-space: nowrap;
691
+ border: 0;
692
+ }
693
+ /* High contrast mode support - Comprehensive accessibility */
694
+ @media (prefers-contrast: high) {
695
+ :root {
696
+ /* High contrast colors for better visibility */
697
+ --color-primary-cyan: #ffffff;
698
+ --color-primary-gold: #ffffff;
699
+ --color-text-primary: #ffffff;
700
+ --color-text-secondary: #ffffff;
701
+ --color-text-tertiary: #cccccc;
702
+ --color-bg-dark: #000000;
703
+ --color-bg-medium: #000000;
704
+ --color-bg-light: #1a1a1a;
705
+
706
+ /* Ensure sufficient contrast for UI elements */
707
+ --color-danger: #ff0000;
708
+ --color-success: #00ff00;
709
+ --color-warning: #ffff00;
870
710
  }
871
- 50% {
872
- transform: scale(1.1);
873
- filter: brightness(1.3) drop-shadow(0 0 15px rgba(255, 170, 0, 0.8));
711
+
712
+ /* Increase border visibility in high contrast mode */
713
+ button,
714
+ .error-boundary__container,
715
+ .loading-state__progress {
716
+ border-width: 3px;
874
717
  }
875
- 75% {
876
- transform: scale(1.15);
877
- filter: brightness(1.4) drop-shadow(0 0 18px rgba(255, 170, 0, 0.9));
718
+ }
719
+ /* Reduced motion support */
720
+ @media (prefers-reduced-motion: reduce) {
721
+ *,
722
+ *::before,
723
+ *::after {
724
+ animation-duration: 0.01ms !important;
725
+ animation-iteration-count: 1 !important;
726
+ transition-duration: 0.01ms !important;
878
727
  }
879
728
  }
729
+ /* Reset default Vite styles */
730
+ #root {
731
+ width: 100vw;
732
+ height: 100vh;
733
+ margin: 0;
734
+ padding: 0;
735
+ overflow: hidden;
736
+ }
737
+ /* Full-screen game container */
738
+ .app-container {
739
+ position: fixed;
740
+ top: 0;
741
+ left: 0;
742
+ width: 100vw;
743
+ height: 100vh;
744
+ margin: 0;
745
+ padding: 0;
746
+ overflow: hidden;
747
+ background: #000000;
748
+ display: flex;
749
+ align-items: center;
750
+ justify-content: center;
751
+ font-family: "Noto Sans KR", sans-serif;
880
752
 
881
- /* Body Part Critical - Body part near failure */
882
- @keyframes bodyPartCritical {
883
- 0%, 100% {
884
- border-color: rgba(255, 68, 68, 0.8);
885
- box-shadow: 0 0 8px rgba(255, 68, 68, 0.5),
886
- inset 0 0 8px rgba(255, 68, 68, 0.3);
887
- }
888
- 50% {
889
- border-color: rgba(255, 68, 68, 1);
890
- box-shadow: 0 0 15px rgba(255, 68, 68, 0.8),
891
- inset 0 0 12px rgba(255, 68, 68, 0.5);
753
+ /* Prevent text selection during game */
754
+ user-select: none;
755
+ -webkit-user-select: none;
756
+ -moz-user-select: none;
757
+ -ms-user-select: none;
758
+
759
+ /* Disable touch callouts on mobile */
760
+ -webkit-touch-callout: none;
761
+
762
+ /* Optimize for game rendering */
763
+ will-change: transform;
764
+ transform: translateZ(0);
765
+ backface-visibility: hidden;
766
+ }
767
+ /* Hide any old game elements */
768
+ .app-container h1,
769
+ .app-container .instructions {
770
+ display: none !important;
771
+ }
772
+ /* Korean typography support */
773
+ /* NOTE: overflow: hidden on body prevents the page itself from scrolling.
774
+ * This is intentional for a full-screen game. Individual screens that need
775
+ * scrollable content (Philosophy, Controls) use internal scrollable containers
776
+ * with overflowY: "auto" on their content areas, which works correctly
777
+ * because the content div has a fixed height within the viewport. */
778
+ body {
779
+ font-family: "Noto Sans KR", sans-serif;
780
+ margin: 0;
781
+ padding: 0;
782
+ overflow: hidden;
783
+ background: #000000;
784
+ width: 100vw;
785
+ height: 100vh;
786
+ }
787
+ /* Traditional Korean color scheme enhancements */
788
+ .app-container::before {
789
+ content: "";
790
+ position: absolute;
791
+ top: 0;
792
+ left: 0;
793
+ right: 0;
794
+ bottom: 0;
795
+ background: radial-gradient(
796
+ circle at center,
797
+ color-mix(in srgb, var(--color-korean-south) 10%, transparent) 0%,
798
+ var(--color-primary-black) 70%
799
+ );
800
+ pointer-events: none;
801
+ z-index: -1;
802
+ }
803
+ /* Performance optimizations for WebGL */
804
+ .app-container canvas {
805
+ will-change: transform;
806
+ transform: translateZ(0);
807
+ backface-visibility: hidden;
808
+ }
809
+ /* Responsive adjustments for different screen sizes */
810
+ @media (max-width: 768px) {
811
+ .app-container {
812
+ width: 100vw !important;
813
+ height: 100vh !important;
892
814
  }
893
- }
894
815
 
895
- /* Guard Indicator Active - Guard stance active */
896
- @keyframes guardActive {
897
- 0%, 100% {
898
- box-shadow: 0 0 12px rgba(0, 255, 136, 0.6),
899
- 0 0 24px rgba(0, 255, 136, 0.4);
900
- }
901
- 50% {
902
- box-shadow: 0 0 18px rgba(0, 255, 136, 0.9),
903
- 0 0 36px rgba(0, 255, 136, 0.6);
816
+ .app-container canvas {
817
+ width: 100vw !important;
818
+ height: 100vh !important;
904
819
  }
905
820
  }
906
-
907
- /* Stance Change Flash - Stance transition effect */
908
- @keyframes stanceChange {
909
- 0% {
910
- opacity: 0;
911
- transform: scale(0.8) rotate(-5deg);
912
- }
913
- 50% {
914
- opacity: 1;
915
- transform: scale(1.1) rotate(2deg);
916
- }
917
- 100% {
918
- opacity: 1;
919
- transform: scale(1) rotate(0deg);
821
+ @media (max-width: 375px) {
822
+ .app-container {
823
+ width: 100vw !important;
824
+ height: 100vh !important;
920
825
  }
921
- }
922
826
 
923
- /* Training Mode Active - Training session indicator */
924
- @keyframes trainingActive {
925
- 0%, 100% {
926
- border-color: rgba(0, 255, 136, 0.8);
927
- filter: brightness(1);
928
- }
929
- 50% {
930
- border-color: rgba(0, 255, 136, 1);
931
- filter: brightness(1.2) drop-shadow(0 0 10px rgba(0, 255, 136, 0.7));
827
+ .app-container canvas {
828
+ width: 100vw !important;
829
+ height: 100vh !important;
932
830
  }
933
831
  }
934
-
935
- /* Vital Point Hover - Targeting assistance */
936
- @keyframes vitalPointHover {
937
- 0%, 100% {
938
- transform: scale(1);
939
- filter: brightness(1);
940
- }
941
- 50% {
942
- transform: scale(1.15);
943
- filter: brightness(1.4) drop-shadow(0 0 12px rgba(255, 170, 0, 0.9));
944
- }
832
+ /* Remove any legacy Vite template styles that might interfere */
833
+ .logo {
834
+ display: none !important;
945
835
  }
946
-
947
- /* Message Slide In - Combat log messages */
948
- @keyframes messageSlideIn {
949
- from {
950
- opacity: 0;
951
- transform: translateX(-20px);
952
- }
953
- to {
954
- opacity: 1;
955
- transform: translateX(0);
956
- }
836
+ .card {
837
+ display: none !important;
838
+ }
839
+ .read-the-docs {
840
+ display: none !important;
957
841
  }
842
+ /* Note: Theme variables are now centralized in index.css */
843
+ /* Performance optimizations for mobile */
844
+ @media (max-width: 768px) {
845
+ .app-container {
846
+ /* Prevent iOS zoom on double-tap */
847
+ touch-action: manipulation;
958
848
 
959
- /* Archetype Badge Glow - Player archetype indicator */
960
- @keyframes archetypeGlow {
961
- 0%, 100% {
962
- box-shadow: 0 0 10px rgba(0, 255, 255, 0.4),
963
- inset 0 0 10px rgba(0, 255, 255, 0.2);
849
+ /* Lock viewport to prevent scrolling */
850
+ position: fixed;
851
+ overflow: hidden;
964
852
  }
965
- 50% {
966
- box-shadow: 0 0 15px rgba(0, 255, 255, 0.6),
967
- inset 0 0 15px rgba(0, 255, 255, 0.3);
853
+ }
854
+ /* High DPI display support */
855
+ @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {
856
+ .app-container canvas {
857
+ image-rendering: -webkit-optimize-contrast;
858
+ image-rendering: crisp-edges;
968
859
  }
969
860
  }
970
-
971
- /* Performance Optimizations */
972
- /* Use will-change sparingly for GPU-friendly properties */
973
- .hud-animated {
974
- /* Limit will-change to widely used, GPU-accelerated properties */
975
- /* Overuse of will-change can degrade performance */
976
- will-change: transform, opacity;
861
+ .app {
862
+ width: 100vw;
863
+ height: 100vh;
864
+ display: flex;
865
+ flex-direction: column;
866
+ background: linear-gradient(135deg, #000a12 0%, #001a25 100%);
867
+ color: #ffffff;
868
+ font-family: "Noto Sans KR", Arial, sans-serif;
869
+ overflow: hidden;
870
+ /* Remove focus outline when the app container is focused via tabIndex.
871
+ * The game container is made focusable for keyboard input capture. */
872
+ outline: none;
977
873
  }
978
-
979
- /* Hardware acceleration hints */
980
- .hud-transform {
981
- transform: translateZ(0);
982
- backface-visibility: hidden;
874
+ .app-header {
875
+ padding: 1rem 2rem;
876
+ background: color-mix(in srgb, var(--color-bg-dark) 90%, transparent);
877
+ border-bottom: 2px solid var(--color-primary-gold);
878
+ display: flex;
879
+ justify-content: space-between;
880
+ align-items: center;
881
+ box-shadow: 0 2px 10px color-mix(in srgb, var(--color-primary-gold) 30%, transparent);
882
+ }
883
+ .app-title {
884
+ margin: 0;
885
+ display: flex;
886
+ flex-direction: column;
887
+ gap: 0.25rem;
888
+ }
889
+ .korean-title {
890
+ font-size: 1.8rem;
891
+ font-weight: bold;
892
+ color: var(--color-primary-gold);
893
+ text-shadow: 2px 2px 4px color-mix(in srgb, var(--color-primary-black) 80%, transparent);
894
+ }
895
+ .english-title {
896
+ font-size: 1rem;
897
+ color: var(--color-info);
898
+ font-style: italic;
899
+ text-shadow: 1px 1px 2px color-mix(in srgb, var(--color-primary-black) 60%, transparent);
900
+ }
901
+ .app-status {
902
+ display: flex;
903
+ flex-direction: column;
904
+ gap: 0.5rem;
905
+ text-align: right;
906
+ }
907
+ .phase-indicator,
908
+ .time-indicator {
909
+ padding: 0.25rem 0.75rem;
910
+ border-radius: 4px;
911
+ font-size: 0.9rem;
912
+ font-weight: bold;
913
+ }
914
+ .phase-indicator {
915
+ background: color-mix(in srgb, var(--color-primary-gold) 20%, transparent);
916
+ color: var(--color-primary-gold);
917
+ border: 1px solid var(--color-primary-gold);
918
+ }
919
+ .time-indicator {
920
+ background: color-mix(in srgb, var(--color-info) 20%, transparent);
921
+ color: var(--color-info);
922
+ border: 1px solid var(--color-info);
923
+ }
924
+ .app-main {
925
+ flex: 1;
926
+ display: flex;
927
+ justify-content: center;
928
+ align-items: center;
929
+ overflow: hidden;
930
+ }
931
+ .app-debug {
932
+ background: color-mix(in srgb, var(--color-primary-black) 80%, transparent);
933
+ color: #00ff00;
934
+ font-family: "Courier New", monospace;
935
+ font-size: 0.8rem;
936
+ max-height: 200px;
937
+ overflow-y: auto;
938
+ }
939
+ .app-debug summary {
940
+ padding: 0.5rem;
941
+ cursor: pointer;
942
+ background: color-mix(in srgb, var(--color-success) 10%, transparent);
943
+ border-bottom: 1px solid #00ff00;
944
+ }
945
+ .app-debug pre {
946
+ padding: 1rem;
947
+ margin: 0;
948
+ white-space: pre-wrap;
949
+ word-wrap: break-word;
983
950
  }
951
+ /* Responsive design */
952
+ @media (max-width: 768px) {
953
+ .app-header {
954
+ padding: 0.5rem 1rem;
955
+ flex-direction: column;
956
+ gap: 0.5rem;
957
+ }
984
958
 
985
- /* Reduce motion for accessibility */
986
- /* Following WCAG 2.1 - Success Criterion 2.3.3: reduce motion, not eliminate it */
987
- @media (prefers-reduced-motion: reduce) {
988
- /* Target HUD animations specifically - most specific rule wins */
989
- .hud-animated {
990
- animation: none !important;
991
- transition-duration: 0.1s !important;
959
+ .korean-title {
960
+ font-size: 1.4rem;
992
961
  }
993
- }
994
- /**
995
- * BreathingIndicator Component Styles
996
- *
997
- * Defines keyframe animation for the pulsing breathing difficulty indicator
998
- */
999
962
 
1000
- @keyframes breathing-pulse {
1001
- 0%, 100% {
1002
- opacity: 1;
963
+ .english-title {
964
+ font-size: 0.9rem;
1003
965
  }
1004
- 50% {
1005
- opacity: 0.7;
966
+
967
+ .app-status {
968
+ flex-direction: row;
969
+ gap: 1rem;
1006
970
  }
1007
971
  }
1008
- /**
1009
- * Training component styles
1010
- * CSS classes for Html overlay components to avoid inline style manipulation
1011
- */
1012
-
1013
- /* Training Controls Button */
1014
- .training-button {
1015
- width: 100%;
1016
- height: 40px;
1017
- border: 2px solid color-mix(in srgb, var(--color-text-primary) 80%, transparent);
1018
- border-radius: 8px;
1019
- color: var(--color-text-primary);
1020
- font-weight: bold;
1021
- cursor: pointer;
972
+ /* Korean traditional design elements */
973
+ .app::before {
974
+ content: "";
975
+ position: fixed;
976
+ top: 0;
977
+ left: 0;
978
+ right: 0;
979
+ bottom: 0;
980
+ background-image: radial-gradient(
981
+ circle at 20% 20%,
982
+ color-mix(in srgb, var(--color-primary-gold) 5%, transparent) 0%,
983
+ transparent 50%
984
+ ),
985
+ radial-gradient(
986
+ circle at 80% 80%,
987
+ color-mix(in srgb, var(--color-info) 5%, transparent) 0%,
988
+ transparent 50%
989
+ );
990
+ pointer-events: none;
991
+ z-index: -1;
992
+ }
993
+ /* Loading screen styles */
994
+ .loading-screen {
1022
995
  display: flex;
1023
- align-items: center;
1024
996
  justify-content: center;
1025
- gap: 8px;
1026
- transition: all 0.2s ease;
1027
- }
1028
-
1029
- .training-button-start {
1030
- background: var(--color-success);
1031
- }
1032
-
1033
- .training-button-stop {
1034
- background: var(--color-korean-south);
997
+ align-items: center;
998
+ min-height: 100vh;
999
+ background: linear-gradient(135deg, #000000 0%, #1a1a2e 50%, #16213e 100%);
1000
+ color: #ffffff;
1001
+ font-family: "Noto Sans KR", Arial, sans-serif;
1035
1002
  }
1036
-
1037
- .training-button:hover {
1038
- transform: scale(1.05);
1039
- box-shadow: 0 0 15px currentColor;
1003
+ .loading-content {
1004
+ text-align: center;
1005
+ animation: pulse 2s ease-in-out infinite;
1040
1006
  }
1041
-
1042
- /* Training Mode Selector */
1043
- .mode-button {
1044
- background: color-mix(in srgb, var(--color-bg-light) 50%, transparent);
1045
- border: 2px solid color-mix(in srgb, var(--color-primary-cyan) 40%, transparent);
1046
- border-radius: 8px;
1047
- padding: 10px;
1048
- cursor: pointer;
1049
- text-align: left;
1050
- color: var(--color-text-primary);
1051
- transition: all 0.2s ease;
1007
+ .korean-title {
1008
+ font-size: 2.5rem;
1009
+ font-weight: 700;
1010
+ color: #ffd700;
1011
+ margin-bottom: 1rem;
1012
+ text-shadow: 0 0 20px color-mix(in srgb, var(--color-primary-gold) 50%, transparent);
1052
1013
  }
1053
-
1054
- .mode-button.selected {
1055
- background: color-mix(in srgb, var(--color-primary-cyan) 25%, transparent);
1056
- border-color: var(--color-primary-cyan);
1057
- box-shadow: 0 0 12px color-mix(in srgb, var(--color-primary-cyan) 50%, transparent);
1014
+ .english-subtitle {
1015
+ font-size: 1.2rem;
1016
+ font-weight: 300;
1017
+ color: #00ffff;
1018
+ margin: 0;
1058
1019
  }
1059
-
1060
- .mode-button:not(.selected):hover {
1061
- background: color-mix(in srgb, var(--color-gray-300) 70%, transparent);
1062
- border-color: var(--color-primary-cyan);
1063
- transform: scale(1.02);
1020
+ /* Error state styles */
1021
+ .error-state {
1022
+ display: flex;
1023
+ flex-direction: column;
1024
+ justify-content: center;
1025
+ align-items: center;
1026
+ min-height: 100vh;
1027
+ background: linear-gradient(135deg, #8b0000 0%, #4b0000 100%);
1028
+ color: #ffffff;
1029
+ font-family: "Noto Sans KR", Arial, sans-serif;
1030
+ text-align: center;
1064
1031
  }
1065
-
1066
- .mode-button:focus-visible {
1067
- outline: 2px solid var(--color-primary-cyan);
1068
- outline-offset: 2px;
1069
- box-shadow: 0 0 12px color-mix(in srgb, var(--color-primary-cyan) 80%, transparent);
1032
+ .error-state h1 {
1033
+ color: #ff4444;
1034
+ margin-bottom: 2rem;
1070
1035
  }
1071
-
1072
- /* Vital Point Button */
1073
- .vital-point-button {
1074
- background: color-mix(in srgb, var(--color-bg-light) 50%, transparent);
1075
- border: 2px solid color-mix(in srgb, var(--color-korean-center) 50%, transparent);
1076
- border-radius: 8px;
1077
- padding: 8px;
1036
+ .error-state button {
1037
+ padding: 1rem 2rem;
1038
+ background: #ffd700;
1039
+ color: #000000;
1040
+ border: none;
1041
+ border-radius: 4px;
1042
+ font-weight: bold;
1078
1043
  cursor: pointer;
1079
- text-align: left;
1080
- color: var(--color-text-primary);
1081
- transition: all 0.2s ease;
1082
- }
1083
-
1084
- .vital-point-button.selected {
1085
- background: color-mix(in srgb, var(--color-korean-center) 30%, transparent);
1044
+ transition: background-color 0.3s ease;
1086
1045
  }
1087
-
1088
- .vital-point-button:not(.selected):hover {
1089
- background: color-mix(in srgb, var(--color-gray-300) 70%, transparent);
1046
+ .error-state button:hover {
1047
+ background: #ffed4e;
1090
1048
  }
1091
-
1092
- /* Training Feedback Animation - Fast and snappy */
1093
- @keyframes feedbackPulse {
1094
- 0% {
1095
- transform: scale(0.9);
1096
- opacity: 0;
1097
- }
1098
- 40% {
1099
- transform: scale(1.05);
1100
- }
1049
+ @keyframes pulse {
1050
+ 0%,
1101
1051
  100% {
1102
- transform: scale(1);
1103
1052
  opacity: 1;
1104
1053
  }
1054
+ 50% {
1055
+ opacity: 0.7;
1056
+ }
1105
1057
  }
1106
-
1107
- .training-feedback {
1108
- background: color-mix(in srgb, var(--color-primary-black) 90%, transparent);
1109
- border: 3px solid var(--color-primary-gold);
1110
- border-radius: 16px;
1111
- color: var(--color-primary-gold);
1058
+ /* App-specific styles for Black Trigram */
1059
+ .app-container {
1060
+ width: 100%;
1061
+ height: 100%;
1062
+ position: relative;
1063
+ background: linear-gradient(45deg, #0a0a0a, #1a1a1e);
1064
+ }
1065
+ .game-canvas {
1066
+ width: 100%;
1067
+ height: 100%;
1068
+ display: block;
1069
+ }
1070
+ .loading-screen {
1071
+ position: absolute;
1072
+ top: 50%;
1073
+ left: 50%;
1074
+ transform: translate(-50%, -50%);
1112
1075
  text-align: center;
1113
- box-shadow: 0 0 30px color-mix(in srgb, var(--color-primary-gold) 50%, transparent);
1114
- animation: feedbackPulse 0.4s ease-out;
1115
- min-width: 200px;
1076
+ color: var(--color-primary-cyan);
1116
1077
  }
1117
-
1118
- .training-feedback.mobile {
1119
- padding: 15px 25px;
1120
- font-size: 18px;
1078
+ .error-screen {
1079
+ position: absolute;
1080
+ top: 50%;
1081
+ left: 50%;
1082
+ transform: translate(-50%, -50%);
1083
+ text-align: center;
1084
+ color: #ff4136;
1085
+ padding: 2rem;
1086
+ border: 1px solid #ff4136;
1087
+ background: color-mix(in srgb, var(--color-danger) 10%, transparent);
1121
1088
  }
1122
-
1123
- .training-feedback.desktop {
1124
- padding: 20px 40px;
1125
- font-size: 24px;
1089
+ /* Fix UI overlay positioning to not interfere with canvas visibility */
1090
+ .test-overlay {
1091
+ pointer-events: none;
1092
+ position: absolute !important; /* Changed from fixed */
1093
+ top: 0;
1094
+ left: 0;
1095
+ width: 100%;
1096
+ height: 100%;
1097
+ z-index: 100; /* Reduced from 500 to ensure canvas visibility */
1098
+ background: transparent;
1126
1099
  }
1127
-
1128
- /* Pulsing Status Indicator (replaces requestAnimationFrame) */
1129
- @keyframes statusPulse {
1130
- 0%, 100% {
1131
- opacity: 0.6;
1132
- box-shadow: 0 0 8px currentColor;
1133
- }
1134
- 50% {
1135
- opacity: 1;
1136
- box-shadow: 0 0 16px currentColor;
1137
- }
1100
+ /* Fix button z-index to be lower than canvas but still interactive */
1101
+ .test-overlay button {
1102
+ z-index: 50 !important; /* Reduced from 400 */
1103
+ pointer-events: auto;
1104
+ position: absolute;
1138
1105
  }
1139
-
1140
- .status-indicator {
1141
- width: 12px;
1142
- height: 12px;
1143
- border-radius: 50%;
1144
- background: var(--color-success);
1106
+ /* Ensure buttons don't cover the center of the canvas */
1107
+ .training-button {
1108
+ top: 60% !important; /* Move down from 50% */
1109
+ left: 5% !important;
1110
+ right: auto !important;
1111
+ width: auto !important;
1112
+ max-width: 200px !important;
1145
1113
  }
1114
+ .combat-button {
1115
+ top: 70% !important; /* Move down from 60% */
1116
+ left: 5% !important;
1117
+ right: auto !important;
1118
+ width: auto !important;
1119
+ max-width: 200px !important;
1120
+ }
1121
+ /* Mobile specific adjustments */
1122
+ @media (max-width: 768px) {
1123
+ .training-button {
1124
+ top: 65% !important;
1125
+ left: 5% !important;
1126
+ right: 5% !important;
1127
+ width: auto !important;
1128
+ font-size: 14px;
1129
+ padding: 10px 16px;
1130
+ }
1146
1131
 
1147
- .status-indicator.active {
1148
- animation: statusPulse 1s ease-in-out infinite;
1132
+ .combat-button {
1133
+ top: 75% !important;
1134
+ left: 5% !important;
1135
+ right: 5% !important;
1136
+ width: auto !important;
1137
+ font-size: 14px;
1138
+ padding: 10px 16px;
1139
+ }
1149
1140
  }
1141
+ @media (max-width: 375px) {
1142
+ .training-button {
1143
+ top: 70% !important;
1144
+ font-size: 12px;
1145
+ padding: 8px 12px;
1146
+ }
1150
1147
 
1151
- .status-indicator.inactive {
1152
- background: var(--color-gray-500);
1148
+ .combat-button {
1149
+ top: 80% !important;
1150
+ font-size: 12px;
1151
+ padding: 8px 12px;
1152
+ }
1153
1153
  }
1154
1154
  /*$vite$:1*/