IsGarrido commited on
Commit
f3130f1
·
verified ·
1 Parent(s): cd1283c

Upload folder using huggingface_hub

Browse files
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ run_local_server.sh
README.md ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Supertonic 2 (TTS)
3
+ emoji: ⚡️
4
+ colorFrom: blue
5
+ colorTo: gray
6
+ sdk: static
7
+ header: mini
8
+ pinned: false
9
+ short_description: Lightning-Fast, On-Device, Multilingual TTS
10
+ language:
11
+ - en
12
+ - ko
13
+ - es
14
+ - pt
15
+ - fr
16
+ tags:
17
+ - speech-synthesis
18
+ - text-to-speech
19
+ - audio
20
+ - voice
21
+ license: openrail
22
+ ---
assets/onnx/duration_predictor.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6d556b3691165c364be91dc0bd894656b5949f5acd2750d8ec2f954010845011
3
+ size 1521526
assets/onnx/text_encoder.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dd5f535ed629f7df86071043e15f541ce1b2ab7f1bdbce4c7892b307bca79fa3
3
+ size 27431318
assets/onnx/tts.json ADDED
@@ -0,0 +1,316 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tts_version": "v1.6.0",
3
+ "split": "opensource-multilingual",
4
+ "ttl_ckpt_path": "unknown.pt",
5
+ "dp_ckpt_path": "unknown.pt",
6
+ "ae_ckpt_path": "unknown.pt",
7
+ "ttl_train": "unknown",
8
+ "dp_train": "unknown",
9
+ "ae_train": "unknown",
10
+ "ttl": {
11
+ "latent_dim": 24,
12
+ "chunk_compress_factor": 6,
13
+ "batch_expander": {
14
+ "n_batch_expand": 6
15
+ },
16
+ "normalizer": {
17
+ "scale": 0.25
18
+ },
19
+ "text_encoder": {
20
+ "char_dict_path": "resources/metadata/char_dict/opensource-multilingual2/char_dict.json",
21
+ "text_embedder": {
22
+ "char_dict_path": "resources/metadata/char_dict/opensource-multilingual2/char_dict.json",
23
+ "char_emb_dim": 256
24
+ },
25
+ "convnext": {
26
+ "idim": 256,
27
+ "ksz": 5,
28
+ "intermediate_dim": 1024,
29
+ "num_layers": 6,
30
+ "dilation_lst": [
31
+ 1,
32
+ 1,
33
+ 1,
34
+ 1,
35
+ 1,
36
+ 1
37
+ ]
38
+ },
39
+ "attn_encoder": {
40
+ "hidden_channels": 256,
41
+ "filter_channels": 1024,
42
+ "n_heads": 4,
43
+ "n_layers": 4,
44
+ "p_dropout": 0.1
45
+ },
46
+ "proj_out": {
47
+ "idim": 256,
48
+ "odim": 256
49
+ }
50
+ },
51
+ "flow_matching": {
52
+ "sig_min": 0
53
+ },
54
+ "style_encoder": {
55
+ "proj_in": {
56
+ "ldim": 24,
57
+ "chunk_compress_factor": 6,
58
+ "odim": 256
59
+ },
60
+ "convnext": {
61
+ "idim": 256,
62
+ "ksz": 5,
63
+ "intermediate_dim": 1024,
64
+ "num_layers": 6,
65
+ "dilation_lst": [
66
+ 1,
67
+ 1,
68
+ 1,
69
+ 1,
70
+ 1,
71
+ 1
72
+ ]
73
+ },
74
+ "style_token_layer": {
75
+ "input_dim": 256,
76
+ "n_style": 50,
77
+ "style_key_dim": 256,
78
+ "style_value_dim": 256,
79
+ "prototype_dim": 256,
80
+ "n_units": 256,
81
+ "n_heads": 2
82
+ }
83
+ },
84
+ "speech_prompted_text_encoder": {
85
+ "text_dim": 256,
86
+ "style_dim": 256,
87
+ "n_units": 256,
88
+ "n_heads": 2
89
+ },
90
+ "uncond_masker": {
91
+ "prob_both_uncond": 0.04,
92
+ "prob_text_uncond": 0.01,
93
+ "std": 0.1,
94
+ "text_dim": 256,
95
+ "n_style": 50,
96
+ "style_key_dim": 256,
97
+ "style_value_dim": 256
98
+ },
99
+ "vector_field": {
100
+ "proj_in": {
101
+ "ldim": 24,
102
+ "chunk_compress_factor": 6,
103
+ "odim": 512
104
+ },
105
+ "time_encoder": {
106
+ "time_dim": 64,
107
+ "hdim": 256
108
+ },
109
+ "main_blocks": {
110
+ "n_blocks": 4,
111
+ "time_cond_layer": {
112
+ "idim": 512,
113
+ "time_dim": 64
114
+ },
115
+ "style_cond_layer": {
116
+ "idim": 512,
117
+ "style_dim": 256
118
+ },
119
+ "text_cond_layer": {
120
+ "idim": 512,
121
+ "text_dim": 256,
122
+ "n_heads": 4,
123
+ "use_residual": true,
124
+ "rotary_base": 10000,
125
+ "rotary_scale": 10
126
+ },
127
+ "convnext_0": {
128
+ "idim": 512,
129
+ "ksz": 5,
130
+ "intermediate_dim": 1024,
131
+ "num_layers": 4,
132
+ "dilation_lst": [
133
+ 1,
134
+ 2,
135
+ 4,
136
+ 8
137
+ ]
138
+ },
139
+ "convnext_1": {
140
+ "idim": 512,
141
+ "ksz": 5,
142
+ "intermediate_dim": 1024,
143
+ "num_layers": 1,
144
+ "dilation_lst": [
145
+ 1
146
+ ]
147
+ },
148
+ "convnext_2": {
149
+ "idim": 512,
150
+ "ksz": 5,
151
+ "intermediate_dim": 1024,
152
+ "num_layers": 1,
153
+ "dilation_lst": [
154
+ 1
155
+ ]
156
+ }
157
+ },
158
+ "last_convnext": {
159
+ "idim": 512,
160
+ "ksz": 5,
161
+ "intermediate_dim": 1024,
162
+ "num_layers": 4,
163
+ "dilation_lst": [
164
+ 1,
165
+ 1,
166
+ 1,
167
+ 1
168
+ ]
169
+ },
170
+ "proj_out": {
171
+ "idim": 512,
172
+ "chunk_compress_factor": 6,
173
+ "ldim": 24
174
+ }
175
+ }
176
+ },
177
+ "ae": {
178
+ "sample_rate": 44100,
179
+ "n_delay": 0,
180
+ "base_chunk_size": 512,
181
+ "chunk_compress_factor": 1,
182
+ "ldim": 24,
183
+ "encoder": {
184
+ "spec_processor": {
185
+ "n_fft": 2048,
186
+ "win_length": 2048,
187
+ "hop_length": 512,
188
+ "n_mels": 228,
189
+ "sample_rate": 44100,
190
+ "eps": 1e-05,
191
+ "norm_mean": 0.0,
192
+ "norm_std": 1.0
193
+ },
194
+ "ksz_init": 7,
195
+ "ksz": 7,
196
+ "num_layers": 10,
197
+ "dilation_lst": [
198
+ 1,
199
+ 1,
200
+ 1,
201
+ 1,
202
+ 1,
203
+ 1,
204
+ 1,
205
+ 1,
206
+ 1,
207
+ 1
208
+ ],
209
+ "intermediate_dim": 2048,
210
+ "idim": 1253,
211
+ "hdim": 512,
212
+ "odim": 24
213
+ },
214
+ "decoder": {
215
+ "ksz_init": 7,
216
+ "ksz": 7,
217
+ "num_layers": 10,
218
+ "dilation_lst": [
219
+ 1,
220
+ 2,
221
+ 4,
222
+ 1,
223
+ 2,
224
+ 4,
225
+ 1,
226
+ 1,
227
+ 1,
228
+ 1
229
+ ],
230
+ "intermediate_dim": 2048,
231
+ "idim": 24,
232
+ "hdim": 512,
233
+ "head": {
234
+ "idim": 512,
235
+ "hdim": 2048,
236
+ "odim": 512,
237
+ "ksz": 3
238
+ }
239
+ }
240
+ },
241
+ "dp": {
242
+ "latent_dim": 24,
243
+ "chunk_compress_factor": 6,
244
+ "normalizer": {
245
+ "scale": 1.0
246
+ },
247
+ "sentence_encoder": {
248
+ "char_emb_dim": 64,
249
+ "char_dict_path": "resources/metadata/char_dict/opensource-multilingual2/char_dict.json",
250
+ "text_embedder": {
251
+ "char_dict_path": "resources/metadata/char_dict/opensource-multilingual2/char_dict.json",
252
+ "char_emb_dim": 64
253
+ },
254
+ "convnext": {
255
+ "idim": 64,
256
+ "ksz": 5,
257
+ "intermediate_dim": 256,
258
+ "num_layers": 6,
259
+ "dilation_lst": [
260
+ 1,
261
+ 1,
262
+ 1,
263
+ 1,
264
+ 1,
265
+ 1
266
+ ]
267
+ },
268
+ "attn_encoder": {
269
+ "hidden_channels": 64,
270
+ "filter_channels": 256,
271
+ "n_heads": 2,
272
+ "n_layers": 2,
273
+ "p_dropout": 0.0
274
+ },
275
+ "proj_out": {
276
+ "idim": 64,
277
+ "odim": 64
278
+ }
279
+ },
280
+ "style_encoder": {
281
+ "proj_in": {
282
+ "ldim": 24,
283
+ "chunk_compress_factor": 6,
284
+ "odim": 64
285
+ },
286
+ "convnext": {
287
+ "idim": 64,
288
+ "ksz": 5,
289
+ "intermediate_dim": 256,
290
+ "num_layers": 4,
291
+ "dilation_lst": [
292
+ 1,
293
+ 1,
294
+ 1,
295
+ 1
296
+ ]
297
+ },
298
+ "style_token_layer": {
299
+ "input_dim": 64,
300
+ "n_style": 8,
301
+ "style_key_dim": 0,
302
+ "style_value_dim": 16,
303
+ "prototype_dim": 64,
304
+ "n_units": 64,
305
+ "n_heads": 2
306
+ }
307
+ },
308
+ "predictor": {
309
+ "sentence_dim": 64,
310
+ "n_style": 8,
311
+ "style_dim": 16,
312
+ "hdim": 128,
313
+ "n_layer": 2
314
+ }
315
+ }
316
+ }
assets/onnx/unicode_indexer.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/onnx/vector_estimator.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:105e9d66fd8756876b210a6b4aa03fc393b1eaca3a8dadcc8d9a3bc785c86a35
3
+ size 132471364
assets/onnx/vocoder.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:19bd51f47a186069c752403518a40f7ea4c647455056d2511f7249691ecddf7c
3
+ size 101405066
assets/voice_styles/F1.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/F2.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/F3.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/F4.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/F5.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/M1.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/M2.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/M3.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/M4.json ADDED
The diff for this file is too large to render. See raw diff
 
assets/voice_styles/M5.json ADDED
The diff for this file is too large to render. See raw diff
 
fonts/EuclidCircularB.woff2 ADDED
Binary file (41.7 kB). View file
 
