llm_cost_tracker 0.10.0 → 0.12.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 (209) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/README.md +11 -5
  4. data/app/assets/llm_cost_tracker/application.css +784 -802
  5. data/app/controllers/llm_cost_tracker/application_controller.rb +14 -2
  6. data/app/controllers/llm_cost_tracker/calls_controller.rb +28 -21
  7. data/app/controllers/llm_cost_tracker/dashboard_controller.rb +1 -4
  8. data/app/controllers/llm_cost_tracker/models_controller.rb +3 -1
  9. data/app/controllers/llm_cost_tracker/pricing_controller.rb +16 -0
  10. data/app/controllers/llm_cost_tracker/tags_controller.rb +3 -1
  11. data/app/helpers/llm_cost_tracker/application_helper.rb +19 -16
  12. data/app/helpers/llm_cost_tracker/chart_helper.rb +22 -6
  13. data/app/helpers/llm_cost_tracker/dashboard_filter_options_helper.rb +1 -11
  14. data/app/helpers/llm_cost_tracker/sortable_table_helper.rb +41 -0
  15. data/app/helpers/llm_cost_tracker/token_usage_helper.rb +4 -6
  16. data/app/models/llm_cost_tracker/call.rb +28 -63
  17. data/app/models/llm_cost_tracker/call_line_item.rb +2 -2
  18. data/app/models/llm_cost_tracker/call_rollup.rb +38 -0
  19. data/app/models/llm_cost_tracker/call_tag.rb +0 -2
  20. data/app/models/llm_cost_tracker/ingestion/inbox_entry.rb +2 -0
  21. data/app/services/llm_cost_tracker/dashboard/data_quality.rb +64 -43
  22. data/app/services/llm_cost_tracker/dashboard/filter.rb +5 -0
  23. data/app/services/llm_cost_tracker/dashboard/masking.rb +31 -0
  24. data/app/services/llm_cost_tracker/dashboard/monthly_budget.rb +63 -0
  25. data/app/services/llm_cost_tracker/dashboard/overview_stats.rb +5 -71
  26. data/app/services/llm_cost_tracker/dashboard/pagination.rb +2 -5
  27. data/app/services/llm_cost_tracker/dashboard/pricing_overview.rb +81 -0
  28. data/app/services/llm_cost_tracker/dashboard/setup_state.rb +6 -68
  29. data/app/services/llm_cost_tracker/dashboard/sort.rb +9 -0
  30. data/app/services/llm_cost_tracker/dashboard/tag_breakdown.rb +20 -12
  31. data/app/services/llm_cost_tracker/dashboard/tag_key_explorer.rb +1 -1
  32. data/app/services/llm_cost_tracker/dashboard/top_models.rb +34 -19
  33. data/app/views/layouts/llm_cost_tracker/application.html.erb +74 -17
  34. data/app/views/llm_cost_tracker/calls/index.html.erb +69 -90
  35. data/app/views/llm_cost_tracker/calls/show.html.erb +132 -125
  36. data/app/views/llm_cost_tracker/dashboard/index.html.erb +120 -159
  37. data/app/views/llm_cost_tracker/data_quality/index.html.erb +140 -194
  38. data/app/views/llm_cost_tracker/errors/database.html.erb +2 -2
  39. data/app/views/llm_cost_tracker/models/index.html.erb +39 -59
  40. data/app/views/llm_cost_tracker/pricing/index.html.erb +93 -0
  41. data/app/views/llm_cost_tracker/shared/_filter_pill_date.html.erb +19 -0
  42. data/app/views/llm_cost_tracker/shared/_filter_pill_model.html.erb +22 -0
  43. data/app/views/llm_cost_tracker/shared/_filter_pill_provider.html.erb +22 -0
  44. data/app/views/llm_cost_tracker/shared/_filter_pill_stream.html.erb +23 -0
  45. data/app/views/llm_cost_tracker/shared/_spend_chart.html.erb +3 -13
  46. data/app/views/llm_cost_tracker/shared/_tag_chips.html.erb +1 -1
  47. data/app/views/llm_cost_tracker/shared/setup_required.html.erb +16 -15
  48. data/app/views/llm_cost_tracker/tags/index.html.erb +27 -32
  49. data/app/views/llm_cost_tracker/tags/show.html.erb +85 -104
  50. data/config/routes.rb +3 -3
  51. data/lib/llm_cost_tracker/budget.rb +25 -28
  52. data/lib/llm_cost_tracker/capture/sdk_payload.rb +34 -0
  53. data/lib/llm_cost_tracker/{parsers → capture}/sse.rb +2 -1
  54. data/lib/llm_cost_tracker/capture/stream_collector.rb +30 -52
  55. data/lib/llm_cost_tracker/capture/stream_tracker.rb +18 -33
  56. data/lib/llm_cost_tracker/capture_verifier.rb +59 -0
  57. data/lib/llm_cost_tracker/charges/cost.rb +27 -0
  58. data/lib/llm_cost_tracker/{billing → charges}/cost_status.rb +14 -4
  59. data/lib/llm_cost_tracker/{billing → charges}/line_item.rb +40 -44
  60. data/lib/llm_cost_tracker/check.rb +5 -0
  61. data/lib/llm_cost_tracker/configuration.rb +13 -61
  62. data/lib/llm_cost_tracker/currency.rb +5 -0
  63. data/lib/llm_cost_tracker/doctor/ingestion_check.rb +15 -49
  64. data/lib/llm_cost_tracker/doctor/price_check.rb +1 -1
  65. data/lib/llm_cost_tracker/doctor/probe.rb +3 -4
  66. data/lib/llm_cost_tracker/doctor/schema_check.rb +3 -6
  67. data/lib/llm_cost_tracker/doctor.rb +66 -64
  68. data/lib/llm_cost_tracker/engine.rb +4 -4
  69. data/lib/llm_cost_tracker/event.rb +12 -20
  70. data/lib/llm_cost_tracker/generators/llm_cost_tracker/install_generator.rb +2 -3
  71. data/lib/llm_cost_tracker/generators/llm_cost_tracker/prices_generator.rb +5 -2
  72. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/create_llm_cost_tracker_calls.rb.erb +4 -5
  73. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/initializer.rb.erb +3 -2
  74. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_call_rollups_provider.rb.erb +4 -0
  75. data/lib/llm_cost_tracker/ingestion/batch.rb +39 -8
  76. data/lib/llm_cost_tracker/ingestion/inbox.rb +8 -9
  77. data/lib/llm_cost_tracker/ingestion/pool.rb +3 -11
  78. data/lib/llm_cost_tracker/ingestion/worker.rb +7 -17
  79. data/lib/llm_cost_tracker/ingestion.rb +24 -36
  80. data/lib/llm_cost_tracker/integrations/anthropic.rb +94 -116
  81. data/lib/llm_cost_tracker/integrations/base.rb +39 -57
  82. data/lib/llm_cost_tracker/integrations/openai/batch_capture.rb +84 -0
  83. data/lib/llm_cost_tracker/integrations/openai/patches.rb +81 -0
  84. data/lib/llm_cost_tracker/integrations/openai.rb +72 -332
  85. data/lib/llm_cost_tracker/integrations/ruby_llm.rb +89 -145
  86. data/lib/llm_cost_tracker/integrations.rb +32 -25
  87. data/lib/llm_cost_tracker/ledger/period/totals.rb +27 -42
  88. data/lib/llm_cost_tracker/ledger/period.rb +5 -10
  89. data/lib/llm_cost_tracker/ledger/rollups.rb +67 -98
  90. data/lib/llm_cost_tracker/ledger/schema/adapter.rb +12 -13
  91. data/lib/llm_cost_tracker/ledger/schema/base.rb +51 -0
  92. data/lib/llm_cost_tracker/ledger/schema/call_line_items.rb +24 -79
  93. data/lib/llm_cost_tracker/ledger/schema/call_rollups.rb +3 -35
  94. data/lib/llm_cost_tracker/ledger/schema/call_tags.rb +4 -41
  95. data/lib/llm_cost_tracker/ledger/schema/calls.rb +30 -99
  96. data/lib/llm_cost_tracker/ledger/schema/ingestion/inbox_entries.rb +26 -0
  97. data/lib/llm_cost_tracker/ledger/schema/ingestion/leases.rb +17 -0
  98. data/lib/llm_cost_tracker/ledger/schema.rb +26 -0
  99. data/lib/llm_cost_tracker/ledger/store.rb +18 -42
  100. data/lib/llm_cost_tracker/ledger/tags/{sql.rb → breakdown.rb} +1 -1
  101. data/lib/llm_cost_tracker/ledger/tags/encoding.rb +4 -6
  102. data/lib/llm_cost_tracker/ledger.rb +14 -11
  103. data/lib/llm_cost_tracker/logging.rb +4 -21
  104. data/lib/llm_cost_tracker/middleware/faraday.rb +63 -51
  105. data/lib/llm_cost_tracker/parsers.rb +140 -29
  106. data/lib/llm_cost_tracker/prices.json +1707 -1
  107. data/lib/llm_cost_tracker/pricing/backfill.rb +52 -80
  108. data/lib/llm_cost_tracker/pricing/calculation.rb +260 -0
  109. data/lib/llm_cost_tracker/pricing/effective_prices.rb +17 -18
  110. data/lib/llm_cost_tracker/pricing/estimator.rb +2 -2
  111. data/lib/llm_cost_tracker/pricing/matcher.rb +84 -0
  112. data/lib/llm_cost_tracker/pricing/mode.rb +53 -35
  113. data/lib/llm_cost_tracker/pricing/price_key.rb +56 -0
  114. data/lib/llm_cost_tracker/pricing/rate.rb +18 -0
  115. data/lib/llm_cost_tracker/pricing/registry.rb +189 -100
  116. data/lib/llm_cost_tracker/pricing/service_rates.rb +69 -0
  117. data/lib/llm_cost_tracker/pricing/source.rb +7 -0
  118. data/lib/llm_cost_tracker/pricing/sync/fetcher.rb +2 -3
  119. data/lib/llm_cost_tracker/pricing/sync/registry_diff.rb +4 -10
  120. data/lib/llm_cost_tracker/pricing/sync/registry_writer.rb +10 -3
  121. data/lib/llm_cost_tracker/pricing/sync.rb +9 -11
  122. data/lib/llm_cost_tracker/pricing/unknown.rb +1 -5
  123. data/lib/llm_cost_tracker/pricing.rb +10 -295
  124. data/lib/llm_cost_tracker/providers/anthropic/parser.rb +93 -0
  125. data/lib/llm_cost_tracker/providers/anthropic/response_parser.rb +30 -0
  126. data/lib/llm_cost_tracker/providers/anthropic/usage_extractor.rb +76 -0
  127. data/lib/llm_cost_tracker/providers/azure/hosts.rb +1 -4
  128. data/lib/llm_cost_tracker/providers/azure/parser.rb +44 -0
  129. data/lib/llm_cost_tracker/providers/gemini/model_families.rb +1 -4
  130. data/lib/llm_cost_tracker/providers/gemini/parser.rb +177 -0
  131. data/lib/llm_cost_tracker/providers/gemini/usage_extractor.rb +76 -0
  132. data/lib/llm_cost_tracker/providers/openai/hosts.rb +1 -7
  133. data/lib/llm_cost_tracker/providers/openai/model_families.rb +5 -8
  134. data/lib/llm_cost_tracker/providers/openai/parser.rb +39 -0
  135. data/lib/llm_cost_tracker/providers/openai/response_parser.rb +152 -0
  136. data/lib/llm_cost_tracker/providers/openai/service_charges.rb +181 -0
  137. data/lib/llm_cost_tracker/providers/openai/usage_extractor.rb +72 -0
  138. data/lib/llm_cost_tracker/providers/openai_compatible/parser.rb +36 -0
  139. data/lib/llm_cost_tracker/providers.rb +35 -0
  140. data/lib/llm_cost_tracker/railtie.rb +0 -7
  141. data/lib/llm_cost_tracker/report/data.rb +3 -4
  142. data/lib/llm_cost_tracker/report/formatter.rb +33 -20
  143. data/lib/llm_cost_tracker/report.rb +1 -1
  144. data/lib/llm_cost_tracker/retention.rb +6 -19
  145. data/lib/llm_cost_tracker/tags/context.rb +9 -6
  146. data/lib/llm_cost_tracker/tags/sanitizer.rb +10 -0
  147. data/lib/llm_cost_tracker/timing.rb +2 -4
  148. data/lib/llm_cost_tracker/tracker.rb +24 -36
  149. data/lib/llm_cost_tracker/usage/catalog.rb +58 -0
  150. data/lib/llm_cost_tracker/usage/dimension.rb +21 -0
  151. data/lib/llm_cost_tracker/{billing/components.yml → usage/dimensions.yml} +24 -46
  152. data/lib/llm_cost_tracker/usage/source.rb +14 -0
  153. data/lib/llm_cost_tracker/usage/token_usage.rb +100 -0
  154. data/lib/llm_cost_tracker/version.rb +1 -1
  155. data/lib/llm_cost_tracker.rb +43 -52
  156. data/lib/tasks/llm_cost_tracker.rake +14 -73
  157. metadata +92 -58
  158. data/app/controllers/llm_cost_tracker/reconciliation_controller.rb +0 -106
  159. data/app/helpers/llm_cost_tracker/dashboard_filter_helper.rb +0 -28
  160. data/app/helpers/llm_cost_tracker/reconciliation_helper.rb +0 -13
  161. data/app/models/llm_cost_tracker/provider_invoice.rb +0 -13
  162. data/app/models/llm_cost_tracker/provider_invoice_import.rb +0 -29
  163. data/app/views/llm_cost_tracker/reconciliation/index.html.erb +0 -183
  164. data/app/views/llm_cost_tracker/shared/_active_filters.html.erb +0 -16
  165. data/app/views/llm_cost_tracker/shared/_filters.html.erb +0 -66
  166. data/app/views/llm_cost_tracker/shared/_sort.html.erb +0 -13
  167. data/lib/llm_cost_tracker/billing/components.rb +0 -95
  168. data/lib/llm_cost_tracker/capture/stream.rb +0 -9
  169. data/lib/llm_cost_tracker/doctor/capture_verifier.rb +0 -61
  170. data/lib/llm_cost_tracker/doctor/check.rb +0 -7
  171. data/lib/llm_cost_tracker/doctor/cost_drift_check.rb +0 -56
  172. data/lib/llm_cost_tracker/doctor/invoice_reconciliation_check.rb +0 -164
  173. data/lib/llm_cost_tracker/doctor/legacy_audit_check.rb +0 -34
  174. data/lib/llm_cost_tracker/doctor/legacy_billing_status_check.rb +0 -20
  175. data/lib/llm_cost_tracker/doctor/pricing_snapshot_drift_check.rb +0 -85
  176. data/lib/llm_cost_tracker/generators/llm_cost_tracker/reconciliation_generator.rb +0 -34
  177. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/create_llm_cost_tracker_reconciliation.rb.erb +0 -60
  178. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_provider_invoice_imports_provider.rb.erb +0 -32
  179. data/lib/llm_cost_tracker/generators/llm_cost_tracker/templates/upgrade_provider_invoices_metadata_index.rb.erb +0 -25
  180. data/lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_provider_invoice_imports_provider_generator.rb +0 -31
  181. data/lib/llm_cost_tracker/generators/llm_cost_tracker/upgrade_provider_invoices_metadata_index_generator.rb +0 -31
  182. data/lib/llm_cost_tracker/ledger/rollups/upsert_sql.rb +0 -40
  183. data/lib/llm_cost_tracker/ledger/schema/ingestion_inbox_entries.rb +0 -57
  184. data/lib/llm_cost_tracker/ledger/schema/ingestion_leases.rb +0 -52
  185. data/lib/llm_cost_tracker/ledger/schema/provider_invoice_imports.rb +0 -56
  186. data/lib/llm_cost_tracker/ledger/schema/provider_invoices.rb +0 -72
  187. data/lib/llm_cost_tracker/masking.rb +0 -39
  188. data/lib/llm_cost_tracker/parsers/anthropic.rb +0 -193
  189. data/lib/llm_cost_tracker/parsers/azure.rb +0 -46
  190. data/lib/llm_cost_tracker/parsers/base.rb +0 -131
  191. data/lib/llm_cost_tracker/parsers/gemini.rb +0 -232
  192. data/lib/llm_cost_tracker/parsers/openai.rb +0 -41
  193. data/lib/llm_cost_tracker/parsers/openai_compatible.rb +0 -51
  194. data/lib/llm_cost_tracker/parsers/openai_service_charges.rb +0 -155
  195. data/lib/llm_cost_tracker/parsers/openai_usage.rb +0 -228
  196. data/lib/llm_cost_tracker/pricing/explainer.rb +0 -74
  197. data/lib/llm_cost_tracker/pricing/lookup.rb +0 -236
  198. data/lib/llm_cost_tracker/pricing/service_charges.rb +0 -206
  199. data/lib/llm_cost_tracker/providers/anthropic/tier_classification.rb +0 -22
  200. data/lib/llm_cost_tracker/reconcile_tasks.rb +0 -134
  201. data/lib/llm_cost_tracker/reconciliation/diff.rb +0 -409
  202. data/lib/llm_cost_tracker/reconciliation/diff_result.rb +0 -44
  203. data/lib/llm_cost_tracker/reconciliation/import_result.rb +0 -19
  204. data/lib/llm_cost_tracker/reconciliation/importer.rb +0 -254
  205. data/lib/llm_cost_tracker/reconciliation/sources/anthropic_usage.rb +0 -172
  206. data/lib/llm_cost_tracker/reconciliation/sources/fingerprint.rb +0 -20
  207. data/lib/llm_cost_tracker/reconciliation/sources/openai_usage.rb +0 -142
  208. data/lib/llm_cost_tracker/reconciliation.rb +0 -118
  209. data/lib/llm_cost_tracker/token_usage.rb +0 -93
