@jjlmoya/utils-finance 1.30.0 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/package.json +1 -1
  2. package/src/category/i18n/fr.ts +159 -159
  3. package/src/category/i18n/ru.ts +158 -158
  4. package/src/category/index.ts +39 -38
  5. package/src/category/seo.astro +1 -1
  6. package/src/components/PreviewNavSidebar.astro +1 -1
  7. package/src/components/PreviewToolbar.astro +1 -1
  8. package/src/data.ts +1 -1
  9. package/src/entries.ts +4 -1
  10. package/src/env.d.ts +1 -1
  11. package/src/index.ts +1 -0
  12. package/src/layouts/PreviewLayout.astro +113 -113
  13. package/src/pages/index.astro +1 -1
  14. package/src/tests/bibliography_wellformed_export.test.ts +46 -0
  15. package/src/tests/faq_count.test.ts +1 -1
  16. package/src/tests/locale_completeness.test.ts +2 -2
  17. package/src/tests/mocks/astro_mock.js +1 -1
  18. package/src/tests/no_h1_in_components.test.ts +1 -1
  19. package/src/tests/script_density.test.ts +94 -94
  20. package/src/tests/seo_length.test.ts +23 -23
  21. package/src/tests/seo_translation_completeness.test.ts +69 -0
  22. package/src/tests/seo_wellformed_export.test.ts +65 -0
  23. package/src/tests/tool_validation.test.ts +17 -17
  24. package/src/tool/compoundInterest/compound-interest-calculator.css +236 -236
  25. package/src/tool/compoundInterest/entry.ts +32 -32
  26. package/src/tool/compoundInterest/i18n/de.ts +195 -195
  27. package/src/tool/compoundInterest/i18n/fr.ts +195 -195
  28. package/src/tool/compoundInterest/i18n/it.ts +195 -195
  29. package/src/tool/compoundInterest/i18n/pl.ts +194 -194
  30. package/src/tool/compoundInterest/i18n/ru.ts +195 -195
  31. package/src/tool/compoundInterest/i18n/tr.ts +195 -195
  32. package/src/tool/compoundInterest/i18n/zh.ts +189 -189
  33. package/src/tool/compoundInterest/seo.astro +15 -15
  34. package/src/tool/courtFeeCalculator/i18n/it.ts +158 -158
  35. package/src/tool/courtFeeCalculator/i18n/ru.ts +158 -158
  36. package/src/tool/courtFeeCalculator/i18n/tr.ts +158 -158
  37. package/src/tool/courtFeeCalculator/seo.astro +15 -15
  38. package/src/tool/courtFeeCalculator/spanish-court-fees-calculator.css +197 -197
  39. package/src/tool/debtSnowball/bibliography.ts +12 -12
  40. package/src/tool/debtSnowball/i18n/de.ts +16 -16
  41. package/src/tool/debtSnowball/i18n/id.ts +16 -16
  42. package/src/tool/debtSnowball/i18n/it.ts +168 -168
  43. package/src/tool/debtSnowball/i18n/nl.ts +16 -16
  44. package/src/tool/debtSnowball/i18n/pl.ts +168 -168
  45. package/src/tool/debtSnowball/i18n/pt.ts +1 -1
  46. package/src/tool/debtSnowball/i18n/ru.ts +1 -1
  47. package/src/tool/debtSnowball/i18n/sv.ts +22 -29
  48. package/src/tool/debtSnowball/i18n/tr.ts +168 -168
  49. package/src/tool/debtSnowball/i18n/zh.ts +168 -168
  50. package/src/tool/debtSnowball/seo.astro +15 -15
  51. package/src/tool/dividendYield/bibliography.astro +14 -0
  52. package/src/tool/dividendYield/bibliography.ts +12 -0
  53. package/src/tool/dividendYield/component.astro +83 -0
  54. package/src/tool/dividendYield/controller.ts +85 -0
  55. package/src/tool/dividendYield/dividend-yield-calculator.css +352 -0
  56. package/src/tool/dividendYield/dom-views.ts +58 -0
  57. package/src/tool/dividendYield/entry.ts +29 -0
  58. package/src/tool/dividendYield/evaluator.ts +16 -0
  59. package/src/tool/dividendYield/i18n/de.ts +53 -0
  60. package/src/tool/dividendYield/i18n/en.ts +138 -0
  61. package/src/tool/dividendYield/i18n/es.ts +49 -0
  62. package/src/tool/dividendYield/i18n/fr.ts +49 -0
  63. package/src/tool/dividendYield/i18n/id.ts +49 -0
  64. package/src/tool/dividendYield/i18n/it.ts +49 -0
  65. package/src/tool/dividendYield/i18n/ja.ts +49 -0
  66. package/src/tool/dividendYield/i18n/ko.ts +25 -0
  67. package/src/tool/dividendYield/i18n/nl.ts +25 -0
  68. package/src/tool/dividendYield/i18n/pl.ts +25 -0
  69. package/src/tool/dividendYield/i18n/pt.ts +25 -0
  70. package/src/tool/dividendYield/i18n/ru.ts +25 -0
  71. package/src/tool/dividendYield/i18n/sv.ts +25 -0
  72. package/src/tool/dividendYield/i18n/tr.ts +25 -0
  73. package/src/tool/dividendYield/i18n/zh.ts +25 -0
  74. package/src/tool/dividendYield/index.ts +11 -0
  75. package/src/tool/dividendYield/logic.test.ts +73 -0
  76. package/src/tool/dividendYield/logic.ts +55 -0
  77. package/src/tool/dividendYield/seo.astro +14 -0
  78. package/src/tool/dividendYield/storage.ts +24 -0
  79. package/src/tool/dividendYield/ui.ts +33 -0
  80. package/src/tool/financialFreedom/financial-freedom-calculator.css +311 -311
  81. package/src/tool/financialFreedom/i18n/en.ts +182 -182
  82. package/src/tool/financialFreedom/i18n/fr.ts +128 -128
  83. package/src/tool/financialFreedom/i18n/id.ts +24 -7
  84. package/src/tool/financialFreedom/i18n/it.ts +24 -7
  85. package/src/tool/financialFreedom/i18n/ja.ts +1 -1
  86. package/src/tool/financialFreedom/i18n/nl.ts +24 -7
  87. package/src/tool/financialFreedom/i18n/pl.ts +24 -7
  88. package/src/tool/financialFreedom/i18n/pt.ts +24 -7
  89. package/src/tool/financialFreedom/i18n/ru.ts +128 -128
  90. package/src/tool/financialFreedom/i18n/sv.ts +1 -1
  91. package/src/tool/financialFreedom/i18n/tr.ts +2 -2
  92. package/src/tool/financialFreedom/i18n/zh.ts +128 -128
  93. package/src/tool/fireCalculator/i18n/it.ts +241 -241
  94. package/src/tool/fireCalculator/i18n/ru.ts +241 -241
  95. package/src/tool/fireCalculator/i18n/tr.ts +241 -241
  96. package/src/tool/fireCalculator/i18n/zh.ts +241 -241
  97. package/src/tool/fireCalculator/seo.astro +15 -15
  98. package/src/tool/ibanBicSwiftConverter/i18n/fr.ts +151 -151
  99. package/src/tool/ibanBicSwiftConverter/i18n/it.ts +118 -118
  100. package/src/tool/ibanBicSwiftConverter/i18n/ru.ts +118 -118
  101. package/src/tool/ibanBicSwiftConverter/i18n/tr.ts +118 -118
  102. package/src/tool/ibanBicSwiftConverter/iban-to-bic-swift-converter.css +366 -366
  103. package/src/tool/ibanBicSwiftConverter/seo.astro +15 -15
  104. package/src/tool/inflation/bibliography.ts +20 -20
  105. package/src/tool/inflation/entry.ts +32 -32
  106. package/src/tool/inflation/i18n/de.ts +284 -284
  107. package/src/tool/inflation/i18n/fr.ts +284 -284
  108. package/src/tool/inflation/i18n/it.ts +284 -284
  109. package/src/tool/inflation/i18n/nl.ts +284 -284
  110. package/src/tool/inflation/i18n/pl.ts +284 -284
  111. package/src/tool/inflation/i18n/pt.ts +284 -284
  112. package/src/tool/inflation/i18n/ru.ts +284 -284
  113. package/src/tool/inflation/i18n/sv.ts +284 -284
  114. package/src/tool/inflation/i18n/tr.ts +284 -284
  115. package/src/tool/inflation/i18n/zh.ts +284 -284
  116. package/src/tool/inflation/seo.astro +15 -15
  117. package/src/tool/lateInterest/bibliography.ts +16 -16
  118. package/src/tool/lateInterest/entry.ts +32 -32
  119. package/src/tool/lateInterest/i18n/de.ts +213 -213
  120. package/src/tool/lateInterest/i18n/es.ts +213 -213
  121. package/src/tool/lateInterest/i18n/it.ts +213 -213
  122. package/src/tool/lateInterest/i18n/nl.ts +213 -213
  123. package/src/tool/lateInterest/i18n/pl.ts +213 -213
  124. package/src/tool/lateInterest/i18n/pt.ts +213 -213
  125. package/src/tool/lateInterest/i18n/ru.ts +213 -213
  126. package/src/tool/lateInterest/i18n/sv.ts +213 -213
  127. package/src/tool/lateInterest/i18n/tr.ts +213 -213
  128. package/src/tool/lateInterest/i18n/zh.ts +213 -213
  129. package/src/tool/lateInterest/seo.astro +15 -15
  130. package/src/tool/legalInterestRate/i18n/it.ts +129 -129
  131. package/src/tool/legalInterestRate/i18n/ru.ts +129 -129
  132. package/src/tool/legalInterestRate/i18n/tr.ts +128 -121
  133. package/src/tool/legalInterestRate/i18n/zh.ts +11 -4
  134. package/src/tool/legalInterestRate/seo.astro +15 -15
  135. package/src/tool/lotteryOptimizer/i18n/it.ts +163 -163
  136. package/src/tool/lotteryOptimizer/i18n/pl.ts +163 -163
  137. package/src/tool/lotteryOptimizer/i18n/ru.ts +163 -163
  138. package/src/tool/lotteryOptimizer/i18n/tr.ts +163 -163
  139. package/src/tool/lotteryOptimizer/i18n/zh.ts +162 -155
  140. package/src/tool/lotteryOptimizer/seo.astro +15 -15
  141. package/src/tool/mortgage/bibliography.ts +20 -20
  142. package/src/tool/mortgage/entry.ts +32 -32
  143. package/src/tool/mortgage/i18n/de.ts +210 -210
  144. package/src/tool/mortgage/i18n/es.ts +210 -210
  145. package/src/tool/mortgage/i18n/fr.ts +210 -210
  146. package/src/tool/mortgage/i18n/id.ts +210 -210
  147. package/src/tool/mortgage/i18n/it.ts +210 -210
  148. package/src/tool/mortgage/i18n/nl.ts +210 -210
  149. package/src/tool/mortgage/i18n/pl.ts +210 -210
  150. package/src/tool/mortgage/i18n/ru.ts +210 -210
  151. package/src/tool/mortgage/i18n/tr.ts +210 -210
  152. package/src/tool/mortgage/i18n/zh.ts +210 -210
  153. package/src/tool/mortgage/mortgage-calculator.css +595 -595
  154. package/src/tool/mortgage/seo.astro +15 -15
  155. package/src/tool/percentageCalculator/bibliography.ts +16 -16
  156. package/src/tool/percentageCalculator/entry.ts +32 -32
  157. package/src/tool/percentageCalculator/i18n/de.ts +220 -220
  158. package/src/tool/percentageCalculator/i18n/en.ts +220 -220
  159. package/src/tool/percentageCalculator/i18n/es.ts +220 -220
  160. package/src/tool/percentageCalculator/i18n/fr.ts +220 -220
  161. package/src/tool/percentageCalculator/i18n/it.ts +220 -220
  162. package/src/tool/percentageCalculator/i18n/pl.ts +220 -220
  163. package/src/tool/percentageCalculator/i18n/ru.ts +220 -220
  164. package/src/tool/percentageCalculator/i18n/tr.ts +220 -220
  165. package/src/tool/percentageCalculator/i18n/zh.ts +220 -220
  166. package/src/tool/percentageCalculator/seo.astro +15 -15
  167. package/src/tool/profitability/i18n/de.ts +24 -7
  168. package/src/tool/profitability/i18n/fr.ts +121 -104
  169. package/src/tool/profitability/i18n/id.ts +2 -2
  170. package/src/tool/profitability/i18n/it.ts +24 -7
  171. package/src/tool/profitability/i18n/ja.ts +1 -1
  172. package/src/tool/profitability/i18n/nl.ts +24 -7
  173. package/src/tool/profitability/i18n/pl.ts +1 -1
  174. package/src/tool/profitability/i18n/pt.ts +24 -7
  175. package/src/tool/profitability/i18n/ru.ts +118 -118
  176. package/src/tool/profitability/i18n/sv.ts +1 -1
  177. package/src/tool/profitability/i18n/tr.ts +1 -1
  178. package/src/tool/profitability/i18n/zh.ts +118 -118
  179. package/src/tool/profitability/profitability-calculator.css +229 -229
  180. package/src/tool/rentIncreaseCalculator/i18n/it.ts +125 -125
  181. package/src/tool/rentIncreaseCalculator/i18n/tr.ts +125 -125
  182. package/src/tool/rentIncreaseCalculator/rent-increase-calculator.css +326 -326
  183. package/src/tool/rentIncreaseCalculator/seo.astro +15 -15
  184. package/src/tool/revolvingCardCalculator/i18n/de.ts +38 -20
  185. package/src/tool/revolvingCardCalculator/i18n/es.ts +19 -18
  186. package/src/tool/revolvingCardCalculator/i18n/fr.ts +32 -28
  187. package/src/tool/revolvingCardCalculator/i18n/id.ts +18 -18
  188. package/src/tool/revolvingCardCalculator/i18n/it.ts +18 -18
  189. package/src/tool/revolvingCardCalculator/i18n/ja.ts +2 -2
  190. package/src/tool/revolvingCardCalculator/i18n/ko.ts +2 -2
  191. package/src/tool/revolvingCardCalculator/i18n/nl.ts +22 -19
  192. package/src/tool/revolvingCardCalculator/i18n/pl.ts +2 -2
  193. package/src/tool/revolvingCardCalculator/i18n/pt.ts +2 -2
  194. package/src/tool/revolvingCardCalculator/i18n/ru.ts +2 -2
  195. package/src/tool/revolvingCardCalculator/i18n/sv.ts +2 -2
  196. package/src/tool/revolvingCardCalculator/i18n/tr.ts +2 -2
  197. package/src/tool/revolvingCardCalculator/i18n/zh.ts +6 -6
  198. package/src/tool/salaryEmployerCost/i18n/de.ts +10 -10
  199. package/src/tool/salaryEmployerCost/i18n/fr.ts +9 -9
  200. package/src/tool/salaryEmployerCost/i18n/id.ts +9 -9
  201. package/src/tool/salaryEmployerCost/i18n/it.ts +9 -9
  202. package/src/tool/salaryEmployerCost/i18n/ja.ts +1 -1
  203. package/src/tool/salaryEmployerCost/i18n/ko.ts +1 -1
  204. package/src/tool/salaryEmployerCost/i18n/nl.ts +2 -2
  205. package/src/tool/salaryEmployerCost/i18n/pl.ts +2 -2
  206. package/src/tool/salaryEmployerCost/i18n/pt.ts +2 -2
  207. package/src/tool/salaryEmployerCost/i18n/ru.ts +2 -2
  208. package/src/tool/salaryEmployerCost/i18n/sv.ts +2 -2
  209. package/src/tool/salaryEmployerCost/i18n/tr.ts +2 -2
  210. package/src/tool/salaryEmployerCost/i18n/zh.ts +2 -2
  211. package/src/tools.ts +2 -1
