@jjlmoya/utils-textiles 1.15.0 → 1.17.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-textiles",
3
- "version": "1.15.0",
3
+ "version": "1.17.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -9,13 +9,13 @@ const { ui = {} } = Astro.props;
9
9
  const calcUI = ui as FabricProjectCalculatorUI;
10
10
  ---
11
11
 
12
- <div class="fabric-calculator-card" id="fabric-calc-app">
13
- <div class="fabric-sidebar">
14
- <div class="config-group">
12
+ <div class="fpc-root" id="fabric-calc-app">
13
+ <div class="fpc-controls">
14
+ <div class="fpc-config">
15
15
  <h3>{calcUI.sectionProject}</h3>
16
- <div class="fabric-field">
16
+ <div class="fpc-field">
17
17
  <label>{calcUI.labelGarmentType}</label>
18
- <select id="garment-type" class="fabric-select">
18
+ <select id="garment-type" class="fpc-select">
19
19
  <option value="skirt">{calcUI.garmentSkirt}</option>
20
20
  <option value="pants">{calcUI.garmentPants}</option>
21
21
  <option value="dress">{calcUI.garmentDress}</option>
@@ -24,72 +24,72 @@ const calcUI = ui as FabricProjectCalculatorUI;
24
24
  <option value="tote">{calcUI.garmentTote}</option>
25
25
  </select>
26
26
  </div>
27
- <div class="fabric-field">
27
+ <div class="fpc-field">
28
28
  <label>{calcUI.labelSize}</label>
29
- <div class="preset-group" id="size-presets">
30
- <button class="preset-pill" data-val="xs_core">{calcUI.sizeXS}</button>
31
- <button class="preset-pill active" data-val="m_core">{calcUI.sizeM}</button>
32
- <button class="preset-pill" data-val="xl_core">{calcUI.sizeXL}</button>
29
+ <div class="fpc-size-options" id="size-presets">
30
+ <button class="fpc-size-option" data-val="xs_core">{calcUI.sizeXS}</button>
31
+ <button class="fpc-size-option active" data-val="m_core">{calcUI.sizeM}</button>
32
+ <button class="fpc-size-option" data-val="xl_core">{calcUI.sizeXL}</button>
33
33
  </div>
34
34
  </div>
35
35
  </div>
36
36
 
37
- <div class="config-group">
37
+ <div class="fpc-config">
38
38
  <h3>{calcUI.sectionMaterial}</h3>
39
- <div class="fabric-field">
39
+ <div class="fpc-field">
40
40
  <label>{calcUI.labelFabricWidth}</label>
41
- <select id="fabric-width" class="fabric-select">
41
+ <select id="fabric-width" class="fpc-select">
42
42
  <option value="90">{calcUI.width90}</option>
43
43
  <option value="115">{calcUI.width115}</option>
44
44
  <option value="140" selected>{calcUI.width140}</option>
45
45
  <option value="150">{calcUI.width150}</option>
46
46
  </select>
47
47
  </div>
48
- <div class="fabric-field">
48
+ <div class="fpc-field">
49
49
  <label>{calcUI.labelSeamAllowance}</label>
50
- <div class="shop-stepper">
51
- <button class="step-btn" id="sub-allow">−</button>
52
- <input type="number" id="seam-allowance" class="fabric-input" value="1.5" step="0.5" min="0" max="5" />
53
- <button class="step-btn" id="add-allow">+</button>
50
+ <div class="fpc-stepper">
51
+ <button class="fpc-step-button" id="sub-allow">−</button>
52
+ <input type="number" id="seam-allowance" class="fpc-input" value="1.5" step="0.5" min="0" max="5" />
53
+ <button class="fpc-step-button" id="add-allow">+</button>
54
54
  </div>
55
55
  </div>
56
56
  </div>
57
57
 
58
- <div class="btn-actions">
59
- <button id="btn-clear-f" class="f-btn f-seco">{calcUI.btnClear}</button>
60
- <button id="btn-share-f" class="f-btn f-prim">{calcUI.btnShare}</button>
58
+ <div class="fpc-actions">
59
+ <button id="btn-clear-f" class="fpc-action fpc-action-secondary">{calcUI.btnClear}</button>
60
+ <button id="btn-share-f" class="fpc-action fpc-action-primary">{calcUI.btnShare}</button>
61
61
  </div>
62
62
  </div>
63
63
 
64
- <main class="fabric-main">
65
- <div id="warning-msg" class="warning-banner"></div>
64
+ <div class="fpc-main">
65
+ <div id="warning-msg" class="fpc-warning"></div>
66
66
 
67
- <section class="magic-result-area">
68
- <span class="result-lbl">{calcUI.resultLabel}</span>
69
- <div class="val"><span id="main-meters">1.40</span><span class="unit">{calcUI.resultUnit}</span></div>
70
- <div class="advice-tag" id="shop-advice"></div>
67
+ <section class="fpc-result">
68
+ <span class="fpc-result-label">{calcUI.resultLabel}</span>
69
+ <div class="fpc-result-value"><span id="main-meters">1.40</span><span class="fpc-result-unit">{calcUI.resultUnit}</span></div>
70
+ <div class="fpc-advice" id="shop-advice"></div>
71
71
  </section>
72
72
 
73
- <div class="layout-container">
74
- <div class="canvas-wrapper">
75
- <div class="scheme-area">
76
- <div class="ruler" id="ruler-col"></div>
77
- <div id="fabric-board-box" class="fabric-board">
78
- <div class="board-empty-state">{calcUI.boardEmpty}</div>
73
+ <div class="fpc-layout">
74
+ <div class="fpc-canvas">
75
+ <div class="fpc-scheme">
76
+ <div class="fpc-ruler" id="ruler-col"></div>
77
+ <div id="fabric-board-box" class="fpc-board">
78
+ <div class="fpc-board-empty">{calcUI.boardEmpty}</div>
79
79
  </div>