@@ -1,107 +1,162 @@
1
1
  :root {
2
- --lct-bg: #f6f9fc;
2
+ --lct-bg: #f7f9fc;
3
+ --lct-surface: #ffffff;
4
+ --lct-surface-2: #f1f4f9;
5
+ --lct-surface-hover: #eef2f7;
3
6
  --lct-panel: #ffffff;
4
- --lct-surface: #eef2f7;
5
- --lct-border: #e3e8ee;
6
- --lct-text: #0a2540;
7
- --lct-muted: #697386;
8
- --lct-accent: #635bff;
9
- --lct-accent-hover: #5048e5;
10
- --lct-accent-soft: #f0edff;
11
- --lct-success: #0f766e;
12
- --lct-success-soft: #ccfbf1;
13
- --lct-warning: #d97706;
14
- --lct-warning-soft: #ffedd5;
15
- --lct-warning-border: #fdba74;
16
- --lct-danger: #dc2626;
17
- --lct-danger-soft: #fee2e2;
18
- --lct-danger-border: #fca5a5;
19
- --lct-warning-copy: #9a3412;
7
+ --lct-panel-head-bg: #fbfcfe;
8
+ --lct-border: #e3e8ef;
9
+ --lct-border-strong: #cbd2dc;
10
+ --lct-text: #0d1b2a;
11
+ --lct-muted: #475467;
12
+ --lct-subtle: #5a6573;
13
+ --lct-accent: #5b54d8;
14
+ --lct-accent-strong: #4540c4;
15
+ --lct-accent-hover: #4540c4;
16
+ --lct-accent-soft: #ecebff;
17
+ --lct-success: #047857;
18
+ --lct-success-soft: #d1fae5;
19
+ --lct-success-border: rgba(4, 120, 87, 0.25);
20
+ --lct-warning: #b45309;
21
+ --lct-warning-soft: #fef3c7;
22
+ --lct-warning-border: rgba(180, 83, 9, 0.30);
23
+ --lct-warning-copy: #b45309;
20
24
  --lct-warning-strong: #7c2d12;
25
+ --lct-danger: #b91c1c;
26
+ --lct-danger-soft: #fde8e8;
27
+ --lct-danger-border: rgba(185, 28, 28, 0.30);
21
28
  --lct-danger-copy: #b91c1c;
22
29
  --lct-danger-strong: #991b1b;
23
30
  --lct-row-hover: #f8fafc;
24
- --lct-th-bg: #fbfcfe;
25
- --lct-toolbar-bg: rgba(255, 255, 255, 0.72);
26
- --lct-toolbar-border: #e7ecf3;
27
- --lct-border-strong: #d4dae2;
28
- --lct-chart-secondary: rgba(10, 37, 64, 0.42);
29
- --lct-chart-marker: rgba(10, 37, 64, 0.45);
30
- --lct-chip-remove: rgba(10, 37, 64, 0.58);
31
- --lct-shadow: 0 1px 2px rgba(10, 37, 64, 0.05), 0 1px 1px rgba(10, 37, 64, 0.03);
32
- --lct-shadow-sm: 0 1px 2px rgba(10, 37, 64, 0.06);
33
- --lct-shadow-md: 0 4px 12px rgba(10, 37, 64, 0.08), 0 1px 2px rgba(10, 37, 64, 0.04);
34
- --lct-shadow-lg: 0 12px 32px rgba(10, 37, 64, 0.12), 0 2px 6px rgba(10, 37, 64, 0.05);
35
- --lct-focus-ring: 0 0 0 3px rgba(99, 91, 255, 0.25);
31
+ --lct-toolbar-bg: rgba(255, 255, 255, 0.92);
32
+ --lct-toolbar-border: #e3e8ef;
33
+ --lct-chart-secondary: rgba(13, 27, 42, 0.42);
34
+ --lct-chart-marker: rgba(13, 27, 42, 0.45);
35
+ --lct-chip-remove: rgba(13, 27, 42, 0.58);
36
+
37
+ --lct-provider-anthropic: #d97757;
38
+ --lct-provider-openai: #10a37f;
39
+ --lct-provider-gemini: #4285f4;
40
+ --lct-provider-ruby_llm: #a91401;
41
+
42
+ --lct-shadow: 0 1px 2px rgba(13, 27, 42, 0.04);
43
+ --lct-shadow-sm: 0 1px 2px rgba(13, 27, 42, 0.04);
44
+ --lct-shadow-md: 0 2px 6px rgba(13, 27, 42, 0.06), 0 1px 2px rgba(13, 27, 42, 0.04);
45
+ --lct-shadow-lg: 0 12px 32px rgba(13, 27, 42, 0.12), 0 2px 6px rgba(13, 27, 42, 0.05);
46
+ --lct-focus-ring: 0 0 0 3px rgba(91, 84, 216, 0.22);
36
47
 
37
48
  --sp-1: 4px;
38
49
  --sp-2: 8px;
39
50
  --sp-3: 12px;
40
51
  --sp-4: 16px;
41
- --sp-5: 24px;
42
- --sp-6: 32px;
43
-
44
- --fs-2xs: 10px;
45
- --fs-xs: 11px;
46
- --fs-sm: 13px;
47
- --fs-md: 14px;
48
- --fs-lg: 18px;
52
+ --sp-5: 20px;
53
+ --sp-6: 24px;
54
+
55
+ --fs-2xs: 10.5px;
56
+ --fs-xs: 11.5px;
57
+ --fs-sm: 12.5px;
58
+ --fs-md: 13.5px;
59
+ --fs-lg: 17px;
49
60
  --fs-xl: 22px;
50
61
  --fs-xxl: 28px;
62
+ --fs-stat: 26px;
51
63
  --fs-display: 30px;
52
64
  --fs-hero: 44px;
53
- --lct-control-height: 40px;
54
65
 
55
- --mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
66
+ --radius-sm: 5px;
67
+ --radius-md: 7px;
68
+ --radius-lg: 10px;
69
+ --radius-pill: 999px;
70
+
71
+ --lct-control-height: 34px;
72
+
73
+ --mono: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", monospace;
56
74
  }
57
75
 
