newportsite 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/newportsite-1.1.3.tgz +0 -0
  2. package/ng-package.json +7 -0
  3. package/obfuscate.js +70 -0
  4. package/package.json +15 -0
  5. package/src/lib/app.component.ts +47 -0
  6. package/src/lib/app.routing.ts +38 -0
  7. package/src/lib/auth/alert.component.html +5 -0
  8. package/src/lib/auth/alert.component.ts +24 -0
  9. package/src/lib/auth/auth.component.html +1 -0
  10. package/src/lib/auth/auth.component.ts +10 -0
  11. package/src/lib/auth/auth.routes.ts +16 -0
  12. package/src/lib/auth/index.ts +4 -0
  13. package/src/lib/auth/login.component.html +87 -0
  14. package/src/lib/auth/login.component.ts +158 -0
  15. package/src/lib/auth/models/index.ts +1 -0
  16. package/src/lib/auth/models/user.ts +25 -0
  17. package/src/lib/auth/register.component.html +157 -0
  18. package/src/lib/auth/register.component.ts +219 -0
  19. package/src/lib/auth/services/alert.service.ts +47 -0
  20. package/src/lib/auth/services/auth.service.ts +28 -0
  21. package/src/lib/auth/services/index.ts +3 -0
  22. package/src/lib/auth/services/user.service.spec.ts +112 -0
  23. package/src/lib/auth/services/user.service.ts +47 -0
  24. package/src/lib/common/card.component.html +72 -0
  25. package/src/lib/common/card.component.ts +102 -0
  26. package/src/lib/common/commands.component.html +8 -0
  27. package/src/lib/common/commands.component.ts +42 -0
  28. package/src/lib/common/context.component.html +9 -0
  29. package/src/lib/common/context.component.ts +38 -0
  30. package/src/lib/common/grid.component.html +20 -0
  31. package/src/lib/common/grid.component.ts +747 -0
  32. package/src/lib/common/index.ts +9 -0
  33. package/src/lib/common/loader.component.html +5 -0
  34. package/src/lib/common/loader.component.ts +27 -0
  35. package/src/lib/common/lookup.component.html +29 -0
  36. package/src/lib/common/lookup.component.ts +115 -0
  37. package/src/lib/common/messagebox.component.html +39 -0
  38. package/src/lib/common/messagebox.component.ts +74 -0
  39. package/src/lib/common/theme-toggle.component.ts +139 -0
  40. package/src/lib/config.ts +62 -0
  41. package/src/lib/containers/default-layout/default-layout.component.html +191 -0
  42. package/src/lib/containers/default-layout/default-layout.component.ts +158 -0
  43. package/src/lib/containers/default-layout/index.ts +1 -0
  44. package/src/lib/containers/index.ts +1 -0
  45. package/src/lib/directives/component.draggable.ts +80 -0
  46. package/src/lib/directives/index.ts +2 -0
  47. package/src/lib/directives/input.directive.spec.ts +158 -0
  48. package/src/lib/directives/input.directive.ts +210 -0
  49. package/src/lib/home/dashboard/dashboard.component.html +38 -0
  50. package/src/lib/home/dashboard/dashboard.component.ts +50 -0
  51. package/src/lib/home/dashboard/index.ts +1 -0
  52. package/src/lib/home/index.component.html +1 -0
  53. package/src/lib/home/index.component.ts +10 -0
  54. package/src/lib/home/index.routes.ts +29 -0
  55. package/src/lib/home/index.ts +1 -0
  56. package/src/lib/home/info/index.ts +1 -0
  57. package/src/lib/home/info/info.component.css +476 -0
  58. package/src/lib/home/info/info.component.html +174 -0
  59. package/src/lib/home/info/info.component.ts +287 -0
  60. package/src/lib/home/model/article.component.html +10 -0
  61. package/src/lib/home/model/article.component.ts +50 -0
  62. package/src/lib/home/model/barchart.component.html +8 -0
  63. package/src/lib/home/model/barchart.component.ts +59 -0
  64. package/src/lib/home/model/index.ts +7 -0
  65. package/src/lib/home/model/itemdetail.component.html +25 -0
  66. package/src/lib/home/model/itemdetail.component.ts +93 -0
  67. package/src/lib/home/model/itemtab.component.html +25 -0
  68. package/src/lib/home/model/itemtab.component.ts +105 -0
  69. package/src/lib/home/model/model.component.html +121 -0
  70. package/src/lib/home/model/model.component.ts +510 -0
  71. package/src/lib/home/model/modeltoolbar.component.html +111 -0
  72. package/src/lib/home/model/modeltoolbar.component.ts +157 -0
  73. package/src/lib/home/model/navigation.component.html +86 -0
  74. package/src/lib/home/model/navigation.component.ts +247 -0
  75. package/src/lib/home/model/services/index.ts +1 -0
  76. package/src/lib/home/model/services/model.service.spec.ts +423 -0
  77. package/src/lib/home/model/services/model.service.ts +319 -0
  78. package/src/lib/home/modelsearch/index.ts +1 -0
  79. package/src/lib/home/modelsearch/modelsearch.component.html +124 -0
  80. package/src/lib/home/modelsearch/modelsearch.component.ts +453 -0
  81. package/src/lib/interfaces/data.interface.ts +131 -0
  82. package/src/lib/interfaces/index.ts +2 -0
  83. package/src/lib/interfaces/item.interface.ts +438 -0
  84. package/src/lib/players/lookup/lookup.directive.ts +6 -0
  85. package/src/lib/players/lookup/lookup.item.component.ts +37 -0
  86. package/src/lib/players/lookup/lookup.item.ts +9 -0
  87. package/src/lib/players/lookup/lookup.player.component.ts +59 -0
  88. package/src/lib/players/lookup/lookup.selector.component.ts +41 -0
  89. package/src/lib/players/model/model.directive.ts +6 -0
  90. package/src/lib/players/model/model.item.component.spec.ts +311 -0
  91. package/src/lib/players/model/model.item.component.ts +3457 -0
  92. package/src/lib/players/model/model.item.ts +9 -0
  93. package/src/lib/players/model/model.player.component.ts +109 -0
  94. package/src/lib/players/model/model.selector.component.ts +59 -0
  95. package/src/lib/scheduler/scheduler.component.html +13 -0
  96. package/src/lib/scheduler/scheduler.component.scss +6 -0
  97. package/src/lib/scheduler/scheduler.component.ts +296 -0
  98. package/src/lib/scheduler/scheduler.routes.ts +15 -0
  99. package/src/lib/scheduler/schedulerdialog.component.html +72 -0
  100. package/src/lib/scheduler/schedulerdialog.component.ts +208 -0
  101. package/src/lib/scheduler/services/scheduler.service.ts +133 -0
  102. package/src/lib/services/auth-state.service.ts +129 -0
  103. package/src/lib/services/auth.interceptor.spec.ts +144 -0
  104. package/src/lib/services/auth.interceptor.ts +44 -0
  105. package/src/lib/services/cache.service.spec.ts +143 -0
  106. package/src/lib/services/cache.service.ts +71 -0
  107. package/src/lib/services/global-error-handler.spec.ts +39 -0
  108. package/src/lib/services/global-error-handler.ts +28 -0
  109. package/src/lib/services/global.service.spec.ts +801 -0
  110. package/src/lib/services/global.service.ts +724 -0
  111. package/src/lib/services/message.service.ts +556 -0
  112. package/src/lib/services/theme.service.ts +96 -0
  113. package/src/lib/template/authtemplate.component.html +6 -0
  114. package/src/lib/template/authtemplate.component.ts +13 -0
  115. package/src/lib/template/basetemplate.component.html +7 -0
  116. package/src/lib/template/basetemplate.component.ts +13 -0
  117. package/src/lib/template/index.ts +3 -0
  118. package/src/lib/template/modeltemplate.component.html +7 -0
  119. package/src/lib/template/modeltemplate.component.ts +21 -0
  120. package/src/lib/utils/piva.spec.ts +56 -0
  121. package/src/lib/utils/piva.ts +29 -0
  122. package/src/lib/validators/email.validator.spec.ts +57 -0
  123. package/src/lib/validators/email.validator.ts +17 -0
  124. package/src/lib/validators/equalPasswords.validator.spec.ts +54 -0
  125. package/src/lib/validators/equalPasswords.validator.ts +17 -0
  126. package/src/lib/validators/index.ts +2 -0
  127. package/src/lib/version.ts +1 -0
  128. package/src/public-api.ts +64 -0
  129. package/src/typings.d.ts +2 -0
  130. package/tsconfig.lib.json +18 -0
  131. package/tsconfig.lib.prod.json +9 -0