80
80
  </div>
81
- <div class="scheme-info" id="board-desc"></div>
81
+ <div class="fpc-scheme-info" id="board-desc"></div>
82
82
  </div>
83
83
  </div>
84
84
 
85
- <section class="merch-section">
86
- <div class="merch-header">
87
- <h3 class="merch-title">{calcUI.merchTitle}</h3>
88
- <button id="copy-list-btn" class="copy-list-btn">{calcUI.btnCopyList}</button>
85
+ <section class="fpc-merch">
86
+ <div class="fpc-merch-header">
87
+ <h3 class="fpc-merch-title">{calcUI.merchTitle}</h3>
88
+ <button id="copy-list-btn" class="fpc-copy-button">{calcUI.btnCopyList}</button>
89
89
  </div>
90
- <ul id="check-list" class="merceria-checklist"></ul>
90
+ <ul id="check-list" class="fpc-checklist"></ul>
91
91
  </section>
92
- </main>
92
+ </div>
93
93
  </div>
94
94
 
95
95
  <script define:vars={{ ui }} is:inline>
@@ -157,17 +157,17 @@ const calcUI = ui as FabricProjectCalculatorUI;
157
157
 
158
158
  function buildPieceEl(nameKey: string, w: number, fold: boolean, col: number): HTMLDivElement {
159
159
  const el = document.createElement('div');
160
- el.className = `piece-block${fold ? ' piece-fold' : ''}`;
160
+ el.className = `fpc-piece${fold ? ' fpc-piece-fold' : ''}`;
161
161
  el.style.width = `${w * 100}%`;
162
162
  el.style.background = PIECE_COLORS[col];
163
163
  el.style.borderColor = PIECE_BORDERS[col];
164
164
  const nameEl = document.createElement('span');
165
- nameEl.className = 'piece-name';
165
+ nameEl.className = 'fpc-piece-name';
166
166
  nameEl.textContent = window.__toolUI.pieceNames[nameKey as PieceNameKey] || nameKey;
167
167
  el.appendChild(nameEl);
168
168
  if (fold) {
169
169
  const foldEl = document.createElement('div');
170
- foldEl.className = 'fold-indicator';
170
+ foldEl.className = 'fpc-fold-indicator';
171
171
  foldEl.textContent = window.__toolUI.foldLabel;
172
172
  el.appendChild(foldEl);
173
173
  }
@@ -176,7 +176,7 @@ const calcUI = ui as FabricProjectCalculatorUI;
176
176
 
177
177
  function buildRowEl(row: PieceRow): HTMLDivElement {
178
178
  const rowEl = document.createElement('div');
179
- rowEl.className = 'piece-row';
179
+ rowEl.className = 'fpc-piece-row';
180
180
  rowEl.style.flex = `0 0 ${row.h * 100}%`;
181
181
  row.pieces.forEach((spec) => {
182
182
  rowEl.appendChild(buildPieceEl(spec.nameKey, spec.w, spec.fold ?? false, spec.col));
@@ -189,7 +189,7 @@ const calcUI = ui as FabricProjectCalculatorUI;
189
189
  const rows = PIECE_ROWS[type];
190
190
  if (!rows?.length) {
191
191
  const empty = document.createElement('div');
192
- empty.className = 'board-empty-state';
192
+ empty.className = 'fpc-board-empty';
193
193
  empty.textContent = window.__toolUI.boardEmpty;
194
194
  board.appendChild(empty);
195
195
  return;
@@ -205,7 +205,7 @@ const calcUI = ui as FabricProjectCalculatorUI;
205
205
  let mark = 0;
206
206
  while (mark <= totalMeters + 0.001) {
207
207
  const markEl = document.createElement('div');
208
- markEl.className = 'ruler-mark';
208
+ markEl.className = 'fpc-ruler-mark';
209
209
  markEl.style.top = `${(mark / totalMeters) * 100}%`;
210
210
  const label = document.createElement('span');
211
211
  label.textContent = `${mark.toFixed(step < 0.5 ? 2 : 1)}m`;
@@ -252,8 +252,8 @@ const calcUI = ui as FabricProjectCalculatorUI;
252
252
  checks.innerHTML = '';
253
253
  items.forEach((text) => {
254
254
  const li = document.createElement('li');
255
- li.className = 'merch-item';
256
- li.innerHTML = `<span class="merch-dot" aria-hidden="true">◆</span>${text}`;
255
+ li.className = 'fpc-merch-item';
256
+ li.innerHTML = `<span class="fpc-merch-dot" aria-hidden="true">◆</span>${text}`;
257
257
  checks.appendChild(li);
258
258
  });
259
259
  }
@@ -285,9 +285,9 @@ const calcUI = ui as FabricProjectCalculatorUI;
285
285
  }
286
286
 
287
287
  function handleSizeClick(e: Event): void {
288
- const btn = (e.target as HTMLElement).closest('.preset-pill');
288
+ const btn = (e.target as HTMLElement).closest('.fpc-size-option');
289
289
  if (!btn) return;
290
- document.getElementById('size-presets')?.querySelectorAll('.preset-pill').forEach((b) => {
290
+ document.getElementById('size-presets')?.querySelectorAll('.fpc-size-option').forEach((b) => {
291
291
  b.classList.remove('active');
292
292
  });
293
293
  btn.classList.add('active');
@@ -311,7 +311,7 @@ const calcUI = ui as FabricProjectCalculatorUI;
311
311
  if (width) width.value = '140';
312
312
  if (allow) allow.value = '1.5';
313
313
  activeSize = 'm_core';
314
- document.getElementById('size-presets')?.querySelectorAll('.preset-pill').forEach((b) => {
314
+ document.getElementById('size-presets')?.querySelectorAll('.fpc-size-option').forEach((b) => {
315
315
  b.classList.toggle('active', b.getAttribute('data-val') === 'm_core');
316
316
  });
317
317
  calculate();
@@ -319,7 +319,7 @@ const calcUI = ui as FabricProjectCalculatorUI;
319
319
 
320
320
  function handleCopyList(): void {
321
321
  const checks = document.getElementById('check-list');
322
- const lines = Array.from(checks?.querySelectorAll('.merch-item') || [])
322
+ const lines = Array.from(checks?.querySelectorAll('.fpc-merch-item') || [])
323
323
  .map((li) => '• ' + (li.textContent || '').replace('◆', '').trim());
324
324
  navigator.clipboard.writeText(lines.join('\n'));
325
325
  flashBtn('copy-list-btn', window.__toolUI.btnCopied);
@@ -340,7 +340,7 @@ const calcUI = ui as FabricProjectCalculatorUI;
340
340
  function restoreSize(q: URLSearchParams): void {
341
341
  if (!q.has('s')) return;
342
342
  activeSize = q.get('s') || 'm_core';
343
- document.getElementById('size-presets')?.querySelectorAll('.preset-pill').forEach((b) => {
343
+ document.getElementById('size-presets')?.querySelectorAll('.fpc-size-option').forEach((b) => {
344
344
  b.classList.toggle('active', b.getAttribute('data-val') === activeSize);
345
345
  });
346
346
  }
@@ -1,600 +1,443 @@
1
- .fabric-calculator-card {
2
- --f-p: #4f46e5;
3
- --f-a: #818cf8;
4
- --f-side: rgba(79, 70, 229, 0.04);
5
-
6
- display: grid;
7
- grid-template-columns: 360px 1fr;
8
- max-width: 1200px;
9
- width: 95%;
10
- margin: 2rem auto;
11
- background: var(--bg-surface);
12
- backdrop-filter: blur(25px);
13
- border-radius: 32px;
14
- overflow: hidden;
15
- border: 1px solid var(--border-color);
16
- box-shadow: 0 40px 100px rgba(0, 0, 0, 0.15);
17
- color: var(--text-main);
18
- }
19
-
20
- .theme-dark .fabric-calculator-card {
21
- --f-side: rgba(255, 255, 255, 0.03);
22
- }
23
-
24
- .fabric-sidebar {
25
- background: var(--f-side);
26
- padding: 2.5rem 2rem;
27
- display: flex;
28
- flex-direction: column;
29
- gap: 2rem;
30
- border-right: 1px solid var(--border-color);
31
- }
32
-
33
- .config-group {
34
- display: flex;
35
- flex-direction: column;
36
- gap: 1.25rem;
37
- }
38
-
39
- .config-group h3 {
40
- font-size: 0.7rem;
41
- font-weight: 900;
42
- text-transform: uppercase;
43
- letter-spacing: 0.18rem;
44
- color: var(--f-p);
45
- margin: 0;
46
- }
47
-
48
- .fabric-field {
49
- display: flex;
50
- flex-direction: column;
51
- gap: 0.6rem;
52
- }
53
-
54
- .fabric-field label {
55
- font-size: 0.72rem;
56
- font-weight: 800;
57
- text-transform: uppercase;
58
- letter-spacing: 0.06rem;
59
- color: var(--text-muted);
60
- }
61
-
62
- .fabric-select {
63
- width: 100%;
64
- padding: 0.85rem 3rem 0.85rem 1.1rem;
65
- border-radius: 14px;
66
- border: 1.5px solid var(--border-color);
67
- background: var(--bg-surface);
68
- font-size: 0.875rem;
69
- font-weight: 700;
70
- color: inherit;
71
- cursor: pointer;
72
- appearance: none;
73
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234F46E5' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
74
- background-repeat: no-repeat;
75
- background-position: right 1rem center;
76
- background-size: 1.1rem;
77
- transition: border-color 0.2s, box-shadow 0.2s;
78
- outline: none;
79
- }
80
-
81
- .fabric-select:focus {
82
- border-color: var(--f-p);
83
- box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.15);
84
- }
85
-
86
- .shop-stepper {
87
- display: grid;
88
- grid-template-columns: 48px 1fr 48px;
89
- align-items: center;
90
- background: var(--bg-surface);
91
- border-radius: 14px;
92
- border: 1.5px solid var(--border-color);
93
- overflow: hidden;
94
- height: 50px;
95
- max-width: 190px;
96
- }
97
-
98
- .step-btn {
99
- height: 100%;
100
- border: none;
101
- background: transparent;
102
- color: var(--f-p);
103
- font-size: 1.6rem;
104
- font-weight: 300;
105
- cursor: pointer;
106
- display: flex;
107
- align-items: center;
108
- justify-content: center;
109
- transition: background 0.15s, color 0.15s;
110
- flex-shrink: 0;
111
- }
112
-
113
- .step-btn:hover {
114
- background: var(--f-p);
115
- color: white;
116
- }
117
-
118
- .fabric-input {
119
- width: 100%;
120
- height: 100%;
121
- border: none;
122
- background: transparent;
123
- text-align: center;
124
- font-size: 1rem;
125
- font-weight: 800;
126
- color: inherit;
127
- padding: 0;
128
- outline: none;
129
- box-shadow: none;
130
- }
131
-
132
- .preset-group {
133
- display: grid;
134
- grid-template-columns: repeat(3, 1fr);
135
- gap: 0.5rem;
136
- }
137
-
138
- .preset-pill {
139
- padding: 0.75rem 0;
140
- border-radius: 12px;
141
- border: 1.5px solid rgba(79, 70, 229, 0.25);
142
- background: rgba(79, 70, 229, 0.06);
143
- font-size: 0.72rem;
144
- font-weight: 900;
145
- color: var(--f-p);
146
- cursor: pointer;
147
- transition: all 0.2s;
148
- text-align: center;
149
- }
150
-
151
- .theme-dark .preset-pill {
152
- background: rgba(79, 70, 229, 0.08);
153
- border-color: rgba(129, 140, 248, 0.3);
154
- color: var(--f-a);
155
- }
156
-
157
- .preset-pill:hover {
158
- background: rgba(79, 70, 229, 0.12);
159
- border-color: var(--f-p);
160
- }
161
-
162
- .preset-pill.active {
163
- background: var(--f-p);
164
- color: white;
165
- border-color: var(--f-p);
166
- box-shadow: 0 6px 16px rgba(79, 70, 229, 0.35);
167
- }
168
-
169
- .btn-actions {
170
- display: grid;
171
- grid-template-columns: 1fr 1fr;
172
- gap: 1rem;
173
- margin-top: auto;
174
- padding-top: 1rem;
175
- }
176
-
177
- .f-btn {
178
- height: 50px;
179
- border-radius: 14px;
180
- font-size: 0.85rem;
181
- font-weight: 800;
182
- cursor: pointer;
183
- border: none;
184
- transition: all 0.2s;
185
- }
186
-
187
- .f-seco {
188
- background: var(--bg-muted);
189
- color: var(--text-muted);
190
- border: 1.5px solid var(--border-color);
191
- }
192
-
193
- .f-seco:hover {
194
- filter: brightness(0.95);
195
- }
196
-
197
- .f-prim {
198
- background: var(--f-p);
199
- color: white;
200
- }
201
-
202
- .f-prim:hover {
203
- filter: brightness(1.1);
204
- }
205
-
206
- .fabric-main {
207
- padding: 3rem;
208
- display: flex;
209
- flex-direction: column;
210
- gap: 2.5rem;
211
- min-width: 0;
212
- }
213
-
214
- .magic-result-area {
215
- background: linear-gradient(145deg, rgba(79, 70, 229, 0.07), rgba(129, 140, 248, 0.03));
216
- padding: 2.5rem 2rem;
217
- border-radius: 28px;
218
- border: 1px solid rgba(79, 70, 229, 0.12);
219
- }
220
-
221
- .result-lbl {
222
- display: block;
223
- font-size: 0.68rem;
224
- font-weight: 900;
225
- text-transform: uppercase;
226
- letter-spacing: 0.12rem;
227
- color: var(--text-muted);
228
- margin-bottom: 0.4rem;
229
- }
230
-
231
- .magic-result-area .val {
232
- font-size: 6rem;
233
- font-weight: 950;
234
- letter-spacing: -5px;
235
- color: var(--f-p);
236
- line-height: 0.85;
237
- }
238
-
239
- .magic-result-area .unit {
240
- font-size: 1.75rem;
241
- font-weight: 900;
242
- opacity: 0.4;
243
- margin-left: 0.5rem;
244
- }
245
-
246
- .advice-tag {
247
- display: inline-flex;
248
- align-items: center;
249
- margin-top: 1.5rem;
250
- padding: 0.85rem 2rem;
251
- background: rgba(79, 70, 229, 0.1);
252
- border: 1.5px solid rgba(79, 70, 229, 0.22);
253
- border-radius: 50px;
254
- font-size: 1rem;
255
- font-weight: 800;
256
- color: var(--f-p);
257
- }
258
-
259
- .theme-dark .advice-tag {
260
- background: rgba(129, 140, 248, 0.12);
261
- border-color: rgba(129, 140, 248, 0.25);
262
- color: var(--f-a);
263
- }
264
-
265
- .layout-container {
266
- min-width: 0;
267
- }
268
-
269
- .canvas-wrapper {
270
- background: var(--bg-muted);
271
- padding: 24px 24px 14px 12px;
272
- border-radius: 28px;
273
- }
274
-
275
- .scheme-area {
276
- display: flex;
277
- align-items: stretch;
278
- gap: 10px;
279
- }
280
-
281
- .ruler {
282
- width: 34px;
283
- flex-shrink: 0;
284
- position: relative;
285
- }
286
-
287
- .ruler-mark {
288
- position: absolute;
289
- left: 0;
290
- right: 0;
291
- display: flex;
292
- align-items: flex-start;
293
- transform: translateY(-50%);
294
- }
295
-
296
- .ruler-mark::before {
297
- content: '';
298
- width: 8px;
299
- height: 1.5px;
300
- background: var(--text-muted);
301
- flex-shrink: 0;
302
- margin-top: 0.42em;
303
- margin-right: 4px;
304
- }
305
-
306
- .ruler-mark span {
307
- font-size: 0.58rem;
308
- font-weight: 700;
309
- color: var(--text-muted);
310
- white-space: nowrap;
311
- }
312
-
313
- .fabric-board {
314
- flex: 1;
315
- height: 300px;
316
- background: var(--bg-surface);
317
- border: 2.5px solid var(--f-p);
318
- padding: 6px 6px 28px;
319
- box-shadow: 0 16px 36px rgba(0, 0, 0, 0.09);
320
- display: flex;
321
- flex-direction: column;
322
- gap: 4px;
323
- position: relative;
324
- overflow: hidden;
325
- border-radius: 4px;
326
- }
327
-
328
- .piece-row {
329
- display: flex;
330
- flex-direction: row;
331
- gap: 4px;
332
- flex-shrink: 0;
333
- align-items: stretch;
334
- }
335
-
336
- .piece-block {
337
- border-radius: 4px;
338
- border: 1.5px solid;
339
- display: flex;
340
- flex-direction: column;
341
- align-items: flex-start;
342
- justify-content: center;
343
- padding: 4px 8px;
344
- overflow: hidden;
345
- min-width: 0;
346
- transition: filter 0.15s;
347
- }
348
-
349
- .piece-block:hover {
350
- filter: brightness(1.08);
351
- }
352
-
353
- .piece-name {
354
- font-size: 0.62rem;
355
- font-weight: 800;
356
- color: var(--text-main);
357
- line-height: 1.2;
358
- white-space: nowrap;
359
- overflow: hidden;
360
- text-overflow: ellipsis;
361
- width: 100%;
362
- }
363
-
364
- .piece-fold {
365
- border-left: 3px dashed rgba(79, 70, 229, 0.65);
366
- }
367
-
368
- .fold-indicator {
369
- font-size: 0.48rem;
370
- font-weight: 800;
371
- color: rgba(79, 70, 229, 0.75);
372
- text-transform: uppercase;
373
- letter-spacing: 0.04em;
374
- margin-top: 2px;
375
- }
376
-
377
- .board-empty-state {
378
- flex: 1;
379
- display: flex;
380
- align-items: center;
381
- justify-content: center;
382
- font-size: 0.8rem;
383
- font-weight: 600;
384
- color: var(--text-muted);
385
- text-align: center;
386
- padding: 2rem;
387
- }
388
-
389
- .scheme-info {
390
- font-size: 0.68rem;
391
- font-weight: 700;
392
- color: var(--text-muted);
393
- margin-top: 0.6rem;
394
- text-align: right;
395
- }
396
-
397
- .merch-section {
398
- min-width: 0;
399
- }
400
-
401
- .merch-header {
402
- display: flex;
403
- align-items: center;
404
- justify-content: space-between;
405
- margin-bottom: 1rem;
406
- padding-bottom: 0.5rem;
407
- border-bottom: 2px solid var(--border-color);
408
- }
409
-
410
- .merch-title {
411
- font-size: 0.7rem;
412
- font-weight: 900;
413
- text-transform: uppercase;
414
- letter-spacing: 0.18rem;
415
- color: var(--f-p);
1
+ #fabric-calc-app {
2
+ --fpc-accent: #4f46e5;
3
+ --fpc-accent-soft: rgba(79, 70, 229, 0.12);
4
+
5
+ width: min(100%, 1120px);
6
+ margin: 1.5rem auto;
7
+ padding: 1rem;
8
+ display: grid;
9
+ grid-template-columns: minmax(260px, 320px) minmax(0, 1fr);
10
+ gap: 1rem;
11
+ color: var(--text-main);
12
+ background: var(--bg-surface);
13
+ border: 1px solid var(--border-color);
14
+ border-radius: 1rem;
15
+ box-shadow: 0 18px 50px rgba(0, 0, 0, 0.14);
16
+ box-sizing: border-box;
17
+ overflow: visible;
18
+ isolation: isolate;
19
+ }
20
+
21
+ #fabric-calc-app *,
22
+ #fabric-calc-app *::before,
23
+ #fabric-calc-app *::after {
24
+ box-sizing: border-box;
25
+ }
26
+
27
+ #fabric-calc-app .fpc-controls,
28
+ #fabric-calc-app .fpc-main,
29
+ #fabric-calc-app .fpc-layout,
30
+ #fabric-calc-app .fpc-canvas,
31
+ #fabric-calc-app .fpc-result,
32
+ #fabric-calc-app .fpc-merch {
33
+ min-width: 0;
34
+ max-width: 100%;
35
+ }
36
+
37
+ #fabric-calc-app .fpc-controls,
38
+ #fabric-calc-app .fpc-config,
39
+ #fabric-calc-app .fpc-field,
40
+ #fabric-calc-app .fpc-main,
41
+ #fabric-calc-app .fpc-checklist {
42
+ display: grid;
43
+ }
44
+
45
+ #fabric-calc-app .fpc-controls,
46
+ #fabric-calc-app .fpc-main {
47
+ gap: 1rem;
48
+ align-content: start;
49
+ }
50
+
51
+ #fabric-calc-app .fpc-config,
52
+ #fabric-calc-app .fpc-result,
53
+ #fabric-calc-app .fpc-canvas,
54
+ #fabric-calc-app .fpc-merch {
55
+ padding: 1rem;
56
+ background: var(--bg-page);
57
+ border: 1px solid var(--border-color);
58
+ border-radius: 0.85rem;
59
+ }
60
+
61
+ #fabric-calc-app .fpc-config,
62
+ #fabric-calc-app .fpc-field {
63
+ gap: 0.85rem;
64
+ }
65
+
66
+ #fabric-calc-app .fpc-config h3,
67
+ #fabric-calc-app .fpc-merch-title {
68
+ margin: 0;
69
+ color: var(--fpc-accent);
70
+ font-size: 0.7rem;
71
+ font-weight: 900;
72
+ letter-spacing: 0.12em;
73
+ text-transform: uppercase;
74
+ }
75
+
76
+ #fabric-calc-app .fpc-field {
77
+ gap: 0.4rem;
78
+ }
79
+
80
+ #fabric-calc-app .fpc-field label,
81
+ #fabric-calc-app .fpc-result-label {
82
+ color: var(--text-muted);
83
+ font-size: 0.7rem;
84
+ font-weight: 850;
85
+ letter-spacing: 0.06em;
86
+ text-transform: uppercase;
87
+ }
88
+
89
+ #fabric-calc-app .fpc-select,
90
+ #fabric-calc-app .fpc-input {
91
+ width: 100%;
92
+ min-height: 44px;
93
+ color: var(--text-main);
94
+ background-color: var(--bg-surface);
95
+ border: 1.5px solid var(--border-color);
96
+ border-radius: 0.7rem;
97
+ outline: none;
98
+ }
99
+
100
+ #fabric-calc-app .fpc-select {
101
+ padding: 0.75rem 2.4rem 0.75rem 0.85rem;
102
+ font-size: 0.875rem;
103
+ font-weight: 750;
104
+ appearance: none;
105
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234F46E5' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
106
+ background-repeat: no-repeat;
107
+ background-position: right 0.85rem center;
108
+ background-size: 1rem;
109
+ }
110
+
111
+ #fabric-calc-app .fpc-select:focus,
112
+ #fabric-calc-app .fpc-input:focus {
113
+ border-color: var(--fpc-accent);
114
+ box-shadow: 0 0 0 3px var(--fpc-accent-soft);
115
+ }
116
+
117
+ #fabric-calc-app .fpc-size-options,
118
+ #fabric-calc-app .fpc-actions,
119
+ #fabric-calc-app .fpc-stepper,
120
+ #fabric-calc-app .fpc-scheme {
121
+ display: grid;
122
+ }
123
+
124
+ #fabric-calc-app .fpc-size-options {
125
+ grid-template-columns: repeat(3, minmax(0, 1fr));
126
+ gap: 0.5rem;
127
+ }
128
+
129
+ #fabric-calc-app .fpc-size-option,
130
+ #fabric-calc-app .fpc-action,
131
+ #fabric-calc-app .fpc-copy-button,
132
+ #fabric-calc-app .fpc-step-button {
133
+ border: 0;
134
+ cursor: pointer;
135
+ font: inherit;
136
+ }
137
+
138
+ #fabric-calc-app .fpc-size-option {
139
+ min-height: 40px;
140
+ padding: 0.6rem 0.4rem;
141
+ color: var(--fpc-accent);
142
+ background: rgba(79, 70, 229, 0.08);
143
+ border: 1px solid rgba(79, 70, 229, 0.28);
144
+ border-radius: 0.7rem;
145
+ font-size: 0.72rem;
146
+ font-weight: 900;
147
+ }
148
+
149
+ #fabric-calc-app .fpc-size-option.active,
150
+ #fabric-calc-app .fpc-action-primary {
151
+ color: #fff;
152
+ background: var(--fpc-accent);
153
+ }
154
+
155
+ #fabric-calc-app .fpc-stepper {
156
+ grid-template-columns: 44px minmax(0, 1fr) 44px;
157
+ overflow: hidden;
158
+ background: var(--bg-surface);
159
+ border: 1.5px solid var(--border-color);
160
+ border-radius: 0.7rem;
161
+ }
162
+
163
+ #fabric-calc-app .fpc-step-button {
164
+ min-height: 44px;
165
+ color: var(--fpc-accent);
166
+ background: transparent;
167
+ font-size: 1.25rem;
168
+ font-weight: 900;
169
+ }
170
+
171
+ #fabric-calc-app .fpc-input {
172
+ min-height: 44px;
173
+ border-block: 0;
174
+ border-radius: 0;
175
+ text-align: center;
176
+ font-size: 1rem;
177
+ font-weight: 850;
178
+ }
179
+
180
+ #fabric-calc-app .fpc-actions {
181
+ grid-template-columns: 1fr 1fr;
182
+ gap: 0.75rem;
183
+ }
184
+
185
+ #fabric-calc-app .fpc-action {
186
+ min-height: 44px;
187
+ border-radius: 0.7rem;
188
+ font-weight: 850;
189
+ }
190
+
191
+ #fabric-calc-app .fpc-action-secondary {
192
+ color: var(--text-main);
193
+ background: var(--bg-muted);
194
+ border: 1px solid var(--border-color);
195
+ }
196
+
197
+ #fabric-calc-app .fpc-main {
198
+ grid-template-columns: minmax(220px, 0.8fr) minmax(0, 1.2fr);
199
+ }
200
+
201
+ #fabric-calc-app .fpc-warning {
202
+ grid-column: 1 / -1;
203
+ display: none;
204
+ padding: 0.85rem 1rem;
205
+ color: #c2410c;
206
+ background: #fff7ed;
207
+ border: 1px solid #fed7aa;
208
+ border-radius: 0.75rem;
209
+ font-size: 0.85rem;
210
+ font-weight: 650;
211
+ }
212
+
213
+ #fabric-calc-app .fpc-result-label {
214
+ display: block;
215
+ margin-bottom: 0.35rem;
216
+ }
217
+
218
+ #fabric-calc-app .fpc-result-value {
219
+ display: flex;
220
+ flex-wrap: wrap;
221
+ align-items: baseline;
222
+ gap: 0.35rem;
223
+ color: var(--fpc-accent);
224
+ font-size: clamp(2.8rem, 5vw, 4.4rem);
225
+ font-weight: 950;
226
+ line-height: 0.95;
227
+ }
228
+
229
+ #fabric-calc-app .fpc-result-unit {
230
+ color: var(--text-muted);
231
+ font-size: 1.25rem;
232
+ font-weight: 900;
233
+ }
234
+
235
+ #fabric-calc-app .fpc-advice {
236
+ display: inline-flex;
237
+ max-width: 100%;
238
+ margin-top: 0.9rem;
239
+ padding: 0.6rem 0.85rem;
240
+ color: var(--fpc-accent);
241
+ background: rgba(79, 70, 229, 0.08);
242
+ border: 1px solid rgba(79, 70, 229, 0.22);
243
+ border-radius: 999px;
244
+ font-size: 0.88rem;
245
+ font-weight: 800;
246
+ overflow-wrap: anywhere;
247
+ }
248
+
249
+ #fabric-calc-app .fpc-scheme {
250
+ grid-template-columns: 38px minmax(0, 1fr);
251
+ gap: 0.55rem;
252
+ }
253
+
254
+ #fabric-calc-app .fpc-ruler,
255
+ #fabric-calc-app .fpc-board {
256
+ height: 260px;
257
+ }
258
+
259
+ #fabric-calc-app .fpc-ruler {
260
+ position: relative;
261
+ }
262
+
263
+ #fabric-calc-app .fpc-ruler-mark {
264
+ position: absolute;
265
+ right: 0;
266
+ left: 0;
267
+ display: flex;
268
+ align-items: flex-start;
269
+ transform: translateY(-50%);
270
+ }
271
+
272
+ #fabric-calc-app .fpc-ruler-mark::before {
273
+ content: '';
274
+ width: 8px;
275
+ height: 1.5px;
276
+ margin-top: 0.42em;
277
+ margin-right: 4px;
278
+ background: var(--text-muted);
279
+ flex-shrink: 0;
280
+ }
281
+
282
+ #fabric-calc-app .fpc-ruler-mark span {
283
+ color: var(--text-muted);
284
+ font-size: 0.58rem;
285
+ font-weight: 750;
286
+ white-space: nowrap;
287
+ }
288
+
289
+ #fabric-calc-app .fpc-board {
290
+ width: 100%;
291
+ min-width: 0;
292
+ padding: 6px 6px 22px;
293
+ display: flex;
294
+ flex-direction: column;
295
+ gap: 4px;
296
+ overflow: hidden;
297
+ background: var(--bg-surface);
298
+ border: 2px solid var(--fpc-accent);
299
+ border-radius: 0.35rem;
300
+ }
301
+
302
+ #fabric-calc-app .fpc-piece-row {
303
+ display: flex;
304
+ gap: 4px;
305
+ align-items: stretch;
306
+ min-height: 0;
307
+ flex-shrink: 0;
308
+ }
309
+
310
+ #fabric-calc-app .fpc-piece {
311
+ min-width: 0;
312
+ padding: 4px 8px;
313
+ display: flex;
314
+ flex-direction: column;
315
+ justify-content: center;
316
+ overflow: hidden;
317
+ border: 1.5px solid;
318
+ border-radius: 0.3rem;
319
+ }
320
+
321
+ #fabric-calc-app .fpc-piece-name {
322
+ width: 100%;
323
+ overflow: hidden;
324
+ color: var(--text-main);
325
+ font-size: 0.62rem;
326
+ font-weight: 850;
327
+ line-height: 1.2;
328
+ text-overflow: ellipsis;
329
+ white-space: nowrap;
330
+ }
331
+
332
+ #fabric-calc-app .fpc-piece-fold {
333
+ border-left: 3px dashed rgba(79, 70, 229, 0.68);
334
+ }
335
+
336
+ #fabric-calc-app .fpc-fold-indicator {
337
+ margin-top: 2px;
338
+ color: rgba(79, 70, 229, 0.78);
339
+ font-size: 0.48rem;
340
+ font-weight: 850;
341
+ letter-spacing: 0.04em;
342
+ text-transform: uppercase;
343
+ }
344
+
345
+ #fabric-calc-app .fpc-board-empty {
346
+ flex: 1;
347
+ display: flex;
348
+ align-items: center;
349
+ justify-content: center;
350
+ padding: 1rem;
351
+ color: var(--text-muted);
352
+ font-size: 0.8rem;
353
+ font-weight: 650;
354
+ text-align: center;
355
+ }
356
+
357
+ #fabric-calc-app .fpc-scheme-info {
358
+ margin-top: 0.55rem;
359
+ color: var(--text-muted);
360
+ font-size: 0.68rem;
361
+ font-weight: 750;
362
+ text-align: right;
363
+ }
364
+
365
+ #fabric-calc-app .fpc-merch-header {
366
+ display: flex;
367
+ align-items: center;
368
+ justify-content: space-between;
369
+ gap: 0.75rem;
370
+ margin-bottom: 0.85rem;
371
+ }
372
+
373
+ #fabric-calc-app .fpc-copy-button {
374
+ min-height: 36px;
375
+ padding: 0 0.8rem;
376
+ color: var(--fpc-accent);
377
+ background: rgba(79, 70, 229, 0.08);
378
+ border: 1px solid rgba(79, 70, 229, 0.2);
379
+ border-radius: 0.65rem;
380
+ font-size: 0.72rem;
381
+ font-weight: 850;
382
+ }
383
+
384
+ #fabric-calc-app .fpc-checklist {
385
+ margin: 0;
386
+ padding: 0;
387
+ gap: 0.5rem;
388
+ list-style: none;
389
+ }
390
+
391
+ #fabric-calc-app .fpc-merch-item {
392
+ display: flex;
393
+ align-items: center;
394
+ gap: 0.5rem;
395
+ color: var(--text-main);
396
+ font-size: 0.875rem;
397
+ font-weight: 650;
398
+ }
399
+
400
+ #fabric-calc-app .fpc-merch-dot {
401
+ color: var(--fpc-accent);
402
+ font-size: 0.5rem;
403
+ flex-shrink: 0;
404
+ opacity: 0.72;
405
+ }
406
+
407
+ @media (max-width: 900px) {
408
+ #fabric-calc-app,
409
+ #fabric-calc-app .fpc-main {
410
+ grid-template-columns: 1fr;
411
+ }
412
+
413
+ #fabric-calc-app .fpc-controls {
414
+ grid-template-columns: repeat(2, minmax(0, 1fr));
415
+ }
416
+
417
+ #fabric-calc-app .fpc-actions {
418
+ grid-column: 1 / -1;
419
+ }
420
+ }
421
+
422
+ @media (max-width: 600px) {
423
+ #fabric-calc-app {
416
424
  margin: 0;
425
+ padding: 0.85rem;
426
+ border-radius: 0.85rem;
417
427
  }