img/chrome.svg ADDED
img/supertonic_lighteninggraphic.svg ADDED
index.html ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Supertonic 2 - Lightning-Fast, On-Device Multilingual TTS</title>
7
+ <meta name="description"
8
+ content="Supertonic 2 - A lightweight, super-fast text-to-speech synthesis system with on-device capabilities. Multi-language support with ONNX Runtime.">
9
+ <link rel="stylesheet" href="styles.css">
10
+ <link rel="preconnect" href="https://fonts.googleapis.com">
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
+ <link
13
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap"
14
+ rel="stylesheet">
15
+ <link
16
+ href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap"
17
+ rel="stylesheet">
18
+ <link rel="stylesheet"
19
+ href="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/devicon.min.css">
20
+
21
+ <!-- Import map for ES modules -->
22
+ <script type="importmap">
23
+ {
24
+ "imports": {
25
+ "onnxruntime-web": "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.23.0/dist/ort.webgpu.min.mjs",
26
+ "fft.js": "https://esm.sh/fft.js@4.0.4"
27
+ }
28
+ }
29
+ </script>
30
+
31
+ <!-- Privacy-friendly analytics by Plausible -->
32
+ <script async src="https://plausible.io/js/pa-GHmWt-afyVp4WuenlUJZX.js"></script>
33
+ <script>
34
+ window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
35
+ plausible.init()
36
+ </script>
37
+
38
+ </head>
39
+ <body>
40
+ <!-- Interactive TTS Demo Section -->
41
+ <section class="interactive-demo" id="interactive-demo">
42
+ <div class="container">
43
+ <div class="demo-container">
44
+ <div class="demo-content">
45
+ <div class="demo-header-wrapper">
46
+ <img src="img/supertonic_lighteninggraphic.svg" alt="Lightning" class="demo-header-icon" />
47
+ <h2 class="demo-header">
48
+ <span class="demo-header-text"><span class="demo-header-bold">Supertonic 2</span> | Lightning Fast, On-Device, Multilingual TTS</span>
49
+ <span class="demo-header-links">
50
+ <a href="https://github.com/supertone-inc/supertonic/" class="demo-header-link" target="_blank" rel="noopener noreferrer"><svg class="demo-header-link-icon" viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>Github</a><a href="https://huggingface.co/Supertone/supertonic-2" class="demo-header-link" target="_blank" rel="noopener noreferrer"><svg class="demo-header-link-icon" viewBox="0 0 95 88" fill="none" width="16" height="16"><path fill="#FFD21E" d="M47.21 76.5a34.75 34.75 0 1 0 0-69.5 34.75 34.75 0 0 0 0 69.5Z" /><path fill="#FF9D0B" d="M81.96 41.75a34.75 34.75 0 1 0-69.5 0 34.75 34.75 0 0 0 69.5 0Zm-73.5 0a38.75 38.75 0 1 1 77.5 0 38.75 38.75 0 0 1-77.5 0Z" /><path fill="#3A3B45" d="M58.5 32.3c1.28.44 1.78 3.06 3.07 2.38a5 5 0 1 0-6.76-2.07c.61 1.15 2.55-.72 3.7-.32ZM34.95 32.3c-1.28.44-1.79 3.06-3.07 2.38a5 5 0 1 1 6.76-2.07c-.61 1.15-2.56-.72-3.7-.32Z" /><path fill="#FF323D" d="M46.96 56.29c9.83 0 13-8.76 13-13.26 0-2.34-1.57-1.6-4.09-.36-2.33 1.15-5.46 2.74-8.9 2.74-7.19 0-13-6.88-13-2.38s3.16 13.26 13 13.26Z" /><path fill="#3A3B45" fillRule="evenodd" d="M39.43 54a8.7 8.7 0 0 1 5.3-4.49c.4-.12.81.57 1.24 1.28.4.68.82 1.37 1.24 1.37.45 0 .9-.68 1.33-1.35.45-.7.89-1.38 1.32-1.25a8.61 8.61 0 0 1 5 4.17c3.73-2.94 5.1-7.74 5.1-10.7 0-2.34-1.57-1.6-4.09-.36l-.14.07c-2.31 1.15-5.39 2.67-8.77 2.67s-6.45-1.52-8.77-2.67c-2.6-1.29-4.23-2.1-4.23.29 0 3.05 1.46 8.06 5.47 10.97Z" clipRule="evenodd" /><path fill="#FF9D0B" d="M70.71 37a3.25 3.25 0 1 0 0-6.5 3.25 3.25 0 0 0 0 6.5ZM24.21 37a3.25 3.25 0 1 0 0-6.5 3.25 3.25 0 0 0 0 6.5ZM17.52 48c-1.62 0-3.06.66-4.07 1.87a5.97 5.97 0 0 0-1.33 3.76 7.1 7.1 0 0 0-1.94-.3c-1.55 0-2.95.59-3.94 1.66a5.8 5.8 0 0 0-.8 7 5.3 5.3 0 0 0-1.79 2.82c-.24.9-.48 2.8.8 4.74a5.22 5.22 0 0 0-.37 5.02c1.02 2.32 3.57 4.14 8.52 6.1 3.07 1.22 5.89 2 5.91 2.01a44.33 44.33 0 0 0 10.93 1.6c5.86 0 10.05-1.8 12.46-5.34 3.88-5.69 3.33-10.9-1.7-15.92-2.77-2.78-4.62-6.87-5-7.77-.78-2.66-2.84-5.62-6.25-5.62a5.7 5.7 0 0 0-4.6 2.46c-1-1.26-1.98-2.25-2.86-2.82A7.4 7.4 0 0 0 17.52 48Zm0 4c.51 0 1.14.22 1.82.65 2.14 1.36 6.25 8.43 7.76 11.18.5.92 1.37 1.31 2.14 1.31 1.55 0 2.75-1.53.15-3.48-3.92-2.93-2.55-7.72-.68-8.01.08-.02.17-.02.24-.02 1.7 0 2.45 2.93 2.45 2.93s2.2 5.52 5.98 9.3c3.77 3.77 3.97 6.8 1.22 10.83-1.88 2.75-5.47 3.58-9.16 3.58-3.81 0-7.73-.9-9.92-1.46-.11-.03-13.45-3.8-11.76-7 .28-.54.75-.76 1.34-.76 2.38 0 6.7 3.54 8.57 3.54.41 0 .7-.17.83-.6.79-2.85-12.06-4.05-10.98-8.17.2-.73.71-1.02 1.44-1.02 3.14 0 10.2 5.53 11.68 5.53.11 0 .2-.03.24-.1.74-1.2.33-2.04-4.9-5.2-5.21-3.16-8.88-5.06-6.8-7.33.24-.26.58-.38 1-.38 3.17 0 10.66 6.82 10.66 6.82s2.02 2.1 3.25 2.1c.28 0 .52-.1.68-.38.86-1.46-8.06-8.22-8.56-11.01-.34-1.9.24-2.85 1.31-2.85Z" /><path fill="#FFD21E" d="M38.6 76.69c2.75-4.04 2.55-7.07-1.22-10.84-3.78-3.77-5.98-9.3-5.98-9.3s-.82-3.2-2.69-2.9c-1.87.3-3.24 5.08.68 8.01 3.91 2.93-.78 4.92-2.29 2.17-1.5-2.75-5.62-9.82-7.76-11.18-2.13-1.35-3.63-.6-3.13 2.2.5 2.79 9.43 9.55 8.56 11-.87 1.47-3.93-1.71-3.93-1.71s-9.57-8.71-11.66-6.44c-2.08 2.27 1.59 4.17 6.8 7.33 5.23 3.16 5.64 4 4.9 5.2-.75 1.2-12.28-8.53-13.36-4.4-1.08 4.11 11.77 5.3 10.98 8.15-.8 2.85-9.06-5.38-10.74-2.18-1.7 3.21 11.65 6.98 11.76 7.01 4.3 1.12 15.25 3.49 19.08-2.12Z" /><path fill="#FF9D0B" d="M77.4 48c1.62 0 3.07.66 4.07 1.87a5.97 5.97 0 0 1 1.33 3.76 7.1 7.1 0 0 1 1.95-.3c1.55 0 2.95.59 3.94 1.66a5.8 5.8 0 0 1 .8 7 5.3 5.3 0 0 1 1.78 2.82c.24.9.48 2.8-.8 4.74a5.22 5.22 0 0 1 .37 5.02c-1.02 2.32-3.57 4.14-8.51 6.1-3.08 1.22-5.9 2-5.92 2.01a44.33 44.33 0 0 1-10.93 1.6c-5.86 0-10.05-1.8-12.46-5.34-3.88-5.69-3.33-10.9 1.7-15.92 2.78-2.78 4.63-6.87 5.01-7.77.78-2.66 2.83-5.62 6.24-5.62a5.7 5.7 0 0 1 4.6 2.46c1-1.26 1.98-2.25 2.87-2.82A7.4 7.4 0 0 1 77.4 48Zm0 4c-.51 0-1.13.22-1.82.65-2.13 1.36-6.25 8.43-7.76 11.18a2.43 2.43 0 0 1-2.14 1.31c-1.54 0-2.75-1.53-.14-3.48 3.91-2.93 2.54-7.72.67-8.01a1.54 1.54 0 0 0-.24-.02c-1.7 0-2.45 2.93-2.45 2.93s-2.2 5.52-5.97 9.3c-3.78 3.77-3.98 6.8-1.22 10.83 1.87 2.75 5.47 3.58 9.15 3.58 3.82 0 7.73-.9 9.93-1.46.1-.03 13.45-3.8 11.76-7-.29-.54-.75-.76-1.34-.76-2.38 0-6.71 3.54-8.57 3.54-.42 0-.71-.17-.83-.6-.8-2.85 12.05-4.05 10.97-8.17-.19-.73-.7-1.02-1.44-1.02-3.14 0-10.2 5.53-11.68 5.53-.1 0-.19-.03-.23-.1-.74-1.2-.34-2.04 4.88-5.2 5.23-3.16 8.9-5.06 6.8-7.33-.23-.26-.57-.38-.98-.38-3.18 0-10.67 6.82-10.67 6.82s-2.02 2.1-3.24 2.1a.74.74 0 0 1-.68-.38c-.87-1.46 8.05-8.22 8.55-11.01.34-1.9-.24-2.85-1.31-2.85Z" /><path fill="#FFD21E" d="M56.33 76.69c-2.75-4.04-2.56-7.07 1.22-10.84 3.77-3.77 5.97-9.3 5.97-9.3s.82-3.2 2.7-2.9c1.86.3 3.23 5.08-.68 8.01-3.92 2.93.78 4.92 2.28 2.17 1.51-2.75 5.63-9.82 7.76-11.18 2.13-1.35 3.64-.6 3.13 2.2-.5 2.79-9.42 9.55-8.55 11 .86 1.47 3.92-1.71 3.92-1.71s9.58-8.71 11.66-6.44c2.08 2.27-1.58 4.17-6.8 7.33-5.23 3.16-5.63 4-4.9 5.2.75 1.2 12.28-8.53 13.36-4.4 1.08 4.11-11.76 5.3-10.97 8.15.8 2.85 9.05-5.38 10.74-2.18 1.69 3.21-11.65 6.98-11.76 7.01-4.31 1.12-15.26 3.49-19.08-2.12Z" /></svg>Models</a><a href="https://chromewebstore.google.com/detail/mdbiaajonlkomihpcaffhkagodbcgbme?utm_source=item-share-cb" class="demo-header-link" target="_blank" rel="noopener noreferrer"><img src="img/chrome.svg" class="demo-header-link-icon" width="16" height="16" alt="Chrome" />Extension</a>
51
+ </span>
52
+ </h2>
53
+ </div>
54
+ <div class="demo-controls">
55
+ <div class="demo-param">
56
+ <div class="speaker-container">
57
+ <label class="speaker-label">Speaker: </label>
58
+ <div class="speaker-list" id="speakerList">
59
+ <span class="speaker-item" data-voice="M1">Alex</span><span class="speaker-separator">, </span>
60
+ <span class="speaker-item" data-voice="M2">James</span><span class="speaker-separator">, </span>
61
+ <span class="speaker-item" data-voice="M3">Robert</span><span class="speaker-separator">, </span>
62
+ <span class="speaker-item" data-voice="M4">Sam</span><span class="speaker-separator">, </span>
63
+ <span class="speaker-item" data-voice="M5">Daniel</span><span class="speaker-separator">, </span>
64
+ <span class="speaker-item" data-voice="F1">Sarah</span><span class="speaker-separator">, </span>
65
+ <span class="speaker-item" data-voice="F2">Lily</span><span class="speaker-separator">, </span>
66
+ <span class="speaker-item" data-voice="F3">Jessica</span><span class="speaker-separator">, </span>
67
+ <span class="speaker-item" data-voice="F4">Olivia</span><span class="speaker-separator">, </span>
68
+ <span class="speaker-item" data-voice="F5">Emily</span>
69
+ <span class="speaker-item speaker-item-create" id="createVoiceBtn" style="display: none;">+Create your own voice</span>
70
+ </div>
71
+ </div>
72
+ <div class="language-info">
73
+ <label class="speaker-label">Language: </label>
74
+ <div class="speaker-list" id="languageList">
75
+ <span class="speaker-item" data-language="en">English</span><span class="speaker-separator">, </span>
76
+ <span class="speaker-item" data-language="es">Spanish</span><span class="speaker-separator">, </span>
77
+ <span class="speaker-item" data-language="pt">Portuguese</span><span class="speaker-separator">, </span>
78
+ <span class="speaker-item" data-language="fr">French</span><span class="speaker-separator">, </span>
79
+ <span class="speaker-item" data-language="ko">Korean</span>
80
+ </div>
81
+ </div>
82
+ </div>
83
+ </div>
84
+
85
+ <div class="demo-input-section">
86
+ <div class="demo-input-label">
87
+ <label for="demoTextInput">Enter text to synthesize:</label>
88
+ </div>
89
+ <div
90
+ id="demoTextInput"
91
+ contenteditable="true"
92
+ spellcheck="false"
93
+ class="demo-text-input-editable"
94
+ data-placeholder="Type any text here to convert it into speech... (minimum 10 characters)">This text-to-speech system runs entirely in your browser, providing fast and private operation without sending any data to external servers.</div>
95
+ <div id="presetControlsRow">
96
+ <div id="presetButtonGroup">
97
+ <span class="preset-icon" aria-hidden="true">
98
+ <svg viewBox="0 0 24 24" width="18" height="18" focusable="false">
99
+ <rect x="4" y="6" width="14" height="2" fill="#000"/>
100
+ <rect x="4" y="10" width="10" height="2" fill="#000"/>
101
+ <rect x="4" y="14" width="14" height="2" fill="#000"/>
102
+ <rect x="4" y="18" width="10" height="2" fill="#000"/>
103
+ </svg>
104
+ </span>
105
+ <span class="preset-item" data-preset="freeform" id="freeformBtn">Freeform</span>
106
+ <span class="preset-item" data-preset="quote" id="presetQuoteBtn">Quote</span>
107
+ <span class="preset-item" data-preset="paragraph" id="presetParagraphBtn">Paragraph</span>
108
+ <span class="preset-item" data-preset="script" id="presetScriptBtn">Script</span>
109
+ <span class="preset-item" data-preset="book" id="presetBookBtn" style="display: none;">Book</span>
110
+ </div>
111
+ <span class="demo-char-counter" id="demoCharCounter">
112
+ <span class="demo-char-warning" id="demoCharWarning"></span>
113
+ <span id="demoCharCount">126</span> characters
114
+ </span>
115
+ </div>
116
+ </div>
117
+
118
+ <div class="demo-output-section">
119
+ <!-- Coming Soon Modal -->
120
+ <div id="comingSoonModal" class="coming-soon-modal">
121
+ <div class="coming-soon-modal-overlay"></div>
122
+ <div class="coming-soon-modal-content">
123
+ <div class="coming-soon-modal-header">
124
+ <h3>Coming Soon</h3>
125
+ </div>
126
+ <div class="coming-soon-modal-body">
127
+ <p>Custom voice creation feature will be available soon.</p>
128
+ </div>
129
+ <div class="coming-soon-modal-footer">
130
+ <button class="coming-soon-modal-btn" id="comingSoonCloseBtn">OK</button>
131
+ </div>
132
+ </div>
133
+ </div>
134
+
135
+ <!-- Parameters in horizontal layout -->
136
+ <div class="demo-params-row">
137
+ <div class="demo-param">
138
+ <div class="demo-param-header">
139
+ <label for="demoTotalSteps">
140
+ Quality: <span class="param-value" id="demoTotalStepsValue">5 Steps</span>
141
+ </label>
142
+ </div>
143
+ <input type="range" id="demoTotalSteps" value="5" min="2" max="16" step="1">
144
+ </div>
145
+ <div class="demo-param">
146
+ <div class="demo-param-header">
147
+ <label for="demoSpeed">
148
+ Speech Speed: <span class="param-value" id="demoSpeedValue">1.0x</span>
149
+ </label>
150
+ </div>
151
+ <input type="range" id="demoSpeed" value="1.0" min="0.8" max="1.3" step="0.05">
152
+ </div>
153
+ <button id="demoGenerateBtn" class="demo-generate-btn" disabled>
154
+ <img src="img/supertonic_lighteninggraphic.svg" alt="Generate" width="20" height="20" />
155
+ <span class="text">Generate Speech</span>
156
+ <span class="shimmer" aria-hidden="true"></span>
157
+ </button>
158
+ </div>
159
+ </div>
160
+ <div id="demoResults" class="demo-results">
161
+ <div class="demo-placeholder">
162
+ <div class="demo-placeholder-icon">🎙️</div>
163
+ <p>Your generated speech will appear here</p>
164
+ </div>
165
+ </div>
166
+ </div>
167
+
168
+ <!-- Moved below content: status box and info banner -->
169
+ <div class="demo-status-box" id="demoStatusBox">
170
+ <div class="demo-status-content">
171
+ <div class="demo-status-text" id="demoStatusText">
172
+ <strong>Initializing...</strong> Loading models...
173
+ </div>
174
+ </div>
175
+ </div>
176
+
177
+ <div id="wasmWarningBanner" class="wasm-warning-banner" style="display: none;">
178
+ Currently using WASM backend. For optimal performance, we recommend using a browser with WebGPU support (Chrome 113+ or Edge 113+).
179
+ </div>
180
+
181
+ <div id="demoError" class="demo-error"></div>
182
+ </div>
183
+ </div>
184
+ </section>
185
+
186
+ <script src="preset-texts.js"></script>
187
+ <!-- Speaker Tooltip -->
188
+ <div id="speakerTooltip" class="speaker-tooltip"></div>
189
+
190
+ <!-- Language Auto-Detection Toast -->
191
+ <div id="languageToast" class="language-toast">
192
+ <span class="language-toast-icon">⚠️</span>
193
+ <span class="language-toast-message" id="languageToastMessage"></span>
194
+ </div>
195
+
196
+ <script type="module" src="script.js"></script>
197
+
198
+ </body>
199
+ </html>
preset-texts.js ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Preset text content for demo buttons
2
+ window.presetTexts = {
3
+ quote: {
4
+ en: "This text-to-speech system runs entirely in your browser, providing fast and private operation without sending any data to external servers.",
5
+ es: "Este sistema de conversión de texto a voz funciona completamente de forma local en el navegador y procesa todos los datos en el dispositivo para ofrecer un rendimiento rápido y seguro.",
6
+ pt: "Este sistema de conversão de texto em fala funciona totalmente de forma local no navegador, processando todos os dados no próprio dispositivo para garantir desempenho rápido e seguro.",
7
+ fr: "Ce système de synthèse vocale fonctionne entièrement en local dans le navigateur et traite toutes les données sur l’appareil afin d’offrir des performances rapides et sécurisées.",
8
+ ko: "이 텍스트 음성 변환 시스템은 브라우저에서 완전히 로컬로 동작하며, 모든 데이터를 기기 내에서 처리해 안전하고 빠른 성능을 제공합니다.",
9
+ },
10
+ paragraph: {
11
+ en: "Flat white and cafe latte are both espresso-based drinks with milk. However, they differ clearly in the amount and texture of the milk, as well as in overall flavor balance. A flat white is designed to highlight the espresso. It uses a very thin layer of finely textured microfoam, creating a smooth and almost flat surface. As a result, the coffee's rich flavor and aroma remain more pronounced. The drink is also typically served in a smaller cup with less milk than a latte. In contrast, a cafe latte contains a higher proportion of steamed milk. It also has a thicker foam layer, which gives it a creamier and milder character. This softens the bitterness and acidity of the espresso. Because of this, it is an approachable and widely enjoyed milk-based coffee.",
12
+ es: "El flat white y el café latte son bebidas a base de espresso con leche. Sin embargo, se diferencian claramente en la cantidad y la textura de la leche, así como en el equilibrio general del sabor. El flat white está pensado para resaltar el carácter del espresso. Utiliza una capa muy fina de microespuma bien integrada, que deja una superficie casi plana. Gracias a ello, el sabor y el aroma del café se perciben de forma más intensa. Además, normalmente se sirve en una taza más pequeña y con menos leche que un latte. En cambio, el café latte contiene una mayor proporción de leche vaporizada. También presenta una capa de espuma más gruesa, lo que le aporta una textura más cremosa y un sabor más suave. Esto atenúa el amargor y la acidez del espresso. Por esa razón, es una bebida fácil de disfrutar para un público amplio.",
13
+ pt: "O flat white e o café latte são bebidas à base de espresso com leite. No entanto, apresentam diferenças claras na quantidade e na textura do leite, bem como no equilíbrio geral do sabor. O flat white foi criado para destacar o sabor do espresso. Ele utiliza uma camada muito fina de microespuma bem integrada, resultando em uma superfície quase plana. Com isso, o aroma e a intensidade do café permanecem mais evidentes. A bebida também costuma ser servida em uma xícara menor, com menos leite do que o latte. Já o café latte possui uma proporção maior de leite vaporizado. Além disso, conta com uma camada de espuma mais espessa, oferecendo uma textura mais cremosa e um sabor mais suave. Isso reduz a percepção do amargor e da acidez do espresso. Por isso, é uma opção acessível e bastante popular.",
14
+ fr: "Le flat white et le café latte sont tous deux des boissons à base d’espresso et de lait. Toutefois, ils se distinguent nettement par la quantité et la texture du lait, ainsi que par l’équilibre global des saveurs. Le flat white met l’accent sur l’espresso. Il utilise une couche très fine de micro-mousse, créant une surface lisse et presque plate. Cela permet aux arômes et à l’intensité du café de rester bien perceptibles. La boisson est également servie dans une tasse plus petite, avec moins de lait qu’un latte. À l’inverse, le café latte contient une proportion plus élevée de lait chaud. Il présente aussi une couche de mousse plus épaisse, ce qui lui donne une texture plus onctueuse et un goût plus doux. Cette composition atténue l’amertume et l’acidité de l’espresso. Ainsi, il s’agit d’une boisson facile à apprécier par un large public.",
15
+ ko: "플랫화이트와 카페라떼는 모두 에스프레소에 우유를 더한 커피입니다. 하지만 우유의 양과 질감, 그리고 전체적인 맛의 균형에서 분명한 차이를 보입니다. 플랫화이트는 에스프레소의 풍미를 중심에 두는 음료입니다. 매우 얇고 고운 마이크로폼 형태의 우유 거품을 사용해 표면이 거의 평평하게 마무리됩니다. 이로 인해 커피의 진한 맛과 향이 우유에 묻히지 않고 또렷하게 느껴집니다. 또한 일반적으로 카페라떼보다 잔의 크기와 우유의 양이 적은 편입니다. 반면 카페라떼는 스팀 밀크의 비중이 더 높습니다. 우유 거품층도 플랫화이트에 비해 두껍게 형성되어 전체적으로 부드럽고 고소한 인상을 줍니다. 그 결과 에스프레소의 쓴맛이나 산미가 완화됩니다. 누구나 부담 없이 마시기 쉬운 밀크 커피로 인식되는 이유입니다."
16
+ },
17
+ script: {
18
+ en:
19
+ `Hello. Today, I would like to talk about one of the long-standing philosophical debates: “Which came first, the chicken or the egg?” This question may seem like simple curiosity, but in fact, it is a topic that allows us to deeply explore how we understand life, evolution, cause, and effect.
20
+
21
+ First, let’s define the question a little more precisely. We often wonder about the order of the egg and the chicken. Which came first, the egg or the chicken? Here, the “egg” could mean a general “egg” or specifically a “chicken egg.” This distinction determines the direction of the discussion.
22
+
23
+ From a philosophical perspective, this problem stimulates reflection on cause and effect. What started first? Causes produce effects, and effects in turn shape causes. Following this logic, we discover a cycle. Eggs exist because there are chickens, and chickens come from eggs. They depend on each other, making it difficult to find a starting point.
24
+
25
+ However, from a scientific perspective, we can offer a slightly different answer. Modern biology and evolutionary theory show that the chicken we know today is the result of long evolution. Chickens are a species of birds whose ancestors gradually changed over tens of millions of years to take their current form. In other words, today’s chicken stands on a continuum of ancestors slightly different from past chickens.
26
+
27
+ Here comes an important clue. There was an egg laid by a chicken ancestor that was not yet a true chicken. A mutation or genetic change occurred in that egg, resulting in the first chicken as we know it today. From this perspective, if we define the egg as a “chicken-laid egg,” then the egg came first. There was an egg in which the changes necessary to become a chicken occurred, and the first chicken hatched from it.
28
+
29
+ While the evolutionary answer is like this, philosophical discussions are still valid. Because cause and effect cannot be completely separated, it requires circular thinking. This question is not mere curiosity; it is a door that makes us ponder causality, the flow of time, and the origin of life.
30
+
31
+ Another perspective comes from religion or mythology. Many cultures believe life was created by a deity. From this viewpoint, the chicken could have been created first, because eggs can only exist if there are chickens. Unlike scientific evidence, mythological perspectives reflect human intuition and belief.
32
+
33
+ Today’s conclusion can be summarized as follows. From philosophical, logical, and mythological viewpoints, it is a circular question. From scientific and evolutionary perspectives, the egg in which the genetic changes necessary to become a chicken occurred came first. In other words, the answer depends on which criteria and perspective we choose.
34
+
35
+ Finally, let’s consider the meaning this debate gives us. Arguing about the order of the egg and the chicken is not just intellectual curiosity. Through this question, we can reflect on the essence of life, the process of change, cause and effect, and our way of thinking.
36
+
37
+ The message I want to convey today is clear. Sometimes, the answer is not important. What matters is asking questions, thinking from various perspectives, and making an effort to understand the world deeply. The debate over which came first, the egg or the chicken, ultimately symbolizes human curiosity and the spirit of inquiry.`,
38
+ es:
39
+ `Hola. Hoy quiero hablar sobre uno de los debates filosóficos más antiguos: “¿Qué fue primero, el huevo o la gallina?” Esta pregunta puede parecer una simple curiosidad, pero en realidad es un tema que nos permite explorar profundamente cómo entendemos la vida, la evolución, la causa y el efecto.
40
+
41
+ Primero, definamos la pregunta un poco más concretamente. A menudo nos preguntamos sobre el orden entre el huevo y la gallina. ¿Qué fue primero, el huevo o la gallina? Aquí, “huevo” podría significar un “huevo” en general o específicamente un “huevo de gallina”. Esta distinción determina la dirección de la discusión.
42
+
43
+ Desde una perspectiva filosófica, este problema nos hace reflexionar sobre la causa y el efecto. ¿Qué comenzó primero? Las causas producen efectos, y los efectos a su vez forman causas. Siguiendo esta lógica, descubrimos un ciclo. Los huevos existen porque hay gallinas, y las gallinas provienen de huevos. Dependen unas de otras, lo que dificulta encontrar un punto de inicio.
44
+
45
+ Sin embargo, desde una perspectiva científica, podemos ofrecer una respuesta algo diferente. La biología moderna y la teoría evolutiva muestran que la gallina que conocemos hoy es el resultado de una larga evolución. Las gallinas son una especie de aves cuyos antepasados cambiaron gradualmente durante decenas de millones de años hasta tomar su forma actual. En otras palabras, la gallina actual se encuentra sobre un continuo de antepasados ligeramente diferentes de las gallinas del pasado.
46
+
47
+ Aquí surge una pista importante. Hubo un huevo puesto por un ancestro de la gallina que aún no era una gallina verdadera. En ese huevo ocurrió una mutación o cambio genético, dando lugar a la primera gallina tal como la conocemos hoy. Desde esta perspectiva, si definimos el huevo como “huevo puesto por una gallina”, entonces el huevo fue primero. Hubo un huevo en el que ocurrieron los cambios necesarios para convertirse en gallina, y de ese huevo nació la primera gallina.
48
+
49
+ Aunque la respuesta evolutiva es así, las discusiones filosóficas siguen siendo válidas. Dado que no se puede separar completamente la causa del efecto, se requiere un pensamiento circular. Esta pregunta no es mera curiosidad; es una puerta que nos hace reflexionar sobre la causalidad, el flujo del tiempo y el origen de la vida.
50
+
51
+ Otra perspectiva proviene de la religión o la mitología. Muchas culturas creen que la vida fue creada por un dios. Desde este punto de vista, la gallina pudo haber sido creada primero, porque los huevos solo pueden existir si hay gallinas. A diferencia de la evidencia científica, la perspectiva mitológica refleja la intuición y la creencia humana.
52
+
53
+ La conclusión de hoy se puede resumir así. Desde los puntos de vista filosófico, lógico y mitológico, es una pregunta circular. Desde los puntos de vista científico y evolutivo, el huevo en el que ocurrieron los cambios genéticos necesarios para convertirse en gallina fue primero. En otras palabras, la respuesta depende de los criterios y la perspectiva que elijamos.
54
+
55
+ Finalmente, consideremos el significado que nos da este debate. Discutir sobre el orden del huevo y la gallina no es solo curiosidad intelectual. A través de esta pregunta, podemos reflexionar sobre la esencia de la vida, el proceso de cambio, la causa y el efecto, y nuestra forma de pensar.
56
+
57
+ El mensaje que quiero transmitir hoy es claro. A veces, la respuesta no es importante. Lo importante es hacer preguntas, pensar desde diversas perspectivas y esforzarse por comprender el mundo profundamente. El debate sobre qué fue primero, el huevo o la gallina, simboliza, en última instancia, la curiosidad humana y el espíritu de investigación.`,
58
+ pt:
59
+ `Olá. Hoje, gostaria de falar sobre um dos debates filosóficos mais antigos: “O que veio primeiro, o ovo ou a galinha?” Esta pergunta pode parecer uma simples curiosidade, mas, na verdade, é um tema que nos permite explorar profundamente como entendemos a vida, a evolução, a causa e o efeito.
60
+
61
+ Primeiro, vamos definir a pergunta de forma um pouco mais precisa. Frequentemente nos perguntamos sobre a ordem entre o ovo e a galinha. O que veio primeiro, o ovo ou a galinha? Aqui, “ovo” pode significar um “ovo” em geral ou especificamente um “ovo de galinha”. Essa distinção determina a direção da discussão.
62
+
63
+ Do ponto de vista filosófico, esse problema estimula a reflexão sobre causa e efeito. O que começou primeiro? As causas produzem efeitos, e os efeitos, por sua vez, formam causas. Seguindo essa lógica, descobrimos um ciclo. Os ovos existem porque existem galinhas, e as galinhas vêm dos ovos. Eles dependem uns dos outros, tornando difícil encontrar um ponto de início.
64
+
65
+ No entanto, do ponto de vista científico, podemos oferecer uma resposta um pouco diferente. A biologia moderna e a teoria da evolução mostram que a galinha que conhecemos hoje é o resultado de uma longa evolução. As galinhas são uma espécie de ave cujos ancestrais mudaram gradualmente ao longo de dezenas de milhões de anos até assumirem a forma atual. Em outras palavras, a galinha de hoje está sobre um contínuo de ancestrais ligeiramente diferentes das galinhas do passado.
66
+
67
+ Aqui surge uma pista importante. Houve um ovo colocado por um ancestral da galinha que ainda não era uma galinha verdadeira. Nesse ovo ocorreu uma mutação ou mudança genética, resultando na primeira galinha como conhecemos hoje. Dessa perspectiva, se definirmos o ovo como “ovo posto por uma galinha”, então o ovo veio primeiro. Houve um ovo em que ocorreram as mudanças necessárias para se tornar uma galinha, e a primeira galinha nasceu desse ovo.
68
+
69
+ Embora a resposta evolutiva seja essa, as discussões filosóficas ainda são válidas. Como causa e efeito não podem ser completamente separados, é necessário um pensamento circular. Esta pergunta não é mera curiosidade; é uma porta que nos faz refletir sobre causalidade, o fluxo do tempo e a origem da vida.
70
+
71
+ Outra perspectiva vem da religião ou da mitologia. Muitas culturas acreditam que a vida foi criada por uma divindade. Deste ponto de vista, a galinha poderia ter sido criada primeiro, porque os ovos só podem existir se houver galinhas. Ao contrário das evidências científicas, a perspectiva mitológica reflete a intuição e a crença humana.
72
+
73
+ A conclusão de hoje pode ser resumida assim. Do ponto de vista filosófico, lógico e mitológico, é uma pergunta circular. Do ponto de vista científico e evolutivo, o ovo em que ocorreram as mudanças genéticas necessárias para se tornar uma galinha veio primeiro. Em outras palavras, a resposta depende dos critérios e da perspectiva que escolhemos.
74
+
75
+ Finalmente, vamos considerar o significado que esse debate nos traz. Discutir a ordem do ovo e da galinha não é apenas curiosidade intelectual. Por meio desta pergunta, podemos refletir sobre a essência da vida, o processo de mudança, causa e efeito e nossa forma de pensar.
76
+
77
+ A mensagem que quero transmitir hoje é clara. Às vezes, a resposta não é importante. O que importa é fazer perguntas, pensar sob diversas perspectivas e esforçar-se para compreender profundamente o mundo. O debate sobre o que veio primeiro, o ovo ou a galinha, simboliza, em última análise, a curiosidade humana e o espírito de investigação.`,
78
+ fr:
79
+ `Bonjour. Aujourd’hui, je voudrais parler de l’un des débats philosophiques les plus anciens : « Qu’est-ce qui est venu en premier, l’œuf ou la poule ? » Cette question peut sembler être une simple curiosité, mais en réalité, c’est un sujet qui nous permet d’explorer profondément comment nous comprenons la vie, l’évolution, la cause et l’effet.
80
+
81
+ Tout d’abord, définissons un peu plus précisément la question. Nous nous demandons souvent quel est l’ordre entre l’œuf et la poule. Qu’est-ce qui est venu en premier, l’œuf ou la poule ? Ici, « œuf » peut signifier un « œuf » en général ou spécifiquement un « œuf de poule ». Cette distinction détermine la direction de la discussion.
82
+
83
+ D’un point de vue philosophique, ce problème incite à réfléchir sur la cause et l’effet. Qu’est-ce qui a commencé en premier ? Les causes produisent des effets, et les effets, à leur tour, forment des causes. En suivant cette logique, nous découvrons un cycle. Les œufs existent parce qu’il y a des poules, et les poules viennent des œufs. Ils dépendent les uns des autres, ce qui rend difficile de trouver un point de départ.
84
+
85
+ Cependant, d’un point de vue scientifique, nous pouvons proposer une réponse légèrement différente. La biologie moderne et la théorie de l’évolution montrent que la poule que nous connaissons aujourd’hui est le résultat d’une longue évolution. Les poules sont une espèce d’oiseaux dont les ancêtres ont progressivement changé au cours de dizaines de millions d’années pour prendre leur forme actuelle. En d’autres termes, la poule d’aujourd’hui se tient sur un continuum d’ancêtres légèrement différents des poules du passé.
86
+
87
+ Voici un indice important. Il y avait un œuf pondu par un ancêtre de la poule qui n’était pas encore une vraie poule. Une mutation ou un changement génétique est survenu dans cet œuf, donnant naissance à la première poule telle que nous la connaissons aujourd’hui. De ce point de vue, si nous définissons l’œuf comme « œuf pondu par une poule », alors l’œuf est venu en premier. Il y avait un œuf dans lequel les changements nécessaires pour devenir une poule se sont produits, et la première poule en est sortie.
88
+
89
+ Bien que la réponse évolutionniste soit ainsi, les discussions philosophiques restent valables. Comme la cause et l’effet ne peuvent pas être complètement séparés, cela exige une pensée circulaire. Cette question n’est pas une simple curiosité ; c’est une porte qui nous fait réfléchir sur la causalité, le flux du temps et l’origine de la vie.
90
+
91
+ Une autre perspective vient de la religion ou de la mythologie. De nombreuses cultures croient que la vie a été créée par une divinité. De ce point de vue, la poule aurait pu être créée en premier, car les œufs ne peuvent exister que s’il y a des poules. Contrairement aux preuves scientifiques, la perspective mythologique reflète l’intuition et la croyance humaines.
92
+
93
+ La conclusion d’aujourd’hui peut se résumer ainsi. Du point de vue philosophique, logique et mythologique, c’est une question circulaire. Du point de vue scientifique et évolutionniste, l’œuf dans lequel se sont produites les modifications génétiques nécessaires pour devenir une poule est venu en premier. En d’autres termes, la réponse dépend des critères et du point de vue que nous choisissons.
94
+
95
+ Enfin, réfléchissons à la signification que ce débat nous apporte. Discuter de l’ordre de l’œuf et de la poule n’est pas seulement une curiosité intellectuelle. À travers cette question, nous pouvons réfléchir à l’essence de la vie, au processus de changement, à la cause et à l’effet, et à notre manière de penser.
96
+
97
+ Le message que je veux transmettre aujourd’hui est clair. Parfois, la réponse n’est pas importante. Ce qui compte, c’est de poser des questions, de penser sous différents angles et de faire un effort pour comprendre profondément le monde. Le débat sur ce qui est venu en premier, l’œuf ou la poule, symbolise finalement la curiosité humaine et l’esprit d’investigation.`,
98
+ ko:
99
+ `안녕하세요. 오늘 저는 오랜 철학적 논쟁 중 하나인, '달걀이 먼저인가, 닭이 먼저인가'라는 주제에 대해 이야기하려 합니다. 이 질문은 단순한 호기심처럼 보이지만, 사실 우리가 생명과 진화, 원인과 결과를 어떻게 이해하는지 깊이 탐구할 수 있는 주제입니다.
100
+
101
+ 먼저, 질문을 조금 더 구체적으로 정의해보겠습니다. 우리는 흔히 달걀과 닭의 순서를 두고 고민합니다. 달걀이 먼저냐, 닭이 먼저냐. 여기서 달걀은 일반적인 '알'을 의미할 수도 있고, 닭이 낳는 '닭 알'을 의미할 수도 있습니다. 이 구분은 논의의 방향을 결정합니다.
102
+
103
+ 철학적 관점에서 보면, 이 문제는 원인과 결과에 대한 고민을 촉발합니다. 무엇이 먼저 시작되었는가. 원인은 결과를 만들어내고, 결과는 다시 원인을 형성합니다. 이 논리를 따라가면 우리는 순환의 고리를 발견하게 됩니다. 달걀은 닭이 있어야 존재하고, 닭은 달걀에서 나옵니다. 서로 의존하며 시작점을 찾기 어렵습니다.
104
+
105
+ 하지만 과학적 관점에서 보면 조금 다른 답을 제시할 수 있습니다. 현대 생물학과 진화론을 살펴보면, 오늘날 우리가 아는 닭은 오랜 진화의 결과입니다. 닭은 조류의 한 종으로, 그 조상들은 수천만 년 동안 서서히 변화를 겪으며 현재의 형태를 갖추었습니다. 즉, 지금의 닭은 과거의 닭과 조금 다른 조상의 연속체 위에 서 있습니다.
106
+
107
+ 여기서 중요한 단서가 나옵니다. 현대 닭의 조상이 완전히 닭이 아닌 상태에서 낳은 알이 있었습니다. 바로 그 알에서 돌연변이나 유전적 변화가 일어나 오늘날 우리가 알고 있는 닭이 태어난 것입니다. 이 관점에서 보면, '닭이 낳은 달걀'이라는 기준으로 달걀을 정의한다면 달걀이 먼저입니다. 닭이 되기 위해 변화가 일어난 알이 있었고, 그 알에서 첫 번째 닭이 탄생했기 때문입니다.
108
+
109
+ 진화론적 답은 이렇지만, 철학적 논의도 여전히 유효합니다. 원인과 결과를 완전히 분리할 수 없다는 점에서, 순환적 사고를 요구합니다. 이 질문은 단순한 호기심을 넘어, 인과관계와 시간의 흐름, 생명의 시작에 대해 깊이 생각하게 만드는 주제입니다.
110
+
111
+ 또 다른 관점으로는 종교적 혹은 신화적 해석도 있습니다. 많은 문화권에서는 생명이 신에 의해 창조되었다고 믿습니다. 이러한 관점에서는 닭이 먼저 창조되었을 수 있습니다. 달걀은 닭이 있어야 존재할 수 있기 때문입니다. 과학적 증거와 달리, 신화적 관점은 인간의 직관과 신념을 반영합니다.
112
+
113
+ 오늘의 결론은 이렇게 정리할 수 있습니다. 철학적, 논리적, 신화적 관점에서 보면 순환적 질문입니다. 과학적, 진화론적 관점에서 보면, 닭이 되기 위한 유전적 변화가 일어난 달걀이 먼저였습니다. 즉, 질문의 답은 우리가 어떤 기준과 관점을 택하느냐에 따라 달라집니다.
114
+
115
+ 마지막으로, 이 논쟁이 우리에게 주는 의미를 생각해봅시다. 달걀과 닭의 순서를 따지는 것은 단순한 지적 호기심에 그치지 않습니다. 우리는 이 질문을 통해 생명의 본질, 변화의 과정, 원인과 결과, 그리고 우리의 사고 방식을 돌아볼 수 있습니다.
116
+
117
+ 오늘 제가 전달하고 싶은 메시지는 명확합니다. 때로는 답이 중요하지 않습니다. 중요한 것은 질문을 던지고, 다양한 관점에서 사고하고, 세상을 깊이 이해하려는 노력입니다. 달걀이 먼저인지 닭이 먼저인지에 대한 토론은 결국 인간의 호기심과 탐구 정신을 상징합니다.
118
+
119
+ 감사합니다.`
120
+ }
121
+ };
script.js ADDED
The diff for this file is too large to render. See raw diff
 
