@acms-subir/core 0.2.0 → 0.3.1

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 (254) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/cli/common.mjs +35 -0
  3. package/cli/legacy.mjs +317 -0
  4. package/cli/main.mjs +66 -0
  5. package/cli/palette.mjs +4 -0
  6. package/cli/preview.mjs +50 -0
  7. package/cli/remote.mjs +55 -0
  8. package/cli/themes.mjs +127 -0
  9. package/cli.mjs +2 -369
  10. package/deploy/Caddyfile +8 -0
  11. package/deploy/Dockerfile +34 -0
  12. package/deploy/compose.https.yml +21 -0
  13. package/deploy/compose.yml +46 -0
  14. package/docs/live-video.md +91 -0
  15. package/docs/theme-authoring.md +103 -0
  16. package/email-runner.mjs +32 -0
  17. package/integration.mjs +189 -2
  18. package/ops-check.mjs +27 -0
  19. package/package.json +27 -5
  20. package/src/actions/index.ts +578 -49
  21. package/src/components/AiCleaner.tsx +291 -0
  22. package/src/components/AiSettings.tsx +575 -0
  23. package/src/components/CommandPalette.tsx +200 -0
  24. package/src/components/ContentList.astro +246 -0
  25. package/src/components/DesignAccess.tsx +182 -0
  26. package/src/components/DesignManager.tsx +418 -46
  27. package/src/components/EmailSettings.tsx +521 -0
  28. package/src/components/EventPage.astro +178 -0
  29. package/src/components/LegalPage.astro +27 -0
  30. package/src/components/LinksManager.tsx +119 -58
  31. package/src/components/LiveCard.astro +174 -0
  32. package/src/components/LiveManager.tsx +910 -0
  33. package/src/components/NavManager.tsx +42 -43
  34. package/src/components/ThemeScript.astro +50 -0
  35. package/src/components/ThemeSections.astro +58 -0
  36. package/src/components/ThemeSectionsEditor.tsx +513 -0
  37. package/src/components/WidgetRenderer.astro +3 -0
  38. package/src/components/booking/BookingFlow.astro +150 -0
  39. package/src/components/booking/HoursEditor.astro +63 -0
  40. package/src/components/builder/PageBuilder.tsx +10 -2
  41. package/src/components/editor/EventPanel.tsx +401 -0
  42. package/src/components/editor/FormatDock.tsx +81 -0
  43. package/src/components/editor/LivePane.tsx +122 -0
  44. package/src/components/editor/MobileToolbar.tsx +93 -0
  45. package/src/components/editor/PostEditor.tsx +605 -223
  46. package/src/components/editor/PreviewOverlay.tsx +242 -43
  47. package/src/components/editor/extensions/calendar.tsx +51 -7
  48. package/src/components/editor/extensions/events.tsx +153 -0
  49. package/src/components/editor/extensions/slash.tsx +7 -1
  50. package/src/components/site/Pager.astro +24 -0
  51. package/src/components/site/PostCard.astro +64 -0
  52. package/src/components/site/TagLabel.astro +11 -0
  53. package/src/layouts/Admin.astro +289 -49
  54. package/src/layouts/Site.astro +352 -59
  55. package/src/lib/agent-api.ts +13 -0
  56. package/src/lib/agent-discovery.ts +40 -0
  57. package/src/lib/agent.ts +114 -0
  58. package/src/lib/ai-config.ts +58 -0
  59. package/src/lib/ai-schema.ts +22 -0
  60. package/src/lib/ai.ts +90 -0
  61. package/src/lib/api-keys.ts +65 -0
  62. package/src/lib/api.ts +56 -0
  63. package/src/lib/auth.ts +25 -5
  64. package/src/lib/backup/content.ts +36 -0
  65. package/src/lib/backup/unzip.ts +12 -1
  66. package/src/lib/backup/zip.ts +1 -1
  67. package/src/lib/booking/agent.ts +108 -0
  68. package/src/lib/booking/availability.ts +221 -0
  69. package/src/lib/booking/emails.ts +115 -0
  70. package/src/lib/booking/forms.ts +77 -0
  71. package/src/lib/booking/service.ts +277 -0
  72. package/src/lib/booking/view.ts +54 -0
  73. package/src/lib/calendar/agent-schema.ts +48 -0
  74. package/src/lib/calendar/agent.ts +136 -0
  75. package/src/lib/calendar/api.ts +81 -0
  76. package/src/lib/calendar/cards.ts +102 -0
  77. package/src/lib/calendar/config.ts +52 -0
  78. package/src/lib/calendar/data.ts +130 -0
  79. package/src/lib/calendar/events.ts +261 -0
  80. package/src/lib/calendar/feeds.ts +43 -0
  81. package/src/lib/calendar/hooks.ts +38 -0
  82. package/src/lib/calendar/http.ts +30 -0
  83. package/src/lib/calendar/ics-write.ts +120 -0
  84. package/src/lib/calendar/ics.ts +15 -5
  85. package/src/lib/calendar/import.ts +203 -0
  86. package/src/lib/calendar/render.ts +120 -37
  87. package/src/lib/calendar/rrule.ts +149 -0
  88. package/src/lib/calendar/seo.ts +48 -0
  89. package/src/lib/design-service.ts +58 -0
  90. package/src/lib/designDiff.ts +145 -0
  91. package/src/lib/designPreview.ts +110 -12
  92. package/src/lib/documents/cleanup.ts +31 -0
  93. package/src/lib/documents/extract.ts +154 -0
  94. package/src/lib/documents/vendor.d.ts +4 -0
  95. package/src/lib/drafts.ts +60 -6
  96. package/src/lib/dynamicBlocks.ts +40 -8
  97. package/src/lib/email/accounts.ts +55 -0
  98. package/src/lib/email/config.ts +86 -0
  99. package/src/lib/email/migration.ts +24 -0
  100. package/src/lib/email/providers.ts +89 -0
  101. package/src/lib/email/service.ts +78 -0
  102. package/src/lib/email/store.ts +167 -0
  103. package/src/lib/email/templates.ts +18 -0
  104. package/src/lib/email/types.ts +32 -0
  105. package/src/lib/email/webhooks.ts +87 -0
  106. package/src/lib/email.ts +15 -0
  107. package/src/lib/env.ts +1 -1
  108. package/src/lib/legal/index.ts +25 -0
  109. package/src/lib/live/client.ts +88 -0
  110. package/src/lib/live/crypto.ts +28 -0
  111. package/src/lib/live/migration.ts +15 -0
  112. package/src/lib/live/providers.ts +152 -0
  113. package/src/lib/live/service.ts +170 -0
  114. package/src/lib/live/signals.ts +89 -0
  115. package/src/lib/live/store.ts +49 -0
  116. package/src/lib/live/types.ts +52 -0
  117. package/src/lib/live/view.ts +78 -0
  118. package/src/lib/mobile/bookings.ts +73 -0
  119. package/src/lib/mobile/calendar.ts +85 -0
  120. package/src/lib/mobile/content.ts +85 -0
  121. package/src/lib/mobile/http.ts +63 -0
  122. package/src/lib/mobile/route.ts +20 -0
  123. package/src/lib/ops.ts +8 -0
  124. package/src/lib/preview.ts +21 -1
  125. package/src/lib/repo/migrations.ts +221 -0
  126. package/src/lib/repo/sql.ts +907 -68
  127. package/src/lib/repo/types.ts +125 -5
  128. package/src/lib/scheduler.ts +27 -0
  129. package/src/lib/schema.ts +316 -1
  130. package/src/lib/search-i18n.ts +3 -0
  131. package/src/lib/socialIcons.ts +32 -0
  132. package/src/lib/tagColor.ts +11 -0
  133. package/src/lib/theme.ts +59 -40
  134. package/src/lib/themeTokens.ts +183 -0
  135. package/src/lib/umami.ts +108 -0
  136. package/src/lib/webhook-sql.ts +68 -0
  137. package/src/lib/webhooks.ts +147 -0
  138. package/src/lib/widgets.ts +1 -0
  139. package/src/middleware.ts +45 -3
  140. package/src/pages/404.astro +23 -0
  141. package/src/pages/[...slug].astro +14 -5
  142. package/src/pages/account/[action].astro +53 -0
  143. package/src/pages/admin/ai.astro +12 -0
  144. package/src/pages/admin/c/[collection]/[id].astro +4 -1
  145. package/src/pages/admin/c/[collection]/index.astro +127 -92
  146. package/src/pages/admin/calendar/bookings.astro +400 -0
  147. package/src/pages/admin/calendar/calendars.astro +265 -0
  148. package/src/pages/admin/calendar/events/[id].astro +56 -0
  149. package/src/pages/admin/calendar/events/index.astro +408 -0
  150. package/src/pages/admin/calendar/index.ts +4 -0
  151. package/src/pages/admin/calendar/integrations.astro +4 -0
  152. package/src/pages/admin/calendar/resources/[id].astro +180 -0
  153. package/src/pages/admin/calendar/resources/index.astro +106 -0
  154. package/src/pages/admin/calendar/resources/link.astro +196 -0
  155. package/src/pages/admin/design.astro +10 -3
  156. package/src/pages/admin/email.astro +13 -0
  157. package/src/pages/admin/index.astro +232 -85
  158. package/src/pages/admin/integrations.astro +237 -0
  159. package/src/pages/admin/links.astro +3 -3
  160. package/src/pages/admin/live.astro +12 -0
  161. package/src/pages/admin/login.astro +14 -10
  162. package/src/pages/admin/navigation.astro +8 -2
  163. package/src/pages/admin/pages/[id].astro +4 -1
  164. package/src/pages/admin/pages/index.astro +41 -48
  165. package/src/pages/admin/settings.astro +418 -367
  166. package/src/pages/admin/tags.astro +4 -4
  167. package/src/pages/admin/users.astro +38 -28
  168. package/src/pages/api/agent/docs.ts +33 -0
  169. package/src/pages/api/agent/index.ts +21 -0
  170. package/src/pages/api/ai/clean.ts +13 -0
  171. package/src/pages/api/ai/draft.ts +14 -0
  172. package/src/pages/api/ai/settings.ts +53 -0
  173. package/src/pages/api/ai/test.ts +12 -0
  174. package/src/pages/api/backup.ts +8 -21
  175. package/src/pages/api/calendar/availability.ts +35 -0
  176. package/src/pages/api/calendar/bookings/[id].ts +49 -0
  177. package/src/pages/api/calendar/bookings/index.ts +73 -0
  178. package/src/pages/api/calendar/calendars.ts +35 -0
  179. package/src/pages/api/calendar/docs.ts +66 -0
  180. package/src/pages/api/calendar/events/[id].ts +63 -0
  181. package/src/pages/api/calendar/events/index.ts +112 -0
  182. package/src/pages/api/calendar/resources.ts +34 -0
  183. package/src/pages/api/design/capabilities.ts +10 -0
  184. package/src/pages/api/design/index.ts +58 -0
  185. package/src/pages/api/design/keys.ts +24 -0
  186. package/src/pages/api/design/media.ts +32 -0
  187. package/src/pages/api/email/run.ts +11 -0
  188. package/src/pages/api/email/settings.ts +61 -0
  189. package/src/pages/api/email/webhooks/[provider].ts +4 -0
  190. package/src/pages/api/live/oauth/youtube/callback.ts +19 -0
  191. package/src/pages/api/live/settings.ts +45 -0
  192. package/src/pages/api/live/status.ts +7 -0
  193. package/src/pages/api/live/thumb.ts +48 -0
  194. package/src/pages/api/mcp.ts +59 -0
  195. package/src/pages/api/media/upload.ts +2 -2
  196. package/src/pages/api/ops/status.ts +39 -0
  197. package/src/pages/api/restore.ts +27 -37
  198. package/src/pages/api/search.ts +18 -4
  199. package/src/pages/api/v1/availability.ts +7 -0
  200. package/src/pages/api/v1/bookings.ts +17 -0
  201. package/src/pages/api/v1/calendars.ts +7 -0
  202. package/src/pages/api/v1/content/[id].ts +7 -0
  203. package/src/pages/api/v1/content/index.ts +7 -0
  204. package/src/pages/api/v1/events.ts +7 -0
  205. package/src/pages/api/v1/resources.ts +7 -0
  206. package/src/pages/api/webhooks/docs.ts +61 -0
  207. package/src/pages/author/[slug].astro +43 -35
  208. package/src/pages/blog/[slug].astro +137 -66
  209. package/src/pages/blog/index.astro +95 -30
  210. package/src/pages/blog/tag/[slug].astro +45 -40
  211. package/src/pages/book/[resource]/[link].astro +70 -0
  212. package/src/pages/book/[resource]/index.astro +63 -0
  213. package/src/pages/book/[resource].ics.ts +38 -0
  214. package/src/pages/book/index.astro +47 -0
  215. package/src/pages/book/manage/[token].astro +108 -0
  216. package/src/pages/calendar/[slug].ics.ts +27 -0
  217. package/src/pages/calendar/feed.ics.ts +15 -0
  218. package/src/pages/calendar/index.astro +191 -0
  219. package/src/pages/embed/book/[resource]/[link].astro +33 -0
  220. package/src/pages/embed/calendar/[slug].astro +43 -0
  221. package/src/pages/events/[slug].astro +74 -0
  222. package/src/pages/events/[slug].ics.ts +25 -0
  223. package/src/pages/index.astro +12 -3
  224. package/src/pages/legal/privacy.astro +4 -0
  225. package/src/pages/legal/terms.astro +4 -0
  226. package/src/pages/links.astro +29 -3
  227. package/src/pages/llms.txt.ts +4 -0
  228. package/src/pages/preview/[type]/[id].astro +27 -6
  229. package/src/pages/search.astro +40 -20
  230. package/src/pages/sitemap.xml.ts +16 -1
  231. package/src/styles/admin.css +924 -105
  232. package/src/styles/cards.css +92 -74
  233. package/src/styles/editor.css +492 -114
  234. package/src/styles/email-settings.css +117 -0
  235. package/src/styles/live-admin.css +126 -0
  236. package/src/styles/live.css +199 -0
  237. package/src/styles/sections.css +12 -0
  238. package/src/styles/site.css +938 -281
  239. package/src/styles/theme-editor.css +135 -0
  240. package/src/theme-sdk/contract.d.mts +619 -0
  241. package/src/theme-sdk/contract.mjs +81 -0
  242. package/src/theme-sdk/index.ts +15 -0
  243. package/src/theme-sdk/tokens.d.mts +148 -0
  244. package/src/theme-sdk/tokens.mjs +55 -0
  245. package/src/themes/editorial/templates/home.astro +4 -4
  246. package/src/themes/editorial/templates/post-minimal.astro +2 -2
  247. package/src/themes/editorial/theme.css +27 -37
  248. package/src/themes/editorial/theme.json +25 -3
  249. package/src/themes/field/theme.json +27 -9
  250. package/src/themes/ink/theme.json +30 -12
  251. package/src/themes/night/theme.css +4 -7
  252. package/src/themes/night/theme.json +28 -10
  253. package/src/virtual.d.ts +14 -0
  254. package/src/worker.ts +5 -1