418
428
 
419
- .copy-list-btn {
420
- font-size: 0.7rem;
421
- font-weight: 800;
422
- color: var(--f-p);
423
- background: rgba(79, 70, 229, 0.08);
424
- border: 1px solid rgba(79, 70, 229, 0.2);
425
- border-radius: 8px;
426
- padding: 0.35rem 0.85rem;
427
- cursor: pointer;
428
- transition: all 0.2s;
429
- }
430
-
431
- .copy-list-btn:hover {
432
- background: rgba(79, 70, 229, 0.15);
433
- }
434
-
435
- .merceria-checklist {
436
- list-style: none;
437
- margin: 0;
438
- padding: 0;
439
- display: flex;
440
- flex-direction: column;
441
- gap: 0.6rem;
442
- }
443
-
444
- .merch-item {
445
- display: flex;
446
- align-items: center;
447
- gap: 0.6rem;
448
- font-size: 0.875rem;
449
- font-weight: 600;
450
- color: var(--text-main);
451
- }
452
-
453
- .merch-dot {
454
- color: var(--f-p);
455
- font-size: 0.5rem;
456
- flex-shrink: 0;
457
- opacity: 0.65;
458
- }
459
-
460
- .warning-banner {
461
- display: none;
462
- background: #fff7ed;
463
- color: #c2410c;
464
- border: 1.5px solid #fed7aa;
465
- padding: 1rem 1.25rem;
466
- border-radius: 16px;
467
- font-size: 0.85rem;
468
- font-weight: 600;
429
+ #fabric-calc-app .fpc-controls,
430
+ #fabric-calc-app .fpc-actions,
431
+ #fabric-calc-app .fpc-size-options {
432
+ grid-template-columns: 1fr;
469
433
  }
