Fraser commited on
Commit
b4531e8
·
1 Parent(s): 21805fd

more stuff

Browse files
src/lib/components/Pages/Pictuary.svelte CHANGED
@@ -8,12 +8,16 @@
8
  import DiscoveredCard from '../Piclets/DiscoveredCard.svelte';
9
  import DraggablePicletCard from '../Piclets/DraggablePicletCard.svelte';
10
  import RosterSlot from '../Piclets/RosterSlot.svelte';
 
 
11
 
12
  let rosterPiclets: PicletInstance[] = $state([]);
13
  let storagePiclets: PicletInstance[] = $state([]);
14
  let discoveredMonsters: Monster[] = $state([]);
15
  let isLoading = $state(true);
16
  let currentlyDragging: PicletInstance | null = $state(null);
 
 
17
 
18
  // Map roster positions for easy access
19
  let rosterMap = $derived(() => {
@@ -53,14 +57,14 @@
53
  function handleRosterClick(position: number) {
54
  const piclet = rosterMap().get(position);
55
  if (piclet) {
56
- console.log('View piclet:', piclet);
57
  } else {
58
- console.log('Add piclet to position:', position);
59
  }
60
  }
61
 
62
  function handleStorageClick(piclet: PicletInstance) {
63
- console.log('View storage piclet:', piclet);
64
  }
65
 
66
  function handleDiscoveredClick(monster: Monster) {
@@ -104,7 +108,25 @@
104
  }
105
  </script>
106
 
107
- <div class="pictuary-page">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  <header class="page-header">
109
  <h1>Pictuary</h1>
110
  <p class="piclet-count">
@@ -193,7 +215,25 @@
193
  {/if}
194
  </div>
195
  {/if}
196
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
 
198
  <style>
199
  .pictuary-page {
 
8
  import DiscoveredCard from '../Piclets/DiscoveredCard.svelte';
9
  import DraggablePicletCard from '../Piclets/DraggablePicletCard.svelte';
10
  import RosterSlot from '../Piclets/RosterSlot.svelte';
11
+ import PicletDetail from '../Piclets/PicletDetail.svelte';
12
+ import AddToRosterDialog from '../Piclets/AddToRosterDialog.svelte';
13
 
14
  let rosterPiclets: PicletInstance[] = $state([]);
15
  let storagePiclets: PicletInstance[] = $state([]);
16
  let discoveredMonsters: Monster[] = $state([]);
17
  let isLoading = $state(true);
18
  let currentlyDragging: PicletInstance | null = $state(null);
19
+ let selectedPiclet: PicletInstance | null = $state(null);
20
+ let addToRosterPosition: number | null = $state(null);
21
 
22
  // Map roster positions for easy access
23
  let rosterMap = $derived(() => {
 
57
  function handleRosterClick(position: number) {
58
  const piclet = rosterMap().get(position);
59
  if (piclet) {
60
+ selectedPiclet = piclet;
61
  } else {
62
+ addToRosterPosition = position;
63
  }
64
  }
65
 
66
  function handleStorageClick(piclet: PicletInstance) {
67
+ selectedPiclet = piclet;
68
  }
69
 
70
  function handleDiscoveredClick(monster: Monster) {
 
108
  }
109
  </script>
110
 
111
+ {#if viewAllMode === 'storage'}
112
+ <ViewAll
113
+ title="Storage"
114
+ type="storage"
115
+ items={storagePiclets}
116
+ onBack={() => viewAllMode = null}
117
+ onItemsChanged={loadPiclets}
118
+ onDragStart={handleDragStart}
119
+ onDragEnd={handleDragEnd}
120
+ />
121
+ {:else if viewAllMode === 'discovered'}
122
+ <ViewAll
123
+ title="Discovered"
124
+ type="discovered"
125
+ items={discoveredMonsters}
126
+ onBack={() => viewAllMode = null}
127
+ />
128
+ {:else}
129
+ <div class="pictuary-page">
130
  <header class="page-header">
131
  <h1>Pictuary</h1>
132
  <p class="piclet-count">
 
215
  {/if}
216
  </div>
217
  {/if}
218
+
219
+ {#if selectedPiclet}
220
+ <PicletDetail
221
+ instance={selectedPiclet}
222
+ onClose={() => selectedPiclet = null}
223
+ onDeleted={loadPiclets}
224
+ />
225
+ {/if}
226
+
227
+ {#if addToRosterPosition !== null}
228
+ <AddToRosterDialog
229
+ position={addToRosterPosition}
230
+ availablePiclets={storagePiclets}
231
+ onClose={() => addToRosterPosition = null}
232
+ onAdded={loadPiclets}
233
+ />
234
+ {/if}
235
+ </div>
236
+ {/if}
237
 
238
  <style>
239
  .pictuary-page {
src/lib/components/Pages/ViewAll.svelte ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { PicletInstance, Monster } from '$lib/db/schema';
3
+ import PicletCard from '../Piclets/PicletCard.svelte';
4
+ import DraggablePicletCard from '../Piclets/DraggablePicletCard.svelte';
5
+ import DiscoveredCard from '../Piclets/DiscoveredCard.svelte';
6
+ import PicletDetail from '../Piclets/PicletDetail.svelte';
7
+
8
+ interface Props {
9
+ title: string;
10
+ type: 'storage' | 'discovered';
11
+ items: PicletInstance[] | Monster[];
12
+ onBack: () => void;
13
+ onItemsChanged?: () => void;
14
+ onDragStart?: (instance: PicletInstance) => void;
15
+ onDragEnd?: () => void;
16
+ }
17
+
18
+ let { title, type, items, onBack, onItemsChanged, onDragStart, onDragEnd }: Props = $props();
19
+ let selectedPiclet: PicletInstance | null = $state(null);
20
+
21
+ function handleItemClick(item: PicletInstance | Monster) {
22
+ if ('currentHp' in item) {
23
+ selectedPiclet = item as PicletInstance;
24
+ } else {
25
+ console.log('View discovered monster:', item);
26
+ }
27
+ }
28
+ </script>
29
+
30
+ <div class="view-all-page">
31
+ <header class="page-header">
32
+ <button class="back-btn" onclick={onBack} aria-label="Back">
33
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
34
+ <path d="M19 12H5m0 0l7 7m-7-7l7-7"></path>
35
+ </svg>
36
+ </button>
37
+ <h1>{title}</h1>
38
+ <div class="header-spacer"></div>
39
+ </header>
40
+
41
+ <div class="content">
42
+ {#if items.length === 0}
43
+ <div class="empty-state">
44
+ <p>No {type === 'storage' ? 'piclets in storage' : 'discovered piclets'} yet.</p>
45
+ </div>
46
+ {:else}
47
+ <div class="items-grid">
48
+ {#each items as item}
49
+ {#if type === 'storage' && 'currentHp' in item}
50
+ <DraggablePicletCard
51
+ instance={item as PicletInstance}
52
+ size={100}
53
+ showDetails={true}
54
+ onClick={() => handleItemClick(item)}
55
+ onDragStart={onDragStart}
56
+ onDragEnd={onDragEnd}
57
+ />
58
+ {:else if type === 'discovered' && 'stats' in item}
59
+ <DiscoveredCard
60
+ monster={item as Monster}
61
+ size={100}
62
+ onClick={() => handleItemClick(item)}
63
+ />
64
+ {/if}
65
+ {/each}
66
+ </div>
67
+ {/if}
68
+ </div>
69
+
70
+ {#if selectedPiclet}
71
+ <PicletDetail
72
+ instance={selectedPiclet}
73
+ onClose={() => selectedPiclet = null}
74
+ onDeleted={() => {
75
+ selectedPiclet = null;
76
+ onItemsChanged?.();
77
+ }}
78
+ />
79
+ {/if}
80
+ </div>
81
+
82
+ <style>
83
+ .view-all-page {
84
+ height: 100%;
85
+ display: flex;
86
+ flex-direction: column;
87
+ background: white;
88
+ }
89
+
90
+ .page-header {
91
+ display: flex;
92
+ align-items: center;
93
+ justify-content: space-between;
94
+ padding: 0.5rem 1rem;
95
+ background: white;
96
+ position: sticky;
97
+ top: 0;
98
+ z-index: 10;
99
+ border-bottom: 1px solid #e5e5ea;
100
+ }
101
+
102
+ .page-header h1 {
103
+ margin: 0;
104
+ font-size: 1.5rem;
105
+ font-weight: bold;
106
+ color: #333;
107
+ }
108
+
109
+ .back-btn {
110
+ background: none;
111
+ border: none;
112
+ padding: 0.5rem;
113
+ cursor: pointer;
114
+ color: #007bff;
115
+ display: flex;
116
+ align-items: center;
117
+ justify-content: center;
118
+ }
119
+
120
+ .header-spacer {
121
+ width: 40px;
122
+ }
123
+
124
+ .content {
125
+ flex: 1;
126
+ overflow-y: auto;
127
+ padding: 1rem;
128
+ padding-bottom: 100px;
129
+ }
130
+
131
+ .empty-state {
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ height: 200px;
136
+ color: #666;
137
+ text-align: center;
138
+ }
139
+
140
+ .items-grid {
141
+ display: grid;
142
+ grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
143
+ gap: 1rem;
144
+ justify-items: center;
145
+ }
146
+ </style>
src/lib/components/Piclets/AddToRosterDialog.svelte ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { PicletInstance } from '$lib/db/schema';
3
+ import PicletCard from './PicletCard.svelte';
4
+ import { moveToRoster } from '$lib/db/piclets';
5
+
6
+ interface Props {
7
+ position: number;
8
+ availablePiclets: PicletInstance[];
9
+ onClose: () => void;
10
+ onAdded?: () => void;
11
+ }
12
+
13
+ let { position, availablePiclets, onClose, onAdded }: Props = $props();
14
+ let isAdding = $state(false);
15
+
16
+ async function handleAddToRoster(piclet: PicletInstance) {
17
+ if (!piclet.id || isAdding) return;
18
+
19
+ isAdding = true;
20
+ try {
21
+ await moveToRoster(piclet.id, position);
22
+ onAdded?.();
23
+ onClose();
24
+ } catch (err) {
25
+ console.error('Failed to add to roster:', err);
26
+ } finally {
27
+ isAdding = false;
28
+ }
29
+ }
30
+ </script>
31
+
32
+ <div class="dialog-overlay" onclick={(e) => e.target === e.currentTarget && onClose()}>
33
+ <div class="dialog-content">
34
+ <header class="dialog-header">
35
+ <h2>Add to Roster</h2>
36
+ <button class="close-btn" onclick={onClose} aria-label="Close">
37
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
38
+ <path d="M6 18L18 6M6 6l12 12"></path>
39
+ </svg>
40
+ </button>
41
+ </header>
42
+
43
+ <div class="dialog-body">
44
+ {#if availablePiclets.length === 0}
45
+ <div class="empty-state">
46
+ <p>No piclets available in storage.</p>
47
+ <p class="hint">Scan objects to discover new piclets!</p>
48
+ </div>
49
+ {:else}
50
+ <p class="instruction">Select a piclet to add to position {position + 1}:</p>
51
+ <div class="piclets-grid">
52
+ {#each availablePiclets as piclet}
53
+ <button
54
+ class="piclet-option"
55
+ onclick={() => handleAddToRoster(piclet)}
56
+ disabled={isAdding}
57
+ >
58
+ <PicletCard instance={piclet} size={100} showDetails={true} />
59
+ </button>
60
+ {/each}
61
+ </div>
62
+ {/if}
63
+ </div>
64
+ </div>
65
+ </div>
66
+
67
+ <style>
68
+ .dialog-overlay {
69
+ position: fixed;
70
+ inset: 0;
71
+ background: rgba(0, 0, 0, 0.5);
72
+ display: flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ z-index: 1000;
76
+ padding: 1rem;
77
+ }
78
+
79
+ .dialog-content {
80
+ background: white;
81
+ border-radius: 16px;
82
+ width: 100%;
83
+ max-width: 600px;
84
+ max-height: 80vh;
85
+ overflow: hidden;
86
+ display: flex;
87
+ flex-direction: column;
88
+ }
89
+
90
+ .dialog-header {
91
+ padding: 1rem;
92
+ border-bottom: 1px solid #e5e5ea;
93
+ position: relative;
94
+ }
95
+
96
+ .dialog-header h2 {
97
+ margin: 0;
98
+ text-align: center;
99
+ font-size: 1.25rem;
100
+ }
101
+
102
+ .close-btn {
103
+ position: absolute;
104
+ top: 1rem;
105
+ right: 1rem;
106
+ background: none;
107
+ border: none;
108
+ padding: 0;
109
+ width: 24px;
110
+ height: 24px;
111
+ cursor: pointer;
112
+ color: #8e8e93;
113
+ }
114
+
115
+ .dialog-body {
116
+ flex: 1;
117
+ overflow-y: auto;
118
+ padding: 1rem;
119
+ }
120
+
121
+ .empty-state {
122
+ text-align: center;
123
+ padding: 3rem 1rem;
124
+ color: #666;
125
+ }
126
+
127
+ .empty-state p {
128
+ margin: 0 0 0.5rem;
129
+ }
130
+
131
+ .hint {
132
+ font-size: 0.875rem;
133
+ color: #8e8e93;
134
+ }
135
+
136
+ .instruction {
137
+ margin: 0 0 1rem;
138
+ color: #666;
139
+ text-align: center;
140
+ }
141
+
142
+ .piclets-grid {
143
+ display: grid;
144
+ grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
145
+ gap: 1rem;
146
+ justify-items: center;
147
+ }
148
+
149
+ .piclet-option {
150
+ background: none;
151
+ border: none;
152
+ padding: 0;
153
+ cursor: pointer;
154
+ transition: transform 0.2s;
155
+ }
156
+
157
+ .piclet-option:not(:disabled):hover {
158
+ transform: scale(1.05);
159
+ }
160
+
161
+ .piclet-option:not(:disabled):active {
162
+ transform: scale(0.95);
163
+ }
164
+
165
+ .piclet-option:disabled {
166
+ opacity: 0.6;
167
+ cursor: not-allowed;
168
+ }
169
+ </style>
src/lib/components/Piclets/PicletDetail.svelte ADDED
@@ -0,0 +1,324 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import type { PicletInstance } from '$lib/db/schema';
3
+ import { deletePicletInstance } from '$lib/db/piclets';
4
+
5
+ interface Props {
6
+ instance: PicletInstance;
7
+ onClose: () => void;
8
+ onDeleted?: () => void;
9
+ }
10
+
11
+ let { instance, onClose, onDeleted }: Props = $props();
12
+ let showDeleteConfirm = $state(false);
13
+
14
+ async function handleDelete() {
15
+ if (!instance.id) return;
16
+
17
+ try {
18
+ await deletePicletInstance(instance.id);
19
+ onDeleted?.();
20
+ onClose();
21
+ } catch (err) {
22
+ console.error('Failed to delete piclet:', err);
23
+ }
24
+ }
25
+
26
+ function getStatPercentage(value: number, max: number = 255): number {
27
+ return Math.round((value / max) * 100);
28
+ }
29
+ </script>
30
+
31
+ <div class="detail-modal" onclick={(e) => e.target === e.currentTarget && onClose()}>
32
+ <div class="detail-content">
33
+ <header class="detail-header">
34
+ <button class="close-btn" onclick={onClose} aria-label="Close">
35
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
36
+ <path d="M6 18L18 6M6 6l12 12"></path>
37
+ </svg>
38
+ </button>
39
+ <h2>{instance.nickname || instance.typeId}</h2>
40
+ </header>
41
+
42
+ <div class="detail-body">
43
+ <div class="image-section">
44
+ <img
45
+ src={instance.imageData || instance.imageUrl}
46
+ alt={instance.nickname || instance.typeId}
47
+ class="piclet-image"
48
+ />
49
+ <div class="basic-info">
50
+ <span class="level">Lv. {instance.level}</span>
51
+ <span class="type">{instance.primaryTypeString}</span>
52
+ {#if instance.secondaryTypeString}
53
+ <span class="type">{instance.secondaryTypeString}</span>
54
+ {/if}
55
+ </div>
56
+ </div>
57
+
58
+ <div class="stats-section">
59
+ <h3>Stats</h3>
60
+ <div class="stat-grid">
61
+ <div class="stat">
62
+ <span class="stat-label">HP</span>
63
+ <div class="stat-bar">
64
+ <div class="stat-fill" style="width: {getStatPercentage(instance.currentHp, instance.maxHp)}%"></div>
65
+ </div>
66
+ <span class="stat-value">{instance.currentHp}/{instance.maxHp}</span>
67
+ </div>
68
+
69
+ <div class="stat">
70
+ <span class="stat-label">Attack</span>
71
+ <div class="stat-bar">
72
+ <div class="stat-fill" style="width: {getStatPercentage(instance.attack)}%"></div>
73
+ </div>
74
+ <span class="stat-value">{instance.attack}</span>
75
+ </div>
76
+
77
+ <div class="stat">
78
+ <span class="stat-label">Defense</span>
79
+ <div class="stat-bar">
80
+ <div class="stat-fill" style="width: {getStatPercentage(instance.defense)}%"></div>
81
+ </div>
82
+ <span class="stat-value">{instance.defense}</span>
83
+ </div>
84
+
85
+ <div class="stat">
86
+ <span class="stat-label">Speed</span>
87
+ <div class="stat-bar">
88
+ <div class="stat-fill" style="width: {getStatPercentage(instance.speed)}%"></div>
89
+ </div>
90
+ <span class="stat-value">{instance.speed}</span>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ <div class="moves-section">
96
+ <h3>Moves</h3>
97
+ <div class="moves-grid">
98
+ {#each instance.moves as move}
99
+ <div class="move">
100
+ <div class="move-name">{move.name}</div>
101
+ <div class="move-pp">PP: {move.currentPp}/{move.pp}</div>
102
+ </div>
103
+ {/each}
104
+ </div>
105
+ </div>
106
+
107
+ <div class="concept-section">
108
+ <h3>Concept</h3>
109
+ <p>{instance.concept}</p>
110
+ </div>
111
+
112
+ <div class="actions">
113
+ {#if showDeleteConfirm}
114
+ <p class="delete-confirm">Are you sure you want to release this piclet?</p>
115
+ <button class="btn btn-danger" onclick={handleDelete}>Yes, Release</button>
116
+ <button class="btn btn-secondary" onclick={() => showDeleteConfirm = false}>Cancel</button>
117
+ {:else}
118
+ <button class="btn btn-danger" onclick={() => showDeleteConfirm = true}>Release</button>
119
+ {/if}
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </div>
124
+
125
+ <style>
126
+ .detail-modal {
127
+ position: fixed;
128
+ inset: 0;
129
+ background: rgba(0, 0, 0, 0.5);
130
+ display: flex;
131
+ align-items: center;
132
+ justify-content: center;
133
+ z-index: 1000;
134
+ padding: 1rem;
135
+ }
136
+
137
+ .detail-content {
138
+ background: white;
139
+ border-radius: 16px;
140
+ width: 100%;
141
+ max-width: 500px;
142
+ max-height: 90vh;
143
+ overflow: hidden;
144
+ display: flex;
145
+ flex-direction: column;
146
+ }
147
+
148
+ .detail-header {
149
+ padding: 1rem;
150
+ border-bottom: 1px solid #e5e5ea;
151
+ position: relative;
152
+ }
153
+
154
+ .detail-header h2 {
155
+ margin: 0;
156
+ text-align: center;
157
+ font-size: 1.25rem;
158
+ }
159
+
160
+ .close-btn {
161
+ position: absolute;
162
+ top: 1rem;
163
+ right: 1rem;
164
+ background: none;
165
+ border: none;
166
+ padding: 0;
167
+ width: 24px;
168
+ height: 24px;
169
+ cursor: pointer;
170
+ color: #8e8e93;
171
+ }
172
+
173
+ .detail-body {
174
+ flex: 1;
175
+ overflow-y: auto;
176
+ padding: 1rem;
177
+ }
178
+
179
+ .image-section {
180
+ text-align: center;
181
+ margin-bottom: 1.5rem;
182
+ }
183
+
184
+ .piclet-image {
185
+ width: 200px;
186
+ height: 200px;
187
+ object-fit: contain;
188
+ margin-bottom: 0.5rem;
189
+ }
190
+
191
+ .basic-info {
192
+ display: flex;
193
+ gap: 0.5rem;
194
+ justify-content: center;
195
+ align-items: center;
196
+ }
197
+
198
+ .level {
199
+ font-weight: 600;
200
+ color: #333;
201
+ }
202
+
203
+ .type {
204
+ background: #e5e5ea;
205
+ padding: 0.25rem 0.75rem;
206
+ border-radius: 12px;
207
+ font-size: 0.875rem;
208
+ text-transform: capitalize;
209
+ }
210
+
211
+ .stats-section,
212
+ .moves-section,
213
+ .concept-section {
214
+ margin-bottom: 1.5rem;
215
+ }
216
+
217
+ h3 {
218
+ margin: 0 0 0.75rem;
219
+ color: #8e8e93;
220
+ font-size: 1rem;
221
+ font-weight: 600;
222
+ }
223
+
224
+ .stat-grid {
225
+ display: flex;
226
+ flex-direction: column;
227
+ gap: 0.75rem;
228
+ }
229
+
230
+ .stat {
231
+ display: grid;
232
+ grid-template-columns: 60px 1fr 60px;
233
+ align-items: center;
234
+ gap: 0.5rem;
235
+ }
236
+
237
+ .stat-label {
238
+ font-size: 0.875rem;
239
+ color: #666;
240
+ }
241
+
242
+ .stat-bar {
243
+ height: 8px;
244
+ background: #f1f1f1;
245
+ border-radius: 4px;
246
+ overflow: hidden;
247
+ }
248
+
249
+ .stat-fill {
250
+ height: 100%;
251
+ background: #007bff;
252
+ transition: width 0.3s;
253
+ }
254
+
255
+ .stat-value {
256
+ text-align: right;
257
+ font-size: 0.875rem;
258
+ font-weight: 600;
259
+ }
260
+
261
+ .moves-grid {
262
+ display: grid;
263
+ grid-template-columns: 1fr 1fr;
264
+ gap: 0.5rem;
265
+ }
266
+
267
+ .move {
268
+ background: #f8f8f8;
269
+ padding: 0.75rem;
270
+ border-radius: 8px;
271
+ }
272
+
273
+ .move-name {
274
+ font-weight: 600;
275
+ margin-bottom: 0.25rem;
276
+ }
277
+
278
+ .move-pp {
279
+ font-size: 0.75rem;
280
+ color: #666;
281
+ }
282
+
283
+ .concept-section p {
284
+ margin: 0;
285
+ color: #666;
286
+ line-height: 1.5;
287
+ }
288
+
289
+ .actions {
290
+ padding-top: 1rem;
291
+ border-top: 1px solid #e5e5ea;
292
+ text-align: center;
293
+ }
294
+
295
+ .delete-confirm {
296
+ margin: 0 0 1rem;
297
+ color: #d73502;
298
+ }
299
+
300
+ .btn {
301
+ padding: 0.75rem 1.5rem;
302
+ border: none;
303
+ border-radius: 8px;
304
+ font-size: 1rem;
305
+ font-weight: 600;
306
+ cursor: pointer;
307
+ transition: transform 0.2s;
308
+ }
309
+
310
+ .btn:active {
311
+ transform: scale(0.95);
312
+ }
313
+
314
+ .btn-danger {
315
+ background: #d73502;
316
+ color: white;
317
+ }
318
+
319
+ .btn-secondary {
320
+ background: #e5e5ea;
321
+ color: #333;
322
+ margin-left: 0.5rem;
323
+ }
324
+ </style>