diff --git a/.beans/nuzlocke-tracker-qars--boss-battle-card-collapsible-team-hardcore-mode-cl.md b/.beans/nuzlocke-tracker-qars--boss-battle-card-collapsible-team-hardcore-mode-cl.md
new file mode 100644
index 0000000..94d33eb
--- /dev/null
+++ b/.beans/nuzlocke-tracker-qars--boss-battle-card-collapsible-team-hardcore-mode-cl.md
@@ -0,0 +1,11 @@
+---
+# nuzlocke-tracker-qars
+title: 'Boss battle card: collapsible team + hardcore mode cleanup'
+status: completed
+type: feature
+priority: normal
+created_at: 2026-02-08T11:01:17Z
+updated_at: 2026-02-08T11:02:45Z
+---
+
+Make boss battle cards collapsible (team hidden by default), larger sprites with Lvl prefix, and hide attempts/lost button in hardcore mode
\ No newline at end of file
diff --git a/frontend/src/components/BossDefeatModal.tsx b/frontend/src/components/BossDefeatModal.tsx
index e3c2089..324f387 100644
--- a/frontend/src/components/BossDefeatModal.tsx
+++ b/frontend/src/components/BossDefeatModal.tsx
@@ -6,9 +6,10 @@ interface BossDefeatModalProps {
onSubmit: (data: CreateBossResultInput) => void
onClose: () => void
isPending?: boolean
+ hardcoreMode?: boolean
}
-export function BossDefeatModal({ boss, onSubmit, onClose, isPending }: BossDefeatModalProps) {
+export function BossDefeatModal({ boss, onSubmit, onClose, isPending, hardcoreMode }: BossDefeatModalProps) {
const [result, setResult] = useState<'won' | 'lost'>('won')
const [attempts, setAttempts] = useState('1')
@@ -16,8 +17,8 @@ export function BossDefeatModal({ boss, onSubmit, onClose, isPending }: BossDefe
e.preventDefault()
onSubmit({
bossBattleId: boss.id,
- result,
- attempts: Number(attempts) || 1,
+ result: hardcoreMode ? 'won' : result,
+ attempts: hardcoreMode ? 1 : Number(attempts) || 1,
})
}
@@ -71,30 +72,34 @@ export function BossDefeatModal({ boss, onSubmit, onClose, isPending }: BossDefe
>
Won
-
+ {!hardcoreMode && (
+
+ )}
-
-
- setAttempts(e.target.value)}
- className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
- />
-
+ {!hardcoreMode && (
+
+
+ setAttempts(e.target.value)}
+ className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
+ />
+
+ )}
diff --git a/frontend/src/pages/RunEncounters.tsx b/frontend/src/pages/RunEncounters.tsx
index f1456f8..f740a24 100644
--- a/frontend/src/pages/RunEncounters.tsx
+++ b/frontend/src/pages/RunEncounters.tsx
@@ -337,6 +337,7 @@ export function RunEncounters() {
useState
(null)
const [showEndRun, setShowEndRun] = useState(false)
const [showShinyModal, setShowShinyModal] = useState(false)
+ const [expandedBosses, setExpandedBosses] = useState>(new Set())
const [showTeam, setShowTeam] = useState(true)
const [filter, setFilter] = useState<'all' | RouteStatus>('all')
@@ -1021,6 +1022,16 @@ export function RunEncounters() {
other: 'border-gray-400 dark:border-gray-500',
}
+ const isBossExpanded = expandedBosses.has(boss.id)
+ const toggleBoss = () => {
+ setExpandedBosses((prev) => {
+ const next = new Set(prev)
+ if (next.has(boss.id)) next.delete(boss.id)
+ else next.add(boss.id)
+ return next
+ })
+ }
+
return (
-
+
+
{boss.spriteUrl && (

)}
@@ -1047,7 +1070,7 @@ export function RunEncounters() {
-
+
e.stopPropagation()}>
{isDefeated ? (
Defeated ✓
@@ -1063,19 +1086,19 @@ export function RunEncounters() {
{/* Boss pokemon team */}
- {boss.pokemon.length > 0 && (
+ {isBossExpanded && boss.pokemon.length > 0 && (
{boss.pokemon
.sort((a, b) => a.order - b.order)
.map((bp) => (
{bp.pokemon.spriteUrl ? (
-

+

) : (
-
+
)}
- {bp.level}
+ Lvl {bp.level}
))}
@@ -1141,6 +1164,7 @@ export function RunEncounters() {
}}
onClose={() => setSelectedBoss(null)}
isPending={createBossResult.isPending}
+ hardcoreMode={run?.rules?.hardcoreMode}
/>
)}