470
434
 
471
- @media (max-width: 1100px) {
472
- .fabric-calculator-card {
473
- display: flex;
474
- flex-direction: column;
475
- grid-template-columns: 1fr;
476
- width: 100%;
477
- border-radius: 1rem;
478
- margin: 0;
479
- overflow: visible;
480
- }
481
-
482
- .fabric-sidebar {
483
- border-right: none;
484
- border-bottom: 1px solid var(--border-color);
485
- padding: 1.75rem 1.5rem;
486
- }
487
-
488
- .btn-actions {
489
- margin-top: 1rem;
490
- }
491
-
492
- .fabric-main {
493
- padding: 2rem 1.5rem;
494
- gap: 2rem;
495
- }
496
-
497
- .magic-result-area .val {
498
- font-size: 4.5rem;
499
- letter-spacing: -3px;
500
- }
435
+ #fabric-calc-app .fpc-scheme {
436
+ grid-template-columns: 34px minmax(0, 1fr);
501
437
  }
502
438
 
503
- @media (max-width: 600px) {
504
- .fabric-calculator-card {
505
- background: transparent;
506
- border: 0;
507
- box-shadow: none;
508
- gap: 1rem;
509
- }
510
-
511
- .fabric-sidebar {
512
- background: var(--bg-surface);
513
- border: 1px solid var(--border-color);
514
- border-radius: 1rem;
515
- padding: 1.25rem;
516
- gap: 1.5rem;
517
- min-width: 0;
518
- }
519
-
520
- .config-group {
521
- gap: 1rem;
522
- min-width: 0;
523
- }
524
-
525
- .fabric-field {
526
- min-width: 0;
527
- }
528
-
529
- .fabric-select,
530
- .fabric-input {
531
- display: block;
532
- min-width: 0;
533
- min-height: 48px;
534
- color: var(--text-main);
535
- }
536
-
537
- .fabric-select {
538
- background-color: var(--bg-surface);
539
- }
540
-
541
- .shop-stepper {
542
- width: 100%;
543
- max-width: none;
544
- grid-template-columns: 48px minmax(0, 1fr) 48px;
545
- }
546
-
547
- .preset-group {
548
- grid-template-columns: 1fr;
549
- }
550
-
551
- .preset-pill {
552
- min-height: 44px;
553
- padding: 0.75rem;
554
- }
555
-
556
- .btn-actions {
557
- grid-template-columns: 1fr;
558
- }
559
-
560
- .fabric-main {
561
- background: var(--bg-surface);
562
- border: 1px solid var(--border-color);
563
- border-radius: 1rem;
564
- padding: 1.25rem;
565
- gap: 1.5rem;
566
- min-width: 0;
567
- }
568
-
569
- .magic-result-area {
570
- padding: 1.5rem 1.25rem;
571
- border-radius: 1rem;
572
- }
573
-
574
- .magic-result-area .val {
575
- font-size: 3rem;
576
- letter-spacing: -2px;
577
- }
578
-
579
- .magic-result-area .unit {
580
- font-size: 1.2rem;
581
- }
582
-
583
- .advice-tag {
584
- font-size: 0.875rem;
585
- padding: 0.7rem 1.25rem;
586
- max-width: 100%;
587
- overflow-wrap: anywhere;
588
- }
589
-
590
- .canvas-wrapper {
591
- padding: 14px 14px 10px 8px;
592
- border-radius: 16px;
593
- min-width: 0;
594
- }
595
-
596
- .fabric-board {
597
- height: 220px;
598
- padding-bottom: 20px;
599
- }
439
+ #fabric-calc-app .fpc-ruler,
440
+ #fabric-calc-app .fpc-board {
441
+ height: 220px;
600
442
  }
443
+ }