@@ -0,0 +1,117 @@
1
+ /* Settings → Email island. Scoped under .ems; reads only admin.css tokens.
2
+ Selection is a tinted fill, never an accent edge stripe. */
3
+ .ems { display: flex; flex-direction: column; gap: 12px; }
4
+ .ems code { font-family: ui-monospace, 'SF Mono', monospace; font-size: 12px; }
5
+ .ems .hint { margin: 0; }
6
+ .ems .flash { margin: 10px 0 0; }
7
+ .ems-status:empty { display: none; }
8
+ .ems-tabs { align-self: flex-start; max-width: 100%; overflow-x: auto; }
9
+ .ems-tabs > [role='tab'] { padding: 5px 12px; }
10
+ .ems-tabs > [role='tab']:focus-visible, .ems .seg > button:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--accent-ring); }
11
+ .ems-panel { display: flex; flex-direction: column; gap: 12px; }
12
+ .ems-panel[hidden] { display: none; }
13
+ .ems-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-card); padding: 16px 18px; }
14
+ .ems-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
15
+ .ems-head h2 { font-size: 14.5px; margin: 0; letter-spacing: -0.01em; }
16
+ .ems-head p { margin: 2px 0 0; color: var(--muted); font-size: 13px; max-width: 64ch; }
17
+ .ems-sub { font-size: 12px; font-weight: 600; color: var(--muted); margin: 16px 0 8px; }
18
+
19
+ /* loading skeleton */
20
+ .ems-skel { display: grid; gap: 10px; }
21
+ .ems-skel i { display: block; height: 56px; border-radius: var(--r-lg); background: var(--panel-2); animation: ems-pulse 1.2s ease-in-out infinite alternate; }
22
+ .ems-skel i:first-child { height: 30px; width: 320px; max-width: 100%; }
23
+ @keyframes ems-pulse { to { opacity: 0.45; } }
24
+ @media (prefers-reduced-motion: reduce) { .ems-skel i { animation: none; } }
25
+
26
+ /* setup checklist */
27
+ .ems-check { list-style: none; margin: 0; padding: 0; display: grid; gap: 1px; background: var(--line); border: 1px solid var(--line); border-radius: var(--r-md); overflow: hidden; }
28
+ .ems-check li { display: grid; grid-template-columns: 22px 150px 1fr; gap: 8px; align-items: baseline; padding: 9px 12px; background: var(--panel); font-size: 13px; }
29
+ .ems-check li::before { font-weight: 700; text-align: center; }
30
+ .ems-check li[data-s='ok']::before { content: '✓'; color: var(--green); }
31
+ .ems-check li[data-s='bad']::before { content: '!'; color: var(--red); }
32
+ .ems-check li[data-s='todo']::before { content: '○'; color: var(--faint); }
33
+ .ems-check li[data-s='manual']::before { content: '↗'; color: var(--amber); }
34
+ .ems-check b { font-weight: 600; }
35
+ .ems-check span { color: var(--text-2); min-width: 0; overflow-wrap: anywhere; }
36
+ .ems-hb { margin: 10px 0 0; font-size: 12.5px; color: var(--muted); }
37
+ .ems-hb.stale { color: var(--amber); }
38
+
39
+ /* choices */
40
+ .ems-toggle { display: flex; gap: 9px; align-items: flex-start; margin: 0 0 12px; cursor: pointer; font-size: 13.5px; }
41
+ .ems-toggle input { accent-color: var(--accent); margin: 3px 0 0; width: 15px; height: 15px; flex: 0 0 auto; }
42
+ .ems-toggle small { display: block; color: var(--muted); font-size: 12px; }
43
+ .ems-grid { border: 0; padding: 0; margin: 4px 0 14px; min-width: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
44
+ .ems-grid.two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
45
+ .ems-grid legend { font-size: 12px; color: var(--muted); font-weight: 500; padding: 0; margin-bottom: 5px; }
46
+ .ems-grid:disabled { opacity: 0.6; }
47
+ .ems-opt { display: flex; gap: 9px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--line-strong); border-radius: var(--r-md); background: var(--panel); cursor: pointer; }
48
+ .ems-opt:hover { background: var(--hover); }
49
+ .ems-opt.on { background: var(--sel); }
50
+ .ems-opt:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
51
+ .ems-opt input { accent-color: var(--accent); margin: 3px 0 0; flex: 0 0 auto; }
52
+ .ems-opt b { display: block; font-size: 13px; }
53
+ .ems-opt small { display: block; color: var(--muted); font-size: 12px; line-height: 1.4; margin-top: 1px; }
54
+ .ems-opt:has(input:disabled) { cursor: not-allowed; }
55
+ .ems-opt-l, .ems-saved { font-style: normal; font-weight: 500; color: var(--faint); margin-left: 4px; }
56
+ .ems-saved { color: var(--green); }
57
+ .ems .field-row.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
58
+ .ems input:disabled, .ems select:disabled { opacity: 0.6; cursor: not-allowed; }
59
+ .ems-env { background: var(--panel-2); border-radius: var(--r-md); padding: 10px 13px; margin: 0 0 12px; font-size: 13px; }
60
+ .ems-env p { margin: 0 0 6px; color: var(--text-2); }
61
+ .ems-env ul { margin: 0; padding: 0; list-style: none; display: flex; flex-wrap: wrap; gap: 6px; }
62
+ .ems-env code { display: inline-block; background: var(--panel); border: 1px solid var(--line); border-radius: 6px; padding: 2px 7px; }
63
+ .ems-note { background: var(--amber-soft); color: var(--text-2); border-radius: var(--r-md); padding: 9px 13px; margin: 0 0 12px; font-size: 13px; }
64
+ .ems-pw { max-width: 340px; margin-top: 4px; }
65
+ .ems-pw .hint { display: block; margin-top: 4px; }
66
+ .ems-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
67
+ .ems-row { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 12px; }
68
+ .ems-row .field { margin-bottom: 0; }
69
+ .ems-grow { flex: 1; min-width: 220px; }
70
+ .ems-list { margin: 0; padding-left: 18px; color: var(--text-2); font-size: 13px; display: grid; gap: 3px; }
71
+
72
+ /* template preview */
73
+ .ems-mail { margin: 0; border: 1px solid var(--line-strong); border-radius: var(--r-md); overflow: hidden; background: var(--panel-2); }
74
+ .ems-mail figcaption { padding: 10px 14px; font-size: 12.5px; color: var(--text-2); border-bottom: 1px solid var(--line); background: var(--panel); }
75
+ .ems-ics { display: inline-block; margin-left: 8px; font-size: 11px; font-weight: 600; padding: 1px 8px; border-radius: var(--r-full); background: var(--blue-soft); color: var(--blue); }
76
+ .ems-html { max-width: 520px; margin: 18px auto; background: #fff; color: #24211c; border-radius: var(--r-md); padding: 22px 26px; box-shadow: var(--shadow-sm); font-size: 14px; }
77
+ .ems-html h3 { font-size: 19px; margin: 6px 0 10px; letter-spacing: -0.01em; }
78
+ .ems-html p { margin: 0 0 8px; }
79
+ .ems-brand { font-weight: 700; font-size: 13px; color: #7d776e; }
80
+ .ems-cta { display: inline-block; margin: 8px 0 14px; padding: 8px 16px; border-radius: 8px; background: #24211c; color: #fff; font-weight: 600; font-size: 13.5px; }
81
+ .ems-small { font-size: 12px; color: #7d776e; }
82
+ .ems-text { margin: 0; padding: 16px 18px; white-space: pre-wrap; font: 12.5px/1.6 ui-monospace, 'SF Mono', monospace; color: var(--text); overflow-x: auto; }
83
+
84
+ /* activity */
85
+ .ems-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-md); }
86
+ .ems-table td, .ems-table th { padding: 10px 12px; vertical-align: top; font-size: 13px; }
87
+ .ems-table .t-sub { font-size: 11.5px; overflow-wrap: anywhere; }
88
+ .ems-rcpt { overflow-wrap: anywhere; font-weight: 600; max-width: 220px; }
89
+ .ems-state { display: inline-block; font-size: 11px; font-weight: 600; padding: 1px 8px; border-radius: var(--r-full); background: var(--sel); color: var(--muted); text-transform: capitalize; }
90
+ .ems-state[data-tone='ok'] { background: var(--green-soft); color: var(--green); }
91
+ .ems-state[data-tone='info'] { background: var(--blue-soft); color: var(--blue); }
92
+ .ems-state[data-tone='warn'] { background: var(--amber-soft); color: var(--amber); }
93
+ .ems-state[data-tone='bad'] { background: var(--red-soft); color: var(--red); }
94
+ .ems-err { margin-top: 4px; font-size: 12px; color: var(--red); overflow-wrap: anywhere; }
95
+ .ems-act { text-align: right; white-space: nowrap; }
96
+ .ems-empty { margin: 0; padding: 18px 4px; color: var(--muted); }
97
+
98
+ @media (max-width: 900px) {
99
+ .ems-grid, .ems .field-row.three { grid-template-columns: repeat(2, minmax(0, 1fr)); }
100
+ }
101
+ @media (max-width: 767px) {
102
+ .ems-card { padding: 14px; }
103
+ .ems-grid, .ems-grid.two, .ems .field-row, .ems .field-row.three { grid-template-columns: 1fr; }
104
+ .ems-check li { grid-template-columns: 22px 1fr; }
105
+ .ems-check li span { grid-column: 2; }
106
+ .ems-actions .btn, .ems-row > .btn { flex: 1; justify-content: center; }
107
+ .ems-pw { max-width: none; }
108
+ .ems-html { margin: 12px; padding: 18px; }
109
+ /* activity rows become stacked cards */
110
+ .ems-scroll { border: 0; overflow: visible; }
111
+ .ems-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
112
+ .ems-table, .ems-table tbody, .ems-table tr, .ems-table td { display: block; width: 100%; }
113
+ .ems-table tr { border: 1px solid var(--line); border-radius: var(--r-md); margin-bottom: 8px; padding: 6px 0; }
114
+ .ems-table td { border: 0; padding: 4px 12px; text-align: left; max-width: none; }
115
+ .ems-table td[data-l]::before { content: attr(data-l); display: block; font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--faint); }
116
+ .ems-table tr:hover td { background: none; }
117
+ }
@@ -0,0 +1,126 @@
1
+ /* Live video admin (LiveManager.tsx). Scoped under .live-admin; reuses the
2
+ Inset Paper tokens from admin.css. */
3
+
4
+ .live-admin { display: flex; flex-direction: column; gap: 14px; max-width: 900px; }
5
+ .live-admin .page-head { margin-bottom: 0; }
6
+ .live-admin .sub { max-width: 60ch; }
7
+ .live-admin code, .live-admin .mono { font-family: ui-monospace, 'SF Mono', monospace; font-size: 12.5px; }
8
+ .live-admin .hint { margin: 0; }
9
+ .live-admin a { color: var(--accent-deep); text-underline-offset: 2px; }
10
+ .live-admin fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
11
+ .live-admin fieldset:disabled { opacity: 0.75; }
12
+ .live-admin input[readonly] { background: var(--panel-2); color: var(--text-2); }
13
+ .live-admin .notice { margin-bottom: 0; font-size: 13px; }
14
+ .live-admin-msgs:empty { display: none; }
15
+ .live-admin-msgs .flash { margin: 0; }
16
+ .live-admin-flash { margin: 10px 0 0 !important; }
17
+
18
+ .live-admin-lede { margin: 0; color: var(--text-2); font-size: 13.5px; max-width: 64ch; }
19
+
20
+ .live-admin-card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow-card); padding: 16px 18px; }
21
+ .live-admin-card h2 { font-size: 14.5px; margin: 0; letter-spacing: -0.01em; color: var(--text); }
22
+ .live-admin-card h3 { font-size: 13px; margin: 0 0 4px; color: var(--text); }
23
+ .live-admin-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
24
+
25
+ /* status marker: dot + text, never a filled badge */
26
+ .live-admin-status { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 600; color: var(--text-2); }
27
+ .live-admin-status i, .live-admin-dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: 50%; background: var(--faint); display: inline-block; }
28
+ .live-admin .is-live i, .live-admin-dot.is-live { background: var(--red); box-shadow: 0 0 0 3px var(--red-soft); }
29
+ .live-admin .is-ok i, .live-admin-dot.is-ok { background: var(--green); }
30
+ .live-admin .is-warn i, .live-admin-dot.is-warn { background: var(--amber); }
31
+ .live-admin .is-bad i, .live-admin-dot.is-bad { background: var(--red); }
32
+ .live-admin-status.is-live { color: var(--red); }
33
+ .live-admin-status.is-ok { color: var(--green); }
34
+ .live-admin-status.is-warn { color: var(--amber); }
35
+ .live-admin-status.is-bad { color: var(--red); }
36
+
37
+ /* right now */
38
+ .live-admin-now p { margin: 0 0 10px; font-size: 14px; color: var(--text); }
39
+ .live-admin-now .live-admin-status { margin-right: 6px; }
40
+ .live-admin-conns { list-style: none; margin: 12px 0 0; padding: 10px 13px; background: var(--panel-2); border-radius: var(--r-md); display: grid; gap: 6px; }
41
+ .live-admin-conns li { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 13px; }
42
+ .live-admin-conns b { font-weight: 600; }
43
+ .live-admin-sched { margin-top: 10px !important; }
44
+
45
+ /* settings */
46
+ .live-admin-modes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-bottom: 14px !important; }
47
+ .live-admin-modes legend { font-size: 12px; color: var(--muted); font-weight: 500; padding: 0; margin-bottom: 5px; }
48
+ .live-admin-mode { display: flex; gap: 9px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--line-strong); border-radius: var(--r-md); cursor: pointer; background: var(--panel); }
49
+ .live-admin-mode:hover { background: var(--hover); }
50
+ .live-admin-mode.on { background: var(--sel); }
51
+ .live-admin-mode:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
52
+ .live-admin-mode input { accent-color: var(--accent); margin: 3px 0 0; flex: 0 0 auto; }
53
+ .live-admin-mode b { display: block; font-size: 13px; }
54
+ .live-admin-mode small { display: block; font-size: 12px; color: var(--muted); margin-top: 1px; line-height: 1.4; }
55
+ .live-admin-fields { margin-bottom: 4px !important; }
56
+ .live-admin-fields > .notice { margin: 0 0 12px !important; }
57
+ /* how it looks */
58
+ .live-admin-look { margin-top: 14px !important; padding-top: 14px !important; border-top: 1px solid var(--line) !important; }
59
+ .live-admin-look legend { font-size: 12px; color: var(--muted); font-weight: 500; padding: 0; float: left; width: 100%; margin-bottom: 6px; }
60
+ .live-admin-styles { clear: both; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
61
+ .live-admin-style > span { min-width: 0; }
62
+ .live-admin-glyph { display: block; position: relative; width: 100%; max-width: 132px; aspect-ratio: 2 / 1; margin: 1px 0 8px; border-radius: 6px; background: var(--panel-2); border: 1px solid var(--line); overflow: hidden; }
63
+ .live-admin-glyph em, .live-admin-glyph s { position: absolute; display: block; border-radius: 3px; }
64
+ .live-admin-glyph em { background: var(--line-strong); }
65
+ .live-admin-glyph s { width: 14px; height: 5px; background: #e0352b; border-radius: 1.5px; }
66
+ .live-admin-glyph.is-poster em { left: 8px; right: 8px; top: 6px; bottom: 16px; }
67
+ .live-admin-glyph.is-poster s { left: 11px; top: 9px; }
68
+ .live-admin-glyph.is-poster::after { content: ''; position: absolute; left: 8px; bottom: 7px; width: 55%; height: 4px; border-radius: 2px; background: var(--line-strong); }
69
+ .live-admin-glyph.is-split em { left: 6px; top: 7px; bottom: 7px; width: 54%; }
70
+ .live-admin-glyph.is-split s { left: 9px; top: 10px; }
71
+ .live-admin-glyph.is-split::after { content: ''; position: absolute; right: 8px; top: 40%; width: 28%; height: 4px; border-radius: 2px; background: var(--line-strong); box-shadow: 0 7px 0 var(--line-strong); }
72
+ .live-admin-glyph.is-row em { left: 6px; top: 35%; height: 30%; width: 28%; }
73
+ .live-admin-glyph.is-row s { left: 8px; top: calc(35% + 2px); width: 9px; height: 4px; }
74
+ .live-admin-glyph.is-row::after { content: ''; position: absolute; left: 40%; top: 46%; width: 44%; height: 4px; border-radius: 2px; background: var(--line-strong); }
75
+ .live-admin-style.on .live-admin-glyph { border-color: var(--accent); }
76
+ .live-admin-look-hint { display: block; margin: 6px 0 10px; }
77
+ .live-admin-look .check-row { margin-top: 6px; }
78
+ .live-admin-sub { margin: 14px 0 2px; font-size: 12px; color: var(--muted); font-weight: 500; }
79
+
80
+ .live-admin-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 4px; }
81
+ .live-admin-place { margin-top: 14px !important; padding-top: 12px; border-top: 1px solid var(--line); }
82
+
83
+ /* provider tabs (text tabs on the kit segmented track) */
84
+ .live-admin-tabs { margin-bottom: 14px; }
85
+ .live-admin-tabs > button { font-size: 12.5px; padding: 5px 14px; gap: 7px; }
86
+ .live-admin-tabs > button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
87
+
88
+ .live-admin-panel[hidden] { display: none; }
89
+ .live-admin-health { padding: 12px 14px; background: var(--panel-2); border-radius: var(--r-md); margin-bottom: 12px; }
90
+ .live-admin-dl { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 8px 16px; margin: 10px 0 0; }
91
+ .live-admin-dl dt { font-size: 11.5px; color: var(--muted); }
92
+ .live-admin-dl dd { margin: 1px 0 0; font-size: 13px; color: var(--text); overflow-wrap: anywhere; }
93
+
94
+ .live-admin-guide { border: 1px solid var(--line); border-radius: var(--r-md); margin-bottom: 14px; }
95
+ .live-admin-guide > summary { cursor: pointer; padding: 10px 13px; font-size: 13px; font-weight: 600; color: var(--text); list-style-position: inside; }
96
+ .live-admin-guide > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--r-md); }
97
+ .live-admin-guide[open] > summary { border-bottom: 1px solid var(--line); }
98
+ .live-admin-guide ol { margin: 0; padding: 12px 16px 4px 34px; display: grid; gap: 8px; font-size: 13px; color: var(--text-2); line-height: 1.5; }
99
+ .live-admin-guide > .hint { padding: 6px 13px 12px; line-height: 1.5; }
100
+ .live-admin-copy { display: flex; gap: 6px; align-items: center; margin-top: 6px; }
101
+ .live-admin-copy input { flex: 1; min-width: 0; }
102
+
103
+ .live-admin-form { margin-bottom: 4px; }
104
+ .live-admin-form > h3 { margin-bottom: 10px; }
105
+ .live-admin-steps-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; margin-top: 14px; }
106
+ .live-admin-step { border: 1px solid var(--line); border-radius: var(--r-md); padding: 12px 13px; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
107
+ .live-admin-step .field { margin-bottom: 0; width: 100%; }
108
+ .live-admin-step .live-admin-actions { margin-top: 0; }
109
+
110
+ .live-admin-danger { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
111
+ .live-admin .btn.ghost.danger { color: var(--red); }
112
+ .live-admin .btn:disabled { opacity: 0.55; cursor: not-allowed; }
113
+ .live-admin-copied:empty { display: none; }
114
+ .live-admin-copied { margin-top: 10px !important; }
115
+
116
+ .live-admin-roadmap p { margin: 4px 0 0; font-size: 13px; color: var(--muted); }
117
+
118
+ @media (max-width: 767px) {
119
+ .live-admin-card { padding: 14px; }
120
+ .live-admin-modes, .live-admin-styles { grid-template-columns: 1fr; }
121
+ .live-admin-glyph { display: none; }
122
+ .live-admin-tabs { display: flex; }
123
+ .live-admin-tabs > button { flex: 1; min-height: 36px; }
124
+ .live-admin-actions .btn { flex: 1; justify-content: center; }
125
+ .live-admin-conns li { flex-wrap: wrap; }
126
+ }
@@ -0,0 +1,199 @@
1
+ /* Live video: the card (all layouts) and the site-wide signals.
2
+ *
3
+ * Theme API — override any of these on :root (or a wrapper) in theme.css:
4
+ * --live-color tag, markers, avatar ring (theme token `live`)
5
+ * --live-ink text on --live-color
6
+ * --live-radius poster + card corners
7
+ * --live-tag-radius the LIVE tag (keep it a rectangle, never a pill)
8
+ * --live-poster-ratio poster shape
9
+ * --live-pulse marker blink duration (0s = still)
10
+ * Hooks: .pc-live[data-layout=poster|split|row|links][data-status=live|upcoming|offline],
11
+ * html[data-live=live|upcoming] while a broadcast is on.
12
+ */
13
+ /* Wrapped in @layer base so theme CSS (inlined unlayered by Site.astro)
14
+ always wins ties, regardless of bundle order in the built head. */
15
+ @layer base {
16
+ :root {
17
+ --live-color: var(--live, #d42f25);
18
+ --live-ink: var(--live-on, #fff);
19
+ --live-radius: var(--r, 16px);
20
+ --live-tag-radius: 5px;
21
+ --live-poster-ratio: 16 / 9;
22
+ --live-pulse: 1.6s;
23
+ }
24
+
25
+ @keyframes pc-live-pulse { 50% { opacity: 0.35; } }
26
+
27
+ .pc-live { margin: 28px 0; color: var(--ink); container-type: inline-size; text-align: left; }
28
+ .pc-live[hidden], .pc-live [hidden], .pc-live-dock[hidden], .pc-live-bar[hidden], .site-live[hidden] { display: none !important; }
29
+ .pc-live :focus-visible, .pc-live-dock :focus-visible, .pc-live-bar :focus-visible, .site-live:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
30
+
31
+ /* ---- offline: one slim row instead of an empty card ---- */
32
+ .pc-live-off {
33
+ display: none; align-items: center; gap: 10px; padding: 12px 16px;
34
+ border: 1px solid var(--line); border-radius: var(--live-radius); background: var(--panel); font-size: 0.92em;
35
+ }
36
+ .pc-live[data-status='offline'] .pc-live-off { display: flex; }
37
+ .pc-live[data-status='offline'] .pc-live-body { display: none; }
38
+ .pc-live-off-dot { width: 7px; height: 7px; border-radius: 2px; background: var(--muted); opacity: 0.6; flex: none; }
39
+ .pc-live-off span { flex: 1; color: var(--muted); }
40
+ .pc-live-off a { font-weight: 600; color: var(--ink); text-decoration: none; white-space: nowrap; }
41
+ .pc-live-off a:hover { text-decoration: underline; text-underline-offset: 3px; }
42
+
43
+ /* ---- card body ---- */
44
+ .pc-live-body {
45
+ background: var(--panel); border: 1px solid var(--line);
46
+ border-radius: calc(var(--live-radius) + 4px); padding: 10px; box-shadow: var(--sh-1);
47
+ }
48
+ .pc-live-media { position: relative; min-width: 0; }
49
+ .pc-live-poster {
50
+ position: relative; display: block; aspect-ratio: var(--live-poster-ratio); overflow: hidden;
51
+ border-radius: var(--live-radius); color: var(--muted);
52
+ background: color-mix(in srgb, var(--live-color) 7%, var(--soft));
53
+ }
54
+ .pc-live[data-status='upcoming'] .pc-live-poster { background: color-mix(in srgb, var(--accent) 8%, var(--soft)); }
55
+ .pc-live-poster img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
56
+ .pc-live-ph { position: absolute; inset: 0; display: grid; place-items: center; }
57
+ .pc-live-ph svg { width: 22%; max-width: 64px; opacity: 0.5; }
58
+
59
+ .pc-live-tag {
60
+ position: absolute; top: 10px; left: 10px; display: inline-flex; align-items: center; gap: 6px;
61
+ padding: 6px 8px; border-radius: var(--live-tag-radius);
62
+ background: var(--live-color); color: var(--live-ink);
63
+ font: 700 11px/1 var(--font-body); letter-spacing: 0.08em;
64
+ }
65
+ .pc-live-tag::before { content: ''; width: 6px; height: 6px; border-radius: 1.5px; background: currentColor; animation: pc-live-pulse var(--live-pulse) ease-in-out infinite; }
66
+ .pc-live[data-status='upcoming'] .pc-live-tag { background: rgb(12 13 16 / 80%); color: #fff; letter-spacing: 0; font-weight: 600; }
67
+ .pc-live[data-status='upcoming'] .pc-live-tag::before { display: none; }
68
+ .pc-live-viewers {
69
+ position: absolute; left: 10px; bottom: 10px; padding: 5px 7px; border-radius: var(--live-tag-radius);
70
+ background: rgb(12 13 16 / 72%); color: #fff; font: 500 11.5px/1 var(--font-body);
71
+ }
72
+ .pc-live-play { position: absolute; inset: 0; }
73
+ .pc-live-play::before {
74
+ content: ''; position: absolute; left: 50%; top: 50%; width: 58px; height: 58px; margin: -29px 0 0 -29px;
75
+ border-radius: 16px; background: rgb(255 255 255 / 92%); box-shadow: 0 10px 28px -10px rgb(0 0 0 / 55%);
76
+ transition: transform 0.15s ease;
77
+ }
78
+ .pc-live-play::after {
79
+ content: ''; position: absolute; left: 50%; top: 50%; margin: -10px 0 0 -5px;
80
+ border-left: 16px solid #17181c; border-top: 10px solid transparent; border-bottom: 10px solid transparent;
81
+ }
82
+ .pc-live-poster:hover .pc-live-play::before { transform: scale(1.06); }
83
+ .pc-live-player iframe { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: var(--live-radius); background: #000; }
84
+
85
+ /* ---- text ---- */
86
+ .pc-live-info { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; padding: 12px 6px 6px; min-width: 0; }
87
+ .pc-live-kicker, .pc-live-mark {
88
+ display: inline-flex; align-items: center; gap: 7px;
89
+ font: 700 11px/1.2 var(--font-body); letter-spacing: 0.08em; text-transform: uppercase; color: var(--live-color);
90
+ }
91
+ .pc-live-kicker::before, .pc-live-mark::before { content: ''; width: 7px; height: 7px; border-radius: 2px; background: currentColor; animation: pc-live-pulse var(--live-pulse) ease-in-out infinite; flex: none; }
92
+ .pc-live[data-status='upcoming'] .pc-live-kicker { color: var(--accent-text, var(--accent)); }
93
+ .pc-live[data-status='upcoming'] .pc-live-kicker::before { animation: none; }
94
+ .pc-live-kicker { display: none; }
95
+ /* typography sits on the inner span: section/prose h2 rules (unlayered) can't reach it */
96
+ .pc-live-title-text { display: block; font: 600 1.08rem/1.3 var(--font-heading); letter-spacing: -0.01em; overflow-wrap: anywhere; }
97
+ .pc-live-meta { margin: 0; color: var(--muted); font-size: 0.86em; }
98
+ .pc-live-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
99
+ .pc-live-btn {
100
+ display: inline-flex; align-items: center; gap: 6px; padding: 9px 14px; cursor: pointer;
101
+ border: 1px solid transparent; border-radius: var(--r-sm, 10px);
102
+ background: var(--btn, var(--ink)); color: var(--btn-ink, var(--bg));
103
+ font: 600 0.88em/1.2 var(--font-body); text-decoration: none; white-space: nowrap;
104
+ }
105
+ .pc-live-btn:hover { filter: brightness(1.08); }
106
+ .pc-live[data-playable='true'] a.pc-live-btn { background: transparent; color: var(--ink); border-color: var(--line); }
107
+ .pc-live-privacy { color: var(--muted); font-size: 0.78em; margin-top: 6px; }
108
+
109
+ /* ---- split: a hero (the "player" section style, or the owner's card style) ---- */
110
+ .pc-live[data-layout='split'] .pc-live-body {
111
+ display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 24px; align-items: center; padding: 12px;
112
+ border-radius: calc(var(--live-radius) + 6px);
113
+ }
114
+ .pc-live[data-layout='split'] .pc-live-info { padding: 4px 8px 4px 0; }
115
+ .pc-live[data-layout='split'] .pc-live-kicker { display: inline-flex; }
116
+ .pc-live[data-layout='split'] .pc-live-title-text { margin: 8px 0 4px; }
117
+ .pc-live[data-layout='split'] .pc-live-title-text {
118
+ font-size: clamp(1.3rem, 3.4cqi, 1.9rem); line-height: 1.12;
119
+ font-weight: var(--display-weight, 650); letter-spacing: var(--display-tracking, -0.03em);
120
+ }
121
+ @container (max-width: 700px) {
122
+ .pc-live[data-layout='split'] .pc-live-body { grid-template-columns: 1fr; gap: 4px; padding: 10px; }
123
+ .pc-live[data-layout='split'] .pc-live-info { padding: 10px 6px 6px; }
124
+ }
125
+
126
+ /* ---- row: compact, for sidebars and busy pages ---- */
127
+ .pc-live[data-layout='row'] .pc-live-body { display: grid; grid-template-columns: 168px minmax(0, 1fr); gap: 16px; align-items: center; padding: 8px; }
128
+ .pc-live[data-layout='row'] .pc-live-poster { border-radius: calc(var(--live-radius) * 0.7); }
129
+ .pc-live[data-layout='row'] .pc-live-tag { top: 6px; left: 6px; padding: 4px 6px; font-size: 10px; }
130
+ .pc-live[data-layout='row'] .pc-live-viewers, .pc-live[data-layout='row'] .pc-live-ph svg { display: none; }
131
+ .pc-live[data-layout='row'] .pc-live-info { padding: 2px 8px 2px 0; }
132
+ .pc-live[data-layout='row'] .pc-live-actions { margin-top: 6px; }
133
+ @container (max-width: 420px) {
134
+ .pc-live[data-layout='row'] .pc-live-body { grid-template-columns: 112px minmax(0, 1fr); gap: 12px; }
135
+ .pc-live[data-layout='row'] .pc-live-tag { font-size: 0; gap: 0; padding: 5px; }
136
+ }
137
+
138
+ /* ---- links page block ---- */
139
+ .pc-live[data-layout='links'] { margin: 12px 0; }
140
+ .pc-live[data-layout='links'] .pc-live-body { padding: 8px; }
141
+ .pc-live[data-layout='links'] .pc-live-info { flex-direction: row; align-items: center; gap: 12px; padding: 10px 4px 2px; }
142
+ .pc-live[data-layout='links'] .pc-live-title { flex: 1; }
143
+ .pc-live[data-layout='links'] .pc-live-title-text { font-size: 0.95rem; }
144
+ .pc-live[data-layout='links'] .pc-live-meta { display: none; }
145
+ .pc-live[data-layout='links'] .pc-live-actions { margin: 0; }
146
+ .pc-live[data-layout='links'] .pc-live-btn { padding: 7px 11px; font-size: 0.82em; }
147
+ html[data-live='live'] .links-avatar { box-shadow: 0 0 0 3px var(--bg), 0 0 0 5px var(--live-color); }
148
+
149
+ /* ---- site-wide: live bar (takes the announcement slot while live) ---- */
150
+ .pc-live-bar {
151
+ display: flex; align-items: center; justify-content: center; gap: 12px; position: relative;
152
+ padding: 9px 44px; background: var(--ink); color: var(--bg); font-size: 14px;
153
+ }
154
+ .pc-live-bar .pc-live-mark { color: color-mix(in srgb, var(--live-color) 70%, var(--bg)); }
155
+ .pc-live-bar-title { opacity: 0.82; min-width: 0; max-width: 46ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
156
+ .pc-live-bar a { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; white-space: nowrap; }
157
+ .pc-live-x {
158
+ position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
159
+ background: none; border: 0; color: inherit; opacity: 0.7; cursor: pointer; font-size: 12px; padding: 6px; border-radius: 6px;
160
+ }
161
+ .pc-live-x:hover { opacity: 1; background: color-mix(in srgb, currentColor 12%, transparent); }
162
+ html[data-live-bar] .announcement-bar { display: none; }
163
+ @media (max-width: 560px) { .pc-live-bar-title { display: none; } }
164
+
165
+ /* ---- site-wide: header marker ---- */
166
+ .site-live {
167
+ display: inline-flex; align-items: center; gap: 7px; padding: 7px 10px; white-space: nowrap;
168
+ border: 1px solid var(--line); border-radius: var(--r-sm, 10px);
169
+ color: var(--ink); font: 600 13px/1 var(--font-body); text-decoration: none;
170
+ }
171
+ .site-live::before { content: ''; width: 7px; height: 7px; border-radius: 2px; background: var(--live-color); animation: pc-live-pulse var(--live-pulse) ease-in-out infinite; }
172
+ .site-live:hover { background: var(--soft); }
173
+
174
+ /* ---- site-wide: floating dock ---- */
175
+ .pc-live-dock {
176
+ position: fixed; right: 16px; bottom: max(16px, env(safe-area-inset-bottom)); z-index: 60;
177
+ width: min(300px, calc(100vw - 32px)); padding: 8px 30px 8px 8px;
178
+ background: var(--panel); color: var(--ink); border: 1px solid var(--line); border-radius: var(--r, 14px);
179
+ box-shadow: var(--sh-3); animation: pc-live-in 0.25s ease-out;
180
+ }
181
+ .pc-live-dock > a { display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 10px; align-items: center; color: inherit; text-decoration: none; }
182
+ .pc-live-dock-thumb {
183
+ position: relative; aspect-ratio: 16 / 9; border-radius: calc(var(--live-radius) * 0.6); overflow: hidden;
184
+ background: color-mix(in srgb, var(--live-color) 10%, var(--soft));
185
+ }
186
+ .pc-live-dock-thumb img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
187
+ .pc-live-dock b { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin-top: 4px; font-size: 13px; line-height: 1.3; font-weight: 600; }
188
+ .pc-live-dock .pc-live-x { top: 6px; right: 4px; transform: none; color: var(--muted); }
189
+ @keyframes pc-live-in { from { opacity: 0; transform: translateY(8px); } }
190
+
191
+ @media (prefers-reduced-motion: reduce) {
192
+ .pc-live-tag::before, .pc-live-kicker::before, .pc-live-mark::before, .site-live::before { animation: none; }
193
+ .pc-live-dock { animation: none; }
194
+ }
195
+ }
196
+
197
+ /* Unlayered on purpose: prose and section rules (`.acms-section h2`, `article h2`)
198
+ are unlayered too, and would otherwise restyle the card's heading. */
199
+ .pc-live h2.pc-live-title { margin: 0; padding: 0; border: 0; font-size: 1rem; line-height: 1; }
@@ -0,0 +1,12 @@
1
+ .acms-sections{display:grid;gap:calc(3rem * var(--density,1));margin-block:2rem}
2
+ .acms-section{padding:clamp(1rem,4vw,3rem);border-radius:var(--r-lg);min-width:0}
3
+ .acms-section h2{font-family:var(--font-heading);font-size:clamp(1.7rem,4vw,3rem);line-height:1.15}
4
+ .section-text{white-space:pre-line;max-width:65ch;color:var(--muted)}
5
+ .section-hero.variant-split{display:grid;grid-template-columns:1fr 1fr;align-items:center;gap:2rem}
6
+ .section-hero.variant-centered{text-align:center}.section-hero.variant-centered .section-text{margin-inline:auto}
7
+ .section-image{width:100%;max-height:32rem;object-fit:cover;border-radius:var(--r)}
8
+ .section-items{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,16rem),1fr));gap:1.25rem;margin-top:1.5rem}
9
+ .variant-list .section-items,.section-faq .section-items{grid-template-columns:1fr}
10
+ .section-items>article:not(.post-card),.section-items>details{background:var(--panel);padding:1.25rem;border:1px solid var(--line);border-radius:var(--r)}
11
+ .section-items summary{cursor:pointer;font-weight:600}.section-cta.variant-panel{background:var(--soft)}
12
+ @media(max-width:640px){.section-hero.variant-split{grid-template-columns:1fr}.acms-section{padding:1rem}}