58
76
  @media (prefers-color-scheme: dark) {
59
- :root {
60
- --lct-bg: #0b1220;
61
- --lct-panel: #111a2e;
62
- --lct-surface: #1a253c;
63
- --lct-border: #233149;
64
- --lct-text: #e6ecf5;
65
- --lct-muted: #8a98b3;
66
- --lct-accent: #8a82ff;
67
- --lct-accent-hover: #a39cff;
68
- --lct-accent-soft: rgba(138, 130, 255, 0.16);
69
- --lct-success: #34d399;
70
- --lct-success-soft: rgba(52, 211, 153, 0.16);
71
- --lct-warning: #fbbf24;
72
- --lct-warning-soft: rgba(251, 191, 36, 0.16);
73
- --lct-warning-border: rgba(251, 191, 36, 0.4);
74
- --lct-danger: #f87171;
75
- --lct-danger-soft: rgba(248, 113, 113, 0.16);
76
- --lct-danger-border: rgba(248, 113, 113, 0.4);
77
- --lct-row-hover: #182238;
78
- --lct-th-bg: #142036;
79
- --lct-toolbar-bg: rgba(17, 26, 46, 0.78);
80
- --lct-toolbar-border: #233149;
81
- --lct-border-strong: #2f3f5c;
82
- --lct-warning-copy: #fcd34d;
77
+ :root:not([data-theme="light"]) {
78
+ --lct-bg: #0f1419;
79
+ --lct-surface: #161b22;
80
+ --lct-surface-2: #1c2229;
81
+ --lct-surface-hover: #232a35;
82
+ --lct-panel: #161b22;
83
+ --lct-panel-head-bg: #1f262e;
84
+ --lct-border: #2a313c;
85
+ --lct-border-strong: #3d4654;
86
+ --lct-text: #e6edf3;
87
+ --lct-muted: #8b949e;
88
+ --lct-subtle: #6e7681;
89
+ --lct-accent: #7c83ff;
90
+ --lct-accent-strong: #a4abff;
91
+ --lct-accent-hover: #a4abff;
92
+ --lct-accent-soft: rgba(124, 131, 255, 0.16);
93
+ --lct-success: #56d364;
94
+ --lct-success-soft: rgba(86, 211, 100, 0.14);
95
+ --lct-success-border: rgba(86, 211, 100, 0.35);
96
+ --lct-warning: #d29922;
97
+ --lct-warning-soft: rgba(210, 153, 34, 0.14);
98
+ --lct-warning-border: rgba(210, 153, 34, 0.35);
99
+ --lct-warning-copy: #d29922;
83
100
  --lct-warning-strong: #fde68a;
84
- --lct-danger-copy: #fca5a5;
101
+ --lct-danger: #f85149;
102
+ --lct-danger-soft: rgba(248, 81, 73, 0.14);
103
+ --lct-danger-border: rgba(248, 81, 73, 0.40);
104
+ --lct-danger-copy: #f85149;
85
105
  --lct-danger-strong: #fecaca;
86
- --lct-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 1px rgba(0, 0, 0, 0.25);
87
- --lct-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
88
- --lct-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.25);
106
+ --lct-row-hover: #1c2229;
107
+ --lct-toolbar-bg: rgba(22, 27, 34, 0.92);
108
+ --lct-toolbar-border: #2a313c;
109
+ --lct-shadow: 0 1px 2px rgba(0, 0, 0, 0.30);
110
+ --lct-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30);
111
+ --lct-shadow-md: 0 2px 6px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.25);
89
112
  --lct-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.3);
90
- --lct-focus-ring: 0 0 0 3px rgba(138, 130, 255, 0.35);
113
+ --lct-focus-ring: 0 0 0 3px rgba(124, 131, 255, 0.30);
91
114
  --lct-chart-secondary: rgba(230, 236, 245, 0.32);
92
115
  --lct-chart-marker: rgba(230, 236, 245, 0.45);
93
116
  --lct-chip-remove: rgba(230, 236, 245, 0.58);
94
117
  }
95
-
96
- .lct-field select {
97
- background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%238a98b3' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M2.5 4.5l3.5 3.5 3.5-3.5'/></svg>");
98
- }
99
-
100
- .lct-field input[type="date"]::-webkit-calendar-picker-indicator {
101
- filter: invert(70%) sepia(8%) saturate(437%) hue-rotate(176deg) brightness(95%) contrast(86%);
102
- }
103
118
  }
104
119
 
120
+ :root[data-theme="dark"] {
121
+ --lct-bg: #0f1419;
122
+ --lct-surface: #161b22;
123
+ --lct-surface-2: #1c2229;
124
+ --lct-surface-hover: #232a35;
125
+ --lct-panel: #161b22;
126
+ --lct-panel-head-bg: #1f262e;
127
+ --lct-border: #2a313c;
128
+ --lct-border-strong: #3d4654;
129
+ --lct-text: #e6edf3;
130
+ --lct-muted: #8b949e;
131
+ --lct-subtle: #6e7681;
132
+ --lct-accent: #7c83ff;
133
+ --lct-accent-strong: #a4abff;
134
+ --lct-accent-hover: #a4abff;
135
+ --lct-accent-soft: rgba(124, 131, 255, 0.16);
136
+ --lct-success: #56d364;
137
+ --lct-success-soft: rgba(86, 211, 100, 0.14);
138
+ --lct-success-border: rgba(86, 211, 100, 0.35);
139
+ --lct-warning: #d29922;
140
+ --lct-warning-soft: rgba(210, 153, 34, 0.14);
141
+ --lct-warning-border: rgba(210, 153, 34, 0.35);
142
+ --lct-warning-copy: #d29922;
143
+ --lct-warning-strong: #fde68a;
144
+ --lct-danger: #f85149;
145
+ --lct-danger-soft: rgba(248, 81, 73, 0.14);
146
+ --lct-danger-border: rgba(248, 81, 73, 0.40);
147
+ --lct-danger-copy: #f85149;
148
+ --lct-danger-strong: #fecaca;
149
+ --lct-row-hover: #1c2229;
150
+ --lct-toolbar-bg: rgba(22, 27, 34, 0.92);
151
+ --lct-toolbar-border: #2a313c;
152
+ --lct-shadow: 0 1px 2px rgba(0, 0, 0, 0.30);
153
+ --lct-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30);
154
+ --lct-shadow-md: 0 2px 6px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.25);
155
+ --lct-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5), 0 2px 6px rgba(0, 0, 0, 0.3);
156
+ --lct-focus-ring: 0 0 0 3px rgba(124, 131, 255, 0.30);
157
+ }
158
+
159
+ * { box-sizing: border-box; }
105
160
  .lct-body { margin: 0; }
106
161
 
107
162
  .lct-app {
@@ -113,885 +168,812 @@
113
168
  min-height: 100vh;
114
169
  }
115
170
 
