prismcast 1.4.2 → 1.5.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 (178) hide show
  1. package/dist/app.js +18 -1
  2. package/dist/app.js.map +1 -1
  3. package/dist/browser/cdp.d.ts +2 -1
  4. package/dist/browser/cdp.js +44 -23
  5. package/dist/browser/cdp.js.map +1 -1
  6. package/dist/browser/channelSelection.d.ts +45 -1
  7. package/dist/browser/channelSelection.js +164 -27
  8. package/dist/browser/channelSelection.js.map +1 -1
  9. package/dist/browser/display.d.ts +0 -4
  10. package/dist/browser/display.js +0 -7
  11. package/dist/browser/display.js.map +1 -1
  12. package/dist/browser/index.d.ts +5 -0
  13. package/dist/browser/index.js +14 -0
  14. package/dist/browser/index.js.map +1 -1
  15. package/dist/browser/precaching.d.ts +5 -0
  16. package/dist/browser/precaching.js +112 -0
  17. package/dist/browser/precaching.js.map +1 -0
  18. package/dist/browser/tuning/directv.d.ts +2 -0
  19. package/dist/browser/tuning/directv.js +723 -0
  20. package/dist/browser/tuning/directv.js.map +1 -0
  21. package/dist/browser/tuning/fox.d.ts +2 -2
  22. package/dist/browser/tuning/fox.js +141 -22
  23. package/dist/browser/tuning/fox.js.map +1 -1
  24. package/dist/browser/tuning/hbo.d.ts +2 -2
  25. package/dist/browser/tuning/hbo.js +110 -41
  26. package/dist/browser/tuning/hbo.js.map +1 -1
  27. package/dist/browser/tuning/hulu.d.ts +2 -2
  28. package/dist/browser/tuning/hulu.js +442 -168
  29. package/dist/browser/tuning/hulu.js.map +1 -1
  30. package/dist/browser/tuning/sling.d.ts +2 -2
  31. package/dist/browser/tuning/sling.js +200 -56
  32. package/dist/browser/tuning/sling.js.map +1 -1
  33. package/dist/browser/tuning/youtubeTv.d.ts +2 -2
  34. package/dist/browser/tuning/youtubeTv.js +243 -57
  35. package/dist/browser/tuning/youtubeTv.js.map +1 -1
  36. package/dist/browser/video.d.ts +1 -1
  37. package/dist/browser/video.js +4 -2
  38. package/dist/browser/video.js.map +1 -1
  39. package/dist/channels/index.js +280 -34
  40. package/dist/channels/index.js.map +1 -1
  41. package/dist/config/health.d.ts +78 -0
  42. package/dist/config/health.js +202 -0
  43. package/dist/config/health.js.map +1 -0
  44. package/dist/config/paths.d.ts +10 -0
  45. package/dist/config/paths.js +14 -0
  46. package/dist/config/paths.js.map +1 -1
  47. package/dist/config/profiles.d.ts +6 -4
  48. package/dist/config/profiles.js +65 -14
  49. package/dist/config/profiles.js.map +1 -1
  50. package/dist/config/providerPacks.d.ts +46 -0
  51. package/dist/config/providerPacks.js +200 -0
  52. package/dist/config/providerPacks.js.map +1 -0
  53. package/dist/config/providers.d.ts +36 -3
  54. package/dist/config/providers.js +168 -8
  55. package/dist/config/providers.js.map +1 -1
  56. package/dist/config/sites.d.ts +1 -12
  57. package/dist/config/sites.js +38 -5
  58. package/dist/config/sites.js.map +1 -1
  59. package/dist/config/userChannels.d.ts +12 -0
  60. package/dist/config/userChannels.js +81 -14
  61. package/dist/config/userChannels.js.map +1 -1
  62. package/dist/config/userConfig.d.ts +5 -1
  63. package/dist/config/userConfig.js +58 -6
  64. package/dist/config/userConfig.js.map +1 -1
  65. package/dist/config/userProfiles.d.ts +81 -0
  66. package/dist/config/userProfiles.js +424 -0
  67. package/dist/config/userProfiles.js.map +1 -0
  68. package/dist/routes/config/channels/index.d.ts +3 -0
  69. package/dist/routes/config/channels/index.js +3 -0
  70. package/dist/routes/config/channels/index.js.map +1 -0
  71. package/dist/routes/config/channels/routes.d.ts +6 -0
  72. package/dist/routes/config/channels/routes.js +797 -0
  73. package/dist/routes/config/channels/routes.js.map +1 -0
  74. package/dist/routes/config/channels/table.d.ts +46 -0
  75. package/dist/routes/config/channels/table.js +811 -0
  76. package/dist/routes/config/channels/table.js.map +1 -0
  77. package/dist/routes/config/index.d.ts +37 -0
  78. package/dist/routes/config/index.js +81 -0
  79. package/dist/routes/config/index.js.map +1 -0
  80. package/dist/routes/config/providers.d.ts +18 -0
  81. package/dist/routes/config/providers.js +573 -0
  82. package/dist/routes/config/providers.js.map +1 -0
  83. package/dist/routes/config/settings.d.ts +39 -0
  84. package/dist/routes/config/settings.js +820 -0
  85. package/dist/routes/config/settings.js.map +1 -0
  86. package/dist/routes/index.d.ts +3 -2
  87. package/dist/routes/index.js +7 -4
  88. package/dist/routes/index.js.map +1 -1
  89. package/dist/routes/playlist.d.ts +5 -1
  90. package/dist/routes/playlist.js +32 -7
  91. package/dist/routes/playlist.js.map +1 -1
  92. package/dist/routes/providers.d.ts +6 -0
  93. package/dist/routes/providers.js +166 -0
  94. package/dist/routes/providers.js.map +1 -0
  95. package/dist/routes/root/content.d.ts +32 -0
  96. package/dist/routes/root/content.js +857 -0
  97. package/dist/routes/root/content.js.map +1 -0
  98. package/dist/routes/root/index.js +197 -0
  99. package/dist/routes/root/index.js.map +1 -0
  100. package/dist/routes/root/scripts/channels.d.ts +1 -0
  101. package/dist/routes/root/scripts/channels.js +745 -0
  102. package/dist/routes/root/scripts/channels.js.map +1 -0
  103. package/dist/routes/root/scripts/config.d.ts +1 -0
  104. package/dist/routes/root/scripts/config.js +1662 -0
  105. package/dist/routes/root/scripts/config.js.map +1 -0
  106. package/dist/routes/root/scripts/index.d.ts +3 -0
  107. package/dist/routes/root/scripts/index.js +8 -0
  108. package/dist/routes/root/scripts/index.js.map +1 -0
  109. package/dist/routes/root/scripts/status.d.ts +1 -0
  110. package/dist/routes/root/scripts/status.js +436 -0
  111. package/dist/routes/root/scripts/status.js.map +1 -0
  112. package/dist/routes/root/styles.d.ts +5 -0
  113. package/dist/routes/root/styles.js +447 -0
  114. package/dist/routes/root/styles.js.map +1 -0
  115. package/dist/routes/ui.js +8 -3
  116. package/dist/routes/ui.js.map +1 -1
  117. package/dist/service/commands.d.ts +5 -3
  118. package/dist/service/commands.js +117 -33
  119. package/dist/service/commands.js.map +1 -1
  120. package/dist/service/generators.d.ts +27 -0
  121. package/dist/service/generators.js +97 -6
  122. package/dist/service/generators.js.map +1 -1
  123. package/dist/streaming/hls.js +18 -1
  124. package/dist/streaming/hls.js.map +1 -1
  125. package/dist/streaming/lifecycle.js +1 -1
  126. package/dist/streaming/lifecycle.js.map +1 -1
  127. package/dist/streaming/monitor.d.ts +1 -38
  128. package/dist/streaming/monitor.js +2 -289
  129. package/dist/streaming/monitor.js.map +1 -1
  130. package/dist/streaming/recovery.d.ts +143 -0
  131. package/dist/streaming/recovery.js +286 -0
  132. package/dist/streaming/recovery.js.map +1 -0
  133. package/dist/streaming/registry.d.ts +1 -1
  134. package/dist/streaming/setup.d.ts +1 -1
  135. package/dist/streaming/setup.js +3 -1
  136. package/dist/streaming/setup.js.map +1 -1
  137. package/dist/streaming/statusEmitter.d.ts +4 -2
  138. package/dist/streaming/statusEmitter.js +5 -0
  139. package/dist/streaming/statusEmitter.js.map +1 -1
  140. package/dist/types/channels.d.ts +68 -0
  141. package/dist/types/channels.js +2 -0
  142. package/dist/types/channels.js.map +1 -0
  143. package/dist/types/config.d.ts +127 -0
  144. package/dist/types/config.js +2 -0
  145. package/dist/types/config.js.map +1 -0
  146. package/dist/types/index.d.ts +7 -429
  147. package/dist/types/index.js +1 -5
  148. package/dist/types/index.js.map +1 -1
  149. package/dist/types/profiles.d.ts +141 -0
  150. package/dist/types/profiles.js +2 -0
  151. package/dist/types/profiles.js.map +1 -0
  152. package/dist/types/selection.d.ts +101 -0
  153. package/dist/types/selection.js +6 -0
  154. package/dist/types/selection.js.map +1 -0
  155. package/dist/types/shared.d.ts +7 -0
  156. package/dist/types/shared.js +6 -0
  157. package/dist/types/shared.js.map +1 -0
  158. package/dist/types/streaming.d.ts +96 -0
  159. package/dist/types/streaming.js +2 -0
  160. package/dist/types/streaming.js.map +1 -0
  161. package/dist/utils/debugFilter.js +3 -1
  162. package/dist/utils/debugFilter.js.map +1 -1
  163. package/dist/utils/format.d.ts +7 -0
  164. package/dist/utils/format.js +22 -0
  165. package/dist/utils/format.js.map +1 -1
  166. package/dist/utils/index.d.ts +1 -0
  167. package/dist/utils/index.js +1 -0
  168. package/dist/utils/index.js.map +1 -1
  169. package/dist/utils/sanitize.d.ts +14 -0
  170. package/dist/utils/sanitize.js +37 -0
  171. package/dist/utils/sanitize.js.map +1 -0
  172. package/package.json +5 -3
  173. package/dist/routes/config.d.ts +0 -76
  174. package/dist/routes/config.js +0 -2187
  175. package/dist/routes/config.js.map +0 -1
  176. package/dist/routes/root.js +0 -3158
  177. package/dist/routes/root.js.map +0 -1
  178. /package/dist/routes/{root.d.ts → root/index.d.ts} +0 -0