@@ -0,0 +1,476 @@
1
+ /* ============================================================
2
+ Newport Project – Info Component
3
+ Fully theme-aware: light (default) + dark via .theme-dark
4
+ ============================================================ */
5
+
6
+ /* ===== Animations ===== */
7
+ @keyframes fadeUp {
8
+ from { opacity: 0; transform: translateY(24px); }
9
+ to { opacity: 1; transform: translateY(0); }
10
+ }
11
+ @keyframes fadeIn {
12
+ from { opacity: 0; }
13
+ to { opacity: 1; }
14
+ }
15
+
16
+ /* ===== Theme tokens ===== */
17
+ :host {
18
+ /* Light defaults – aligned with global --app-accent (#007bff / #00a8ff) */
19
+ --i-accent: var(--app-accent);
20
+ --i-accent-hover: var(--app-accent-hover);
21
+ --i-accent-text: #ffffff;
22
+ --i-accent-muted: var(--app-accent-bg);
23
+ --i-hero-bg: var(--app-surface);
24
+ --i-hero-text: var(--app-text);
25
+ --i-hero-sub: var(--app-text-secondary);
26
+ --i-stats-bg: var(--app-background);
27
+ --i-stats-border: var(--app-border);
28
+ --i-stats-text: var(--app-text);
29
+ --i-stats-label: var(--app-text-secondary);
30
+ --i-cta-bg-a: #0a2540;
31
+ --i-cta-bg-b: #1a4080;
32
+ --i-cta-tag-bg: rgba(255,255,255,0.15);
33
+ --i-outline-border: var(--app-accent);
34
+ --i-outline-text: var(--app-accent);
35
+ }
36
+
37
+ :host-context(.theme-dark) {
38
+ --i-cta-bg-a: #0f172a;
39
+ --i-cta-bg-b: #1e3a5f;
40
+ --i-cta-tag-bg: rgba(0, 168, 255, 0.2);
41
+ }
42
+
43
+ /* ===== Page wrapper ===== */
44
+ .info-page {
45
+ overflow-y: auto;
46
+ overflow-x: hidden;
47
+ height: 100%;
48
+ background-color: var(--app-background);
49
+ color: var(--app-text);
50
+ }
51
+
52
+ /* ===== Hero ===== */
53
+ .hero {
54
+ position: relative;
55
+ background-color: var(--i-hero-bg);
56
+ padding: 7rem 2rem 5rem;
57
+ text-align: center;
58
+ overflow: hidden;
59
+ }
60
+
61
+ .hero-content {
62
+ position: relative;
63
+ z-index: 2;
64
+ max-width: 760px;
65
+ margin: 0 auto;
66
+ animation: fadeUp 0.8s ease-out both;
67
+ }
68
+
69
+ .hero-badge {
70
+ display: inline-block;
71
+ background: var(--i-accent-muted);
72
+ color: var(--i-accent);
73
+ border: 1px solid var(--i-accent);
74
+ border-radius: 999px;
75
+ padding: 0.3rem 1rem;
76
+ font-size: 0.78rem;
77
+ font-weight: 600;
78
+ letter-spacing: 0.08em;
79
+ text-transform: uppercase;
80
+ margin-bottom: 1.5rem;
81
+ }
82
+
83
+ .hero-title {
84
+ font-size: clamp(2.5rem, 6vw, 4.2rem);
85
+ font-weight: 800;
86
+ line-height: 1.1;
87
+ color: var(--i-hero-text);
88
+ background-color: transparent;
89
+ margin: 0 0 0.75rem;
90
+ letter-spacing: -0.02em;
91
+ }
92
+
93
+ .accent {
94
+ color: var(--i-accent);
95
+ }
96
+
97
+ .hero-version {
98
+ font-size: 0.9rem;
99
+ color: var(--i-stats-label);
100
+ margin-bottom: 1.5rem;
101
+ letter-spacing: 0.05em;
102
+ }
103
+
104
+ .hero-desc {
105
+ font-size: 1.15rem;
106
+ color: var(--i-hero-sub);
107
+ line-height: 1.7;
108
+ max-width: 600px;
109
+ margin: 0 auto 2.5rem;
110
+ animation: fadeUp 0.8s ease-out 0.15s both;
111
+ }
112
+
113
+ .hero-actions {
114
+ display: flex;
115
+ gap: 1rem;
116
+ justify-content: center;
117
+ flex-wrap: wrap;
118
+ animation: fadeUp 0.8s ease-out 0.3s both;
119
+ }
120
+
121
+ /* Wave separator */
122
+ .hero-wave {
123
+ position: absolute;
124
+ bottom: -1px;
125
+ left: 0;
126
+ right: 0;
127
+ line-height: 0;
128
+ z-index: 1;
129
+ }
130
+
131
+ .hero-wave svg {
132
+ width: 100%;
133
+ height: 60px;
134
+ display: block;
135
+ }
136
+
137
+ .wave-path {
138
+ fill: var(--app-background);
139
+ }
140
+
141
+ /* ===== Buttons ===== */
142
+ .btn-primary {
143
+ display: inline-block;
144
+ padding: 0.75rem 1.75rem;
145
+ background: var(--i-accent);
146
+ color: var(--i-accent-text);
147
+ border-radius: 8px;
148
+ font-weight: 600;
149
+ font-size: 0.95rem;
150
+ text-decoration: none;
151
+ transition: background 0.2s, transform 0.2s, box-shadow 0.2s;
152
+ letter-spacing: 0.02em;
153
+ }
154
+
155
+ .btn-primary:hover {
156
+ background: var(--i-accent-hover);
157
+ transform: translateY(-2px);
158
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
159
+ color: var(--i-accent-text);
160
+ text-decoration: none;
161
+ }
162
+
163
+ .btn-primary.large {
164
+ padding: 0.9rem 2.2rem;
165
+ font-size: 1.05rem;
166
+ margin-top: 2rem;
167
+ }
168
+
169
+ .btn-outline {
170
+ display: inline-block;
171
+ padding: 0.75rem 1.75rem;
172
+ background: transparent;
173
+ color: var(--i-outline-text);
174
+ border: 2px solid var(--i-outline-border);
175
+ border-radius: 8px;
176
+ font-weight: 600;
177
+ font-size: 0.95rem;
178
+ text-decoration: none;
179
+ transition: background 0.2s, transform 0.2s, color 0.2s;
180
+ letter-spacing: 0.02em;
181
+ }
182
+
183
+ .btn-outline:hover {
184
+ background: var(--i-accent-muted);
185
+ transform: translateY(-2px);
186
+ color: var(--i-accent);
187
+ text-decoration: none;
188
+ }
189
+
190
+ /* ===== Stats bar ===== */
191
+ .stats {
192
+ background: var(--i-stats-bg);
193
+ border-top: 1px solid var(--i-stats-border);
194
+ border-bottom: 1px solid var(--i-stats-border);
195
+ padding: 2rem 2rem;
196
+ }
197
+
198
+ .stats-grid {
199
+ display: flex;
200
+ align-items: center;
201
+ justify-content: center;
202
+ gap: 0;
203
+ flex-wrap: wrap;
204
+ max-width: 900px;
205
+ margin: 0 auto;
206
+ }
207
+
208
+ .stat-item {
209
+ display: flex;
210
+ flex-direction: column;
211
+ align-items: center;
212
+ padding: 0.5rem 3rem;
213
+ animation: fadeIn 0.8s ease-out both;
214
+ }
215
+
216
+ .stat-number {
217
+ font-size: 2.2rem;
218
+ font-weight: 800;
219
+ color: var(--i-accent);
220
+ line-height: 1;
221
+ margin-bottom: 0.3rem;
222
+ }
223
+
224
+ .stat-label {
225
+ font-size: 0.82rem;
226
+ color: var(--i-stats-label);
227
+ text-transform: uppercase;
228
+ letter-spacing: 0.06em;
229
+ font-weight: 500;
230
+ }
231
+
232
+ .stat-divider {
233
+ width: 1px;
234
+ height: 48px;
235
+ background: var(--i-stats-border);
236
+ flex-shrink: 0;
237
+ }
238
+
239
+ /* ===== Tech Stack ===== */
240
+ .tech-stack {
241
+ padding: 5rem 2rem;
242
+ max-width: 1200px;
243
+ margin: 0 auto;
244
+ }
245
+
246
+ .tech-grid {
247
+ display: grid;
248
+ grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
249
+ gap: 1.5rem;
250
+ }
251
+
252
+ .tech-card {
253
+ text-align: center;
254
+ padding: 2rem 1.5rem;
255
+ border-radius: 12px;
256
+ background: var(--app-surface);
257
+ border: 1px solid var(--app-border);
258
+ transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
259
+ }
260
+
261
+ .tech-card:hover {
262
+ transform: translateY(-4px);
263
+ border-color: var(--i-accent);
264
+ box-shadow: 0 8px 28px var(--app-shadow);
265
+ }
266
+
267
+ .tech-icon {
268
+ font-size: 2rem;
269
+ margin-bottom: 0.75rem;
270
+ line-height: 1;
271
+ }
272
+
273
+ .tech-card h3 {
274
+ font-size: 1rem;
275
+ font-weight: 700;
276
+ color: var(--i-accent);
277
+ margin: 0 0 0.5rem;
278
+ text-transform: uppercase;
279
+ letter-spacing: 0.06em;
280
+ }
281
+
282
+ .tech-card p {
283
+ font-size: 0.88rem;
284
+ color: var(--app-text-secondary);
285
+ line-height: 1.6;
286
+ margin: 0;
287
+ }
288
+
289
+ /* ===== Architecture ===== */
290
+ .architecture {
291
+ padding: 5rem 2rem;
292
+ max-width: 900px;
293
+ margin: 0 auto;
294
+ }
295
+
296
+ .arch-list {
297
+ display: flex;
298
+ flex-direction: column;
299
+ gap: 1.25rem;
300
+ }
301
+
302
+ .arch-item {
303
+ display: flex;
304
+ gap: 1.25rem;
305
+ align-items: flex-start;
306
+ padding: 1.25rem 1.5rem;
307
+ border-radius: 10px;
308
+ background: var(--app-surface);
309
+ border: 1px solid var(--app-border);
310
+ transition: border-color 0.2s;
311
+ }
312
+
313
+ .arch-item:hover {
314
+ border-color: var(--i-accent);
315
+ }
316
+
317
+ .arch-dot {
318
+ flex-shrink: 0;
319
+ width: 10px;
320
+ height: 10px;
321
+ margin-top: 6px;
322
+ border-radius: 50%;
323
+ background: var(--i-accent);
324
+ }
325
+
326
+ .arch-body h4 {
327
+ font-size: 1rem;
328
+ font-weight: 700;
329
+ color: var(--app-text);
330
+ margin: 0 0 0.3rem;
331
+ }
332
+
333
+ .arch-body p {
334
+ font-size: 0.9rem;
335
+ color: var(--app-text-secondary);
336
+ line-height: 1.6;
337
+ margin: 0;
338
+ }
339
+
340
+ /* ===== Features ===== */
341
+ .features {
342
+ padding: 6rem 2rem;
343
+ max-width: 1200px;
344
+ margin: 0 auto;
345
+ }
346
+
347
+ .section-header {
348
+ text-align: center;
349
+ margin-bottom: 3.5rem;
350
+ }
351
+
352
+ .section-tag {
353
+ display: inline-block;
354
+ background: var(--i-accent-muted);
355
+ color: var(--i-accent);
356
+ border-radius: 999px;
357
+ padding: 0.25rem 0.85rem;
358
+ font-size: 0.75rem;
359
+ font-weight: 700;
360
+ letter-spacing: 0.1em;
361
+ text-transform: uppercase;
362
+ margin-bottom: 1rem;
363
+ }
364
+
365
+ .section-tag.light {
366
+ background: rgba(255, 255, 255, 0.18);
367
+ color: #ffffff;
368
+ }
369
+
370
+ .section-header h2 {
371
+ font-size: clamp(1.8rem, 4vw, 2.6rem);
372
+ font-weight: 700;
373
+ color: var(--app-text);
374
+ margin: 0.5rem 0 1rem;
375
+ letter-spacing: -0.01em;
376
+ }
377
+
378
+ .section-header p {
379
+ font-size: 1.05rem;
380
+ color: var(--app-text-secondary);
381
+ max-width: 540px;
382
+ margin: 0 auto;
383
+ line-height: 1.65;
384
+ }
385
+
386
+ .feature-grid {
387
+ display: grid;
388
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
389
+ gap: 1.5rem;
390
+ }
391
+
392
+ .feature-card {
393
+ padding: 2rem 1.75rem;
394
+ border-radius: 12px;
395
+ background: var(--app-surface);
396
+ border: 1px solid var(--app-border);
397
+ transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
398
+ color: var(--app-text);
399
+ }
400
+
401
+ .feature-card:hover {
402
+ transform: translateY(-4px);
403
+ border-color: var(--i-accent);
404
+ box-shadow: 0 8px 28px var(--app-shadow);
405
+ }
406
+
407
+ .feature-icon {
408
+ font-size: 2rem;
409
+ margin-bottom: 1rem;
410
+ line-height: 1;
411
+ }
412
+
413
+ .feature-card h3 {
414
+ font-size: 1.15rem;
415
+ font-weight: 700;
416
+ color: var(--app-text);
417
+ margin: 0 0 0.6rem;
418
+ }
419
+
420
+ .feature-card p {
421
+ font-size: 0.93rem;
422
+ color: var(--app-text-secondary);
423
+ line-height: 1.65;
424
+ margin: 0;
425
+ }
426
+
427
+ /* ===== CTA ===== */
428
+ .cta {
429
+ background: linear-gradient(135deg, var(--i-cta-bg-a) 0%, var(--i-cta-bg-b) 100%);
430
+ padding: 6rem 2rem;
431
+ text-align: center;
432
+ color: #ffffff;
433
+ }
434
+
435
+ .cta-content {
436
+ max-width: 640px;
437
+ margin: 0 auto;
438
+ }
439
+
440
+ .cta h2 {
441
+ font-size: clamp(1.8rem, 4vw, 2.4rem);
442
+ font-weight: 700;
443
+ color: #ffffff;
444
+ margin: 0.75rem 0 1rem;
445
+ letter-spacing: -0.01em;
446
+ }
447
+
448
+ .cta p {
449
+ font-size: 1.05rem;
450
+ color: rgba(255, 255, 255, 0.82);
451
+ line-height: 1.65;
452
+ margin: 0;
453
+ }
454
+
455
+ /* ===== Footer ===== */
456
+ .info-footer {
457
+ text-align: center;
458
+ padding: 1.5rem 2rem;
459
+ font-size: 0.82rem;
460
+ color: var(--app-text-secondary);
461
+ border-top: 1px solid var(--app-border);
462
+ background: var(--app-surface);
463
+ }
464
+
465
+ /* ===== Responsive ===== */
466
+ @media (max-width: 768px) {
467
+ .hero { padding: 5rem 1.5rem 4rem; }
468
+ .hero-actions { flex-direction: column; align-items: center; }
469
+ .stat-item { padding: 0.5rem 1.5rem; }
470
+ .stat-divider { display: none; }
471
+ .stats-grid { gap: 1rem; }
472
+ .tech-stack { padding: 3rem 1.5rem; }
473
+ .architecture { padding: 3rem 1.5rem; }
474
+ .features { padding: 4rem 1.5rem; }
475
+ .cta { padding: 4rem 1.5rem; }
476
+ }
@@ -0,0 +1,174 @@
1
+ <!-- info.component -->
2
+ <div class="info-page">
3
+ <!-- ===== Hero ===== -->
4
+ <section class="hero">
5
+ <div class="hero-content">
6
+ <div class="hero-badge">{{ t.heroBadge }}</div>
7
+ <h1 class="hero-title">Newport<span class="accent"> Project</span></h1>
8
+ <p class="hero-version">{{ t.versionLabel }} {{ version }}</p>
9
+ <p class="hero-desc">{{ t.desc }}</p>
10
+ <div class="hero-actions">
11
+ <a [href]="mail1" class="btn-primary">{{ t.cta1 }}</a>
12
+ <a [href]="mail2" class="btn-outline">{{ t.cta2 }}</a>
13
+ </div>
14
+ </div>
15
+ <div class="hero-wave">
16
+ <svg
17
+ viewBox="0 0 1440 80"
18
+ preserveAspectRatio="none"
19
+ xmlns="http://www.w3.org/2000/svg">
20
+ <path
21
+ d="M0,40 C360,80 1080,0 1440,40 L1440,80 L0,80 Z"
22
+ class="wave-path" />
23
+ </svg>
24
+ </div>
25
+ </section>
26
+
27
+ <!-- ===== Stats ===== -->
28
+ <section class="stats">
29
+ <div class="stats-grid">
30
+ <div class="stat-item">
31
+ <span class="stat-number">10×</span>
32
+ <span class="stat-label">{{ t.stat1 }}</span>
33
+ </div>
34
+ <div class="stat-divider"></div>
35
+ <div class="stat-item">
36
+ <span class="stat-number">100%</span>
37
+ <span class="stat-label">{{ t.stat2 }}</span>
38
+ </div>
39
+ <div class="stat-divider"></div>
40
+ <div class="stat-item">
41
+ <span class="stat-number">∞</span>
42
+ <span class="stat-label">{{ t.stat3 }}</span>
43
+ </div>
44
+ <div class="stat-divider"></div>
45
+ <div class="stat-item">
46
+ <span class="stat-number">24/7</span>
47
+ <span class="stat-label">{{ t.stat4 }}</span>
48
+ </div>
49
+ </div>
50
+ </section>
51
+
52
+ <!-- ===== Tech Stack ===== -->
53
+ <section class="tech-stack">
54
+ <div class="section-header">
55
+ <span class="section-tag">{{ t.techTag }}</span>
56
+ <h2>{{ t.techTitle }}</h2>
57
+ <p>{{ t.techSubtitle }}</p>
58
+ </div>
59
+ <div class="tech-grid">
60
+ <div class="tech-card">
61
+ <div class="tech-icon">&#9881;</div>
62
+ <h3>{{ t.techFe }}</h3>
63
+ <p>{{ t.techFeDesc }}</p>
64
+ </div>
65
+ <div class="tech-card">
66
+ <div class="tech-icon">&#9889;</div>
67
+ <h3>{{ t.techBe }}</h3>
68
+ <p>{{ t.techBeDesc }}</p>
69
+ </div>
70
+ <div class="tech-card">
71
+ <div class="tech-icon">&#128451;</div>
72
+ <h3>{{ t.techData }}</h3>
73
+ <p>{{ t.techDataDesc }}</p>
74
+ </div>
75
+ <div class="tech-card">
76
+ <div class="tech-icon">&#9729;</div>
77
+ <h3>{{ t.techOps }}</h3>
78
+ <p>{{ t.techOpsDesc }}</p>
79
+ </div>
80
+ </div>
81
+ </section>
82
+
83
+ <!-- ===== Architecture ===== -->
84
+ <section class="architecture">
85
+ <div class="section-header">
86
+ <span class="section-tag">{{ t.archTag }}</span>
87
+ <h2>{{ t.archTitle }}</h2>
88
+ <p>{{ t.archSubtitle }}</p>
89
+ </div>
90
+ <div class="arch-list">
91
+ @for (item of t.archItems; track item.label) {
92
+ <div class="arch-item">
93
+ <div class="arch-dot"></div>
94
+ <div class="arch-body">
95
+ <h4>{{ item.label }}</h4>
96
+ <p>{{ item.detail }}</p>
97
+ </div>
98
+ </div>
99
+ }
100
+ </div>
101
+ </section>
102
+
103
+ <!-- ===== Features ===== -->
104
+ <section class="features">
105
+ <div class="section-header">
106
+ <span class="section-tag">{{ t.featTag }}</span>
107
+ <h2>{{ t.featTitle }}</h2>
108
+ <p>{{ t.featSubtitle }}</p>
109
+ </div>
110
+ <div class="feature-grid">
111
+ <div class="feature-card">
112
+ <div class="feature-icon">&#128196;</div>
113
+ <h3>{{ t.f1Title }}</h3>
114
+ <p>{{ t.f1Desc }}</p>
115
+ </div>
116
+ <div class="feature-card">
117
+ <div class="feature-icon">&#128202;</div>
118
+ <h3>{{ t.f2Title }}</h3>
119
+ <p>{{ t.f2Desc }}</p>
120
+ </div>
121
+ <div class="feature-card">
122
+ <div class="feature-icon">&#128197;</div>
123
+ <h3>{{ t.f3Title }}</h3>
124
+ <p>{{ t.f3Desc }}</p>
125
+ </div>
126
+ <div class="feature-card">
127
+ <div class="feature-icon">&#128200;</div>
128
+ <h3>{{ t.f4Title }}</h3>
129
+ <p>{{ t.f4Desc }}</p>
130
+ </div>
131
+ <div class="feature-card">
132
+ <div class="feature-icon">&#128279;</div>
133
+ <h3>{{ t.f5Title }}</h3>
134
+ <p>{{ t.f5Desc }}</p>
135
+ </div>
136
+ <div class="feature-card">
137
+ <div class="feature-icon">&#128274;</div>
138
+ <h3>{{ t.f6Title }}</h3>
139
+ <p>{{ t.f6Desc }}</p>
140
+ </div>
141
+ <div class="feature-card">
142
+ <div class="feature-icon">&#128451;</div>
143
+ <h3>{{ t.f7Title }}</h3>
144
+ <p>{{ t.f7Desc }}</p>
145
+ </div>
146
+ <div class="feature-card">
147
+ <div class="feature-icon">&#128161;</div>
148
+ <h3>{{ t.f8Title }}</h3>
149
+ <p>{{ t.f8Desc }}</p>
150
+ </div>
151
+ <div class="feature-card">
152
+ <div class="feature-icon">&#9729;</div>
153
+ <h3>{{ t.f9Title }}</h3>
154
+ <p>{{ t.f9Desc }}</p>
155
+ </div>
156
+ </div>
157
+ </section>
158
+
159
+ <!-- ===== CTA ===== -->
160
+ <section class="cta">
161
+ <div class="cta-content">
162
+ <span class="section-tag light">{{ t.ctaTag }}</span>
163
+ <h2>{{ t.ctaTitle }}</h2>
164
+ <p>{{ t.ctaSubtitle }}</p>
165
+ <a [href]="mailCta" class="btn-primary large">{{ t.ctaBtn }}</a>
166
+ </div>
167
+ </section>
168
+
169
+ <!-- ===== Footer ===== -->
170
+ <footer class="info-footer">
171
+ <span>Newport Project &copy; {{ version }} &mdash; {{ t.rights }}</span>
172
+ </footer>
173
+ </div>
174
+ <!-- fine info.component -->