116
- .lct-shell {
117
- max-width: 1180px;
118
- margin: 0 auto;
119
- padding: 24px;
120
- }
121
-
122
- .lct-header {
171
+ .lct-toolbar {
123
172
  display: flex;
124
- align-items: flex-start;
125
- justify-content: space-between;
126
- gap: 24px;
127
- margin-bottom: 20px;
128
- }
129
-
130
- .lct-header-copy { display: grid; gap: 6px; }
131
-
132
- .lct-title {
133
- margin: 0;
134
- font-size: var(--fs-display);
135
- font-weight: 700;
136
- letter-spacing: -0.01em;
137
- line-height: 1.2;
173
+ align-items: center;
174
+ height: 48px;
175
+ padding: 0 var(--sp-5);
176
+ background: var(--lct-toolbar-bg);
177
+ border-bottom: 1px solid var(--lct-toolbar-border);
178
+ position: sticky;
179
+ top: 0;
180
+ z-index: 100;
181
+ backdrop-filter: blur(10px);
138
182
  }
139
-
140
- .lct-nav { display: flex; gap: 4px; flex-wrap: wrap; }
141
-
142
- .lct-nav a {
143
- color: var(--lct-muted);
144
- text-decoration: none;
183
+ .lct-toolbar-brand {
184
+ display: flex;
185
+ align-items: center;
186
+ gap: var(--sp-2);
187
+ font-weight: 600;
145
188
  font-size: var(--fs-md);
146
- font-weight: 500;
147
- padding: 8px 12px;
148
- border-radius: 6px;
189
+ color: var(--lct-text);
190
+ text-decoration: none;
149
191
  }
150
-
151
- .lct-nav a:hover { color: var(--lct-accent); background: rgba(99, 91, 255, 0.06); }
152
- .lct-nav .lct-active { background: var(--lct-accent-soft); color: var(--lct-accent); font-weight: 700; }
153
-
154
- .lct-panel {
155
- background: var(--lct-panel);
192
+ .lct-toolbar-brand .lct-brandmark {
193
+ width: 22px;
194
+ height: 22px;
195
+ border-radius: var(--radius-sm);
196
+ background: linear-gradient(135deg, var(--lct-accent), color-mix(in oklab, var(--lct-accent) 75%, white));
197
+ display: grid;
198
+ place-items: center;
199
+ color: white;
200
+ box-shadow: 0 2px 6px rgba(91, 84, 216, 0.25);
201
+ }
202
+ .lct-toolbar-brand .lct-brandmark svg { width: 13px; height: 13px; }
203
+ .lct-toolbar-right { margin-left: auto; display: flex; align-items: center; gap: var(--sp-2); }
204
+
205
+ .lct-theme-toggle {
206
+ display: inline-grid;
207
+ place-items: center;
208
+ width: 30px;
209
+ height: 30px;
210
+ padding: 0;
211
+ background: transparent;
156
212
  border: 1px solid var(--lct-border);
157
- border-radius: 8px;
158
- padding: 20px;
159
- box-shadow: var(--lct-shadow);
213
+ border-radius: var(--radius-sm);
214
+ color: var(--lct-muted);
215
+ cursor: pointer;
160
216
  }
217
+ .lct-theme-toggle:hover { background: var(--lct-surface-2); color: var(--lct-text); border-color: var(--lct-border-strong); }
218
+ .lct-theme-toggle svg { width: 15px; height: 15px; }
219
+ .lct-theme-toggle .lct-icon-sun { display: none; }
220
+ .lct-theme-toggle .lct-icon-moon { display: block; }
221
+ @media (prefers-color-scheme: dark) {
222
+ :root:not([data-theme="light"]) .lct-theme-toggle .lct-icon-sun { display: block; }
223
+ :root:not([data-theme="light"]) .lct-theme-toggle .lct-icon-moon { display: none; }
224
+ }
225
+ :root[data-theme="dark"] .lct-theme-toggle .lct-icon-sun { display: block; }
226
+ :root[data-theme="dark"] .lct-theme-toggle .lct-icon-moon { display: none; }
161
227
 
162
- .lct-panel-tight { padding: 16px 18px; }
163
-
164
- .lct-panel + .lct-panel,
165
- .lct-stat-grid + .lct-panel { margin-top: 16px; }
166
- .lct-grid > .lct-panel + .lct-panel,
167
- .lct-grid > .lct-stat-grid + .lct-panel { margin-top: 0; }
168
-
169
- .lct-breadcrumb {
228
+ .lct-shell {
229
+ display: grid;
230
+ grid-template-columns: 200px 1fr;
231
+ min-height: calc(100vh - 48px);
232
+ }
233
+ .lct-sidebar {
234
+ border-right: 1px solid var(--lct-border);
235
+ background: var(--lct-surface);
236
+ }
237
+ .lct-sidebar-inner {
238
+ position: sticky;
239
+ top: 48px;
240
+ max-height: calc(100vh - 48px);
241
+ overflow-y: auto;
242
+ padding: var(--sp-3) var(--sp-2);
243
+ }
244
+ .lct-sidebar-section {
245
+ font-size: var(--fs-2xs);
246
+ text-transform: uppercase;
247
+ letter-spacing: 0.10em;
248
+ color: var(--lct-subtle);
249
+ font-weight: 700;
250
+ padding: var(--sp-3) var(--sp-3) var(--sp-1);
251
+ }
252
+ .lct-sidebar-section + .lct-sidebar-link,
253
+ .lct-sidebar-link + .lct-sidebar-section { margin-top: var(--sp-2); }
254
+ .lct-sidebar-link {
255
+ display: flex;
170
256
  align-items: center;
257
+ gap: var(--sp-2);
258
+ padding: 7px var(--sp-3);
259
+ border-radius: var(--radius-sm);
171
260
  color: var(--lct-muted);
172
- display: flex;
173
261
  font-size: var(--fs-sm);
174
- gap: 8px;
175
- margin-bottom: 14px;
176
- }
177
- .lct-breadcrumb-link {
178
- color: var(--lct-muted);
262
+ font-weight: 500;
179
263
  text-decoration: none;
180
- transition: color 0.15s ease;
264
+ cursor: pointer;
181
265
  }
182
- .lct-breadcrumb-link:hover { color: var(--lct-text); }
183
- .lct-breadcrumb-link:focus-visible {
184
- color: var(--lct-text);
185
- outline: 2px solid var(--lct-accent-soft);
186
- outline-offset: 2px;
187
- border-radius: 2px;
266
+ .lct-sidebar-link:hover { color: var(--lct-text); background: var(--lct-surface-2); }
267
+ .lct-sidebar-link.lct-active {
268
+ color: var(--lct-accent-strong);
269
+ background: var(--lct-accent-soft);
270
+ font-weight: 600;
271
+ box-shadow: inset 2px 0 0 var(--lct-accent);
188
272
  }
189
- .lct-breadcrumb-sep { color: var(--lct-border-strong); }
190
- .lct-breadcrumb-current { color: var(--lct-text); font-weight: 500; }
273
+ .lct-sidebar-link svg { width: 13px; height: 13px; flex-shrink: 0; color: var(--lct-subtle); }
274
+ .lct-sidebar-link.lct-active svg { color: var(--lct-accent); }
191
275
 
192
- .lct-banner {
276
+ .lct-content { padding: var(--sp-4) var(--sp-5) var(--sp-6); max-width: none; }
277
+
278
+ .lct-alert {
279
+ display: flex;
193
280
  align-items: center;
194
- border-radius: 8px;
281
+ gap: var(--sp-3);
282
+ padding: 10px var(--sp-4);
283
+ border-radius: var(--radius-md);
195
284
  border: 1px solid;
196
- display: flex;
197
- gap: 20px;
198
- justify-content: space-between;
199
- margin-bottom: 16px;
200
- padding: 12px 16px;
201
- }
202
-
203
- .lct-banner-body { flex: 1; min-width: 0; }
204
- .lct-banner-title { font-size: var(--fs-md); font-weight: 600; margin: 0; }
205
- .lct-banner-muted { color: var(--lct-muted); font-weight: 400; }
206
-
207
- .lct-banner-warning { background: var(--lct-warning-soft); border-color: var(--lct-warning-border); color: var(--lct-warning-strong); }
208
- .lct-banner-warning .lct-banner-muted,
209
- .lct-banner-warning .lct-banner-copy { color: var(--lct-warning-copy); }
210
-
211
- .lct-banner-danger { background: var(--lct-danger-soft); border-color: var(--lct-danger-border); color: var(--lct-danger-strong); }
212
- .lct-banner-danger .lct-banner-muted,
213
- .lct-banner-danger .lct-banner-copy { color: var(--lct-danger-copy); }
214
-
215
- .lct-muted { color: var(--lct-muted); }
216
-
217
- .lct-code {
218
- background: var(--lct-surface);
219
- border-radius: 4px;
220
- padding: 2px 6px;
285
+ font-size: var(--fs-sm);
286
+ margin-bottom: var(--sp-3);
287
+ }
288
+ .lct-alert-warn { background: var(--lct-warning-soft); border-color: var(--lct-warning-border); color: var(--lct-warning); }
289
+ .lct-alert-danger { background: var(--lct-danger-soft); border-color: var(--lct-danger-border); color: var(--lct-danger); }
290
+ .lct-alert-info { background: var(--lct-accent-soft); border-color: color-mix(in oklab, var(--lct-accent) 22%, transparent); color: var(--lct-accent-strong); }
291
+ .lct-alert svg { flex-shrink: 0; }
292
+ .lct-alert strong { font-weight: 600; }
293
+ .lct-alert code {
221
294
  font-family: var(--mono);
222
- font-size: 0.92em;
223
- }
224
-
225
- .lct-grid { display: grid; gap: 16px; margin-bottom: 16px; }
226
-
227
- .lct-hero {
228
- align-items: stretch;
229
- display: grid;
230
- gap: 14px;
231
- grid-template-columns: minmax(0, 0.65fr) minmax(320px, 1fr);
232
- margin-bottom: 16px;
295
+ font-size: var(--fs-xs);
296
+ background: color-mix(in oklab, currentColor 10%, transparent);
297
+ padding: 1px 5px;
298
+ border-radius: 3px;
299
+ color: inherit;
233
300
  }
234
-
235
- .lct-hero-primary { align-content: space-between; display: grid; gap: 14px; }
236
-
237
- .lct-hero-value {
238
- font-size: var(--fs-hero);
239
- font-variant-numeric: tabular-nums;
240
- font-weight: 750;
241
- letter-spacing: -0.02em;
242
- line-height: 1.05;
243
- margin: 0;
301
+ .lct-alert-action {
302
+ margin-left: auto;
303
+ padding: 5px 11px;
304
+ background: var(--lct-surface);
305
+ border: 1px solid currentColor;
306
+ border-radius: var(--radius-sm);
307
+ font-weight: 600;
308
+ font-size: var(--fs-xs);
309
+ color: inherit;
310
+ cursor: pointer;
311
+ text-decoration: none;
244
312
  }
245
313
 
246
- .lct-hero-side { display: grid; gap: 14px; }
247
-
248
314
  .lct-stat-grid {
249
315
  display: grid;
250
- gap: 14px;
251
- grid-auto-rows: 1fr;
252
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
316
+ grid-template-columns: repeat(4, minmax(0, 1fr));
317
+ gap: var(--sp-2);
318
+ margin-bottom: var(--sp-3);
253
319
  }
254
-
255
- .lct-hero-side .lct-stat-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
256
- .lct-stat-grid-spaced { margin-bottom: 16px; }
257
- .lct-two-col { align-items: start; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
320
+ @media (max-width: 1024px) { .lct-stat-grid { grid-template-columns: repeat(2, 1fr); } }
321
+ @media (max-width: 640px) { .lct-stat-grid { grid-template-columns: 1fr; } }
258
322
 
259
323
  .lct-stat {
260
- align-items: flex-start;
261
- background: var(--lct-panel);
324
+ background: var(--lct-surface);
262
325
  border: 1px solid var(--lct-border);
263
- border-radius: 8px;
326
+ border-radius: var(--radius-md);
327
+ padding: var(--sp-3) var(--sp-3) var(--sp-3) var(--sp-4);
328
+ position: relative;
329
+ overflow: hidden;
330
+ box-shadow: var(--lct-shadow-sm);
264
331
  display: flex;
265
332
  flex-direction: column;
266
- padding: 16px;
333
+ align-items: flex-start;
334
+ }
335
+ .lct-stat::before {
336
+ content: "";
337
+ position: absolute;
338
+ left: 0; top: 0; bottom: 0;
339
+ width: 3px;
340
+ background: var(--lct-accent);
341
+ }
342
+ .lct-stat-ok::before { background: var(--lct-success); }
343
+ .lct-stat-warn::before { background: var(--lct-warning); }
344
+ .lct-stat-danger::before { background: var(--lct-danger); }
345
+ .lct-stat-head {
346
+ display: flex;
347
+ align-items: center;
348
+ justify-content: space-between;
349
+ margin-bottom: var(--sp-2);
350
+ width: 100%;
351
+ }
352
+ .lct-stat-label {
353
+ font-size: var(--fs-2xs);
354
+ color: var(--lct-muted);
355
+ font-weight: 700;
356
+ text-transform: uppercase;
357
+ letter-spacing: 0.08em;
358
+ margin: 0;
267
359
  }
268
- .lct-stat .lct-stat-value { order: 1; }
269
- .lct-stat .lct-stat-label { order: 2; margin: 6px 0 0; }
270
- .lct-stat .lct-delta-badge { order: 3; }
271
-
272
360
  .lct-stat-value {
273
- font-size: var(--fs-xxl);
274
- font-variant-numeric: tabular-nums;
361
+ font-size: var(--fs-stat);
275
362
  font-weight: 700;
363
+ line-height: 1.1;
364
+ font-variant-numeric: tabular-nums;
276
365
  letter-spacing: -0.01em;
366
+ color: var(--lct-text);
277
367
  margin: 0;
278
368
  }
279
-
280
- .lct-stat-sub { color: var(--lct-muted); font-size: var(--fs-xs); margin: 4px 0 0; }
281
-
282
- .lct-stat-label,
283
- .lct-field label,
284
- .lct-call-summary-label,
285
- .lct-call-breakdown-title,
286
- .lct-chip-label {
369
+ .lct-stat-unit {
370
+ font-size: var(--fs-sm);
371
+ font-weight: 500;
287
372
  color: var(--lct-muted);
373
+ margin-left: 3px;
374
+ }
375
+ .lct-stat-foot {
288
376
  font-size: var(--fs-xs);
289
- font-weight: 600;
290
- letter-spacing: 0;
291
- text-transform: none;
292
- }
293
- .lct-stat-label { margin: 0 0 6px; }
294
- .lct-call-breakdown-title { color: var(--lct-text); font-size: var(--fs-md); margin: 0 0 10px; }
295
- .lct-chip-label { color: var(--lct-accent); font-weight: 700; }
296
- .lct-field label { color: var(--lct-text); font-size: var(--fs-md); font-weight: 500; }
297
-
298
- .lct-section-copy,
299
- .lct-stat-copy,
300
- .lct-banner-copy,
301
- .lct-call-breakdown-empty {
302
377
  color: var(--lct-muted);
303
- margin: 0;
378
+ margin-top: 6px;
379
+ font-variant-numeric: tabular-nums;
304
380
  }
305
- .lct-section-copy { font-size: var(--fs-md); margin-top: 4px; }
306
- .lct-stat-copy { font-size: var(--fs-sm); margin-top: 6px; }
307
- .lct-banner-copy { font-size: var(--fs-sm); margin-top: 4px; }
308
- .lct-call-breakdown-empty { font-size: var(--fs-sm); }
309
-
310
- .lct-section-title { margin: 0 0 8px; font-size: var(--fs-lg); font-weight: 600; letter-spacing: -0.01em; }
381
+ .lct-stat-section-label {
382
+ font-size: var(--fs-2xs);
383
+ font-weight: 700;
384
+ text-transform: uppercase;
385
+ letter-spacing: 0.08em;
386
+ color: var(--lct-muted);
387
+ margin: var(--sp-3) 0 var(--sp-2);
388
+ }
389
+ .lct-stat-section-label:first-child { margin-top: 0; }
311
390
 
312
- .lct-section-head {
313
- align-items: flex-start;
391
+ .lct-tabs {
314
392
  display: flex;
315
- justify-content: space-between;
316
- gap: 16px;
317
- margin-bottom: 14px;
393
+ gap: var(--sp-1);
394
+ border-bottom: 1px solid var(--lct-border);
395
+ margin-bottom: var(--sp-3);
318
396
  }
319
-
320
- .lct-table { border-collapse: collapse; width: 100%; font-size: var(--fs-sm); }
321
-
322
- .lct-num { font-variant-numeric: tabular-nums; text-align: right !important; white-space: nowrap; }
323
- .lct-num-muted { color: var(--lct-muted); }
324
-
325
- .lct-table-compact th,
326
- .lct-table-compact td { padding: 10px 12px; }
327
-
328
- .lct-badge {
329
- align-items: center;
330
- border-radius: 999px;
331
- display: inline-flex;
332
- font-size: var(--fs-xs);
397
+ .lct-tab {
398
+ padding: 8px 14px 9px;
399
+ font-size: var(--fs-sm);
400
+ font-weight: 500;
401
+ color: var(--lct-muted);
402
+ text-decoration: none;
403
+ border-bottom: 2px solid transparent;
404
+ margin-bottom: -1px;
405
+ }
406
+ .lct-tab:hover { color: var(--lct-text); }
407
+ .lct-tab.lct-active {
408
+ color: var(--lct-accent-strong);
409
+ border-bottom-color: var(--lct-accent);
333
410
  font-weight: 600;
334
- letter-spacing: 0.02em;
335
- line-height: 1;
336
- padding: 4px 10px;
337
- text-transform: uppercase;
338
- vertical-align: middle;
339
411
  }
340
- .lct-badge-ok { background: var(--lct-success-soft); color: var(--lct-success); }
341
- .lct-badge-warn { background: var(--lct-warning-soft); color: var(--lct-warning-strong); }
412
+ .lct-tab-count {
413
+ margin-left: 6px;
414
+ font-size: var(--fs-2xs);
415
+ color: var(--lct-subtle);
416
+ font-variant-numeric: tabular-nums;
417
+ }
418
+ .lct-stat-spark { height: 28px; margin-top: 8px; display: block; width: 100%; color: var(--lct-accent); }
342
419
 
343
- .lct-delta-badge {
344
- align-items: center;
345
- border-radius: 999px;
420
+ .lct-delta-badge,
421
+ .lct-delta {
346
422
  display: inline-flex;
423
+ align-items: center;
424
+ gap: 2px;
347
425
  font-size: var(--fs-xs);
426
+ font-weight: 700;
348
427
  font-variant-numeric: tabular-nums;
349
- font-weight: 600;
350
- gap: 6px;
351
- letter-spacing: 0.01em;
352
- line-height: 1;
353
- margin: 10px 0 0;
354
- padding: 4px 10px 4px 8px;
355
- }
356
- .lct-delta-dot {
357
- border-radius: 999px;
358
- display: inline-block;
359
- height: 6px;
360
- width: 6px;
361
- background: currentColor;
362
- flex-shrink: 0;
363
428
  }
364
- .lct-delta-neutral { background: var(--lct-surface); color: var(--lct-muted); box-shadow: inset 0 0 0 1px rgba(105, 115, 134, 0.2); }
365
- .lct-delta-up { background: var(--lct-danger-soft); color: #991b1b; box-shadow: inset 0 0 0 1px rgba(220, 38, 38, 0.2); }
366
- .lct-delta-down { background: var(--lct-success-soft); color: #115e59; box-shadow: inset 0 0 0 1px rgba(15, 118, 110, 0.2); }
367
-
368
- .lct-table-wrap { overflow-x: auto; }
429
+ .lct-delta-up { color: var(--lct-danger); }
430
+ .lct-delta-down { color: var(--lct-success); }
431
+ .lct-delta-flat,
432
+ .lct-delta-neutral { color: var(--lct-muted); }
369
433
 
370
- .lct-table th,
371
- .lct-table td {
434
+ .lct-panel {
435
+ background: var(--lct-panel);
436
+ border: 1px solid var(--lct-border);
437
+ border-radius: var(--radius-md);
438
+ margin-bottom: var(--sp-3);
439
+ box-shadow: var(--lct-shadow-sm);
440
+ }
441
+ .lct-panel-head {
442
+ display: flex;
443
+ align-items: center;
444
+ gap: var(--sp-3);
445
+ padding: 9px var(--sp-4);
372
446
  border-bottom: 1px solid var(--lct-border);
373
- padding: 12px;
374
- text-align: left;
375
- vertical-align: middle;
447
+ background: var(--lct-panel-head-bg);
448
+ border-radius: var(--radius-md) var(--radius-md) 0 0;
376
449
  }
377
-
378
- .lct-table tbody tr:last-child td { border-bottom: 0; }
379
-
380
- .lct-table th {
381
- background: var(--lct-th-bg);
382
- color: var(--lct-muted);
450
+ .lct-panel-title {
451
+ font-size: var(--fs-md);
383
452
  font-weight: 600;
384
- font-size: var(--fs-xs);
385
- letter-spacing: 0;
386
- text-transform: none;
387
- position: sticky;
388
- top: 0;
389
- z-index: 1;
390
- }
391
-
392
- .lct-table tbody tr {
393
- transition: background-color 0.1s ease;
394
- }
395
- .lct-table tbody tr:hover { background: var(--lct-row-hover); }
396
-
397
- @media (prefers-reduced-motion: reduce) {
398
- .lct-table tbody tr { transition: none; }
399
- }
400
-
401
- .lct-table td:last-child,
402
- .lct-table th:last-child,
403
- .lct-calls-table td:last-child,
404
- .lct-calls-table th:last-child { text-align: right; }
405
-
406
- .lct-bar-track,
407
- .lct-budget-track,
408
- .lct-stack-track {
409
- background: var(--lct-surface);
410
- border-radius: 999px;
411
- overflow: hidden;
453
+ margin: 0;
454
+ letter-spacing: -0.005em;
412
455
  }
413
- .lct-bar-track { height: 8px; min-width: 96px; }
414
- .lct-budget-track { height: 10px; border: 1px solid var(--lct-border); position: relative; }
415
- .lct-stack-track { height: 12px; display: flex; }
416
-
417
- .lct-bar-fill,
418
- .lct-budget-fill,
419
- .lct-stack-fill { height: 100%; display: block; }
420
- .lct-bar-fill { background: var(--lct-accent); }
421
- .lct-budget-fill { background: linear-gradient(90deg, #635bff, #7a73ff); transition: width 0.2s ease; }
422
- .lct-budget-fill--warn { background: linear-gradient(90deg, #f59e0b, #d97706); }
423
- .lct-budget-fill--over { background: linear-gradient(90deg, #ef4444, #b91c1c); }
424
- .lct-stack-fill-input { background: var(--lct-accent); }
425
- .lct-stack-fill-cache-read { background: #22c55e; }
426
- .lct-stack-fill-cache-write { background: #f59e0b; }
427
- .lct-stack-fill-cache-write-extended { background: #a855f7; }
428
- .lct-stack-fill-audio-input { background: #ec4899; }
429
- .lct-stack-fill-image-input { background: #f97316; }
430
- .lct-stack-fill-output { background: #0ea5e9; }
431
- .lct-stack-fill-audio-output { background: #14b8a6; }
432
- .lct-stack-fill-image-output { background: #84cc16; }
433
-
434
- .lct-budget { display: grid; gap: 10px; }
435
- .lct-budget-head { align-items: baseline; display: flex; gap: 10px; justify-content: space-between; }
436
- .lct-budget-spent {
437
- font-size: var(--fs-xl);
438
- font-variant-numeric: tabular-nums;
439
- font-weight: 700;
456
+ .lct-page-title {
457
+ font-size: var(--fs-lg);
458
+ font-weight: 600;
459
+ margin: 0 0 var(--sp-3);
440
460
  letter-spacing: -0.01em;
461
+ color: var(--lct-text);
441
462
  }
442
- .lct-budget-of { color: var(--lct-muted); font-size: var(--fs-sm); font-weight: 500; }
443
- .lct-budget-percent { font-size: var(--fs-md); font-variant-numeric: tabular-nums; font-weight: 700; }
444
- .lct-budget-marker {
445
- border-left: 2px dashed var(--lct-chart-marker);
446
- bottom: 0;
447
- position: absolute;
448
- top: 0;
463
+ .lct-panel-intro {
464
+ margin: 0;
465
+ padding: var(--sp-3) var(--sp-4);
466
+ font-size: var(--fs-sm);
467
+ color: var(--lct-muted);
468
+ line-height: 1.5;
469
+ }
470
+ .lct-panel-intro code { font-family: var(--mono); font-size: 0.9em; color: var(--lct-text); background: var(--lct-surface-2); padding: 1px 4px; border-radius: 3px; }
471
+ .lct-breadcrumb-back {
472
+ font-size: var(--fs-xs);
473
+ color: var(--lct-muted);
474
+ margin: 0 0 4px;
449
475
  }
450
- .lct-budget-projection {
451
- align-items: baseline;
476
+ .lct-breadcrumb-back a { color: var(--lct-accent-strong); text-decoration: none; font-weight: 600; }
477
+ .lct-breadcrumb-back a:hover { text-decoration: underline; }
478
+ .lct-panel-meta {
479
+ margin-left: auto;
480
+ font-size: var(--fs-xs);
452
481
  color: var(--lct-muted);
482
+ font-variant-numeric: tabular-nums;
453
483
  display: flex;
454
- flex-wrap: wrap;
455
- font-size: var(--fs-sm);
456
- gap: 8px 12px;
457
- justify-content: space-between;
458
- margin: 0;
484
+ gap: var(--sp-3);
485
+ align-items: center;
459
486
  }
460
- .lct-budget-projection strong { color: var(--lct-text); }
461
- .lct-budget-projection-status { font-weight: 600; }
462
- .lct-budget-projection-status--over { color: var(--lct-warning-copy); }
463
- .lct-budget-projection-status--under { color: var(--lct-muted); }
464
- .lct-budget-meta { color: var(--lct-muted); font-size: var(--fs-xs); }
487
+ .lct-panel-meta a { color: var(--lct-accent-strong); font-weight: 600; text-decoration: none; }
488
+ .lct-panel-meta a:hover { text-decoration: underline; }
489
+ .lct-panel-body { padding: var(--sp-3) var(--sp-4); }
465
490
 
466
- .lct-chart { display: block; height: 180px; width: 100%; }
467
- .lct-chart-area { fill: rgba(99, 91, 255, 0.12); }
468
- .lct-chart-line-secondary {
469
- fill: none;
470
- opacity: 0.75;
471
- stroke: var(--lct-chart-secondary);
472
- stroke-dasharray: 5 4;
473
- stroke-linejoin: round;
474
- stroke-linecap: round;
475
- stroke-width: 1.5;
476
- }
477
- .lct-chart-line { fill: none; stroke: var(--lct-accent); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
478
- .lct-chart-dot { fill: var(--lct-accent); }
479
- .lct-chart-grid { stroke: var(--lct-border); stroke-dasharray: 2 3; }
480
- .lct-chart-axis { fill: var(--lct-muted); font-family: var(--mono); font-size: var(--fs-2xs); }
481
- .lct-chart-legend {
491
+ .lct-grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
492
+ @media (max-width: 900px) { .lct-grid-2 { grid-template-columns: 1fr; } }
493
+
494
+ .lct-page-title-meta {
495
+ font-size: var(--fs-sm);
496
+ font-weight: 500;
482
497
  color: var(--lct-muted);
483
- display: flex;
484
- font-size: var(--fs-xs);
498
+ margin-left: 6px;
485
499
  font-variant-numeric: tabular-nums;
486
- justify-content: space-between;
487
- margin-top: 10px;
488
- }
489
- .lct-chart-legend-compare { align-items: center; display: inline-flex; gap: 12px; }
490
- .lct-chart-key { align-items: center; display: inline-flex; gap: 6px; }
491
- .lct-chart-key-line { background: var(--lct-accent); border-radius: 999px; display: inline-block; height: 2px; width: 16px; }
492
- .lct-chart-key-line-secondary { background: var(--lct-chart-secondary); position: relative; }
493
- .lct-chart-key-line-secondary::after {
494
- background: linear-gradient(90deg, transparent 40%, var(--lct-bg) 40%, var(--lct-bg) 60%, transparent 60%);
495
- content: "";
496
- inset: -1px 0;
497
- position: absolute;
498
500
  }
499
- .lct-chart-empty {
501
+ .lct-page-subtitle {
502
+ margin: -8px 0 var(--sp-3);
503
+ display: inline-flex;
500
504
  align-items: center;
505
+ gap: 8px;
501
506
  color: var(--lct-muted);
502
- display: flex;
503
507
  font-size: var(--fs-sm);
504
- height: 180px;
505
- justify-content: center;
506
508
  }
507
- .lct-tag-chips { display: flex; flex-wrap: wrap; gap: 4px; max-width: 380px; }
508
- .lct-tag-chip {
509
- align-items: center;
510
- background: var(--lct-surface);
511
- border: 1px solid var(--lct-border);
512
- border-radius: 4px;
509
+ .lct-page-subtitle-sep { color: var(--lct-subtle); }
510
+ .lct-stat-value-sm {
511
+ font-size: var(--fs-md);
512
+ font-weight: 600;
513
+ line-height: 1.2;
513
514
  color: var(--lct-text);
514
- display: inline-flex;
515
- font-family: var(--mono);
516
- font-size: var(--fs-xs);
517
- gap: 0;
518
- line-height: 1.4;
519
- padding: 2px 6px;
520
- text-decoration: none;
521
- white-space: nowrap;
515
+ margin: 0;
522
516
  }
523
- .lct-tag-chip-more { background: transparent; border: 1px dashed var(--lct-border); color: var(--lct-muted); }
524
- .lct-tag-empty { color: var(--lct-muted); font-size: var(--fs-sm); font-style: italic; }
525
517
 
526
- .lct-empty {
527
- padding: 56px 28px;
528
- text-align: center;
529
- background:
530
- radial-gradient(ellipse 60% 50% at 50% 0%, rgba(99, 91, 255, 0.04), transparent 70%),
531
- var(--lct-panel);
532
- }
533
- .lct-state-title { font-size: var(--fs-lg); font-weight: 600; margin: 0 0 6px; letter-spacing: -0.005em; }
534
- .lct-state-copy { color: var(--lct-muted); margin: 0 auto; max-width: 480px; font-size: var(--fs-sm); line-height: 1.55; }
535
- .lct-state-pre {
536
- background: var(--lct-bg);
537
- border: 1px solid var(--lct-border);
538
- border-radius: 6px;
539
- color: var(--lct-text);
540
- font-family: var(--mono);
518
+ .lct-meta-strip {
519
+ display: grid;
520
+ grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
521
+ gap: var(--sp-3) var(--sp-4);
522
+ padding: var(--sp-3) var(--sp-4);
523
+ margin: 0;
524
+ }
525
+ .lct-meta-strip-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
526
+ .lct-meta-strip-item dt {
527
+ font-size: var(--fs-2xs);
528
+ font-weight: 700;
529
+ text-transform: uppercase;
530
+ letter-spacing: 0.06em;
531
+ color: var(--lct-muted);
532
+ margin: 0;
533
+ }
534
+ .lct-meta-strip-item dd {
541
535
  font-size: var(--fs-sm);
542
- line-height: 1.55;
543
- margin: 12px auto 0;
544
- max-width: 560px;
545
- overflow: auto;
546
- padding: 12px 14px;
547
- text-align: left;
536
+ color: var(--lct-text);
537
+ font-variant-numeric: tabular-nums;
538
+ margin: 0;
539
+ word-break: break-all;
548
540
  }
549
- .lct-state-actions { display: flex; gap: 8px; justify-content: center; margin-top: 20px; }
550
541
 
551
- .lct-toolbar {
552
- background: var(--lct-toolbar-bg);
553
- backdrop-filter: blur(10px);
554
- border-color: var(--lct-toolbar-border);
555
- box-shadow: none;
556
- padding: 16px;
557
- margin-bottom: 16px;
558
- position: sticky;
559
- top: 12px;
560
- z-index: 10;
542
+ .lct-disclose { padding: 0; }
543
+ .lct-disclose-summary {
544
+ cursor: pointer;
545
+ list-style: none;
546
+ user-select: none;
561
547
  }
562
-
563
- .lct-toolbar-head {
564
- align-items: flex-start;
565
- display: flex;
566
- gap: 16px;
567
- justify-content: space-between;
568
- margin-bottom: 12px;
548
+ .lct-disclose-summary::-webkit-details-marker { display: none; }
549
+ .lct-disclose-summary::after {
550
+ content: "▸";
551
+ margin-left: 6px;
552
+ color: var(--lct-subtle);
553
+ font-size: var(--fs-xs);
554
+ transition: transform 0.15s ease;
555
+ display: inline-block;
556
+ }
557
+ .lct-disclose[open] .lct-disclose-summary::after { transform: rotate(90deg); }
558
+ .lct-disclose-summary:hover { background: var(--lct-surface-2); }
559
+ .lct-disclose-hint {
560
+ margin-left: auto;
561
+ font-size: var(--fs-xs);
562
+ color: var(--lct-muted);
563
+ font-weight: 500;
569
564
  }
570
565
 
571
- .lct-toolbar-actions { align-items: center; display: flex; gap: 8px; flex-wrap: wrap; }
572
-
573
- .lct-toolbar-actions .lct-button,
574
- .lct-banner .lct-button { font-size: var(--fs-sm); height: 32px; padding: 0 12px; }
575
-
576
- .lct-filters { display: block; }
566
+ .lct-pre {
567
+ margin: 0;
568
+ padding: var(--sp-3) var(--sp-4);
569
+ font-family: var(--mono);
570
+ font-size: var(--fs-xs);
571
+ color: var(--lct-text);
572
+ background: var(--lct-surface-2);
573
+ border-top: 1px solid var(--lct-border);
574
+ overflow-x: auto;
575
+ white-space: pre-wrap;
576
+ word-break: break-word;
577
+ }
577
578
 
578
- .lct-filter-row {
579
- align-items: flex-end;
579
+ .lct-stack-track {
580
580
  display: flex;
581
- flex-wrap: wrap;
582
- gap: 12px;
581
+ width: 100%;
582
+ height: 10px;
583
+ border-radius: 999px;
584
+ overflow: hidden;
585
+ background: var(--lct-surface-2);
583
586
  }
584
-
585
- .lct-filter-actions {
586
- align-items: flex-end;
587
+ .lct-stack-fill { height: 100%; display: block; }
588
+ .lct-stack-fill-input { background: var(--lct-accent); }
589
+ .lct-stack-fill-output { background: color-mix(in oklab, var(--lct-accent) 55%, white); }
590
+ .lct-stack-fill-cache-read { background: color-mix(in oklab, var(--lct-accent) 80%, white); }
591
+ .lct-stack-fill-cache-write { background: color-mix(in oklab, var(--lct-accent) 70%, white); }
592
+ .lct-stack-fill-cache-write-extended { background: color-mix(in oklab, var(--lct-accent) 45%, white); }
593
+ .lct-stack-fill-audio-input { background: var(--lct-provider-anthropic); }
594
+ .lct-stack-fill-audio-output { background: color-mix(in oklab, var(--lct-provider-anthropic) 60%, white); }
595
+ .lct-stack-fill-image-input { background: var(--lct-provider-openai); }
596
+ .lct-stack-fill-image-output { background: color-mix(in oklab, var(--lct-provider-openai) 60%, white); }
597
+
598
+ .lct-stack-legend {
587
599
  display: flex;
588
600
  flex-wrap: wrap;
589
- gap: 8px;
590
- margin-left: auto;
601
+ gap: 8px 20px;
602
+ margin-top: 12px;
603
+ font-size: var(--fs-xs);
591
604
  }
592
-
593
- .lct-field {
605
+ .lct-stack-legend-item {
594
606
  display: flex;
595
- flex: 1 1 160px;
596
- flex-direction: column;
597
- gap: 6px;
598
- min-width: 140px;
607
+ align-items: center;
608
+ gap: 8px;
609
+ color: var(--lct-muted);
610
+ font-variant-numeric: tabular-nums;
599
611
  }
612
+ .lct-stack-key { display: inline-flex; align-items: center; gap: 6px; color: var(--lct-text); font-weight: 500; }
613
+ .lct-stack-swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
614
+ .lct-stack-meta { color: var(--lct-muted); }
615
+ .lct-stack-empty { color: var(--lct-muted); font-size: var(--fs-sm); margin: 0; }
600
616
 
601
- .lct-field input,
602
- .lct-field select {
603
- appearance: none;
604
- -webkit-appearance: none;
605
- -moz-appearance: none;
606
- background: var(--lct-panel);
607
- border: 1px solid var(--lct-border);
608
- border-radius: 8px;
609
- box-sizing: border-box;
610
- color: var(--lct-text);
611
- font-family: inherit;
612
- font-size: var(--fs-md);
613
- height: var(--lct-control-height);
614
- line-height: 1.2;
615
- padding: 0 12px;
616
- width: 100%;
617
- }
617
+ .lct-legend { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--lct-muted); }
618
+ .lct-legend-dot { width: 9px; height: 9px; border-radius: 2px; }
619
+ .lct-legend-dot-current { background: var(--lct-accent); }
620
+ .lct-legend-dot-prior { background: var(--lct-subtle); }
618
621
 
619
- .lct-field select {
620
- background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%23697386' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M2.5 4.5l3.5 3.5 3.5-3.5'/></svg>");
621
- background-position: right 10px center;
622
- background-repeat: no-repeat;
623
- background-size: 12px 12px;
624
- padding-right: 32px;
622
+ .lct-tbl { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
623
+ .lct-tbl th {
624
+ font-size: var(--fs-2xs);
625
+ font-weight: 700;
626
+ text-transform: uppercase;
627
+ letter-spacing: 0.08em;
628
+ color: var(--lct-muted);
629
+ text-align: left;
630
+ padding: 9px var(--sp-4);
631
+ border-bottom: 1px solid var(--lct-border-strong);
632
+ white-space: nowrap;
625
633
  }
626
-
627
- .lct-field input[type="date"] {
634
+ .lct-tbl td {
635
+ padding: 9px var(--sp-4);
636
+ border-bottom: 1px solid var(--lct-border);
628
637
  font-variant-numeric: tabular-nums;
629
- padding-right: 8px;
638
+ vertical-align: middle;
639
+ color: var(--lct-text);
630
640
  }
641
+ .lct-tbl tr:last-child td { border-bottom: 0; }
642
+ .lct-tbl tr:hover td { background: var(--lct-row-hover); }
643
+ .lct-num { text-align: right !important; white-space: nowrap; font-variant-numeric: tabular-nums; }
644
+ .lct-num-muted { color: var(--lct-muted); }
645
+ .lct-tbl th.lct-num { text-align: right; }
631
646
 
632
- .lct-field input[type="date"]::-webkit-calendar-picker-indicator {
633
- cursor: pointer;
634
- filter: invert(45%) sepia(8%) saturate(437%) hue-rotate(176deg) brightness(95%) contrast(86%);
635
- opacity: 0.85;
647
+ .lct-tbl th.lct-sortable { cursor: pointer; user-select: none; }
648
+ .lct-tbl th.lct-sortable a { color: inherit; text-decoration: none; display: inline-block; }
649
+ .lct-tbl th.lct-sortable:hover { background: var(--lct-surface-hover); color: var(--lct-text); }
650
+ .lct-sort-ind {
651
+ display: inline-block;
652
+ margin-left: 4px;
653
+ opacity: 0;
654
+ font-size: 9px;
655
+ color: var(--lct-muted);
656
+ vertical-align: 1px;
636
657
  }
658
+ .lct-tbl th.lct-sortable:hover .lct-sort-ind { opacity: 0.6; }
659
+ .lct-tbl th.lct-sortable.lct-sorted { color: var(--lct-text); }
660
+ .lct-tbl th.lct-sortable.lct-sorted .lct-sort-ind { opacity: 1; color: var(--lct-accent); }
637
661
 
638
- .lct-field input::placeholder { color: var(--lct-muted); }
639
-
640
- .lct-field input:hover,
641
- .lct-field select:hover { border-color: var(--lct-border-strong); }
662
+ .lct-table-wrap { overflow-x: auto; }
642
663
 
643
- .lct-field input:focus,
644
- .lct-field select:focus {
645
- border-color: var(--lct-accent);
646
- box-shadow: var(--lct-focus-ring);
647
- outline: none;
664
+ .lct-model-cell { display: inline-flex; align-items: center; gap: var(--sp-2); }
665
+ .lct-provider-dot {
666
+ width: 8px;
667
+ height: 8px;
668
+ border-radius: var(--radius-pill);
669
+ flex-shrink: 0;
648
670
  }
671
+ .lct-provider-dot-anthropic { background: var(--lct-provider-anthropic); }
672
+ .lct-provider-dot-openai { background: var(--lct-provider-openai); }
673
+ .lct-provider-dot-gemini { background: var(--lct-provider-gemini); }
674
+ .lct-provider-dot-ruby_llm { background: var(--lct-provider-ruby_llm); }
649
675
 
650
- .lct-results-toolbar {
651
- align-items: center;
652
- display: flex;
653
- flex-wrap: wrap;
654
- gap: 12px;
655
- margin: -4px 0 8px;
676
+ .lct-code-id {
677
+ font-family: var(--mono);
678
+ font-size: var(--fs-xs);
679
+ color: var(--lct-accent-strong);
656
680
  }
657
-
658
- .lct-results-toolbar .lct-pagination-per { order: 0; margin-right: auto; }
659
- .lct-results-toolbar .lct-sort { order: 1; margin-left: auto; }
660
-
661
- .lct-sort {
681
+ .lct-tag-chips { display: inline-flex; flex-wrap: wrap; gap: 4px; max-width: 380px; }
682
+ .lct-tag-chip {
662
683
  align-items: center;
663
- background: var(--lct-surface);
664
- border-radius: 6px;
684
+ background: var(--lct-accent-soft);
685
+ border: 0;
686
+ border-radius: var(--radius-pill);
687
+ color: var(--lct-text);
665
688
  display: inline-flex;
666
- flex-wrap: wrap;
667
- gap: 2px;
668
- padding: 2px;
669
- }
670
-
671
- .lct-sort-option {
672
- border-radius: 4px;
673
- color: var(--lct-muted);
674
- display: inline-block;
689
+ font-family: var(--mono);
675
690
  font-size: var(--fs-xs);
676
- font-weight: 500;
677
- padding: 4px 8px;
691
+ line-height: 1.5;
692
+ padding: 2px 9px 2px 8px;
678
693
  text-decoration: none;
694
+ white-space: nowrap;
679
695
  }
680
-
681
- .lct-sort-option:hover { background: var(--lct-panel); color: var(--lct-text); }
682
- .lct-sort-option.is-active {
683
- background: var(--lct-panel);
684
- box-shadow: var(--lct-shadow);
685
- color: var(--lct-text);
696
+ .lct-tag-chip-key { color: var(--lct-accent); font-weight: 700; margin-right: 3px; letter-spacing: 0.02em; }
697
+ .lct-tag-chip-more {
698
+ background: transparent;
699
+ border: 1px dashed var(--lct-border-strong);
700
+ color: var(--lct-muted);
701
+ font-family: var(--mono);
702
+ padding: 1px 8px;
686
703
  }
687
704
 
688
- .lct-button {
689
- align-items: center;
690
- background: var(--lct-accent);
691
- border: 1px solid var(--lct-accent);
692
- border-radius: 8px;
693
- box-shadow: var(--lct-shadow-sm);
694
- color: #ffffff;
695
- cursor: pointer;
696
- display: inline-flex;
697
- font-family: inherit;
698
- font-size: var(--fs-md);
699
- font-weight: 600;
700
- justify-content: center;
701
- line-height: 1.2;
702
- height: var(--lct-control-height);
703
- padding: 0 14px;
704
- text-decoration: none;
705
- transition: background-color 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease, transform 0.08s ease;
706
- white-space: nowrap;
707
- }
705
+ .lct-spark { display: inline-block; width: 80px; height: 22px; vertical-align: middle; color: var(--lct-accent); }
708
706
 
709
- .lct-button:hover {
710
- background: var(--lct-accent-hover);
711
- border-color: var(--lct-accent-hover);
712
- box-shadow: var(--lct-shadow-md);
713
- transform: translateY(-1px);
707
+ .lct-bar {
708
+ display: inline-block;
709
+ height: 4px;
710
+ background: var(--lct-accent);
711
+ border-radius: var(--radius-pill);
712
+ vertical-align: middle;
713
+ opacity: 0.75;
714
714
  }
715
715
 
716
- .lct-button:active {
717
- transform: translateY(0);
718
- box-shadow: var(--lct-shadow-sm);
716
+ .lct-status-pill {
717
+ display: inline-flex;
718
+ align-items: center;
719
+ gap: 4px;
720
+ padding: 2px 8px;
721
+ border-radius: var(--radius-pill);
722
+ font-size: var(--fs-xs);
723
+ font-weight: 600;
719
724
  }
725
+ .lct-status-pill-ok { background: var(--lct-success-soft); color: var(--lct-success); }
726
+ .lct-status-pill-warn { background: var(--lct-warning-soft); color: var(--lct-warning); }
727
+ .lct-status-pill-danger { background: var(--lct-danger-soft); color: var(--lct-danger); }
728
+ .lct-status-pill-neutral{ background: var(--lct-surface-2); color: var(--lct-muted); }
720
729
 
721
- .lct-button:focus-visible,
722
- .lct-chip-remove:focus-visible,
723
- .lct-clear-link:focus-visible,
724
- .lct-nav a:focus-visible {
725
- box-shadow: var(--lct-focus-ring);
726
- outline: none;
730
+ .lct-filter-row {
731
+ display: flex;
732
+ align-items: center;
733
+ gap: 6px;
734
+ margin-bottom: var(--sp-3);
735
+ flex-wrap: wrap;
727
736
  }
728
-
729
- .lct-button-secondary {
730
- background: var(--lct-panel);
731
- border-color: var(--lct-border);
737
+ .lct-filter-pill {
738
+ display: inline-flex;
739
+ align-items: center;
740
+ gap: 6px;
741
+ height: 30px;
742
+ padding: 0 10px;
743
+ background: var(--lct-surface);
744
+ border: 1px solid var(--lct-border-strong);
745
+ border-radius: var(--radius-sm);
746
+ font-size: var(--fs-sm);
732
747
  color: var(--lct-text);
748
+ cursor: pointer;
749
+ line-height: 1;
750
+ text-decoration: none;
751
+ list-style: none;
752
+ user-select: none;
733
753
  }
734
- .lct-button-secondary:hover {
735
- background: var(--lct-row-hover);
736
- border-color: var(--lct-border-strong);
754
+ .lct-filter-pill::-webkit-details-marker { display: none; }
755
+ .lct-filter-pill:hover { background: var(--lct-surface-2); }
756
+ .lct-filter-pop {
757
+ position: relative;
758
+ display: inline-block;
759
+ }
760
+ .lct-filter-pop[open] .lct-filter-pill {
761
+ border-color: var(--lct-accent);
762
+ box-shadow: var(--lct-focus-ring);
737
763
  }
738
- .lct-button-secondary:active {
764
+ .lct-filter-pop-body {
765
+ position: absolute;
766
+ top: calc(100% + 6px);
767
+ left: 0;
768
+ z-index: 50;
739
769
  background: var(--lct-surface);
770
+ border: 1px solid var(--lct-border);
771
+ border-radius: var(--radius-md);
772
+ box-shadow: var(--lct-shadow-md);
773
+ padding: var(--sp-3);
774
+ display: flex;
775
+ align-items: flex-end;
776
+ gap: var(--sp-2);
740
777
  }
741
-
742
- @media (prefers-reduced-motion: reduce) {
743
- .lct-button { transition: none; }
744
- .lct-button:hover { transform: none; }
778
+ .lct-filter-pop-field { display: flex; flex-direction: column; gap: 4px; }
779
+ .lct-filter-pop-field label {
780
+ font-size: var(--fs-2xs);
781
+ font-weight: 700;
782
+ color: var(--lct-muted);
783
+ text-transform: uppercase;
784
+ letter-spacing: 0.08em;
745
785
  }
746
-
747
- .lct-button-compact {
786
+ .lct-filter-pop-field input {
787
+ font: inherit;
748
788
  font-size: var(--fs-sm);
749
- height: 32px;
750
- min-height: 32px;
789
+ height: var(--lct-control-height);
751
790
  padding: 0 10px;
752
- }
753
-
754
- .lct-toolbar-note { color: var(--lct-muted); font-size: var(--fs-xs); margin: 10px 0 0; }
755
-
756
- .lct-chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
757
-
758
- .lct-chip {
759
- align-items: center;
760
- background: var(--lct-accent-soft);
761
- border: 1px solid rgba(99, 91, 255, 0.12);
762
- border-radius: 999px;
791
+ border: 1px solid var(--lct-border-strong);
792
+ border-radius: var(--radius-sm);
793
+ background: var(--lct-surface);
763
794
  color: var(--lct-text);
764
- display: inline-flex;
765
- font-size: var(--fs-sm);
766
- gap: 8px;
767
- min-height: 28px;
768
- padding: 0 10px;
769
- }
770
-
771
- .lct-chip-remove {
772
- color: var(--lct-chip-remove);
773
- font-size: var(--fs-lg);
774
795
  line-height: 1;
775
- text-decoration: none;
796
+ min-width: 140px;
776
797
  }
777
-
778
- .lct-chip-remove:hover,
779
- .lct-clear-link:hover { color: var(--lct-accent); }
780
-
781
- .lct-clear-link {
782
- color: var(--lct-accent);
798
+ .lct-filter-pop-field input:focus { outline: none; box-shadow: var(--lct-focus-ring); border-color: var(--lct-accent); }
799
+ .lct-filter-pop-field select {
800
+ font: inherit;
783
801
  font-size: var(--fs-sm);
784
- font-weight: 600;
785
- margin-left: 4px;
786
- text-decoration: none;
802
+ height: var(--lct-control-height);
803
+ padding: 0 28px 0 10px;
804
+ border: 1px solid var(--lct-border-strong);
805
+ border-radius: var(--radius-sm);
806
+ background: var(--lct-surface);
807
+ color: var(--lct-text);
808
+ line-height: 1;
809
+ min-width: 180px;
810
+ appearance: none;
811
+ -webkit-appearance: none;
812
+ background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
813
+ background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%;
814
+ background-size: 5px 5px, 5px 5px;
815
+ background-repeat: no-repeat;
787
816
  }
788
-
789
- .lct-summary-row {
790
- align-items: center;
817
+ .lct-filter-pop-field select:focus { outline: none; box-shadow: var(--lct-focus-ring); border-color: var(--lct-accent); }
818
+ .lct-filter-pill svg { color: var(--lct-subtle); flex-shrink: 0; }
819
+ .lct-filter-pill-key {
791
820
  color: var(--lct-muted);
792
- display: flex;
793
- flex-wrap: wrap;
794
- gap: 8px;
795
- font-size: var(--fs-sm);
796
- margin-top: 12px;
821
+ font-weight: 500;
797
822
  }
798
-
799
- .lct-pagination {
800
- align-items: center;
801
- display: flex;
802
- justify-content: space-between;
803
- gap: 12px 20px;
804
- margin-top: 18px;
805
- flex-wrap: wrap;
806
- padding-top: 16px;
807
- border-top: 1px solid var(--lct-border);
823
+ .lct-filter-pill-key::after { content: ":"; margin: 0 1px 0 0; }
824
+ .lct-filter-pill-value {
825
+ color: var(--lct-text);
826
+ font-weight: 600;
808
827
  }
809
-
810
- .lct-pagination-info {
811
- display: flex;
812
- align-items: center;
813
- gap: 12px 18px;
814
- color: var(--lct-muted);
815
- font-size: var(--fs-sm);
816
- font-variant-numeric: tabular-nums;
817
- flex-wrap: wrap;
828
+ .lct-filter-pill .lct-chev { color: var(--lct-subtle); }
829
+ .lct-filter-pill.lct-active {
830
+ border-color: color-mix(in oklab, var(--lct-accent) 50%, var(--lct-border-strong));
831
+ background: var(--lct-accent-soft);
818
832
  }
819
-
820
- .lct-pagination-info strong { color: var(--lct-text); font-weight: 600; }
821
-
822
- .lct-pagination-per { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }
823
- .lct-pagination-per-label { color: var(--lct-muted); font-size: var(--fs-xs); font-weight: 500; }
824
-
825
- .lct-pagination-per-option {
833
+ .lct-filter-pill.lct-active .lct-filter-pill-key,
834
+ .lct-filter-pill.lct-active .lct-filter-pill-value { color: var(--lct-accent-strong); }
835
+ .lct-filter-row-meta {
836
+ margin-left: auto;
826
837
  color: var(--lct-muted);
827
- text-decoration: none;
828
- padding: 2px 8px;
829
- border-radius: 999px;
830
838
  font-size: var(--fs-xs);
831
839
  font-variant-numeric: tabular-nums;
832
840
  }
833
-
834
- .lct-pagination-per-option:hover { background: transparent; color: var(--lct-text); }
835
- .lct-pagination-per-option.is-active { color: var(--lct-text); font-weight: 600; background: var(--lct-surface); }
836
-
837
- .lct-pagination-nav {
838
- display: inline-flex;
839
- align-items: center;
840
- gap: 0;
841
- margin-left: auto;
842
- border: 1px solid var(--lct-border);
843
- border-radius: 8px;
844
- background: var(--lct-panel);
845
- overflow: hidden;
841
+ .lct-filter-clear {
842
+ color: var(--lct-accent-strong);
843
+ font-size: var(--fs-xs);
844
+ font-weight: 600;
845
+ cursor: pointer;
846
+ padding: 0 6px;
847
+ text-decoration: none;
846
848
  }
849
+ .lct-filter-clear:hover { text-decoration: underline; }
847
850
 
848
- .lct-page-link {
849
- min-width: 40px;
850
- height: 40px;
851
- padding: 0;
851
+ .lct-button {
852
+ font: inherit;
853
+ height: var(--lct-control-height);
854
+ padding: 0 var(--sp-4);
855
+ border: 1px solid transparent;
856
+ border-radius: var(--radius-sm);
857
+ font-weight: 600;
858
+ font-size: var(--fs-sm);
859
+ cursor: pointer;
860
+ line-height: 1;
861
+ text-decoration: none;
852
862
  display: inline-flex;
853
863
  align-items: center;
854
864
  justify-content: center;
855
- border-radius: 0;
856
- border: 0;
857
- border-right: 1px solid var(--lct-border);
858
- background: transparent;
865
+ }
866
+ .lct-button-primary {
867
+ background: var(--lct-accent);
868
+ color: white;
869
+ box-shadow: 0 1px 2px rgba(91, 84, 216, 0.35);
870
+ }
871
+ .lct-button-primary:hover { background: var(--lct-accent-strong); }
872
+ .lct-button-secondary {
873
+ background: var(--lct-surface);
874
+ border-color: var(--lct-border-strong);
859
875
  color: var(--lct-text);
860
- font-size: var(--fs-sm);
861
- font-variant-numeric: tabular-nums;
862
- font-weight: 500;
863
- text-decoration: none;
864
- transition: background-color 0.1s ease, border-color 0.1s ease, color 0.1s ease;
865
876
  }
877
+ .lct-button-secondary:hover { background: var(--lct-surface-2); }
866
878
 
867
- .lct-page-link:hover { background: var(--lct-row-hover); }
868
- .lct-page-link.is-current { background: var(--lct-accent); color: #fff; font-weight: 600; cursor: default; }
869
- .lct-page-link.is-disabled { color: var(--lct-muted); background: transparent; cursor: not-allowed; opacity: 0.55; }
870
-
871
- .lct-page-arrow { font-size: var(--fs-lg); line-height: 1; min-width: 40px; }
872
-
873
- .lct-page-gap {
874
- align-items: center;
875
- border-right: 1px solid var(--lct-border);
879
+ .lct-seg {
876
880
  display: inline-flex;
877
- height: 40px;
878
- justify-content: center;
879
- min-width: 40px;
880
- text-align: center;
881
- color: var(--lct-muted);
882
- font-variant-numeric: tabular-nums;
883
- user-select: none;
884
- }
885
-
886
- .lct-pagination-nav > *:last-child { border-right: 0; }
887
-
888
- .lct-nowrap { white-space: nowrap; }
889
-
890
- .lct-detail-grid { align-items: start; display: grid; gap: 16px; grid-template-columns: repeat(3, minmax(0, 1fr)); }
891
-
892
- .lct-dl {
893
- display: grid;
894
- gap: 12px;
895
- grid-template-columns: minmax(120px, 0.45fr) minmax(0, 1fr);
896
- margin: 0;
881
+ background: var(--lct-surface-2);
882
+ border: 1px solid var(--lct-border);
883
+ border-radius: var(--radius-sm);
884
+ padding: 2px;
897
885
  }
898
-
899
- .lct-dl dt {
900
- color: var(--lct-muted);
901
- font-size: var(--fs-sm);
886
+ .lct-seg a {
887
+ padding: 4px 10px;
888
+ font-size: var(--fs-xs);
902
889
  font-weight: 500;
890
+ color: var(--lct-muted);
891
+ border-radius: 4px;
892
+ cursor: pointer;
893
+ text-decoration: none;
903
894
  }
904
- .lct-dl dd { color: var(--lct-text); font-size: var(--fs-sm); margin: 0; min-width: 0; overflow-wrap: anywhere; word-break: break-word; }
905
-
906
- .lct-pre {
907
- background: #0f172a;
908
- border-radius: 8px;
909
- color: #e5e7eb;
910
- margin: 0;
911
- overflow: auto;
912
- padding: 16px;
895
+ .lct-seg a:hover { background: var(--lct-surface); color: var(--lct-text); }
896
+ .lct-seg a.lct-active {
897
+ background: var(--lct-surface);
898
+ color: var(--lct-text);
899
+ font-weight: 600;
900
+ box-shadow: 0 1px 2px rgba(13, 27, 42, 0.07), inset 0 0 0 1px var(--lct-border-strong);
913
901
  }
914
902
 
915
- .lct-call-hero {
916
- align-items: start;
903
+ .lct-pagination {
917
904
  display: flex;
918
- gap: 20px;
919
- justify-content: space-between;
920
- margin-bottom: 20px;
921
- }
922
-
923
- .lct-call-title { margin-bottom: 8px; }
924
-
925
- .lct-call-subtitle {
926
905
  align-items: center;
906
+ gap: var(--sp-3);
907
+ padding: 7px var(--sp-4);
908
+ border-top: 1px solid var(--lct-border);
909
+ font-size: var(--fs-xs);
927
910
  color: var(--lct-muted);
928
- display: flex;
929
- flex-wrap: wrap;
930
- gap: 8px;
931
- margin: 0;
932
- }
933
-
934
- .lct-call-summary {
935
- display: grid;
936
- gap: 10px;
937
- grid-template-columns: repeat(2, minmax(0, 1fr));
938
- min-width: min(420px, 100%);
939
911
  }
940
-
941
- .lct-call-summary-item {
942
- background: var(--lct-row-hover);
943
- border: 1px solid var(--lct-border);
944
- border-radius: 8px;
945
- display: grid;
946
- gap: 4px;
947
- padding: 10px 12px;
912
+ .lct-pagination-info { font-variant-numeric: tabular-nums; }
913
+ .lct-pagination-info strong { color: var(--lct-text); }
914
+ .lct-pagination-perpage { margin-left: auto; }
915
+ .lct-pagination .lct-seg { padding: 1px; }
916
+ .lct-pagination .lct-seg a { padding: 2px 8px; font-size: var(--fs-2xs); }
917
+ .lct-pagination-nav { display: flex; gap: 2px; align-items: center; }
918
+ .lct-pagination-nav::before {
919
+ content: "";
920
+ width: 1px;
921
+ height: 14px;
922
+ background: var(--lct-border);
923
+ margin: 0 4px;
948
924
  }
949
-
950
- .lct-call-breakdown-grid {
951
- display: grid;
952
- gap: 16px;
953
- grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
954
- margin-bottom: 16px;
925
+ .lct-page-link {
926
+ display: inline-grid;
927
+ place-items: center;
928
+ min-width: 22px;
929
+ height: 22px;
930
+ padding: 0 6px;
931
+ border-radius: var(--radius-sm);
932
+ font-size: var(--fs-2xs);
933
+ font-weight: 600;
934
+ color: var(--lct-muted);
935
+ background: transparent;
936
+ cursor: pointer;
937
+ text-decoration: none;
955
938
  }
956
-
957
- .lct-stack-legend { display: grid; gap: 8px; margin-top: 12px; }
958
-
959
- .lct-stack-legend-item {
960
- align-items: center;
939
+ .lct-page-link:hover { background: var(--lct-surface-2); color: var(--lct-text); }
940
+ .lct-page-link.lct-current { background: var(--lct-accent); color: white; box-shadow: 0 1px 2px rgba(91, 84, 216, 0.35); }
941
+ .lct-page-link.lct-disabled { color: var(--lct-subtle); cursor: default; }
942
+ .lct-page-link.lct-disabled:hover { background: transparent; color: var(--lct-subtle); }
943
+
944
+ .lct-heatmap { display: grid; grid-template-columns: repeat(30, 1fr); gap: 2px; }
945
+ .lct-heatmap .lct-cell { height: 18px; border-radius: 2px; background: var(--lct-surface-2); }
946
+ .lct-heatmap .lct-l1 { background: color-mix(in oklab, var(--lct-accent) 14%, transparent); }
947
+ .lct-heatmap .lct-l2 { background: color-mix(in oklab, var(--lct-accent) 30%, transparent); }
948
+ .lct-heatmap .lct-l3 { background: color-mix(in oklab, var(--lct-accent) 50%, transparent); }
949
+ .lct-heatmap .lct-l4 { background: color-mix(in oklab, var(--lct-accent) 75%, transparent); }
950
+ .lct-heatmap .lct-l5 { background: var(--lct-accent); }
951
+ .lct-heatmap-labels {
961
952
  display: flex;
962
- font-size: var(--fs-sm);
963
- gap: 12px;
964
953
  justify-content: space-between;
954
+ padding: 6px 0 0;
955
+ font-size: var(--fs-2xs);
956
+ color: var(--lct-muted);
957
+ font-variant-numeric: tabular-nums;
965
958
  }
966
959
 
967
- .lct-stack-key { align-items: center; display: inline-flex; gap: 8px; }
968
- .lct-stack-swatch { border-radius: 999px; display: inline-block; height: 8px; width: 8px; }
969
- .lct-stack-meta { color: var(--lct-muted); font-variant-numeric: tabular-nums; }
970
-
971
- @media (max-width: 800px) {
972
- .lct-header { flex-direction: column; }
973
-
974
- .lct-hero,
975
- .lct-stat-grid,
976
- .lct-two-col { grid-template-columns: 1fr; }
977
-
978
- .lct-filters { gap: 12px; }
979
-
980
- .lct-filter-row,
981
- .lct-filter-row-basic { align-items: stretch; grid-template-columns: 1fr; }
982
-
983
- .lct-filter-actions { justify-content: flex-start; width: 100%; }
984
-
985
- .lct-toolbar { padding: 16px; position: static; }
986
-
987
- .lct-pagination { align-items: flex-start; flex-direction: column; }
988
-
989
- .lct-pagination-nav { margin-left: 0; width: 100%; overflow-x: auto; }
990
-
991
- .lct-detail-grid { grid-template-columns: 1fr; }
992
-
993
- .lct-call-hero { flex-direction: column; }
960
+ .lct-chart { width: 100%; height: auto; display: block; }
961
+ .lct-chart-area { fill: url(#lct-chart-grad); }
962
+ .lct-chart-line { fill: none; stroke: var(--lct-accent); stroke-width: 2.25; stroke-linejoin: round; stroke-linecap: round; }
963
+ .lct-chart-line-secondary { fill: none; stroke: var(--lct-chart-secondary); stroke-width: 1.4; stroke-dasharray: 3 3; }
964
+ .lct-chart-dot { fill: var(--lct-accent); }
965
+ .lct-chart-peak { fill: var(--lct-accent); stroke: var(--lct-accent-soft); stroke-width: 4; }
966
+ .lct-chart-grid { stroke: var(--lct-border); stroke-dasharray: 2 4; }
967
+ .lct-chart-axis { fill: var(--lct-muted); font-family: var(--mono); font-size: var(--fs-2xs); }
994
968
 
995
- .lct-call-summary,
996
- .lct-call-breakdown-grid { grid-template-columns: 1fr; min-width: 0; }
969
+ .lct-empty {
970
+ padding: 56px 28px;
971
+ text-align: center;
972
+ background: var(--lct-panel);
997
973
  }
974
+ .lct-state-title { font-size: var(--fs-lg); font-weight: 600; margin: 0 0 6px; letter-spacing: -0.005em; }
975
+ .lct-state-copy { color: var(--lct-muted); margin: 0 auto; max-width: 480px; font-size: var(--fs-sm); line-height: 1.55; }
976
+
977
+ .lct-setup-card { max-width: 640px; margin: var(--sp-5) auto 0; }
978
+ .lct-setup-body p { margin: 0 0 var(--sp-2); font-size: var(--fs-sm); color: var(--lct-text); line-height: 1.55; }
979
+ .lct-setup-body p:last-child { margin-bottom: 0; }