@@ -0,0 +1,65 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { readdirSync, readFileSync, existsSync } from 'fs';
3
+ import { join, relative } from 'path';
4
+
5
+ function findSeoAstroFiles(dir: string): string[] {
6
+ const files: string[] = [];
7
+ if (!existsSync(dir)) return files;
8
+ const entries = readdirSync(dir, { withFileTypes: true });
9
+
10
+ for (const entry of entries) {
11
+ const fullPath = join(dir, entry.name);
12
+ if (entry.isDirectory()) {
13
+ files.push(...findSeoAstroFiles(fullPath));
14
+ } else if (entry.isFile() && entry.name === 'seo.astro') {
15
+ files.push(fullPath);
16
+ }
17
+ }
18
+
19
+ return files;
20
+ }
21
+
22
+ const toolDir = join(process.cwd(), 'src', 'tool');
23
+ const seoFiles = findSeoAstroFiles(toolDir);
24
+
25
+ describe('SEO Component Wellformed Export', () => {
26
+ it('found tool seo.astro components', () => {
27
+ expect(seoFiles.length).toBeGreaterThan(0);
28
+ });
29
+
30
+ seoFiles.forEach((file) => {
31
+ const relativePath = relative(process.cwd(), file);
32
+
33
+ it(`${relativePath} should dynamically load SEO sections and use SEORenderer`, () => {
34
+ const content = readFileSync(file, 'utf-8');
35
+
36
+ const usesSeoRenderer =
37
+ content.includes('@jjlmoya/utils-shared') &&
38
+ (content.includes('SEORenderer') || content.includes('SEOArticle'));
39
+
40
+ const acquiresDynamicContent =
41
+ content.includes('.i18n') ||
42
+ content.includes('loader') ||
43
+ content.includes('await loader') ||
44
+ content.includes('.seo');
45
+
46
+ const isBrokenPattern =
47
+ /sections\s*=\s*\[\s*\]/.test(content) && !acquiresDynamicContent;
48
+
49
+ expect(
50
+ usesSeoRenderer,
51
+ `File "${relativePath}" does not import or use SEORenderer from @jjlmoya/utils-shared.`,
52
+ ).toBe(true);
53
+
54
+ expect(
55
+ isBrokenPattern,
56
+ `File "${relativePath}" relies on a static sections=[] prop default without fetching content from entry.i18n, resulting in empty SEO text on consumers.`,
57
+ ).toBe(false);
58
+
59
+ expect(
60
+ acquiresDynamicContent,
61
+ `File "${relativePath}" does not fetch dynamic i18n content for SEO rendering.`,
62
+ ).toBe(true);
63
+ });
64
+ });
65
+ });
@@ -1,17 +1,17 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { ALL_TOOLS } from '../tools';
3
- import { financeCategory } from '../data';
4
-
5
- describe('Tool Validation Suite', () => {
6
- describe('Library Registration', () => {
7
- it('should have 17 tools in ALL_TOOLS', () => {
8
- expect(ALL_TOOLS.length).toBe(17);
9
- });
10
-
11
- it('financeCategory should be defined', () => {
12
- expect(financeCategory).toBeDefined();
13
- expect(financeCategory.i18n).toBeDefined();
14
- });
15
- });
16
- });
17
-
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ALL_TOOLS } from '../tools';
3
+ import { financeCategory } from '../data';
4
+
5
+ describe('Tool Validation Suite', () => {
6
+ describe('Library Registration', () => {
7
+ it('should have 18 tools in ALL_TOOLS', () => {
8
+ expect(ALL_TOOLS.length).toBe(18);
9
+ });
10
+
11
+ it('financeCategory should be defined', () => {
12
+ expect(financeCategory).toBeDefined();
13
+ expect(financeCategory.i18n).toBeDefined();
14
+ });
15
+ });
16
+ });
17
+
@@ -1,24 +1,24 @@
1
- .cic-root {
2
- --cic-accent: #10b981;
3
- --cic-accent-text: #059669;
4
- --cic-accent-icon-bg: #d1fae5;
5
- --cic-bg: #fff;
6
- --cic-bg-panel: rgba(248, 250, 252, 0.3);
7
- --cic-bg-card: #fff;
8
- --cic-bg-header: rgba(248, 250, 252, 0.5);
9
- --cic-border: #e2e8f0;
10
- --cic-border-subtle: #f1f5f9;
11
- --cic-text: #0f172a;
12
- --cic-text-muted: #64748b;
13
- --cic-text-subtle: #94a3b8;
14
- --cic-input-bg: #fff;
15
- --cic-input-border: #e2e8f0;
16
- --cic-summary-bg: #fff;
17
- --cic-insight-bg: #ecfdf5;
18
- --cic-insight-text: #065f46;
19
-
20
- background: var(--cic-bg);
21
- border-radius: 1.5rem;
1
+ .cic-root {
2
+ --cic-accent: #10b981;
3
+ --cic-accent-text: #059669;
4
+ --cic-accent-icon-bg: #d1fae5;
5
+ --cic-bg: #fff;
6
+ --cic-bg-panel: rgba(248, 250, 252, 0.3);
7
+ --cic-bg-card: #fff;
8
+ --cic-bg-header: rgba(248, 250, 252, 0.5);
9
+ --cic-border: #e2e8f0;
10
+ --cic-border-subtle: #f1f5f9;
11
+ --cic-text: #0f172a;
12
+ --cic-text-muted: #64748b;
13
+ --cic-text-subtle: #94a3b8;
14
+ --cic-input-bg: #fff;
15
+ --cic-input-border: #e2e8f0;
16
+ --cic-summary-bg: #fff;
17
+ --cic-insight-bg: #ecfdf5;
18
+ --cic-insight-text: #065f46;
19
+
20
+ background: var(--cic-bg);
21
+ border-radius: 1.5rem;
22
22
  box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
23
23
  border: 1px solid var(--cic-border-subtle);
24
24
  overflow: hidden;
@@ -33,187 +33,187 @@
33
33
  .cic-root *::after {
34
34
  box-sizing: border-box;
35
35
  }
36
-
37
- .theme-dark .cic-root {
38
- --cic-accent-text: #34d399;
39
- --cic-accent-icon-bg: rgba(16, 185, 129, 0.2);
40
- --cic-bg: #1e293b;
41
- --cic-bg-panel: rgba(15, 23, 42, 0.1);
42
- --cic-bg-card: #1e293b;
43
- --cic-bg-header: rgba(30, 41, 59, 0.5);
44
- --cic-border: #334155;
45
- --cic-border-subtle: #334155;
46
- --cic-text: #fff;
47
- --cic-text-muted: #94a3b8;
48
- --cic-text-subtle: #64748b;
49
- --cic-input-bg: #0f172a;
50
- --cic-input-border: #334155;
51
- --cic-summary-bg: #1e293b;
52
- --cic-insight-bg: rgba(16, 185, 129, 0.1);
53
- --cic-insight-text: #6ee7b7;
54
- }
55
-
36
+
37
+ .theme-dark .cic-root {
38
+ --cic-accent-text: #34d399;
39
+ --cic-accent-icon-bg: rgba(16, 185, 129, 0.2);
40
+ --cic-bg: #1e293b;
41
+ --cic-bg-panel: rgba(15, 23, 42, 0.1);
42
+ --cic-bg-card: #1e293b;
43
+ --cic-bg-header: rgba(30, 41, 59, 0.5);
44
+ --cic-border: #334155;
45
+ --cic-border-subtle: #334155;
46
+ --cic-text: #fff;
47
+ --cic-text-muted: #94a3b8;
48
+ --cic-text-subtle: #64748b;
49
+ --cic-input-bg: #0f172a;
50
+ --cic-input-border: #334155;
51
+ --cic-summary-bg: #1e293b;
52
+ --cic-insight-bg: rgba(16, 185, 129, 0.1);
53
+ --cic-insight-text: #6ee7b7;
54
+ }
55
+
56
56
  .cic-header {
57
- padding: 1.5rem;
58
- border-bottom: 1px solid var(--cic-border-subtle);
59
- background: var(--cic-bg-header);
60
- display: flex;
61
- flex-wrap: wrap;
62
- gap: 1rem;
57
+ padding: 1.5rem;
58
+ border-bottom: 1px solid var(--cic-border-subtle);
59
+ background: var(--cic-bg-header);
60
+ display: flex;
61
+ flex-wrap: wrap;
62
+ gap: 1rem;
63
63
  align-items: center;
64
64
  justify-content: space-between;
65
65
  min-width: 0;
66
66
  }
67
-
67
+
68
68
  .cic-header-left {
69
69
  display: flex;
70
70
  align-items: center;
71
71
  gap: 0.75rem;
72
72
  min-width: 0;
73
73
  }
74
-
74
+
75
75
  .cic-icon-wrap {
76
- padding: 0.625rem;
77
- background: var(--cic-accent-icon-bg);
78
- border-radius: 0.75rem;
79
- color: var(--cic-accent-text);
76
+ padding: 0.625rem;
77
+ background: var(--cic-accent-icon-bg);
78
+ border-radius: 0.75rem;
79
+ color: var(--cic-accent-text);
80
80
  display: flex;
81
81
  align-items: center;
82
82
  justify-content: center;
83
83
  flex-shrink: 0;
84
84
  }
85
-
86
- .cic-icon {
87
- width: 1.5rem;
88
- height: 1.5rem;
89
- }
90
-
85
+
86
+ .cic-icon {
87
+ width: 1.5rem;
88
+ height: 1.5rem;
89
+ }
90
+
91
91
  .cic-title {
92
92
  font-size: 1.25rem;
93
93
  font-weight: 700;
94
94
  color: var(--cic-text);
95
95
  overflow-wrap: anywhere;
96
96
  }
97
-
98
- .cic-realtime {
99
- display: flex;
100
- align-items: center;
101
- gap: 0.5rem;
102
- font-size: 0.875rem;
103
- color: var(--cic-text-muted);
104
- }
105
-
106
- .cic-dot {
107
- width: 0.5rem;
108
- height: 0.5rem;
109
- border-radius: 50%;
110
- background: var(--cic-accent);
111
- animation: cic-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
112
- }
113
-
114
- @keyframes cic-pulse {
115
- 0%, 100% { opacity: 1; }
116
- 50% { opacity: 0.4; }
117
- }
118
-
97
+
98
+ .cic-realtime {
99
+ display: flex;
100
+ align-items: center;
101
+ gap: 0.5rem;
102
+ font-size: 0.875rem;
103
+ color: var(--cic-text-muted);
104
+ }
105
+
106
+ .cic-dot {
107
+ width: 0.5rem;
108
+ height: 0.5rem;
109
+ border-radius: 50%;
110
+ background: var(--cic-accent);
111
+ animation: cic-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
112
+ }
113
+
114
+ @keyframes cic-pulse {
115
+ 0%, 100% { opacity: 1; }
116
+ 50% { opacity: 0.4; }
117
+ }
118
+
119
119
  .cic-grid {
120
120
  display: grid;
121
121
  min-width: 0;
122
122
  }
123
-
123
+
124
124
  .cic-panel-left {
125
- padding: 1.5rem;
126
- display: flex;
127
- flex-direction: column;
128
- gap: 1.5rem;
125
+ padding: 1.5rem;
126
+ display: flex;
127
+ flex-direction: column;
128
+ gap: 1.5rem;
129
129
  background: var(--cic-bg-panel);
130
130
  border-bottom: 1px solid var(--cic-border-subtle);
131
131
  min-width: 0;
132
132
  }
133
-
133
+
134
134
  .cic-fields {
135
135
  display: flex;
136
136
  flex-direction: column;
137
137
  gap: 1rem;
138
138
  min-width: 0;
139
139
  }
140
-
140
+
141
141
  .cic-grid-2 {
142
142
  display: grid;
143
143
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
144
144
  gap: 1rem;
145
145
  min-width: 0;
146
146
  }
147
-
148
- .cic-label {
149
- display: block;
150
- font-size: 0.75rem;
151
- font-weight: 700;
152
- color: var(--cic-text-subtle);
153
- text-transform: uppercase;
154
- letter-spacing: 0.1em;
155
- margin-bottom: 0.5rem;
156
- }
157
-
147
+
148
+ .cic-label {
149
+ display: block;
150
+ font-size: 0.75rem;
151
+ font-weight: 700;
152
+ color: var(--cic-text-subtle);
153
+ text-transform: uppercase;
154
+ letter-spacing: 0.1em;
155
+ margin-bottom: 0.5rem;
156
+ }
157
+
158
158
  .cic-input-wrap {
159
159
  position: relative;
160
160
  min-width: 0;
161
161
  }
162
-
163
- .cic-currency {
164
- position: absolute;
165
- left: 0.5rem;
166
- top: 50%;
167
- transform: translateY(-50%);
168
- color: var(--cic-text-subtle);
169
- font-weight: 700;
170
- pointer-events: none;
171
- font-size: 0.75rem;
172
- }
173
-
174
- .cic-currency-right {
175
- left: auto;
176
- right: 0.5rem;
177
- }
178
-
162
+
163
+ .cic-currency {
164
+ position: absolute;
165
+ left: 0.5rem;
166
+ top: 50%;
167
+ transform: translateY(-50%);
168
+ color: var(--cic-text-subtle);
169
+ font-weight: 700;
170
+ pointer-events: none;
171
+ font-size: 0.75rem;
172
+ }
173
+
174
+ .cic-currency-right {
175
+ left: auto;
176
+ right: 0.5rem;
177
+ }
178
+
179
179
  .cic-input {
180
- width: 100%;
181
- padding: 0.75rem 1rem;
182
- background: var(--cic-input-bg);
183
- border: 2px solid var(--cic-input-border);
184
- border-radius: 0.75rem;
185
- outline: none;
186
- transition: border-color 0.2s;
187
- color: var(--cic-text);
180
+ width: 100%;
181
+ padding: 0.75rem 1rem;
182
+ background: var(--cic-input-bg);
183
+ border: 2px solid var(--cic-input-border);
184
+ border-radius: 0.75rem;
185
+ outline: none;
186
+ transition: border-color 0.2s;
187
+ color: var(--cic-text);
188
188
  font-weight: 700;
189
189
  font-size: 1.125rem;
190
190
  min-width: 0;
191
191
  }
192
-
193
- .cic-input-prefixed {
194
- padding-left: 3.5rem;
195
- }
196
-
197
- .cic-input-suffixed {
198
- padding-right: 5rem;
199
- }
200
-
201
- .cic-input:focus {
202
- border-color: var(--cic-accent);
203
- }
204
-
192
+
193
+ .cic-input-prefixed {
194
+ padding-left: 3.5rem;
195
+ }
196
+
197
+ .cic-input-suffixed {
198
+ padding-right: 5rem;
199
+ }
200
+
201
+ .cic-input:focus {
202
+ border-color: var(--cic-accent);
203
+ }
204
+
205
205
  .cic-summary {
206
- background: var(--cic-summary-bg);
207
- border-radius: 1rem;
208
- padding: 1rem;
209
- border: 1px solid var(--cic-border);
210
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
206
+ background: var(--cic-summary-bg);
207
+ border-radius: 1rem;
208
+ padding: 1rem;
209
+ border: 1px solid var(--cic-border);
210
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
211
211
  display: flex;
212
212
  flex-direction: column;
213
213
  gap: 0.75rem;
214
214
  min-width: 0;
215
215
  }
216
-
216
+
217
217
  .cic-summary-row {
218
218
  display: flex;
219
219
  justify-content: space-between;
@@ -222,69 +222,69 @@
222
222
  gap: 0.75rem;
223
223
  min-width: 0;
224
224
  }
225
-
225
+
226
226
  .cic-summary-label {
227
227
  display: flex;
228
228
  align-items: center;
229
229
  gap: 0.5rem;
230
230
  min-width: 0;
231
231
  }
232
-
233
- .cic-dot-neutral {
234
- width: 0.75rem;
235
- height: 0.75rem;
236
- border-radius: 50%;
237
- background: var(--cic-text-subtle);
238
- flex-shrink: 0;
239
- }
240
-
241
- .cic-dot-accent {
242
- width: 0.75rem;
243
- height: 0.75rem;
244
- border-radius: 50%;
245
- background: var(--cic-accent);
246
- flex-shrink: 0;
247
- }
248
-
249
- .cic-text-muted {
250
- color: var(--cic-text-muted);
251
- }
252
-
253
- .cic-text-accent {
254
- color: var(--cic-accent-text);
255
- font-weight: 500;
256
- }
257
-
232
+
233
+ .cic-dot-neutral {
234
+ width: 0.75rem;
235
+ height: 0.75rem;
236
+ border-radius: 50%;
237
+ background: var(--cic-text-subtle);
238
+ flex-shrink: 0;
239
+ }
240
+
241
+ .cic-dot-accent {
242
+ width: 0.75rem;
243
+ height: 0.75rem;
244
+ border-radius: 50%;
245
+ background: var(--cic-accent);
246
+ flex-shrink: 0;
247
+ }
248
+
249
+ .cic-text-muted {
250
+ color: var(--cic-text-muted);
251
+ }
252
+
253
+ .cic-text-accent {
254
+ color: var(--cic-accent-text);
255
+ font-weight: 500;
256
+ }
257
+
258
258
  .cic-summary-value {
259
259
  font-weight: 700;
260
260
  color: var(--cic-text);
261
261
  overflow-wrap: anywhere;
262
262
  text-align: right;
263
263
  }
264
-
265
- .cic-summary-value-accent {
266
- color: var(--cic-accent-text);
267
- }
268
-
264
+
265
+ .cic-summary-value-accent {
266
+ color: var(--cic-accent-text);
267
+ }
268
+
269
269
  .cic-summary-total {
270
- padding-top: 0.75rem;
271
- margin-top: 0.25rem;
272
- border-top: 1px solid var(--cic-border-subtle);
270
+ padding-top: 0.75rem;
271
+ margin-top: 0.25rem;
272
+ border-top: 1px solid var(--cic-border-subtle);
273
273
  display: flex;
274
274
  justify-content: space-between;
275
275
  align-items: flex-end;
276
276
  gap: 1rem;
277
277
  min-width: 0;
278
278
  }
279
-
280
- .cic-total-label {
281
- color: var(--cic-text-subtle);
282
- font-size: 0.75rem;
283
- font-weight: 700;
284
- text-transform: uppercase;
285
- letter-spacing: 0.05em;
286
- }
287
-
279
+
280
+ .cic-total-label {
281
+ color: var(--cic-text-subtle);
282
+ font-size: 0.75rem;
283
+ font-weight: 700;
284
+ text-transform: uppercase;
285
+ letter-spacing: 0.05em;
286
+ }
287
+
288
288
  .cic-total-value {
289
289
  font-size: 1.5rem;
290
290
  font-weight: 900;
@@ -292,7 +292,7 @@
292
292
  overflow-wrap: anywhere;
293
293
  text-align: right;
294
294
  }
295
-
295
+
296
296
  .cic-panel-right {
297
297
  padding: 1.5rem;
298
298
  display: flex;
@@ -300,7 +300,7 @@
300
300
  min-height: 500px;
301
301
  min-width: 0;
302
302
  }
303
-
303
+
304
304
  .cic-canvas-wrap {
305
305
  position: relative;
306
306
  width: 100%;
@@ -349,50 +349,50 @@
349
349
  min-height: 320px;
350
350
  }
351
351
  }
352
-
353
- .cic-insight {
354
- display: none;
355
- margin-top: 1rem;
356
- padding: 1rem;
357
- background: var(--cic-insight-bg);
358
- border-radius: 0.75rem;
359
- font-size: 0.875rem;
360
- color: var(--cic-insight-text);
361
- opacity: 0;
362
- transition: opacity 0.5s;
363
- }
364
-
365
- @media (min-width: 768px) {
366
- .cic-insight {
367
- display: block;
368
- }
369
- }
370
-
371
- @media (min-width: 1024px) {
372
- .cic-grid {
373
- grid-template-columns: 4fr 8fr;
374
- }
375
-
376
- .cic-panel-left {
377
- border-bottom: none;
378
- border-right: 1px solid var(--cic-border-subtle);
379
- }
380
-
381
- .cic-panel-right {
382
- padding: 2rem;
383
- min-height: auto;
384
- }
385
- }
386
-
387
- .cic-insight.cic-insight-visible {
388
- opacity: 1;
389
- }
390
-
391
- .cic-insight-year {
392
- font-weight: 700;
393
- color: #10b981;
394
- }
395
-
396
- .theme-dark .cic-insight-year {
397
- color: #fff;
398
- }
352
+
353
+ .cic-insight {
354
+ display: none;
355
+ margin-top: 1rem;
356
+ padding: 1rem;
357
+ background: var(--cic-insight-bg);
358
+ border-radius: 0.75rem;
359
+ font-size: 0.875rem;
360
+ color: var(--cic-insight-text);
361
+ opacity: 0;
362
+ transition: opacity 0.5s;
363
+ }
364
+
365
+ @media (min-width: 768px) {
366
+ .cic-insight {
367
+ display: block;
368
+ }
369
+ }
370
+
371
+ @media (min-width: 1024px) {
372
+ .cic-grid {
373
+ grid-template-columns: 4fr 8fr;
374
+ }
375
+
376
+ .cic-panel-left {
377
+ border-bottom: none;
378
+ border-right: 1px solid var(--cic-border-subtle);
379
+ }
380
+
381
+ .cic-panel-right {
382
+ padding: 2rem;
383
+ min-height: auto;
384
+ }
385
+ }
386
+
387
+ .cic-insight.cic-insight-visible {
388
+ opacity: 1;
389
+ }
390
+
391
+ .cic-insight-year {
392
+ font-weight: 700;
393
+ color: #10b981;
394
+ }
395
+
396
+ .theme-dark .cic-insight-year {
397
+ color: #fff;
398
+ }