@@ -0,0 +1,447 @@
1
+ /* Copyright(C) 2024-2026, HJD (https://github.com/hjdhjd). All rights reserved.
2
+ *
3
+ * styles.ts: Landing page CSS generator for PrismCast.
4
+ */
5
+ import { OPTIONAL_COLUMNS } from "../config/index.js";
6
+ /**
7
+ * Generates additional CSS styles specific to the landing page. Uses CSS custom properties for theme support.
8
+ * @returns CSS styles as a string.
9
+ */
10
+ export function generateLandingPageStyles() {
11
+ return [
12
+ // Override header to use space-between for logo/title on left and status on right.
13
+ ".header { justify-content: space-between; }",
14
+ ".header-left { display: flex; align-items: center; gap: 20px; }",
15
+ // Header links (GitHub, More by HJD).
16
+ ".header-links { display: flex; align-items: center; gap: 8px; font-size: 13px; }",
17
+ ".header-links a { color: var(--text-muted); text-decoration: none; transition: color 0.2s; }",
18
+ ".header-links a:hover { color: var(--text-primary); }",
19
+ ".header-links-sep { color: var(--text-muted); }",
20
+ // Header status bar styles.
21
+ ".header-status { display: flex; gap: 20px; align-items: center; font-size: 13px; color: var(--text-secondary); }",
22
+ ".header-status span { white-space: nowrap; }",
23
+ // Stream count popover. Clickable when streams are active; popover drops from the right edge of the header.
24
+ "#stream-count { background: none; border: none; color: inherit; font: inherit; padding: 0; }",
25
+ "#stream-count.clickable { cursor: pointer; }",
26
+ "#stream-count.clickable:hover { color: var(--text-primary); }",
27
+ ".stream-popover .dropdown-menu { right: 0; left: auto; min-width: 220px; }",
28
+ ".stream-popover-row { display: flex; align-items: center; gap: 8px; padding: 6px 12px; font-size: 13px; white-space: nowrap; }",
29
+ ".stream-popover-logo { height: 18px; width: auto; max-width: 80px; vertical-align: middle; }",
30
+ ".stream-popover-channel { color: var(--text-primary); }",
31
+ ".stream-popover-show { color: var(--text-muted); }",
32
+ ".stream-popover-duration { color: var(--text-muted); margin-left: auto; }",
33
+ // Subtab styles for Configuration tab.
34
+ ".subtab-bar { display: flex; border-bottom: 1px solid var(--border-default); margin-bottom: 20px; gap: 2px; flex-wrap: wrap; }",
35
+ ".subtab-btn { padding: 8px 16px; border: none; background: var(--subtab-bg); cursor: pointer; font-size: 13px; font-weight: 500; ",
36
+ "color: var(--tab-text); border-radius: var(--radius-md) var(--radius-md) 0 0; transition: all 0.2s; }",
37
+ ".subtab-btn:hover { background: var(--subtab-bg-hover); color: var(--tab-text-hover); }",
38
+ ".subtab-btn.active { background: var(--subtab-bg-active); color: var(--subtab-text-active); border-bottom: 2px solid var(--subtab-border-active); }",
39
+ ".subtab-panel { display: none; }",
40
+ ".subtab-panel.active { display: block; }",
41
+ // Channels tab subtab styles. Scoped to avoid collision with Configuration tab subtabs.
42
+ ".channels-subtab-bar { display: flex; border-bottom: 1px solid var(--border-default); margin-bottom: 20px; gap: 2px; flex-wrap: wrap; }",
43
+ ".channels-subtab-btn { padding: 8px 16px; border: none; background: var(--subtab-bg); cursor: pointer; font-size: 13px; font-weight: 500; ",
44
+ "color: var(--tab-text); border-radius: var(--radius-md) var(--radius-md) 0 0; transition: all 0.2s; }",
45
+ ".channels-subtab-btn:hover { background: var(--subtab-bg-hover); color: var(--tab-text-hover); }",
46
+ ".channels-subtab-btn.active { background: var(--subtab-bg-active); color: var(--subtab-text-active); ",
47
+ "border-bottom: 2px solid var(--subtab-border-active); }",
48
+ ".channels-subtab-panel { display: none; }",
49
+ ".channels-subtab-panel.active { display: block; }",
50
+ // Empty state styling for Providers panel.
51
+ ".empty-state { text-align: center; padding: 40px 20px; color: var(--text-secondary); }",
52
+ ".empty-state-title { font-size: 16px; font-weight: 600; color: var(--text-primary); margin: 0 0 8px 0; }",
53
+ ".empty-state-text { font-size: 14px; margin: 0; max-width: 500px; margin-left: auto; margin-right: auto; line-height: 1.5; }",
54
+ // Wizard modal styles.
55
+ ".wizard-modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; ",
56
+ "justify-content: center; align-items: center; }",
57
+ ".wizard-modal-content { background: var(--surface-overlay); border-radius: var(--radius-lg); box-shadow: 0 8px 32px rgba(0,0,0,0.3); ",
58
+ "width: 640px; max-width: 90vw; max-height: 85vh; display: flex; flex-direction: column; overflow: hidden; }",
59
+ ".wizard-header { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; ",
60
+ "border-bottom: 1px solid var(--border-default); }",
61
+ ".wizard-header h3 { margin: 0; font-size: 18px; color: var(--text-heading); }",
62
+ ".wizard-close { background: none; border: none; font-size: 20px; cursor: pointer; color: var(--text-muted); padding: 4px 8px; }",
63
+ ".wizard-close:hover { color: var(--text-primary); }",
64
+ // Step indicator.
65
+ ".wizard-steps { display: flex; align-items: center; justify-content: center; padding: 16px 20px; gap: 4px; }",
66
+ ".wizard-step { display: flex; flex-direction: column; align-items: center; gap: 4px; }",
67
+ ".wizard-step-line { width: 32px; height: 2px; background: var(--border-default); margin-bottom: 18px; }",
68
+ ".step-circle { width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; ",
69
+ "font-size: 13px; font-weight: 600; border: 2px solid var(--border-default); color: var(--text-muted); background: var(--surface-overlay); }",
70
+ ".wizard-step.active .step-circle { border-color: var(--interactive-primary); color: var(--interactive-primary); background: var(--surface-overlay); }",
71
+ ".wizard-step.completed .step-circle { border-color: var(--interactive-primary); color: #fff; background: var(--interactive-primary); }",
72
+ ".step-label { font-size: 11px; color: var(--text-muted); }",
73
+ ".wizard-step.active .step-label { color: var(--interactive-primary); font-weight: 600; }",
74
+ ".wizard-step.clickable { cursor: pointer; }",
75
+ ".wizard-step.clickable:not(.completed) .step-circle:hover { border-color: var(--interactive-primary); color: var(--interactive-primary); }",
76
+ // Wizard content area.
77
+ ".wizard-content { padding: 20px; overflow-y: auto; flex: 1; min-height: 300px; }",
78
+ ".wizard-content label { display: block; margin-bottom: 6px; font-weight: 500; color: var(--text-primary); font-size: 14px; }",
79
+ ".wizard-content input[type=\"text\"], .wizard-content textarea { width: 100%; padding: 8px 10px; border: 1px solid var(--border-default); ",
80
+ "border-radius: var(--radius-md); font-size: 14px; font-family: inherit; background: var(--surface-overlay); color: var(--text-primary); ",
81
+ "box-sizing: border-box; }",
82
+ ".wizard-content input[type=\"text\"]:focus, .wizard-content textarea:focus { outline: none; border-color: var(--interactive-primary); }",
83
+ ".wizard-content textarea { resize: vertical; min-height: 60px; }",
84
+ ".wizard-content .field-hint { font-size: 12px; color: var(--text-muted); margin-top: 4px; margin-bottom: 12px; }",
85
+ ".wizard-content .field-group { margin-bottom: 16px; }",
86
+ // Wizard profile radio buttons.
87
+ ".wizard-profile-category { margin-bottom: 16px; }",
88
+ ".wizard-profile-category h4 { font-size: 13px; color: var(--text-secondary); margin: 0 0 4px 0; text-transform: uppercase; letter-spacing: 0.5px; }",
89
+ ".wizard-category-desc { font-size: 12px; color: var(--text-muted); margin-bottom: 8px; }",
90
+ ".wizard-content label.wizard-profile-option { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; ",
91
+ "border: 1px solid var(--border-default); border-radius: var(--radius-md); margin-bottom: 4px; cursor: pointer; }",
92
+ ".wizard-profile-option:hover { background: var(--surface-hover); }",
93
+ ".wizard-profile-option input[type=\"radio\"] { margin-top: 5px; flex-shrink: 0; }",
94
+ ".wizard-profile-option .profile-option-name { font-weight: 500; font-size: 14px; color: var(--text-primary); }",
95
+ ".wizard-profile-option .profile-option-summary { font-weight: 400; font-size: 12px; color: var(--text-muted); }",
96
+ ".wizard-profile-option .profile-option-desc { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }",
97
+ // Wizard strategy radio buttons.
98
+ ".wizard-content label.wizard-strategy-option { display: flex; align-items: flex-start; gap: 8px; padding: 10px 12px; ",
99
+ "border: 1px solid var(--border-default); border-radius: var(--radius-md); margin-bottom: 6px; cursor: pointer; }",
100
+ ".wizard-strategy-option:hover { background: var(--surface-hover); }",
101
+ ".wizard-strategy-option input[type=\"radio\"] { margin-top: 5px; flex-shrink: 0; }",
102
+ ".wizard-strategy-label { font-weight: 500; font-size: 14px; color: var(--text-primary); }",
103
+ ".wizard-strategy-desc { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }",
104
+ // Wizard flag checkboxes.
105
+ ".wizard-content label.wizard-flag { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; margin-bottom: 4px; }",
106
+ ".wizard-flag input[type=\"checkbox\"] { margin-top: 5px; flex-shrink: 0; }",
107
+ ".wizard-flag-label { font-size: 14px; color: var(--text-primary); }",
108
+ ".wizard-flag-desc { font-size: 12px; color: var(--text-secondary); margin-top: 2px; }",
109
+ // Wizard review summary.
110
+ ".wizard-review-table { width: 100%; border-collapse: collapse; font-size: 14px; }",
111
+ ".wizard-review-table td { padding: 6px 8px; border-bottom: 1px solid var(--border-default); }",
112
+ ".wizard-review-table td:first-child { font-weight: 500; color: var(--text-secondary); width: 120px; white-space: nowrap; }",
113
+ // Wizard validation error.
114
+ ".wizard-error { padding: 0 20px; color: var(--status-error-text); font-size: 13px; }",
115
+ // Wizard buttons.
116
+ ".wizard-buttons { display: flex; justify-content: space-between; align-items: center; padding: 16px 20px; ",
117
+ "border-top: 1px solid var(--border-default); }",
118
+ ".wizard-buttons-right { display: flex; gap: 8px; }",
119
+ // Domain row for adding multiple domains.
120
+ ".wizard-domain-row { border: 1px solid var(--border-default); border-radius: var(--radius-md); padding: 12px; margin-bottom: 8px; }",
121
+ ".wizard-domain-row .field-group:last-child { margin-bottom: 0; }",
122
+ ".wizard-add-domain { background: none; border: none; color: var(--interactive-primary); cursor: pointer; font-size: 13px; padding: 4px 0; }",
123
+ ".wizard-add-domain:hover { text-decoration: underline; }",
124
+ // Export and import modal styles: body area, profile list items, section header, and option labels.
125
+ ".export-modal-body { padding: 20px; overflow-y: auto; font-size: 14px; }",
126
+ ".export-section-header { margin-bottom: 12px; font-weight: 500; }",
127
+ ".export-option-label { display: flex; align-items: center; gap: 8px; cursor: pointer; }",
128
+ ".export-profile-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; margin-bottom: 4px; ",
129
+ "border: 1px solid var(--border-default); border-radius: var(--radius-md); cursor: pointer; }",
130
+ ".export-profile-item:hover { background: var(--surface-hover); }",
131
+ ".export-profile-info { min-width: 0; }",
132
+ ".export-profile-name { font-weight: 600; font-size: 14px; }",
133
+ ".export-profile-meta { font-size: 12px; color: var(--text-muted); }",
134
+ ".export-divider { border-top: 1px solid var(--border-default); margin: 16px 0; }",
135
+ ".export-hint { font-size: 12px; color: var(--text-muted); margin-top: 6px; margin-left: 24px; }",
136
+ ".import-summary-table { width: 100%; font-size: 13px; margin: 12px 0; }",
137
+ ".import-summary-table td { padding: 4px 0; }",
138
+ ".import-summary-label { color: var(--text-muted); }",
139
+ // Panel header layout for description and reset link alignment.
140
+ ".panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }",
141
+ // Settings panel description styling (replaces redundant header titles).
142
+ ".settings-panel-description { margin: 0; font-size: 15px; color: var(--text-primary); }",
143
+ ".settings-panel-description p { margin: 0; }",
144
+ ".description-hint { font-size: 13px; color: var(--text-secondary); margin-top: 4px; }",
145
+ // Streams table container - outer border with rounded corners.
146
+ "#streams-container { border: 1px solid var(--border-default); border-radius: var(--radius-md); overflow: hidden; margin-bottom: 20px; }",
147
+ // Streams table - minimal design with no borders between columns.
148
+ ".streams-table { width: 100%; border-collapse: collapse; margin: 0; }",
149
+ ".streams-table td { padding: 6px 10px; border: none; color: var(--text-primary); vertical-align: middle; }",
150
+ ".streams-table td:first-child { padding-left: 12px; }",
151
+ ".streams-table td:last-child { padding-right: 12px; }",
152
+ ".streams-table .empty-row td { padding: 10px 12px; text-align: center; color: var(--text-muted); }",
153
+ ".streams-table .empty-row:hover { background: transparent; }",
154
+ ".streams-table .stream-row { cursor: pointer; }",
155
+ ".streams-table .stream-row:hover { background: var(--table-row-hover); }",
156
+ ".streams-table .chevron { width: 20px; color: var(--text-muted); font-size: 10px; }",
157
+ ".streams-table .stream-info { width: 180px; max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; font-size: 13px; }",
158
+ ".streams-table .stream-duration { font-weight: 400; color: var(--text-secondary); }",
159
+ ".streams-table .channel-logo { height: 24px; width: auto; max-width: 100px; vertical-align: middle; margin-right: 4px; }",
160
+ ".streams-table .channel-text { vertical-align: middle; }",
161
+ ".streams-table .stream-show { max-width: 250px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-secondary); font-size: 13px; }",
162
+ ".streams-table .stream-health { text-align: right; white-space: nowrap; font-size: 13px; }",
163
+ ".streams-table .stream-details td { padding: 10px 12px 12px 32px; background: var(--surface-sunken); }",
164
+ ".streams-table .details-content { font-size: 12px; color: var(--text-secondary); }",
165
+ ".streams-table .details-header { display: flex; justify-content: space-between; align-items: flex-start; gap: 20px; margin-bottom: 10px; }",
166
+ ".streams-table .details-url { word-break: break-all; flex: 1; min-width: 0; }",
167
+ ".streams-table .details-started { white-space: nowrap; flex-shrink: 0; }",
168
+ ".streams-table .details-metrics { display: flex; align-items: baseline; gap: 20px; }",
169
+ ".streams-table .details-issue { flex: 1; min-width: 0; }",
170
+ ".streams-table .details-recovery { white-space: nowrap; flex-shrink: 0; }",
171
+ ".streams-table .details-memory { white-space: nowrap; flex-shrink: 0; }",
172
+ ".streams-table .client-count { font-size: 0.85em; color: var(--text-muted); margin-right: 8px; white-space: nowrap; }",
173
+ // Log viewer styles.
174
+ ".log-viewer { background: var(--dark-surface-bg); color: var(--dark-text-secondary); padding: 15px; border-radius: var(--radius-lg); ",
175
+ "font-family: 'SF Mono', Monaco, monospace; font-size: 12px; height: 500px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; }",
176
+ ".log-viewer::-webkit-scrollbar { width: 8px; }",
177
+ ".log-viewer::-webkit-scrollbar-track { background: var(--dark-scrollbar-track); }",
178
+ ".log-viewer::-webkit-scrollbar-thumb { background: var(--dark-scrollbar-thumb); border-radius: var(--radius-md); }",
179
+ ".log-viewer::-webkit-scrollbar-thumb:hover { background: var(--dark-scrollbar-thumb-hover); }",
180
+ ".log-entry { color: var(--dark-text-secondary); }",
181
+ ".log-error { color: var(--dark-text-error); }",
182
+ ".log-warn { color: var(--dark-text-warn); }",
183
+ ".log-debug { color: var(--dark-text-debug); }",
184
+ ".log-muted { color: var(--dark-text-muted); }",
185
+ ".log-connecting { color: var(--dark-text-muted); }",
186
+ // Channel table styles. The wrapper uses fit-content so it shrinks when columns are hidden, with max-width: 100% to prevent viewport overflow. We use
187
+ // border-collapse: separate so that border-radius works on the header cells. Overflow is auto so the table scrolls on narrow screens; dropdown menus escape
188
+ // the container via portal to <body>.
189
+ ".channel-table-wrapper { width: fit-content; max-width: 100%; margin: 0 auto 20px; border: 1px solid var(--border-default); " +
190
+ "border-radius: var(--radius-lg); overflow: auto; }",
191
+ ".channel-table { width: 100%; border-collapse: separate; border-spacing: 0; table-layout: auto; min-width: 650px; margin: 0; }",
192
+ ".channel-table th, .channel-table td { padding: 10px 12px; text-align: left; border: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }",
193
+ ".channel-table th { background: var(--table-header-bg); font-weight: 600; font-size: 13px; border-bottom: 1px solid var(--border-default); }",
194
+ ".channel-table tbody tr:nth-child(even):not(.user-channel) { background: var(--table-row-even); }",
195
+ ".channel-table tr:hover { background: var(--table-row-hover); }",
196
+ ".channel-table .col-key { min-width: 170px; }",
197
+ ".channel-table .col-name { min-width: 200px; }",
198
+ ".channel-table .col-provider { min-width: 200px; }",
199
+ ".channel-table .col-actions, .channel-table td:last-child { min-width: 168px; white-space: nowrap; overflow: visible; }",
200
+ ".provider-select { width: 100%; padding: 2px 4px; font-size: 12px; border: 1px solid var(--form-input-border); ",
201
+ "border-radius: 3px; background: var(--form-input-bg); color: var(--text-primary); }",
202
+ // Optional column width, alignment, and visibility rules. Generated from OPTIONAL_COLUMNS to keep a single source of truth for column metadata.
203
+ ...OPTIONAL_COLUMNS.flatMap((col) => [
204
+ ".channel-table ." + col.cssClass + " { min-width: " + col.width + (col.align === "center" ? "; text-align: center" : "") + "; }",
205
+ ".channel-table.hide-" + col.cssClass + " ." + col.cssClass + " { display: none; }"
206
+ ]),
207
+ // Sortable header styles. Clickable headers with pointer cursor and subtle hover effect.
208
+ ".channel-table th.sortable { cursor: pointer; user-select: none; }",
209
+ ".channel-table th.sortable:hover { background: var(--surface-hover); }",
210
+ // Column picker dropdown. The Actions header uses flex layout to push the ellipsis button to the far right.
211
+ ".channel-table th.col-actions { display: flex; align-items: center; justify-content: space-between; }",
212
+ ".column-picker { position: relative; }",
213
+ ".btn-col-picker { font-size: 16px; line-height: 1; vertical-align: middle; padding: 0 4px; color: var(--text-muted); cursor: pointer; " +
214
+ "background: none; border: none; border-radius: 3px; }",
215
+ ".btn-col-picker:hover { color: var(--text-primary); background: var(--surface-hover); }",
216
+ ".column-picker-menu { min-width: 140px; }",
217
+ // Key column styling: monospace at a slightly smaller size with secondary color to reduce visual weight.
218
+ ".ch-key { color: var(--text-secondary); font-family: var(--font-mono); font-size: 13px; }",
219
+ // Responsive: hide Key and all optional columns on phones.
220
+ "@media (max-width: 768px) { .channel-table .col-key, .channel-table td:nth-child(1), .channel-table th:nth-child(1) { display: none; } " +
221
+ OPTIONAL_COLUMNS.map((col) => ".channel-table ." + col.cssClass).join(", ") + " { display: none; } }",
222
+ // User channel row tinting to distinguish custom/override channels from predefined.
223
+ ".channel-table tr.user-channel { background: var(--user-channel-tint); }",
224
+ ".channel-table tr.user-channel:hover { background: var(--user-channel-tint-hover); }",
225
+ // Disabled predefined channel row styling and hide-disabled toggle.
226
+ ".channel-table tr.channel-disabled { opacity: 0.5; }",
227
+ ".channel-table tr.channel-disabled td { color: var(--text-tertiary); }",
228
+ ".channel-table.hide-disabled tr.channel-disabled { display: none; }",
229
+ // Provider-filtered channel row styling. Uses reduced opacity and italic text to distinguish from manually disabled rows. The compound selector ensures that rows
230
+ // which are both disabled and provider-filtered render at the disabled-level opacity (0.5) rather than the more aggressive unavailable-level opacity (0.4).
231
+ ".channel-table tr.channel-unavailable { opacity: 0.4; font-style: italic; }",
232
+ ".channel-table tr.channel-unavailable td { color: var(--text-tertiary); }",
233
+ ".channel-table tr.channel-unavailable.channel-disabled { opacity: 0.5; }",
234
+ ".channel-table.hide-disabled tr.channel-unavailable { display: none; }",
235
+ ".no-provider-label { color: var(--text-tertiary); font-size: 12px; }",
236
+ ".text-muted { color: var(--text-muted); }",
237
+ // Provider filter toolbar layout.
238
+ ".provider-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 10px; }",
239
+ ".provider-toolbar .toolbar-group { display: flex; align-items: center; gap: 6px; }",
240
+ ".provider-toolbar .toolbar-label { font-size: 13px; color: var(--text-secondary); white-space: nowrap; }",
241
+ ".provider-toolbar .toolbar-spacer { flex: 1; }",
242
+ // Provider dropdown multi-select.
243
+ ".provider-dropdown-menu { min-width: 200px; max-height: 300px; overflow-y: auto; }",
244
+ ".provider-option { display: flex; align-items: center; gap: 6px; padding: 5px 12px; font-size: 13px; cursor: pointer; color: var(--text-primary); }",
245
+ ".provider-option:hover { background: var(--surface-sunken); }",
246
+ ".provider-option input[type=\"checkbox\"] { margin: 0; }",
247
+ // Provider chips.
248
+ ".provider-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }",
249
+ ".provider-chip { display: inline-flex; align-items: center; gap: 4px; background: var(--surface-elevated); border: 1px solid var(--border-default); ",
250
+ "border-radius: 12px; padding: 2px 8px 2px 10px; font-size: 12px; color: var(--text-secondary); min-height: 24px; }",
251
+ ".chip-close { background: none; border: none; cursor: pointer; font-size: 14px; line-height: 1; padding: 0 2px; color: var(--text-muted); ",
252
+ "transition: color 0.2s; }",
253
+ ".chip-close:hover { color: var(--text-primary); }",
254
+ // Bulk assign dropdown.
255
+ ".bulk-assign-select { font-size: 13px; padding: 4px 8px; border: 1px solid var(--border-default); border-radius: var(--radius-md); ",
256
+ "background: var(--surface-page); color: var(--text-primary); cursor: pointer; }",
257
+ // Responsive: stack provider toolbar groups vertically on small screens.
258
+ "@media (max-width: 768px) { .provider-toolbar { flex-direction: column; align-items: flex-start; } }",
259
+ // Icon button styling for channel action buttons.
260
+ ".btn-icon { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: none; ",
261
+ "border-radius: var(--radius-md); background: transparent; cursor: pointer; color: var(--text-secondary); transition: color 0.15s, background 0.15s; }",
262
+ ".btn-icon:hover { background: var(--surface-hover); }",
263
+ ".user-channel .btn-icon:hover { background: var(--user-channel-tint-hover); }",
264
+ ".btn-icon-edit:hover { color: var(--interactive-edit); }",
265
+ ".btn-icon-delete:hover { color: var(--interactive-delete); }",
266
+ ".btn-icon-revert:hover { color: var(--interactive-edit); }",
267
+ ".btn-icon-enable:hover { color: var(--interactive-success); }",
268
+ ".btn-icon-disable:hover { color: var(--interactive-delete); }",
269
+ ".btn-icon-login:hover { color: var(--interactive-primary); }",
270
+ ".btn-icon-copy:hover { color: var(--interactive-primary); }",
271
+ ".btn-icon-placeholder { display: inline-block; width: 28px; height: 28px; }",
272
+ // Health indicator colors. The login icon only uses health-success (provider verified). The health icon uses both (channel last-tune result).
273
+ ".health-success { color: var(--interactive-success); }",
274
+ ".health-failed { color: var(--interactive-delete); }",
275
+ // Health icon is non-interactive — no hover effect, default cursor. The .user-channel override needs matching specificity (0-3-0) to prevent the
276
+ // tinted hover background from making the health icon look clickable on user-defined channel rows.
277
+ ".btn-icon-health { cursor: default; }",
278
+ ".btn-icon-health:hover { background: transparent; color: var(--text-secondary); }",
279
+ ".user-channel .btn-icon-health:hover { background: transparent; }",
280
+ // Override hover to preserve health color when set.
281
+ ".btn-icon-health.health-success:hover { color: var(--interactive-success); }",
282
+ ".btn-icon-health.health-failed:hover { color: var(--interactive-delete); }",
283
+ ".copy-dropdown .dropdown-item { font-size: 12px; }",
284
+ // JS tooltip styling. The tooltip element is appended to <body> and positioned via getBoundingClientRect() so it's immune to overflow and stacking contexts.
285
+ // Only activated when the primary input can't hover (hover: none), targeting iPadOS where Safari doesn't show native title tooltips. On pure-touch
286
+ // devices without a trackpad, the JS loads but mouseenter never fires so the tooltip stays hidden. Desktop (hover: hover) skips initialization entirely.
287
+ ".btn-icon-tooltip { position: fixed; padding: 4px 8px; border-radius: var(--radius-sm); background: var(--surface-overlay); color: var(--text-primary); ",
288
+ "font-size: 12px; white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity 0.5s; z-index: 10000; ",
289
+ "box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); }",
290
+ ".btn-icon-tooltip.visible { opacity: 1; transition: opacity 0.1s; }",
291
+ // Channel toolbar with operation buttons and display controls.
292
+ ".channel-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; margin-bottom: 15px; }",
293
+ ".channel-toolbar .toolbar-group { display: flex; align-items: center; gap: 6px; }",
294
+ ".channel-toolbar .toolbar-spacer { flex: 1; }",
295
+ ".channel-toolbar .toggle-label { font-size: 12px; color: var(--text-secondary); cursor: pointer; display: flex; align-items: center; gap: 4px; ",
296
+ "user-select: none; }",
297
+ // Dropdown menu used by the Import button in the channel toolbar.
298
+ ".dropdown { position: relative; display: inline-block; }",
299
+ ".dropdown-menu { display: none; position: absolute; top: 100%; left: 0; z-index: 1000; min-width: 180px; padding: 4px 0; margin-top: 2px; ",
300
+ "background: var(--surface-overlay); border: 1px solid var(--border-default); border-radius: var(--radius-md); ",
301
+ "box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); }",
302
+ ".dropdown-menu.show { display: block; }",
303
+ ".dropdown-item { padding: 6px 12px; font-size: 13px; cursor: pointer; color: var(--text-primary); }",
304
+ ".dropdown-item:hover { background: var(--surface-sunken); }",
305
+ ".dropdown-option { display: block; padding: 2px 12px 6px 24px; font-size: 12px; color: var(--text-secondary); cursor: pointer; user-select: none; }",
306
+ ".dropdown-divider { height: 1px; margin: 4px 0; background: var(--border-default); }",
307
+ // Channel form styles. Inputs use full width; selects use width classes from ui.ts for consistency with settings forms.
308
+ ".channel-form { background: var(--form-bg); border: 1px solid var(--border-default); border-radius: var(--radius-lg); padding: 20px; margin-bottom: 20px; }",
309
+ ".channel-form h3 { margin-top: 0; margin-bottom: 15px; color: var(--text-heading-secondary); }",
310
+ ".channel-form .form-row { margin-bottom: 4px; }",
311
+ ".channel-form .form-row:last-child { margin-bottom: 0; }",
312
+ ".channel-form .form-input { width: 100%; box-sizing: border-box; }",
313
+ // Advanced toggle styles.
314
+ ".advanced-toggle { color: var(--interactive-primary); cursor: pointer; font-size: 13px; margin-top: 5px; margin-bottom: 15px; }",
315
+ ".advanced-toggle:hover { text-decoration: underline; }",
316
+ ".advanced-fields { display: none; }",
317
+ ".advanced-fields.show { display: block; }",
318
+ // Profile reference section styles.
319
+ ".profile-reference { background: var(--surface-elevated); border: 1px solid var(--border-default); border-radius: var(--radius-lg); margin: 20px 0; ",
320
+ "padding: 20px; }",
321
+ ".profile-reference-header { display: flex; justify-content: space-between; align-items: flex-start; }",
322
+ ".profile-reference h3 { margin: 0 0 10px 0; color: var(--text-heading-secondary); }",
323
+ ".profile-reference-close { color: var(--text-secondary); font-size: 18px; background: none; border: none; cursor: pointer; padding: 0 5px; }",
324
+ ".profile-reference-close:hover { color: var(--text-primary); }",
325
+ ".reference-intro { color: var(--text-secondary); font-size: 13px; margin-bottom: 20px; }",
326
+ ".profile-category { margin-bottom: 20px; }",
327
+ ".profile-category:last-child { margin-bottom: 0; }",
328
+ ".profile-category h4 { color: var(--text-heading-secondary); font-size: 14px; font-weight: 600; margin: 0 0 8px 0; }",
329
+ ".category-desc { color: var(--text-tertiary); font-size: 12px; margin: 0 0 10px 0; }",
330
+ ".profile-list { margin: 0; padding: 0; }",
331
+ ".profile-list dt { font-family: var(--font-mono); font-size: 13px; font-weight: 600; margin-top: 10px; color: var(--text-primary); }",
332
+ ".profile-list dt:first-child { margin-top: 0; }",
333
+ ".profile-list dd { color: var(--text-secondary); font-size: 13px; margin: 4px 0 0 0; }",
334
+ ".selector-guide-heading { margin-top: 20px !important; border-top: 1px solid var(--border-default); padding-top: 16px; }",
335
+ // API Reference index.
336
+ ".api-index { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px 24px; margin-top: 12px; }",
337
+ ".api-index-group { display: flex; flex-direction: column; gap: 2px; }",
338
+ ".api-index a { color: var(--text-secondary); text-decoration: none; font-size: 12px; line-height: 1.5; }",
339
+ ".api-index a:hover { color: var(--interactive-primary); }",
340
+ ".api-index a code { font-size: 11px; }",
341
+ ".api-index-heading { font-weight: 600; font-size: 13px !important; color: var(--text-primary) !important; margin-bottom: 1px; }",
342
+ ".api-index-desc { color: var(--text-muted); font-size: 11px; margin-bottom: 3px; }",
343
+ // Other landing page styles.
344
+ ".endpoint code { font-size: 13px; }",
345
+ // Modified value indicator styling.
346
+ ".form-group.modified { border-left: 3px solid var(--interactive-primary); padding-left: 12px; }",
347
+ ".modified-dot { display: inline-block; width: 8px; height: 8px; background: var(--interactive-primary); border-radius: 50%; margin-right: 6px; ",
348
+ "vertical-align: middle; }",
349
+ // Per-setting reset button styling.
350
+ ".btn-reset { background: transparent; border: 1px solid var(--border-default); border-radius: var(--radius-md); padding: 4px 8px; margin-left: 8px; ",
351
+ "cursor: pointer; font-size: 14px; color: var(--text-secondary); transition: all 0.15s ease; }",
352
+ ".btn-reset:hover { background: var(--surface-elevated); border-color: var(--interactive-primary); color: var(--interactive-primary); }",
353
+ // Backup subtab section styling.
354
+ ".backup-group { margin-bottom: 35px; }",
355
+ ".backup-group-title { font-size: 16px; font-weight: 600; margin-bottom: 15px; color: var(--text-heading); ",
356
+ "padding-bottom: 8px; border-bottom: 1px solid var(--border-default); }",
357
+ ".backup-section { margin-bottom: 20px; padding: 20px; background: var(--surface-elevated); border-radius: var(--radius-lg); ",
358
+ "border: 1px solid var(--border-default); }",
359
+ ".backup-section h3 { margin-top: 0; margin-bottom: 10px; color: var(--text-heading-secondary); font-size: 15px; }",
360
+ ".backup-section p { color: var(--text-secondary); margin-bottom: 15px; font-size: 14px; }",
361
+ ".backup-section code { background: var(--surface-code); padding: 2px 5px; border-radius: 3px; font-size: 12px; }",
362
+ "#import-settings-file, #import-channels-file, #import-m3u-file { display: none; }",
363
+ ".btn-export { background: var(--surface-elevated); border: 1px solid var(--border-default); color: var(--text-primary); ",
364
+ "padding: 10px 20px; border-radius: var(--radius-md); font-size: 14px; cursor: pointer; transition: all 0.15s ease; }",
365
+ ".btn-export:hover { border-color: var(--interactive-primary); color: var(--interactive-primary); }",
366
+ ".btn-import { background: var(--surface-elevated); border: 1px solid var(--border-default); color: var(--text-primary); ",
367
+ "padding: 10px 20px; border-radius: var(--radius-md); font-size: 14px; cursor: pointer; transition: all 0.15s ease; }",
368
+ ".btn-import:hover { border-color: var(--interactive-primary); color: var(--interactive-primary); }",
369
+ // Login modal styles for channel authentication.
370
+ ".login-modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: flex; ",
371
+ "align-items: center; justify-content: center; z-index: 1000; }",
372
+ ".login-modal-content { background: var(--surface-overlay); padding: 30px; border-radius: var(--radius-lg); max-width: 450px; width: 90%; ",
373
+ "box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); }",
374
+ ".login-modal-content h3 { margin-top: 0; margin-bottom: 15px; color: var(--text-heading); }",
375
+ ".login-modal-content p { color: var(--text-secondary); margin-bottom: 15px; font-size: 14px; line-height: 1.5; }",
376
+ ".login-modal-hint { font-size: 13px; color: var(--text-muted); }",
377
+ ".login-modal-buttons { margin-top: 20px; text-align: right; }",
378
+ // Restart dialog modal styles for pending restart notification.
379
+ ".restart-modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: none; ",
380
+ "align-items: center; justify-content: center; z-index: 1000; }",
381
+ ".restart-modal-content { background: var(--surface-overlay); padding: 30px; border-radius: var(--radius-lg); max-width: 400px; width: 90%; ",
382
+ "box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); text-align: center; }",
383
+ ".restart-modal-content h3 { margin-top: 0; margin-bottom: 15px; color: var(--text-heading); }",
384
+ ".restart-modal-content p { color: var(--text-secondary); margin-bottom: 0; font-size: 14px; line-height: 1.5; }",
385
+ ".restart-modal-status { margin: 16px 0; color: var(--text-muted); font-size: 13px; }",
386
+ ".restart-modal-buttons { display: flex; gap: 12px; justify-content: center; margin-top: 20px; }",
387
+ ".btn-danger { background: var(--interactive-danger); color: white; border: none; padding: 10px 20px; border-radius: var(--radius-md); ",
388
+ "font-size: 14px; cursor: pointer; transition: all 0.15s ease; }",
389
+ ".btn-danger:hover { opacity: 0.9; }",
390
+ // Toast notification container: fixed top-right, above all modals.
391
+ ".toast-container { position: fixed; top: 20px; right: 20px; z-index: 1001; display: flex; flex-direction: column; gap: 8px; pointer-events: none; }",
392
+ // Individual toast: themed colors, slide-in animation, close button.
393
+ ".toast { padding: 12px 36px 12px 16px; border-radius: var(--radius-md); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); min-width: 280px; max-width: 420px; ",
394
+ "font-size: 13px; line-height: 1.4; white-space: pre-line; position: relative; pointer-events: auto; animation: toastIn 0.3s ease-out; }",
395
+ ".toast.toast-exit { animation: toastOut 0.3s ease-in forwards; }",
396
+ // Type variants using existing theme status variables.
397
+ ".toast.success { background: var(--status-success-bg); border: 1px solid var(--status-success-border); color: var(--status-success-text); }",
398
+ ".toast.error { background: var(--status-error-bg); border: 1px solid var(--status-error-border); color: var(--status-error-text); }",
399
+ ".toast.warning { background: var(--status-warning-bg); border: 1px solid var(--status-warning-border); color: var(--status-warning-text); }",
400
+ ".toast.info { background: var(--status-info-bg); border: 1px solid var(--status-info-border); color: var(--status-info-text); }",
401
+ // Close button positioned top-right within each toast.
402
+ ".toast-close { position: absolute; top: 8px; right: 8px; background: none; border: none; cursor: pointer; font-size: 16px; line-height: 1; padding: 0 4px; ",
403
+ "color: inherit; opacity: 0.6; }",
404
+ ".toast-close:hover { opacity: 1; }",
405
+ // Action button for toasts with an undo or similar inline action.
406
+ ".toast-action { display: inline-block; margin-left: 8px; padding: 2px 10px; border: 1px solid currentColor; border-radius: var(--radius-sm); ",
407
+ "background: none; color: inherit; cursor: pointer; font-size: 12px; font-weight: 600; opacity: 0.8; vertical-align: baseline; }",
408
+ ".toast-action:hover { opacity: 1; background: rgba(0, 0, 0, 0.1); }",
409
+ // Toast slide animations.
410
+ "@keyframes toastIn { from { transform: translateX(120%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }",
411
+ "@keyframes toastOut { from { transform: translateX(0); opacity: 1; } to { transform: translateX(120%); opacity: 0; } }",
412
+ // Responsive: full-width toasts on narrow screens.
413
+ "@media (max-width: 768px) { .toast-container { left: 20px; right: 20px; } .toast { min-width: 0; max-width: none; } }",
414
+ // Loading state for buttons.
415
+ ".btn.loading { opacity: 0.7; pointer-events: none; }",
416
+ ".btn.loading::after { content: '...'; }",
417
+ // Inline copy button for Quick Start section.
418
+ ".btn-copy-inline { background: var(--surface-elevated); border: 1px solid var(--border-default); padding: 2px 8px; font-size: 12px; ",
419
+ "border-radius: var(--radius-sm); cursor: pointer; color: var(--text-secondary); margin-left: 6px; vertical-align: middle; }",
420
+ ".btn-copy-inline:hover { background: var(--surface-hover); color: var(--text-primary); }",
421
+ ".copy-feedback-inline { color: var(--stream-healthy); font-size: 12px; margin-left: 8px; display: none; }",
422
+ // Version display styles.
423
+ ".version-container { display: inline-flex; align-items: center; gap: 6px; }",
424
+ ".version { font-size: 13px; color: var(--text-muted); font-weight: 400; text-decoration: none; transition: color 0.2s; }",
425
+ ".version:hover { color: var(--text-primary); }",
426
+ ".version.version-update { color: var(--interactive-primary); }",
427
+ ".version.version-update:hover { color: var(--interactive-primary-hover, var(--interactive-primary)); text-decoration: underline; }",
428
+ ".version-check { background: none; border: none; padding: 0; margin: 0; cursor: pointer; font-size: 14px; color: var(--text-muted); ",
429
+ "line-height: 1; transition: color 0.2s, transform 0.3s; opacity: 0.7; }",
430
+ ".version-check:hover { color: var(--text-primary); opacity: 1; }",
431
+ ".version-check.checking { animation: spin 1s linear infinite; pointer-events: none; }",
432
+ ".version-check.up-to-date { color: var(--stream-healthy); opacity: 1; }",
433
+ ".version-check.check-error { color: var(--stream-error); opacity: 1; }",
434
+ "@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }",
435
+ // Changelog modal styles.
436
+ ".changelog-modal { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); display: none; ",
437
+ "align-items: center; justify-content: center; z-index: 1000; }",
438
+ ".changelog-modal-content { background: var(--surface-overlay); padding: 30px; border-radius: var(--radius-lg); max-width: 500px; width: 90%; ",
439
+ "box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); }",
440
+ ".changelog-modal-content h3 { margin-top: 0; margin-bottom: 20px; color: var(--text-heading); }",
441
+ ".changelog-list { margin: 0 0 20px 0; padding: 0 0 0 20px; color: var(--text-secondary); font-size: 14px; line-height: 1.6; }",
442
+ ".changelog-list li { margin-bottom: 8px; }",
443
+ ".changelog-list li:last-child { margin-bottom: 0; }",
444
+ ".changelog-modal-buttons { display: flex; gap: 12px; justify-content: flex-end; }"
445
+ ].join("\n");
446
+ }
447
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/routes/root/styles.ts"],"names":[],"mappings":"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"}
package/dist/routes/ui.js CHANGED
@@ -95,6 +95,7 @@ export function generateBaseStyles() {
95
95
  ".form-select { flex: 0 0 auto; padding: 8px 12px; border: 1px solid var(--form-input-border); border-radius: var(--radius-md); ",
96
96
  "background: var(--form-input-bg); color: var(--text-primary); font-size: 14px; cursor: pointer; }",
97
97
  ".form-checkbox { flex: none; width: 18px; height: 18px; cursor: pointer; accent-color: var(--interactive-primary); }",
98
+ ".checkbox-list-grid { font-size: 13px; }",
98
99
  // Focus states.
99
100
  ".form-input:focus, .form-select:focus { border-color: var(--interactive-primary); outline: none; box-shadow: 0 0 0 2px var(--border-focus); }",
100
101
  // Disabled states.
@@ -231,7 +232,7 @@ export function generateTabScript(options = {}) {
231
232
  " try { localStorage.setItem('" + localStorageKey + "', category); } catch(e) {}",
232
233
  " if(updateUrl !== false) {",
233
234
  " var parsed = parseHash();",
234
- " var subtab = (category === 'config') ? parsed.subtab : null;",
235
+ " var subtab = ((category === 'config') || (category === 'channels')) ? parsed.subtab : null;",
235
236
  " updateHash(category, subtab);",
236
237
  " }",
237
238
  " document.dispatchEvent(new CustomEvent('tabactivated', { detail: { category: category } }));",
@@ -269,6 +270,9 @@ export function generateTabScript(options = {}) {
269
270
  " if(parsed.tab === 'config' && parsed.subtab && window.switchConfigSubtab) {",
270
271
  " window.switchConfigSubtab(parsed.subtab, false);",
271
272
  " }",
273
+ " if(parsed.tab === 'channels' && parsed.subtab && window.switchChannelsSubtab) {",
274
+ " window.switchChannelsSubtab(parsed.subtab, false);",
275
+ " }",
272
276
  " }",
273
277
  " });",
274
278
  // Determine initial tab: hash > localStorage > default.
@@ -287,8 +291,9 @@ export function generateTabScript(options = {}) {
287
291
  " document.dispatchEvent(new CustomEvent('tabactivated', { detail: { category: category } }));",
288
292
  " }",
289
293
  " }",
290
- // Store parsed hash for subtab script to use.
291
- " window.initialHashSubtab = parsed.subtab;",
294
+ // Store parsed hash for subtab scripts to use. Config and Channels tabs each read their own variable.
295
+ " window.initialHashSubtab = (parsed.tab === 'config') ? parsed.subtab : null;",
296
+ " window.initialChannelsHashSubtab = (parsed.tab === 'channels') ? parsed.subtab : null;",
292
297
  "})();",
293
298
  "</script>"
294
299
  ].join("\n");
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/routes/ui.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/routes/ui.ts"],"names":[],"mappings":"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"}
@@ -14,17 +14,19 @@ export declare function handleInstall(force: boolean): Promise<number>;
14
14
  */
15
15
  export declare function handleUninstall(): Promise<number>;
16
16
  /**
17
- * Handles the `service start` command. Starts the service if it is installed but not running.
17
+ * Handles the `service start` command. Starts the service if it is installed but not running. If the service file contains stale paths (e.g., after a Homebrew
18
+ * upgrade), they are fixed automatically before starting.
18
19
  * @returns Exit code (0 for success, 1 for error).
19
20
  */
20
21
  export declare function handleStart(): Promise<number>;
21
22
  /**
22
- * Handles the `service stop` command. Stops the service if it is running.
23
+ * Handles the `service stop` command. Always attempts to stop the service regardless of whether it appears to be running, ensuring that loaded-but-not-running
24
+ * state (common on launchd after a crash) is properly cleared.
23
25
  * @returns Exit code (0 for success, 1 for error).
24
26
  */
25
27
  export declare function handleStop(): Promise<number>;
26
28
  /**
27
- * Handles the `service restart` command. Stops the service if running, then starts it.
29
+ * Handles the `service restart` command. Stops the service, then compares paths and regenerates the service file if needed before starting.
28
30
  * @returns Exit code (0 for success, 1 for error).
29
31
  */
30
32
  export declare function handleRestart(): Promise<number>;