styles.css ADDED
@@ -0,0 +1,1840 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ margin: 0;
3
+ padding: 0;
4
+ box-sizing: border-box;
5
+ }
6
+
7
+ strong {
8
+ font-weight: normal;
9
+ }
10
+
11
+ /* ------------------------------
12
+ 1. Font Import & Variable Setup
13
+ ------------------------------ */
14
+ @font-face {
15
+ font-family: 'Euclid Circular B';
16
+ src: url('fonts/EuclidCircularB.woff2') format('woff2');
17
+ font-style: normal;
18
+ font-display: swap;
19
+ }
20
+
21
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
22
+
23
+ :root {
24
+ --font-display: 'Euclid Circular B', sans-serif;
25
+ --font-body: 'Inter', sans-serif;
26
+ --font-mono: 'IBM Plex Mono', monospace;
27
+
28
+ --color-text-default: #161615;
29
+ --color-text-secondary: #5d5d5d;
30
+ /* Accent colors */
31
+ --accent-yellow: #FFFF00;
32
+ --accent-pink: #FF69B4;
33
+ }
34
+
35
+ /* ------------------------------
36
+ 2. Base Typography (h1 ~ p)
37
+ ------------------------------ */
38
+ h1 {
39
+ font-family: var(--font-display);
40
+ font-size: 4rem;
41
+ line-height: 1.2;
42
+ letter-spacing: -0.01em;
43
+ color: var(--color-text-default);
44
+ font-weight: 400;
45
+ }
46
+
47
+ h2 {
48
+ font-family: var(--font-display);
49
+ font-size: 2.5rem;
50
+ line-height: 1.3;
51
+ letter-spacing: -0.01em;
52
+ color: var(--color-text-default);
53
+ font-weight: 400;
54
+ }
55
+
56
+ h3 {
57
+ font-family: var(--font-display);
58
+ font-size: clamp(1.5rem, 4vw, 2.3rem);
59
+ line-height: 125%;
60
+ letter-spacing: -0.035em;
61
+ font-weight: 300;
62
+ }
63
+
64
+ h4 {
65
+ font-family: var(--font-body);
66
+ font-size: 1.5rem;
67
+ line-height: 1.4;
68
+ color: var(--color-text-default);
69
+ font-weight: 400;
70
+ }
71
+
72
+ h5 {
73
+ font-family: var(--font-body);
74
+ font-size: 1.25rem;
75
+ line-height: 1.5;
76
+ color: var(--color-text-default);
77
+ font-weight: 400;
78
+ }
79
+
80
+ h6 {
81
+ font-family: var(--font-body);
82
+ font-size: 1.125rem;
83
+ line-height: 1.5;
84
+ color: var(--color-text-default);
85
+ font-weight: 400;
86
+ }
87
+
88
+ p {
89
+ font-family: var(--font-body);
90
+ font-size: 1rem;
91
+ line-height: 1.6;
92
+ color: var(--color-text-secondary);
93
+ }
94
+
95
+ html {
96
+ font-size: 16px;
97
+ overflow-x: hidden;
98
+ overflow-y: auto;
99
+ max-width: 100%;
100
+ scroll-behavior: smooth;
101
+ }
102
+
103
+ @media (max-width: 1280px) {
104
+ html {
105
+ font-size: 15px;
106
+ }
107
+ }
108
+
109
+ @media (max-width: 768px) {
110
+ html {
111
+ font-size: 14px;
112
+ }
113
+ }
114
+
115
+ :root {
116
+ /* Dark Mode */
117
+ --dark-mode: true;
118
+
119
+ /* Primary */
120
+ --supertone_blue: #227cff;
121
+ --primary: var(--supertone_blue);
122
+ --primary-dark: #0849CC;
123
+ --primary-light: var(--supertone_blue);
124
+ --accent: var(--supertone_blue);
125
+
126
+ /* Secondary / Highlight */
127
+ --highlight: #f4fa7d;
128
+
129
+ /* Backgrounds */
130
+ --light: #000000;
131
+ --light-lighter: #1a1a1a;
132
+ --light-darker: #2a2a2a;
133
+
134
+ /* Text */
135
+ --text: #ffffff;
136
+ --text-secondary: #b0b0b0;
137
+ --text-muted: #888888;
138
+
139
+ /* Border */
140
+ --border: #444444;
141
+
142
+ /* Status / Semantic */
143
+ --success: #3FB950;
144
+
145
+ /* Gradients */
146
+ --gradient: linear-gradient(135deg, var(--supertone_blue) 0%, var(--supertone_blue) 100%);
147
+ --gradient-alt: linear-gradient(135deg, var(--supertone_blue) 0%, var(--supertone_blue) 100%);
148
+ }
149
+
150
+ body {
151
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
152
+ background: var(--light);
153
+ color: var(--text);
154
+ line-height: 1.6;
155
+ overflow-x: hidden;
156
+ max-width: 100%;
157
+ position: relative;
158
+ font-weight: 300;
159
+ }
160
+
161
+ .container {
162
+ max-width: 1280px;
163
+ margin: 0 auto;
164
+ padding: 0 2rem;
165
+ }
166
+
167
+ @media (min-width: 1921px) {
168
+ .container {
169
+ max-width: none;
170
+ }
171
+
172
+ /* Scale elements by 1.75x for large screens */
173
+ .demo-result-item.supertonic-result-item {
174
+ --result-title-size: calc(1rem * 1.75);
175
+ }
176
+
177
+ .demo-result-item.supertonic-result-item .demo-result-title {
178
+ font-size: calc(1rem * 1.75);
179
+ }
180
+
181
+ .demo-result-item.supertonic-result-item .demo-result-info .stat-value {
182
+ font-size: calc(1rem * 1.75);
183
+ }
184
+
185
+ .demo-result-item.supertonic-result-item .demo-result-info .stat-label {
186
+ font-size: calc(0.7rem * 1.75);
187
+ }
188
+
189
+ .demo-result-item.supertonic-result-item .demo-result-info .stat-value .stat-label.stat-suffix {
190
+ font-size: calc(0.7rem * 1.75);
191
+ }
192
+
193
+ .demo-result-item.supertonic-result-item .custom-audio-player .time-display {
194
+ font-size: calc(1rem * 1.75);
195
+ }
196
+
197
+ #play-pause-btn {
198
+ width: calc(40px * 1.75) !important;
199
+ height: calc(40px * 1.75) !important;
200
+ }
201
+
202
+ #play-pause-btn svg {
203
+ width: calc(24px * 1.75) !important;
204
+ height: calc(24px * 1.75) !important;
205
+ }
206
+
207
+ .demo-result-item {
208
+ padding: calc(1rem * 1.75) calc(1.5rem * 1.75) !important;
209
+ }
210
+
211
+ .demo-download-btn svg {
212
+ width: calc(16px * 1.75) !important;
213
+ height: calc(16px * 1.75) !important;
214
+ }
215
+
216
+ .demo-result-item.supertonic-result-item .demo-result-info .stat-value .stat-prefix {
217
+ left: calc(-2.3rem * 1.75);
218
+ }
219
+ }
220
+
221
+ @media (max-width: 1280px) {
222
+ .container {
223
+ max-width: 100%;
224
+ padding: 0 1.5rem;
225
+ }
226
+ }
227
+
228
+ .btn {
229
+ display: inline-flex;
230
+ align-items: center;
231
+ gap: 0.535rem;
232
+ padding: 0.8rem 2.1rem;
233
+ border-radius: 1rem;
234
+ text-decoration: none;
235
+ transition: all 0.3s ease;
236
+ font-size: 1rem;
237
+ cursor: pointer;
238
+ border: 1px solid;
239
+ font-family: inherit;
240
+ line-height: 150%;
241
+ background: var(--light);
242
+ }
243
+
244
+ .btn-primary {
245
+ background: var(--gradient);
246
+ color: white;
247
+ border-color: transparent;
248
+ box-shadow: 0 4px 20px rgba(57, 121, 255, 0.3);
249
+ }
250
+
251
+ .btn-primary:hover {
252
+ transform: translateY(-2px);
253
+ box-shadow: 0 6px 30px rgba(57, 121, 255, 0.5);
254
+ }
255
+
256
+ .btn-secondary {
257
+ background: rgba(242, 242, 242, 0);
258
+ color: var(--text);
259
+ width: 11rem;
260
+ display: flex;
261
+ justify-content: center;
262
+ align-items: center;
263
+ }
264
+
265
+ .btn-secondary:hover {
266
+ border-color: var(--primary);
267
+ background: var(--light);
268
+ transform: translateY(-2px);
269
+ }
270
+
271
+ /* Text toggle style for btn-secondary buttons */
272
+ .btn.btn-secondary.text-toggle {
273
+ background: none;
274
+ border: none;
275
+ padding: 0;
276
+ display: inline;
277
+ font-family: inherit;
278
+ border-radius: 0;
279
+ box-shadow: none;
280
+ transform: none;
281
+ gap: 0;
282
+ font-size: 1rem;
283
+ cursor: pointer;
284
+ transition: all 0.3s ease;
285
+ text-decoration: none;
286
+ width: auto;
287
+ justify-content: initial;
288
+ align-items: initial;
289
+ }
290
+
291
+ /* Preset item styles (matching speaker-item) */
292
+ .preset-item {
293
+ font-size: 1rem;
294
+ color: #999;
295
+ cursor: pointer;
296
+ transition: all 0.2s ease;
297
+ padding: 0.25rem 0;
298
+ white-space: nowrap;
299
+ }
300
+
301
+ .preset-item:hover {
302
+ color: #ddd;
303
+ }
304
+
305
+ .preset-item.active {
306
+ color: var(--text);
307
+ opacity: 1;
308
+ text-decoration: underline;
309
+ text-decoration-style: solid;
310
+ text-decoration-thickness: 1px;
311
+ text-underline-offset: 4px;
312
+ }
313
+
314
+ .preset-icon {
315
+ display: inline-flex;
316
+ align-items: center;
317
+ vertical-align: middle;
318
+ }
319
+
320
+ .preset-icon svg {
321
+ display: block;
322
+ fill: #ffffff !important;
323
+ }
324
+
325
+ .preset-icon svg rect {
326
+ fill: #ffffff !important;
327
+ }
328
+
329
+ .btn.btn-secondary.text-toggle:hover {
330
+ opacity: 0.7;
331
+ border-color: transparent;
332
+ background: transparent;
333
+ transform: none;
334
+ }
335
+
336
+ .btn.btn-secondary.text-toggle.active {
337
+ color: var(--supertone_blue);
338
+ text-decoration: underline;
339
+ text-decoration-style: wavy;
340
+ text-decoration-thickness: 1px;
341
+ text-decoration-color: var(--supertone_blue);
342
+ text-underline-offset: 4px;
343
+ border-color: transparent;
344
+ background: transparent;
345
+ font-weight: 400;
346
+ }
347
+
348
+ .btn.btn-secondary svg {
349
+ color: var(--text-secondary);
350
+ }
351
+
352
+ #presetButtonGroup #presetBookBtn {
353
+ display: none;
354
+ }
355
+
356
+ .stat {
357
+ text-align: center;
358
+ padding: 0 1.25rem 0 1.25rem;
359
+ flex-shrink: 0;
360
+ position: relative;
361
+ }
362
+
363
+ .stat-value {
364
+ font-size: 8rem;
365
+ color: var(--text);
366
+ margin-bottom: 0;
367
+ font-family: var(--font-display);
368
+ line-height: 150%;
369
+ letter-spacing: -0.04em;
370
+ }
371
+
372
+ .stat-label {
373
+ font-size: 1rem;
374
+ text-transform: none;
375
+ letter-spacing: normal;
376
+ line-height: 1.3125rem;
377
+ font-family: var(--font-body);
378
+ display: inline-flex;
379
+ align-items: center;
380
+ }
381
+
382
+ .stat-arrow {
383
+ margin-left: 0.25em;
384
+ display: inline-block;
385
+ }
386
+
387
+ /* Interactive TTS Demo Section */
388
+ .interactive-demo {
389
+ padding: 3.0rem 0 0.5rem 0;
390
+ }
391
+
392
+ .demo-container {
393
+ margin: 0 auto;
394
+ background: none;
395
+ border-radius: 12px;
396
+ padding: 2.5rem 4.5rem 0;
397
+ box-shadow: none;
398
+ }
399
+
400
+ .demo-status-box {
401
+ display: flex;
402
+ justify-content: space-between;
403
+ align-items: center;
404
+ gap: 0.75rem;
405
+ padding: 0.2rem 1rem;
406
+ background: rgba(255, 152, 0, 0.1);
407
+ border: 1px solid rgba(255, 152, 0, 0.3);
408
+ border-radius: 8px;
409
+ margin-bottom: 0rem;
410
+ min-height: 45px;
411
+ position: relative;
412
+ overflow: hidden;
413
+ --status-progress: 0%;
414
+ --status-progress-color: rgba(255, 152, 0, 0.2);
415
+ z-index: 0;
416
+ }
417
+
418
+ .demo-status-box::before {
419
+ content: '';
420
+ position: absolute;
421
+ inset: 0;
422
+ width: var(--status-progress, 0%);
423
+ background: var(--status-progress-color);
424
+ transition: width 0.4s ease;
425
+ z-index: 0;
426
+ pointer-events: none;
427
+ }
428
+
429
+ .demo-status-box > * {
430
+ position: relative;
431
+ z-index: 1;
432
+ }
433
+
434
+ .demo-status-content {
435
+ flex: 1;
436
+ display: flex;
437
+ flex-direction: column;
438
+ gap: 0.5rem;
439
+ }
440
+
441
+ .demo-status-box.success {
442
+ background: rgba(63, 185, 80, 0.1);
443
+ border-color: rgba(63, 185, 80, 0.3);
444
+ font-family: 'IBM Plex Mono', monospace;
445
+ --status-progress-color: rgba(63, 185, 80, 0.2);
446
+ }
447
+
448
+ .demo-status-box.success .demo-status-text {
449
+ color: var(--success);
450
+ }
451
+
452
+ .demo-status-box.success * {
453
+ font-family: inherit;
454
+ }
455
+
456
+ .demo-status-text {
457
+ font-family: 'IBM Plex Mono', monospace;
458
+ font-size: 0.85rem;
459
+ font-weight: 400;
460
+ }
461
+
462
+ .demo-status-box.error {
463
+ background: rgba(239, 68, 68, 0.1);
464
+ border-color: rgba(239, 68, 68, 0.3);
465
+ --status-progress-color: rgba(239, 68, 68, 0.2);
466
+ }
467
+
468
+ .demo-status-box.error .demo-status-text {
469
+ color: #ef4444;
470
+ }
471
+
472
+ /* WASM Warning Banner - subtle persistent notification */
473
+ .wasm-warning-banner {
474
+ padding: 0.5rem 1rem;
475
+ background: rgba(239, 68, 68, 0.08);
476
+ border: 1px solid rgba(239, 68, 68, 0.25);
477
+ border-radius: 6px;
478
+ font-family: var(--font-body);
479
+ font-size: 0.8rem;
480
+ color: #b91c1c;
481
+ margin-top: 0.5rem;
482
+ line-height: 1.4;
483
+ }
484
+
485
+ .demo-content {
486
+ display: grid;
487
+ grid-template-columns: 1fr;
488
+ gap: 1rem;
489
+ margin-bottom: 2rem;
490
+ }
491
+
492
+ .demo-input-section,
493
+ .demo-output-section {
494
+ display: flex;
495
+ flex-direction: column;
496
+ width: 100%;
497
+ min-width: 0;
498
+ }
499
+
500
+ .demo-input-section {
501
+ height: 100%;
502
+ position: relative;
503
+ overflow: visible;
504
+ }
505
+
506
+ .demo-input-label {
507
+ display: none;
508
+ }
509
+
510
+ .demo-input-section label {
511
+ display: block;
512
+ color: var(--text);
513
+ font-size: 1.125rem;
514
+ margin: 0;
515
+ }
516
+
517
+ .demo-char-counter {
518
+ display: flex;
519
+ align-items: center;
520
+ gap: 0.375rem;
521
+ font-size: 1rem;
522
+ color: var(--text-muted);
523
+ justify-content: flex-end;
524
+ }
525
+
526
+ .demo-char-counter.error,
527
+ .demo-char-counter.warning {
528
+ color: var(--text-muted);
529
+ }
530
+
531
+ .demo-char-counter.valid {
532
+ color: var(--text-muted);
533
+ }
534
+
535
+ .demo-char-warning {
536
+ color: #ef4444;
537
+ font-size: 1rem;
538
+ transition: all 0.2s ease;
539
+ }
540
+
541
+ #demoCharCount {
542
+ display: inline-block;
543
+ min-width: 1.5ch;
544
+ text-align: right;
545
+ font-variant-numeric: tabular-nums;
546
+ }
547
+
548
+ .demo-char-counter.valid .demo-char-warning {
549
+ display: none;
550
+ }
551
+
552
+ .demo-input-section textarea,
553
+ .demo-text-input-editable {
554
+ width: 100%;
555
+ padding: 0;
556
+ background: none;
557
+ border: none;
558
+ border-radius: 0;
559
+ position: relative;
560
+ color: var(--text);
561
+ font-size: 2rem;
562
+ font-weight: 400;
563
+ line-height: 1.2;
564
+ font-family: inherit;
565
+ resize: vertical;
566
+ overflow-y: auto;
567
+ transition: all 0.3s ease;
568
+ margin-bottom: 0;
569
+ min-height: 90px;
570
+ height: 330px;
571
+ max-height: none;
572
+ flex: 0 0 auto;
573
+ -webkit-text-decoration-skip-ink: none;
574
+ text-decoration-skip-ink: none;
575
+ }
576
+
577
+ /* Hide spellcheck underlines */
578
+ .demo-text-input-editable::spelling-error,
579
+ #demoTextInput::spelling-error {
580
+ text-decoration: none !important;
581
+ background: none !important;
582
+ }
583
+
584
+ #demoTextInput {
585
+ position: relative;
586
+ overflow-y: auto;
587
+ scrollbar-color: transparent transparent;
588
+ scrollbar-width: thin;
589
+ white-space: pre-wrap;
590
+ word-wrap: break-word;
591
+ transition: scrollbar-color 0.3s ease;
592
+ }
593
+
594
+ .demo-input-section::after {
595
+ content: '';
596
+ position: absolute;
597
+ left: -27px;
598
+ top: 0;
599
+ width: 4px;
600
+ height: var(--demo-text-input-height, 330px);
601
+ min-height: 90px;
602
+ background: var(--text);
603
+ pointer-events: none;
604
+ z-index: 10;
605
+ }
606
+
607
+ #demoTextInput.scrolling {
608
+ scrollbar-color: var(--light) transparent;
609
+ }
610
+
611
+ #demoTextInput::-webkit-scrollbar {
612
+ width: 10px;
613
+ }
614
+
615
+ #demoTextInput::-webkit-scrollbar-track {
616
+ background: transparent !important;
617
+ border: none;
618
+ }
619
+
620
+ #demoTextInput::-webkit-scrollbar-thumb {
621
+ background: transparent !important;
622
+ border-radius: 999px;
623
+ transition: background 0.3s ease;
624
+ }
625
+
626
+ #demoTextInput.scrolling::-webkit-scrollbar-thumb {
627
+ background: var(--light) !important;
628
+ }
629
+
630
+ #demoTextInput.scrolling::-webkit-scrollbar-thumb:hover {
631
+ background: var(--light-darker) !important;
632
+ }
633
+
634
+ .demo-input-section textarea:focus,
635
+ .demo-text-input-editable:focus {
636
+ outline: none;
637
+ border-color: transparent;
638
+ background: none;
639
+ }
640
+
641
+ .demo-input-section textarea::placeholder {
642
+ color: var(--text-muted);
643
+ }
644
+
645
+ /* Placeholder for contenteditable */
646
+ .demo-text-input-editable:empty:before {
647
+ content: attr(data-placeholder);
648
+ color: var(--text-muted);
649
+ pointer-events: none;
650
+ }
651
+
652
+ .demo-header-wrapper {
653
+ position: relative;
654
+ margin-bottom: 1rem;
655
+ }
656
+
657
+ .demo-header-icon {
658
+ position: absolute;
659
+ left: -27px;
660
+ top: 57%;
661
+ transform: translateY(-50%) scale(1.3);
662
+ transform-origin: center;
663
+ width: 20px;
664
+ height: 20px;
665
+ }
666
+
667
+ .demo-header {
668
+ font-family: var(--font-body);
669
+ font-size: 1rem;
670
+ font-weight: 400;
671
+ line-height: 1.6;
672
+ color: var(--text);
673
+ margin: 0;
674
+ display: flex;
675
+ justify-content: space-between;
676
+ align-items: center;
677
+ gap: 1rem;
678
+ width: 100%;
679
+ }
680
+
681
+ .demo-header-text {
682
+ flex: 1;
683
+ }
684
+
685
+ .demo-header-links {
686
+ display: flex;
687
+ align-items: center;
688
+ gap: 15px;
689
+ white-space: nowrap;
690
+ flex-shrink: 0;
691
+ }
692
+
693
+ .demo-header-bold {
694
+ font-weight: 600;
695
+ color: var(--text);
696
+ }
697
+
698
+ .highlight-multilingual {
699
+ color: var(--text);
700
+ }
701
+
702
+ .demo-header-link {
703
+ color: #ffffff;
704
+ text-decoration: underline;
705
+ text-decoration-style: solid;
706
+ text-decoration-thickness: 1px;
707
+ text-underline-offset: 4px;
708
+ transition: opacity 0.2s ease;
709
+ text-decoration-skip-ink: none;
710
+ display: inline-flex;
711
+ align-items: center;
712
+ gap: 0.25rem;
713
+ }
714
+
715
+ .demo-header-link:hover {
716
+ opacity: 0.8;
717
+ }
718
+
719
+ .demo-header-link-icon {
720
+ width: 16px;
721
+ height: 16px;
722
+ flex-shrink: 0;
723
+ display: inline-block;
724
+ vertical-align: middle;
725
+ }
726
+
727
+
728
+ .demo-controls {
729
+ display: grid;
730
+ grid-template-columns: 1fr;
731
+ gap: 0.5rem;
732
+ margin-bottom: 1rem;
733
+ }
734
+
735
+ .demo-params-row {
736
+ display: grid;
737
+ grid-template-columns: 1fr 1fr 2fr;
738
+ gap: 1rem;
739
+ align-items: flex-start;
740
+ margin: 1.5rem 0 1rem;
741
+ }
742
+
743
+ .demo-params-row .demo-param {
744
+ display: flex;
745
+ flex-direction: column;
746
+ }
747
+
748
+ .demo-params-row #demoGenerateBtn {
749
+ align-self: flex-end;
750
+ margin-top: 0;
751
+ grid-column: 3;
752
+ }
753
+
754
+ .demo-param {
755
+ display: flex;
756
+ flex-direction: column;
757
+ }
758
+
759
+ .demo-param-header {
760
+ display: flex;
761
+ justify-content: space-between;
762
+ align-items: center;
763
+ margin-bottom: 0.35rem;
764
+ gap: 1rem;
765
+ font-weight: 400;
766
+ }
767
+
768
+ .demo-param label {
769
+ font-size: 1rem;
770
+ color: var(--text);
771
+ display: flex;
772
+ align-items: center;
773
+ gap: 0.5rem;
774
+ font-weight: 600;
775
+ }
776
+
777
+ .param-value {
778
+ font-size: 1rem;
779
+ color: var(--text);
780
+ }
781
+
782
+ .demo-params-row .param-value {
783
+ font-weight: 400;
784
+ color: #999;
785
+ }
786
+
787
+ .demo-param input[type="range"] {
788
+ width: 100%;
789
+ height: 18px;
790
+ background: transparent;
791
+ outline: none;
792
+ -webkit-appearance: none;
793
+ appearance: none;
794
+ cursor: pointer;
795
+ margin: 0;
796
+ padding: 0;
797
+ }
798
+
799
+ .demo-param input[type="range"]::-webkit-slider-thumb {
800
+ -webkit-appearance: none;
801
+ appearance: none;
802
+ width: 14px;
803
+ height: 14px;
804
+ background: #000;
805
+ border: 1px solid #ffffff;
806
+ border-radius: 50%;
807
+ cursor: pointer;
808
+ margin-top: -7px;
809
+ }
810
+
811
+ .demo-param input[type="range"]::-webkit-slider-thumb:hover {
812
+ background: #000;
813
+ border: 1px solid #ffffff;
814
+ }
815
+
816
+ .demo-param input[type="range"]::-moz-range-thumb {
817
+ width: 14px;
818
+ height: 14px;
819
+ background: #000;
820
+ border: 1px solid #ffffff;
821
+ border-radius: 50%;
822
+ cursor: pointer;
823
+ }
824
+
825
+ .demo-param input[type="range"]::-moz-range-thumb:hover {
826
+ background: #000;
827
+ border: 1px solid #ffffff;
828
+ }
829
+
830
+ .demo-param input[type="range"]::-webkit-slider-runnable-track {
831
+ width: 100%;
832
+ height: 1px;
833
+ background: #999;
834
+ border: none;
835
+ border-radius: 0;
836
+ }
837
+
838
+ .demo-param input[type="range"]::-moz-range-track {
839
+ width: 100%;
840
+ height: 1px;
841
+ background: #999;
842
+ border: none;
843
+ border-radius: 0;
844
+ }
845
+
846
+ /* Reusable text toggle style */
847
+ .text-toggle {
848
+ font-size: 1rem;
849
+ cursor: pointer;
850
+ transition: all 0.3s ease;
851
+ text-decoration: none;
852
+ background: none;
853
+ border: none;
854
+ padding: 0;
855
+ font-family: inherit;
856
+ font-weight: 400;
857
+ }
858
+
859
+ .text-toggle:hover {
860
+ opacity: 0.7;
861
+ }
862
+
863
+ .text-toggle.active {
864
+ color: var(--supertone_blue);
865
+ text-decoration: underline;
866
+ text-decoration-style: wavy;
867
+ text-decoration-thickness: 1px;
868
+ text-decoration-color: var(--supertone_blue);
869
+ text-underline-offset: 4px;
870
+ }
871
+
872
+ /* Speaker List Styles */
873
+ .speaker-container {
874
+ display: flex;
875
+ flex-wrap: nowrap;
876
+ align-items: center;
877
+ gap: 0.3rem;
878
+ }
879
+
880
+ .speaker-label {
881
+ font-size: 1rem;
882
+ color: var(--text);
883
+ font-weight: 400;
884
+ white-space: pre;
885
+ flex-shrink: 0;
886
+ }
887
+
888
+ .speaker-list {
889
+ display: flex;
890
+ flex-wrap: nowrap;
891
+ align-items: center;
892
+ overflow-x: auto;
893
+ }
894
+
895
+ .speaker-item {
896
+ font-size: 1rem;
897
+ color: #999;
898
+ cursor: pointer;
899
+ transition: all 0.2s ease;
900
+ white-space: nowrap;
901
+ }
902
+
903
+ .speaker-separator {
904
+ color: #999;
905
+ font-size: 1rem;
906
+ pointer-events: none;
907
+ white-space: pre;
908
+ }
909
+
910
+ .speaker-item:hover {
911
+ color: #ddd;
912
+ }
913
+
914
+ .speaker-item.active {
915
+ color: var(--text);
916
+ opacity: 1;
917
+ text-decoration: underline;
918
+ text-decoration-style: solid;
919
+ text-decoration-thickness: 1px;
920
+ text-underline-offset: 4px;
921
+ }
922
+
923
+ .speaker-item.disabled {
924
+ opacity: 0.4;
925
+ cursor: not-allowed;
926
+ pointer-events: none;
927
+ }
928
+
929
+ .auto-detect-text {
930
+ font-size: 1rem;
931
+ color: #999;
932
+ padding: 0.25rem 0;
933
+ white-space: nowrap;
934
+ text-decoration: underline;
935
+ text-decoration-style: solid;
936
+ text-decoration-thickness: 1px;
937
+ text-underline-offset: 4px;
938
+ }
939
+
940
+ .language-info {
941
+ display: flex;
942
+ flex-wrap: nowrap;
943
+ align-items: center;
944
+ gap: 0.3rem;
945
+ margin-top: 0.25rem;
946
+ }
947
+
948
+ .language-info .speaker-label {
949
+ margin-right: 0;
950
+ }
951
+
952
+ .speaker-item-create {
953
+ color: #ffffff;
954
+ opacity: 1;
955
+ }
956
+
957
+ .speaker-item-create:hover {
958
+ opacity: 0.8;
959
+ text-decoration: underline;
960
+ text-decoration-style: solid;
961
+ text-decoration-thickness: 1px;
962
+ text-underline-offset: 4px;
963
+ }
964
+
965
+ /* Speaker Tooltip */
966
+ .speaker-tooltip {
967
+ position: fixed;
968
+ display: none;
969
+ background: var(--text);
970
+ color: var(--light);
971
+ padding: 0.25rem 0.75rem;
972
+ border-radius: 4px;
973
+ font-size: 0.875rem;
974
+ line-height: 1.4;
975
+ white-space: nowrap;
976
+ z-index: 10000;
977
+ pointer-events: none;
978
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
979
+ }
980
+
981
+ /* Coming Soon Modal */
982
+ .coming-soon-modal {
983
+ display: none;
984
+ position: fixed;
985
+ top: 0;
986
+ left: 0;
987
+ right: 0;
988
+ bottom: 0;
989
+ z-index: 10000;
990
+ align-items: center;
991
+ justify-content: center;
992
+ padding: 1rem;
993
+ }
994
+
995
+ .coming-soon-modal.show {
996
+ display: flex;
997
+ animation: modalFadeIn 0.2s ease-out;
998
+ }
999
+
1000
+ .coming-soon-modal-overlay {
1001
+ position: absolute;
1002
+ top: 0;
1003
+ left: 0;
1004
+ right: 0;
1005
+ bottom: 0;
1006
+ background: rgba(0, 0, 0, 0.5);
1007
+ backdrop-filter: blur(4px);
1008
+ }
1009
+
1010
+ .coming-soon-modal-content {
1011
+ position: relative;
1012
+ background: white;
1013
+ border-radius: 0.75rem;
1014
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
1015
+ max-width: 400px;
1016
+ width: 100%;
1017
+ overflow: hidden;
1018
+ animation: modalSlideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
1019
+ }
1020
+
1021
+ .coming-soon-modal-header {
1022
+ padding: 1.5rem 1.5rem 1rem;
1023
+ text-align: center;
1024
+ border-bottom: 1px solid var(--light-darker);
1025
+ }
1026
+
1027
+ .coming-soon-modal-header h3 {
1028
+ font-family: var(--font-display);
1029
+ font-size: 1.25rem;
1030
+ font-weight: 500;
1031
+ color: var(--text);
1032
+ margin: 0;
1033
+ }
1034
+
1035
+ .coming-soon-modal-body {
1036
+ padding: 1.5rem;
1037
+ text-align: center;
1038
+ }
1039
+
1040
+ .coming-soon-modal-body p {
1041
+ font-family: var(--font-body);
1042
+ font-size: 1rem;
1043
+ color: var(--text-secondary);
1044
+ margin: 0;
1045
+ line-height: 1.6;
1046
+ }
1047
+
1048
+ .coming-soon-modal-footer {
1049
+ padding: 1rem 1.5rem 1.5rem;
1050
+ display: flex;
1051
+ justify-content: center;
1052
+ }
1053
+
1054
+ .coming-soon-modal-btn {
1055
+ padding: 0.75rem 2rem;
1056
+ border-radius: 0.5rem;
1057
+ font-family: var(--font-body);
1058
+ font-size: 1rem;
1059
+ font-weight: 500;
1060
+ cursor: pointer;
1061
+ transition: all 0.2s ease;
1062
+ border: none;
1063
+ outline: none;
1064
+ background: var(--supertone_blue);
1065
+ color: white;
1066
+ }
1067
+
1068
+ .coming-soon-modal-btn:hover {
1069
+ background: var(--primary-dark);
1070
+ transform: translateY(-1px);
1071
+ box-shadow: 0 4px 12px rgba(34, 124, 255, 0.3);
1072
+ }
1073
+
1074
+ .coming-soon-modal-btn:active {
1075
+ transform: translateY(0);
1076
+ }
1077
+
1078
+ .demo-generate-btn {
1079
+ display: inline-flex;
1080
+ align-items: center;
1081
+ justify-content: center;
1082
+ gap: 0.5rem;
1083
+ width: 100%;
1084
+ padding: 0.875rem 1.5rem;
1085
+ border: 1px solid var(--accent-yellow);
1086
+ border-radius: 999px;
1087
+ background: none;
1088
+ font-size: 0.9375rem;
1089
+ font-family: inherit;
1090
+ cursor: pointer;
1091
+ margin-top: 1.5rem;
1092
+ }
1093
+
1094
+ #demoGenerateBtn {
1095
+ color: var(--accent-yellow);
1096
+ font-weight: 400;
1097
+ }
1098
+
1099
+ #demoGenerateBtn img {
1100
+ flex-shrink: 0;
1101
+ transform: scale(1.3);
1102
+ transform-origin: center;
1103
+ filter: brightness(0) invert(90%) sepia(100%) saturate(1000%) hue-rotate(0deg);
1104
+ }
1105
+
1106
+ .demo-generate-btn:disabled {
1107
+ opacity: 0.5;
1108
+ cursor: not-allowed;
1109
+ }
1110
+
1111
+ .demo-results {
1112
+ flex: 1;
1113
+ background: var(--light-lighter);
1114
+ border: 1px solid var(--border);
1115
+ border-radius: 0.5rem;
1116
+ padding: 0;
1117
+ display: flex;
1118
+ flex-direction: column;
1119
+ width: 100%;
1120
+ min-width: 0;
1121
+ overflow-x: hidden;
1122
+ grid-column: 1 / -1;
1123
+ font-family: var(--font-mono);
1124
+ font-weight: 400;
1125
+ }
1126
+
1127
+ #demoResults {
1128
+ display: none;
1129
+ }
1130
+
1131
+ .demo-placeholder {
1132
+ flex: 1;
1133
+ display: flex;
1134
+ flex-direction: column;
1135
+ align-items: center;
1136
+ justify-content: center;
1137
+ text-align: center;
1138
+ color: var(--text-muted);
1139
+ }
1140
+
1141
+ .demo-placeholder-icon {
1142
+ font-size: 2.5rem;
1143
+ margin-bottom: 0.75rem;
1144
+ opacity: 0.5;
1145
+ animation: float 3s ease-in-out infinite;
1146
+ }
1147
+
1148
+ .demo-placeholder.generating .demo-placeholder-icon {
1149
+ animation: spin 2s linear infinite;
1150
+ }
1151
+
1152
+ @keyframes float {
1153
+ 0%, 100% {
1154
+ transform: translateY(0px);
1155
+ }
1156
+ 50% {
1157
+ transform: translateY(-10px);
1158
+ }
1159
+ }
1160
+
1161
+ @keyframes spin {
1162
+ 0% {
1163
+ transform: rotate(0deg);
1164
+ }
1165
+ 100% {
1166
+ transform: rotate(360deg);
1167
+ }
1168
+ }
1169
+
1170
+ .demo-placeholder p {
1171
+ font-size: 1rem;
1172
+ color: var(--text-muted);
1173
+ margin: 0;
1174
+ }
1175
+
1176
+ .demo-result-item {
1177
+ --result-progress: 0%;
1178
+ --result-title-size: 1rem;
1179
+ position: relative;
1180
+ overflow: hidden;
1181
+ z-index: 0;
1182
+ display: grid;
1183
+ grid-template-columns: 12% 40% auto;
1184
+ column-gap: 2rem;
1185
+ row-gap: 1rem;
1186
+ align-items: center;
1187
+ padding: 1rem 1.5rem;
1188
+ background: #000;
1189
+ }
1190
+
1191
+ .demo-result-item.supertonic-result-item {
1192
+ background: #000;
1193
+ }
1194
+
1195
+ body.comparison-mode .demo-result-item {
1196
+ grid-template-columns: 23% 31% auto;
1197
+ }
1198
+
1199
+ #demoResults > .demo-result-item + .demo-result-item {
1200
+ border-top: 1px dashed #aaa;
1201
+ }
1202
+
1203
+ .demo-result-item.supertonic-result-item::before {
1204
+ content: '';
1205
+ position: absolute;
1206
+ top: 0;
1207
+ left: 0;
1208
+ width: var(--result-progress, 0%);
1209
+ height: 100%;
1210
+ background: #1a1a1a;
1211
+ pointer-events: none;
1212
+ z-index: -1;
1213
+ transition: width 0.1s ease;
1214
+ }
1215
+
1216
+ .demo-result-title {
1217
+ display: flex;
1218
+ flex-direction: column;
1219
+ gap: 0.1rem;
1220
+ font-size: var(--result-title-size, 1rem);
1221
+ line-height: 1.2;
1222
+ grid-column: 1;
1223
+ justify-content: center;
1224
+ font-weight: 400;
1225
+ }
1226
+
1227
+ .demo-result-title span {
1228
+ font-weight: 400;
1229
+ }
1230
+
1231
+ .demo-result-title .title-status {
1232
+ font-size: 0.85rem;
1233
+ color: var(--text-secondary);
1234
+ display: none;
1235
+ }
1236
+
1237
+ .demo-result-title .title-status.status-success {
1238
+ color: var(--success);
1239
+ }
1240
+
1241
+ .demo-result-title .title-status.status-error {
1242
+ color: #ef4444;
1243
+ }
1244
+
1245
+ .demo-result-title .title-status.status-running {
1246
+ color: var(--accent);
1247
+ }
1248
+
1249
+ .demo-result-title .title-sub {
1250
+ color: var(--text-secondary);
1251
+ }
1252
+
1253
+ .demo-result-info {
1254
+ display: flex;
1255
+ flex-direction: row;
1256
+ align-items: center;
1257
+ justify-content: space-evenly;
1258
+ align-self: stretch;
1259
+ padding: 0;
1260
+ margin: 0;
1261
+ flex-wrap: wrap;
1262
+ grid-column: 2;
1263
+ }
1264
+
1265
+ .demo-result-info .stat {
1266
+ text-align: center;
1267
+ padding: 0;
1268
+ flex-shrink: 0;
1269
+ position: relative;
1270
+ }
1271
+
1272
+ .demo-result-info .stat-value {
1273
+ font-size: var(--result-title-size, 1rem);
1274
+ color: var(--text);
1275
+ margin-bottom: -0.2rem;
1276
+ line-height: 150%;
1277
+ letter-spacing: -0.04em;
1278
+ font-weight: 400;
1279
+ font-family: var(--font-mono);
1280
+ position: relative;
1281
+ }
1282
+
1283
+ .demo-result-info .stat-label {
1284
+ color: var(--text-secondary);
1285
+ font-size: 0.7rem;
1286
+ text-transform: none;
1287
+ letter-spacing: normal;
1288
+ line-height: 1.3125rem;
1289
+ font-weight: 400;
1290
+ font-family: var(--font-mono);
1291
+ }
1292
+
1293
+ .demo-result-info .stat-value .stat-label.stat-suffix {
1294
+ margin-left: 0.1rem;
1295
+ font-size: 0.7rem;
1296
+ line-height: 1;
1297
+ }
1298
+
1299
+ .demo-result-info .stat-value .stat-value-segment {
1300
+ position: relative;
1301
+ display: inline-block;
1302
+ }
1303
+
1304
+ .demo-result-info .stat-value .stat-value-number {
1305
+ display: inline-block;
1306
+ transition: color 0.3s ease, transform 0.3s ease;
1307
+ }
1308
+
1309
+ #demoResults.quote-mode .stat-value-number {
1310
+ transition-duration: 0.1s;
1311
+ }
1312
+
1313
+ .demo-result-info .stat-value .stat-prefix {
1314
+ position: absolute;
1315
+ top: 0.2rem;
1316
+ left: -2.3rem;
1317
+ transform: scale(0.8);
1318
+ line-height: 1;
1319
+ }
1320
+
1321
+ .demo-result-item audio {
1322
+ width: 100%;
1323
+ height: 48px;
1324
+ border-radius: 8px;
1325
+ margin-top: 0.5rem;
1326
+ }
1327
+
1328
+ .demo-result-actions {
1329
+ display: flex;
1330
+ gap: 0.75rem;
1331
+ align-items: center;
1332
+ margin-left: auto;
1333
+ }
1334
+
1335
+ .demo-download-btn {
1336
+ display: inline-flex;
1337
+ align-items: center;
1338
+ justify-content: center;
1339
+ padding: 0.5rem;
1340
+ background: transparent;
1341
+ color: var(--text);
1342
+ border: none;
1343
+ border-radius: 50%;
1344
+ cursor: pointer;
1345
+ transition: color 0.2s ease, transform 0.2s ease;
1346
+ }
1347
+
1348
+ .demo-download-btn:hover {
1349
+ color: #ffffff;
1350
+ transform: scale(1.05);
1351
+ }
1352
+
1353
+ .demo-download-btn svg {
1354
+ width: 16px;
1355
+ height: 16px;
1356
+ }
1357
+
1358
+ .demo-error {
1359
+ display: none;
1360
+ padding: 0.75rem 1rem;
1361
+ background: rgba(239, 68, 68, 0.1);
1362
+ border: 1px solid rgba(239, 68, 68, 0.3);
1363
+ border-radius: 8px;
1364
+ color: #ef4444;
1365
+ font-size: 1rem;
1366
+ line-height: 1.4;
1367
+ }
1368
+
1369
+ .demo-error.active {
1370
+ display: block;
1371
+ }
1372
+
1373
+ /* ↓ 1440px 이하 */
1374
+ @media (max-width: 1440px) {
1375
+ .container {
1376
+ max-width: 1200px;
1377
+ padding: 0 2rem;
1378
+ }
1379
+ }
1380
+
1381
+ /* ↓ 1280px 이하 */
1382
+ @media (max-width: 1280px) {
1383
+ .container {
1384
+ max-width: 1100px;
1385
+ padding: 0 2rem;
1386
+ }
1387
+ }
1388
+
1389
+ /* ↓ 768px 이하 */
1390
+ @media (max-width: 768px) {
1391
+ .container {
1392
+ padding: 0 1.5rem;
1393
+ }
1394
+
1395
+ .btn-secondary {
1396
+ width: auto;
1397
+ display: inline-block;
1398
+ }
1399
+
1400
+ .btn {
1401
+ justify-content: center;
1402
+ }
1403
+
1404
+ /* Interactive Demo Responsive */
1405
+ .interactive-demo {
1406
+ padding: 3.0rem 0 0.5rem 0 !important;
1407
+ }
1408
+
1409
+ .demo-container {
1410
+ padding: 1rem;
1411
+ }
1412
+
1413
+ .demo-content {
1414
+ grid-template-columns: 1fr;
1415
+ gap: 1rem;
1416
+ }
1417
+
1418
+ .demo-controls {
1419
+ grid-template-columns: 1fr;
1420
+ gap: 0.875rem;
1421
+ }
1422
+
1423
+ .demo-params-row {
1424
+ grid-template-columns: 1fr;
1425
+ gap: 0.875rem;
1426
+ }
1427
+
1428
+ .demo-params-row #demoGenerateBtn {
1429
+ width: 100%;
1430
+ align-self: stretch;
1431
+ }
1432
+
1433
+ .demo-param-header {
1434
+ flex-direction: row;
1435
+ align-items: center;
1436
+ justify-content: space-between;
1437
+ gap: 0.5rem;
1438
+ flex-wrap: nowrap;
1439
+ }
1440
+
1441
+ .demo-status-box {
1442
+ flex-direction: column;
1443
+ align-items: flex-start;
1444
+ padding: 0.625rem 0.875rem;
1445
+ }
1446
+
1447
+ .demo-status-content {
1448
+ width: 100%;
1449
+ }
1450
+
1451
+ .demo-results {
1452
+ min-height: 200px;
1453
+ padding: 0;
1454
+ overflow-x: hidden;
1455
+ }
1456
+
1457
+ .demo-output-section {
1458
+ width: 100%;
1459
+ min-width: 0;
1460
+ overflow: hidden;
1461
+ }
1462
+
1463
+ .demo-result-title {
1464
+ flex-direction: row;
1465
+ flex-wrap: nowrap;
1466
+ align-items: center;
1467
+ gap: 0.5rem;
1468
+ }
1469
+
1470
+ .demo-result-info {
1471
+ gap: 0.75rem;
1472
+ flex-wrap: wrap;
1473
+ justify-content: flex-start;
1474
+ }
1475
+
1476
+ .demo-result-info .stat {
1477
+ padding: 0;
1478
+ flex: 1 1 calc(50% - 0.4rem);
1479
+ min-width: 0;
1480
+ }
1481
+
1482
+ .demo-result-info .stat:first-child {
1483
+ flex-basis: 100%;
1484
+ }
1485
+
1486
+ .demo-result-info .stat-value {
1487
+ font-size: 1.5rem;
1488
+ }
1489
+
1490
+ .demo-result-info .stat-label {
1491
+ font-size: 0.7rem;
1492
+ }
1493
+
1494
+ .demo-char-counter {
1495
+ justify-content: flex-end;
1496
+ text-align: right;
1497
+ width: 100%;
1498
+ }
1499
+
1500
+ .stat-value {
1501
+ font-size: 5rem;
1502
+ }
1503
+ }
1504
+
1505
+ /* Selection */
1506
+ ::selection {
1507
+ background: var(--primary);
1508
+ color: white;
1509
+ }
1510
+
1511
+
1512
+ /* Custom Audio Player Styles */
1513
+ .custom-audio-player {
1514
+ display: flex;
1515
+ align-items: center;
1516
+ gap: 1rem;
1517
+ padding: 0;
1518
+ background: none;
1519
+ border-radius: 0;
1520
+ margin-top: 0;
1521
+ border: none;
1522
+ font-weight: 400;
1523
+ grid-column: 3;
1524
+ width: 100%;
1525
+ flex-wrap: wrap;
1526
+ }
1527
+
1528
+ .player-btn {
1529
+ width: 40px;
1530
+ height: 40px;
1531
+ border-radius: 50%;
1532
+ border: none;
1533
+ background: #ddd;
1534
+ color: var(--bg-dark);
1535
+ font-size: 20px;
1536
+ cursor: pointer;
1537
+ display: flex;
1538
+ align-items: center;
1539
+ justify-content: center;
1540
+ transition: all 0.3s ease;
1541
+ flex-shrink: 0;
1542
+ }
1543
+
1544
+ .player-btn svg {
1545
+ width: 24px;
1546
+ height: 24px;
1547
+ display: block;
1548
+ pointer-events: none;
1549
+ color: #000;
1550
+ }
1551
+
1552
+ .player-btn:hover {
1553
+ background: #ffffff;
1554
+ transform: scale(1.05);
1555
+ }
1556
+
1557
+ .player-btn:active {
1558
+ transform: scale(0.95);
1559
+ }
1560
+
1561
+ .demo-result-item.supertonic-result-item .player-btn:hover,
1562
+ .demo-result-item.supertonic-result-item .player-btn:focus-visible {
1563
+ background: #ffffff;
1564
+ color: #000;
1565
+ }
1566
+
1567
+ .custom-audio-player .time-display {
1568
+ font-size: 1rem;
1569
+ color: var(--text-secondary);
1570
+ font-weight: 400;
1571
+ min-width: 42px;
1572
+ text-align: center;
1573
+ flex-shrink: 0;
1574
+ }
1575
+
1576
+ .progress-container {
1577
+ flex: 1;
1578
+ cursor: pointer;
1579
+ padding: 0.5rem 0;
1580
+ }
1581
+
1582
+ .progress-bar {
1583
+ width: 100%;
1584
+ height: 6px;
1585
+ background: #999;
1586
+ border-radius: 3px;
1587
+ overflow: hidden;
1588
+ position: relative;
1589
+ }
1590
+
1591
+ .progress-bar:hover {
1592
+ height: 8px;
1593
+ transition: height 0.2s ease;
1594
+ }
1595
+
1596
+ .progress-fill {
1597
+ width: 0%;
1598
+ height: 100%;
1599
+ background: #ffffff;
1600
+ border-radius: 3px;
1601
+ transition: width 0.1s linear;
1602
+ position: relative;
1603
+ }
1604
+
1605
+ .progress-fill::after {
1606
+ content: '';
1607
+ position: absolute;
1608
+ right: 0;
1609
+ top: 50%;
1610
+ transform: translateY(-50%);
1611
+ width: 12px;
1612
+ height: 12px;
1613
+ background: #ffffff;
1614
+ border-radius: 50%;
1615
+ box-shadow: 0 0 8px rgba(255, 255, 255, 0.6);
1616
+ opacity: 0;
1617
+ transition: opacity 0.2s ease;
1618
+ }
1619
+
1620
+ .progress-container:hover .progress-fill::after {
1621
+ opacity: 1;
1622
+ }
1623
+
1624
+ .supertonic-result-item {
1625
+ --provider-color: #ffffff;
1626
+ }
1627
+
1628
+ #presetControlsRow {
1629
+ display: flex;
1630
+ gap: 0.4rem;
1631
+ margin-top: 0.75rem;
1632
+ flex-wrap: wrap;
1633
+ align-items: center;
1634
+ justify-content: space-between;
1635
+ color: #000;
1636
+ }
1637
+
1638
+ #presetButtonGroup {
1639
+ display: flex;
1640
+ gap: 0.7rem;
1641
+ flex-wrap: wrap;
1642
+ }
1643
+
1644
+ @media (max-width: 768px) {
1645
+ .demo-result-item {
1646
+ grid-template-columns: 1fr;
1647
+ padding: 1rem 0;
1648
+ }
1649
+
1650
+ .demo-result-title,
1651
+ .demo-result-info,
1652
+ .custom-audio-player {
1653
+ grid-column: 1;
1654
+ }
1655
+
1656
+ .custom-audio-player {
1657
+ width: 100%;
1658
+ padding: 0 1rem;
1659
+ }
1660
+
1661
+ #demoTextInput {
1662
+ height: 264.6px;
1663
+ min-height: 90px;
1664
+ }
1665
+ }
1666
+
1667
+ /* Modal Animations */
1668
+ @keyframes modalFadeIn {
1669
+ from {
1670
+ opacity: 0;
1671
+ }
1672
+ to {
1673
+ opacity: 1;
1674
+ }
1675
+ }
1676
+
1677
+ @keyframes modalSlideUp {
1678
+ from {
1679
+ opacity: 0;
1680
+ transform: translateY(30px) scale(0.95);
1681
+ }
1682
+ to {
1683
+ opacity: 1;
1684
+ transform: translateY(0) scale(1);
1685
+ }
1686
+ }
1687
+
1688
+ /* Language Auto-Detection Toast */
1689
+ .language-toast {
1690
+ position: fixed;
1691
+ bottom: 2rem;
1692
+ left: 50%;
1693
+ transform: translateX(-50%) translateY(100px);
1694
+ background: linear-gradient(135deg, rgba(30, 30, 30, 0.95), rgba(20, 20, 20, 0.98));
1695
+ color: #fff;
1696
+ padding: 0.875rem 1.5rem;
1697
+ border-radius: 12px;
1698
+ font-family: var(--font-body);
1699
+ font-size: 0.9375rem;
1700
+ font-weight: 500;
1701
+ display: flex;
1702
+ align-items: center;
1703
+ gap: 0.625rem;
1704
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.1);
1705
+ z-index: 10000;
1706
+ opacity: 0;
1707
+ visibility: hidden;
1708
+ transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1),
1709
+ opacity 0.3s ease,
1710
+ visibility 0.3s ease;
1711
+ backdrop-filter: blur(10px);
1712
+ -webkit-backdrop-filter: blur(10px);
1713
+ }
1714
+
1715
+ .language-toast.show {
1716
+ opacity: 1;
1717
+ visibility: visible;
1718
+ transform: translateX(-50%) translateY(0);
1719
+ }
1720
+
1721
+ .language-toast-icon {
1722
+ font-size: 1.125rem;
1723
+ filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.3));
1724
+ }
1725
+
1726
+ .language-toast-message {
1727
+ letter-spacing: -0.01em;
1728
+ }
1729
+
1730
+ .language-toast-message strong {
1731
+ font-weight: 600;
1732
+ color: var(--accent-yellow);
1733
+ }
1734
+
1735
+ @media (max-width: 572px) {
1736
+ /* interactive-demo padding 상단 3rem -> 1rem */
1737
+ .interactive-demo {
1738
+ padding: 1rem 0 0.5rem 0 !important;
1739
+ }
1740
+
1741
+ /* 1. demo-header: Supertonic 2 이후 문장 줄바꿈, line-height 1.6 -> 1.2 */
1742
+ .demo-header {
1743
+ line-height: 1.2;
1744
+ flex-direction: column;
1745
+ align-items: flex-start;
1746
+ gap: 0.5rem;
1747
+ }
1748
+
1749
+ .demo-header .demo-header-bold {
1750
+ display: block;
1751
+ margin-bottom: 0.25rem;
1752
+ }
1753
+
1754
+ .demo-header .demo-header-bold::after {
1755
+ content: '';
1756
+ }
1757
+
1758
+ .demo-header-links {
1759
+ align-self: flex-start;
1760
+ }
1761
+
1762
+ /* 번개 아이콘과 H2 상하정렬: 중앙 -> 상단 */
1763
+ .demo-header-icon {
1764
+ top: 0;
1765
+ transform: translateY(0) scale(1.3);
1766
+ }
1767
+
1768
+ /* speaker-container, language-info의 레이블과 선택항목간 상하정렬: 중앙 -> 상단 */
1769
+ .speaker-container {
1770
+ align-items: flex-start;
1771
+ }
1772
+
1773
+ .language-info {
1774
+ align-items: flex-start;
1775
+ flex-wrap: nowrap; /* 레이블과 리스트는 같은 줄 유지 */
1776
+ }
1777
+
1778
+ /* 2. speaker-list, languageList 줄바꿈 - 한 항목씩 줄바꿈 */
1779
+ .speaker-list {
1780
+ flex-wrap: wrap;
1781
+ }
1782
+
1783
+ /* language-info 내부의 speaker-list도 동일하게 처리 */
1784
+ .language-info .speaker-list {
1785
+ flex-wrap: wrap;
1786
+ }
1787
+
1788
+ /* 3. demo-input-section 폭 대응, padding 제거 */
1789
+ .demo-input-section {
1790
+ width: 100%;
1791
+ max-width: 100%;
1792
+ }
1793
+
1794
+ /* demo-input-section::after left -27px -> -17px */
1795
+ .demo-input-section::after {
1796
+ left: -17px;
1797
+ }
1798
+
1799
+
1800
+ /* 4. demo-params-row: param 1,2는 1열, Generate 버튼은 2열 */
1801
+ .demo-params-row {
1802
+ grid-template-columns: 1fr 1fr;
1803
+ gap: 0.875rem;
1804
+ }
1805
+
1806
+ .demo-params-row .demo-param:nth-child(1),
1807
+ .demo-params-row .demo-param:nth-child(2) {
1808
+ grid-column: span 1;
1809
+ }
1810
+
1811
+ .demo-params-row #demoGenerateBtn {
1812
+ grid-column: 1 / -1;
1813
+ width: 100%;
1814
+ }
1815
+
1816
+ /* 5. demoResults 박스 폭 대응 */
1817
+ .demo-results {
1818
+ width: 100%;
1819
+ max-width: 100%;
1820
+ }
1821
+
1822
+ #demoResults {
1823
+ width: 100%;
1824
+ max-width: 100%;
1825
+ }
1826
+ }
1827
+
1828
+ @media (max-width: 768px) {
1829
+ .demo-char-counter.valid {
1830
+ justify-content: flex-start;
1831
+ text-align: left;
1832
+ }
1833
+
1834
+ .language-toast {
1835
+ bottom: 1.5rem;
1836
+ padding: 0.75rem 1.25rem;
1837
+ font-size: 0.875rem;
1838
+ max-width: calc(100vw - 2rem);
1839
+ }
1840
+ }