@mevdragon/vidfarm-devcli 0.16.0 → 0.18.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 (38) hide show
  1. package/.agents/skills/farmville-saas-ux/SKILL.md +156 -0
  2. package/.agents/skills/farmville-saas-ux/assets/starter.html +294 -0
  3. package/.agents/skills/farmville-saas-ux/references/components.md +340 -0
  4. package/.agents/skills/farmville-saas-ux/references/porting-guide.md +121 -0
  5. package/.agents/skills/farmville-saas-ux/references/tokens.md +271 -0
  6. package/.agents/skills/vidfarm-media/SKILL.md +4 -3
  7. package/.agents/skills/vidfarm-media/references/tts.md +20 -1
  8. package/SKILL.director.md +20 -20
  9. package/SKILL.platform.md +4 -4
  10. package/dist/src/account-pages-legacy.js +2 -2
  11. package/dist/src/app.js +721 -101
  12. package/dist/src/cli.js +11 -10
  13. package/dist/src/devcli/clips.js +64 -64
  14. package/dist/src/editor-chat.js +2 -2
  15. package/dist/src/frontend/homepage-client.js +162 -2
  16. package/dist/src/frontend/homepage-store.js +30 -1
  17. package/dist/src/frontend/homepage-view.js +111 -4
  18. package/dist/src/homepage.js +184 -1
  19. package/dist/src/landing-page.js +367 -0
  20. package/dist/src/primitive-registry.js +278 -2
  21. package/dist/src/reskin/agency-page.js +299 -0
  22. package/dist/src/reskin/calendar-page.js +567 -0
  23. package/dist/src/reskin/chat-page.js +607 -0
  24. package/dist/src/reskin/discover-page.js +1096 -0
  25. package/dist/src/reskin/document.js +663 -0
  26. package/dist/src/reskin/help-page.js +356 -0
  27. package/dist/src/reskin/index-page.js +62 -0
  28. package/dist/src/reskin/inpaint-page.js +541 -0
  29. package/dist/src/reskin/job-runs-page.js +477 -0
  30. package/dist/src/reskin/library-page.js +688 -0
  31. package/dist/src/reskin/login-page.js +262 -0
  32. package/dist/src/reskin/pricing-page.js +388 -0
  33. package/dist/src/reskin/settings-page.js +687 -0
  34. package/dist/src/reskin/theme.js +362 -0
  35. package/dist/src/services/serverless-records.js +54 -0
  36. package/dist/src/services/swipe-customize.js +434 -0
  37. package/package.json +1 -1
  38. package/public/assets/homepage-client-app.js +22 -22
@@ -0,0 +1,362 @@
1
+ // ─────────────────────────────────────────────────────────────────────────
2
+ // /reskin/* shared design system — "farmville-saas-ux" (warm sunny Fillout)
3
+ // ─────────────────────────────────────────────────────────────────────────
4
+ // This is the SHARED, ISOLATED stylesheet for the /reskin/* migration surface,
5
+ // where we port old vidfarm pages into the new design system one at a time.
6
+ //
7
+ // CSS isolation contract (do not break it):
8
+ // • Every /reskin page is its own standalone HTML document (see document.ts)
9
+ // with only THIS stylesheet — it never shares a <style> with the live app,
10
+ // so nothing here can conflict with old-page CSS and vice versa.
11
+ // • Belt-and-suspenders: every design token is prefixed `--rk-` and every
12
+ // class is prefixed `rk-`. Even if this CSS were ever inlined next to app
13
+ // CSS, there would be no collision.
14
+ // • Page modules add ONLY page-scoped classes prefixed `rk-<page>-` and lean
15
+ // on the shared primitives below. Never introduce an unprefixed class.
16
+ //
17
+ // The token values are copied from the farmville-saas-ux skill (honey-gold
18
+ // accent over a neutral base, heavy rounded display type, soft cards, glass
19
+ // pill nav, warm-dark footer).
20
+ export const RESKIN_PAGES = [
21
+ { slug: "settings", label: "Settings", emoji: "⚙️", blurb: "Profile, wallet, channels & developer keys", live: "/settings", done: true },
22
+ { slug: "library", label: "Library", emoji: "🎬", blurb: "Your projects, renders & mined clips (tabbed)", live: "/library", done: true },
23
+ { slug: "discover", label: "Discover", emoji: "✨", blurb: "Template feed · swipe · categories", live: "/discover", done: true },
24
+ { slug: "chat", label: "Brainstorm", emoji: "💬", blurb: "Full AI brainstorm chat", live: "/chat", done: true },
25
+ { slug: "calendar", label: "Calendar", emoji: "📅", blurb: "Scheduled posts", live: "/calendar", done: true },
26
+ { slug: "job-runs", label: "Job runs", emoji: "🩺", blurb: "Render & job history", live: "/job-runs", done: true },
27
+ { slug: "agency", label: "Agency", emoji: "🏢", blurb: "Agency / client workspaces", live: "/agency", done: true },
28
+ { slug: "pricing", label: "Pricing", emoji: "💳", blurb: "Plans & wallet top-up", live: "/pricing", done: true },
29
+ { slug: "login", label: "Login", emoji: "🔑", blurb: "Sign in / sign up", live: "/login", done: true },
30
+ { slug: "help", label: "Help", emoji: "🆘", blurb: "Help & getting started", live: "/help", done: true }
31
+ ];
32
+ /** Google Fonts + preconnect for the reskin display/body stack. Put in <head>. */
33
+ export const RESKIN_FONT_LINKS = `<link rel="preconnect" href="https://fonts.googleapis.com">
34
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
35
+ <link href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;500;600;700;800&family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">`;
36
+ /** The complete shared stylesheet. Injected once per reskin document. */
37
+ export const RESKIN_CSS = `
38
+ :root{
39
+ --rk-font-display:"Hanken Grotesk","blMelody",ui-sans-serif,system-ui,sans-serif;
40
+ --rk-font-body:"Inter",ui-sans-serif,system-ui,-apple-system,sans-serif;
41
+ --rk-font-mono:ui-monospace,"SFMono-Regular",Menlo,Monaco,Consolas,monospace;
42
+ /* honey gold — the one joy accent */
43
+ --rk-gold-500:#ffc738;--rk-gold-600:#f6c744;--rk-gold-700:#fcb900;--rk-gold-tint:#fff5e4;--rk-gold-tint2:#ffe9cc;
44
+ /* ink + neutral scale */
45
+ --rk-ink:#171717;--rk-n-800:#262626;--rk-n-700:#404040;--rk-n-600:#525252;--rk-n-500:#737373;--rk-n-400:#a3a3a3;
46
+ --rk-n-300:#d4d4d4;--rk-n-200:#ededed;--rk-n-100:#f5f5f5;--rk-n-50:#fbfbfb;--rk-white:#fff;
47
+ /* support pastels */
48
+ --rk-sky:#3f9fe0;--rk-sky-tint:#e2effd;--rk-violet:#9f5bde;--rk-violet-tint:#e4ddfd;
49
+ --rk-green:#22c55e;--rk-green-tint:#dcfce7;--rk-coral:#f97316;--rk-coral-tint:#ffe9cc;
50
+ --rk-red:#ef4444;--rk-red-tint:#fee2e2;
51
+ /* semantic */
52
+ --rk-bg:var(--rk-n-50);--rk-bg-section:var(--rk-n-100);--rk-surface:var(--rk-white);
53
+ --rk-border:var(--rk-n-200);--rk-border-strong:var(--rk-n-300);
54
+ --rk-text:var(--rk-n-700);--rk-text-muted:var(--rk-n-500);--rk-text-faint:var(--rk-n-400);
55
+ /* radius */
56
+ --rk-r-sm:6px;--rk-r-md:8px;--rk-r-lg:10px;--rk-r-xl:12px;--rk-r-2xl:16px;--rk-r-3xl:24px;--rk-r-full:9999px;
57
+ /* shadow — diffuse soft sunlight, never harsh */
58
+ --rk-shadow-xs:0 1px 2px 0 #0000000d;
59
+ --rk-shadow-sm:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;
60
+ --rk-shadow-md:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;
61
+ --rk-shadow-lg:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;
62
+ --rk-shadow-xl:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;
63
+ --rk-shadow-card:0 1px 2px #0000000d,0 8px 24px -12px #00000014;
64
+ --rk-shadow-nav:0 4px 24px -8px #00000026,0 1px 2px #0000000d;
65
+ --rk-ring-gold:0 0 0 3px var(--rk-gold-600),0 0 14px rgba(246,199,68,.4);
66
+ /* type scale */
67
+ --rk-text-xs:.75rem;--rk-text-sm:.875rem;--rk-text-base:1rem;--rk-text-lg:1.125rem;
68
+ --rk-text-xl:1.25rem;--rk-text-2xl:1.5rem;--rk-text-3xl:1.875rem;--rk-text-4xl:2.25rem;--rk-text-5xl:3rem;
69
+ /* space + motion */
70
+ --rk-container:75rem;--rk-gutter:clamp(1rem,4vw,2rem);--rk-section-y:clamp(3rem,6vw,5rem);
71
+ --rk-glass-blur:16px;--rk-ease:cubic-bezier(.22,1,.36,1);--rk-dur:200ms;
72
+ }
73
+
74
+ *,*::before,*::after{box-sizing:border-box}
75
+ .rk-root{margin:0;font-family:var(--rk-font-body);color:var(--rk-text);background:var(--rk-bg);
76
+ -webkit-font-smoothing:antialiased;line-height:1.5;min-height:100vh}
77
+ .rk-root a{text-decoration:none;color:inherit}
78
+ .rk-root h1,.rk-root h2,.rk-root h3,.rk-root h4{font-family:var(--rk-font-display);font-weight:800;
79
+ letter-spacing:-.025em;line-height:1.1;color:var(--rk-ink);margin:0}
80
+ .rk-root p{margin:0}
81
+ .rk-root code{font-family:var(--rk-font-mono);font-size:.9em;background:var(--rk-n-100);
82
+ padding:2px 6px;border-radius:6px;color:var(--rk-n-700)}
83
+
84
+ /* layout */
85
+ .rk-container{width:min(var(--rk-container),100%);margin:0 auto;padding:0 var(--rk-gutter)}
86
+ .rk-container-wide{width:min(85rem,100%);margin:0 auto;padding:0 var(--rk-gutter)}
87
+ .rk-page{padding:24px 0 80px}
88
+ .rk-page-head{display:grid;gap:4px;margin-bottom:18px}
89
+ .rk-h1{font-size:var(--rk-text-3xl);letter-spacing:-.03em}
90
+ .rk-sub{font-size:var(--rk-text-base);color:var(--rk-text-muted)}
91
+ .rk-stack{display:grid;gap:16px}
92
+ .rk-row{display:flex;align-items:center;gap:12px}
93
+ .rk-spread{display:flex;align-items:center;justify-content:space-between;gap:16px}
94
+ .rk-wrap{flex-wrap:wrap}
95
+ .rk-grid{display:grid;gap:20px}
96
+ .rk-grid-2{grid-template-columns:repeat(2,1fr)}
97
+ .rk-grid-3{grid-template-columns:repeat(3,1fr)}
98
+ .rk-grid-4{grid-template-columns:repeat(4,1fr)}
99
+ @media(max-width:900px){.rk-grid-3,.rk-grid-4{grid-template-columns:repeat(2,1fr)}}
100
+ @media(max-width:620px){.rk-grid-2,.rk-grid-3,.rk-grid-4{grid-template-columns:1fr}}
101
+ .rk-muted{color:var(--rk-text-muted)}.rk-faint{color:var(--rk-text-faint)}
102
+ .rk-mono{font-family:var(--rk-font-mono)}
103
+
104
+ /* app chrome — fixed LEFT sidebar nav + content column */
105
+ .rk-app{min-height:100vh}
106
+ .rk-sidebar{position:fixed;left:0;top:0;bottom:0;width:248px;z-index:50;display:flex;flex-direction:column;gap:4px;
107
+ padding:20px 14px 16px;background:#fff;border-right:1px solid var(--rk-border);overflow-y:auto}
108
+ .rk-content{margin-left:248px;min-height:100vh;background:var(--rk-bg)}
109
+ .rk-sidebar-brand{display:flex;align-items:center;gap:8px;padding:6px 10px 18px;font-family:var(--rk-font-display);
110
+ font-weight:800;font-size:20px;color:var(--rk-ink);letter-spacing:-.02em}
111
+ .rk-sidebar-nav{display:flex;flex-direction:column;gap:3px;flex:1;min-height:0}
112
+ .rk-sidebar-sep{height:1px;background:var(--rk-border);margin:8px}
113
+ .rk-sidebar-item{display:flex;align-items:center;padding:9px 13px;border-radius:var(--rk-r-lg);
114
+ font-size:14px;font-weight:600;color:var(--rk-n-600);white-space:nowrap;
115
+ transition:background var(--rk-dur) var(--rk-ease),color var(--rk-dur) var(--rk-ease)}
116
+ .rk-sidebar-item:hover{background:var(--rk-n-100);color:var(--rk-ink)}
117
+ .rk-sidebar-item.is-active{background:var(--rk-gold-tint);color:var(--rk-ink)}
118
+ /* AI chat dock — draggable FAB (defaults to the old sidebar-foot spot) + popup panel.
119
+ * The panel is 2x the sidebar width and, when it opens on the left, visually
120
+ * REPLACES the nav (sidebar goes visibility:hidden via body.rk-chat-left so the
121
+ * layout never jumps). If the FAB was dragged to the right half of the viewport
122
+ * the panel anchors right instead, so it is never cut off. */
123
+ .rk-fab{position:fixed;left:16px;bottom:16px;z-index:90;width:56px;height:56px;border-radius:var(--rk-r-full);
124
+ border:0;cursor:grab;background:var(--rk-gold-500);color:var(--rk-ink);display:grid;place-items:center;
125
+ box-shadow:var(--rk-shadow-lg);touch-action:none;user-select:none;-webkit-user-select:none;
126
+ transition:transform var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease),opacity var(--rk-dur) var(--rk-ease)}
127
+ .rk-fab:hover{transform:translateY(-2px);box-shadow:0 6px 18px -6px rgba(252,185,0,.6),var(--rk-shadow-lg)}
128
+ .rk-fab.is-dragging{cursor:grabbing;transition:none;transform:scale(1.08)}
129
+ .rk-fab.is-open{opacity:0;pointer-events:none;transform:scale(.6)}
130
+ .rk-fab svg{width:26px;height:26px}
131
+ .rk-aichat{position:fixed;z-index:95;top:12px;bottom:12px;left:12px;width:min(440px,calc(100vw - 24px));
132
+ display:flex;flex-direction:row;background:var(--rk-surface);border:1px solid var(--rk-border);
133
+ border-radius:var(--rk-r-3xl);box-shadow:var(--rk-shadow-xl);overflow:hidden;
134
+ animation:rk-aichat-in .22s var(--rk-ease)}
135
+ .rk-aichat.has-files{width:min(772px,calc(100vw - 24px))}
136
+ .rk-aichat.is-right{left:auto;right:12px}
137
+ .rk-aichat[hidden]{display:none}
138
+ @keyframes rk-aichat-in{from{opacity:0;transform:translateY(12px) scale(.98)}to{opacity:1;transform:none}}
139
+ .rk-chat-left .rk-sidebar{visibility:hidden}
140
+
141
+ /* left Files pane — baked into the panel; My Files + Temp as root folders of
142
+ one virtual root + directory nav. Also reused inline by /reskin/settings. */
143
+ .rk-aichat-files{flex:none;width:266px;display:none;flex-direction:column;min-height:0;
144
+ border-right:1px solid var(--rk-border);background:var(--rk-n-50)}
145
+ .rk-aichat.has-files .rk-aichat-files{display:flex}
146
+ .rk-aichat-files .rk-aichat-crumbs{padding-top:22px}
147
+ .rk-aichat-crumbs{display:flex;flex-wrap:wrap;align-items:center;gap:1px;padding:0 12px 8px;flex:none}
148
+ .rk-aichat-crumb{padding:2px 6px;border-radius:var(--rk-r-sm);cursor:pointer;background:transparent;border:0;
149
+ color:var(--rk-text-muted);font-size:12px;font-weight:600;font-family:inherit;max-width:120px;overflow:hidden;
150
+ text-overflow:ellipsis;white-space:nowrap}
151
+ .rk-aichat-crumb:hover{background:var(--rk-n-100);color:var(--rk-ink)}
152
+ .rk-aichat-crumb.is-current{color:var(--rk-ink)}
153
+ .rk-aichat-crumb-sep{color:var(--rk-n-300);font-size:12px}
154
+ .rk-aichat-files-body{flex:1;min-height:0;overflow-y:auto;padding:2px 8px 12px;display:grid;gap:2px;align-content:start}
155
+ .rk-aichat-frow{display:flex;align-items:center;gap:9px;width:100%;padding:8px 9px;border-radius:var(--rk-r-lg);
156
+ border:0;background:transparent;cursor:pointer;text-align:left;font-family:inherit;min-width:0;
157
+ transition:background var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease)}
158
+ .rk-aichat-frow:hover{background:#fff;box-shadow:var(--rk-shadow-xs)}
159
+ .rk-aichat-fic{width:30px;height:30px;border-radius:var(--rk-r-md);flex:none;display:grid;place-items:center;
160
+ font-size:11px;font-weight:700;overflow:hidden}
161
+ .rk-aichat-fic-folder{background:var(--rk-gold-tint2);color:var(--rk-gold-700)}
162
+ .rk-aichat-fic-file{background:var(--rk-n-100);color:var(--rk-n-600)}
163
+ .rk-aichat-fic img,.rk-aichat-fic video{width:100%;height:100%;object-fit:cover}
164
+ .rk-aichat-fmain{flex:1;min-width:0;display:grid;gap:1px}
165
+ .rk-aichat-fname{font-size:12.5px;font-weight:600;color:var(--rk-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
166
+ .rk-aichat-fmeta{font-size:11px;color:var(--rk-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
167
+ .rk-aichat-fadd{flex:none;font-size:11px;font-weight:700;color:var(--rk-gold-700);opacity:0;transition:opacity var(--rk-dur) var(--rk-ease)}
168
+ .rk-aichat-frow:hover .rk-aichat-fadd{opacity:1}
169
+ .rk-aichat-fstate{padding:22px 14px;text-align:center;font-size:12.5px;color:var(--rk-text-muted);line-height:1.5;display:grid;gap:8px;justify-items:center}
170
+ .rk-aichat-fstate a{color:var(--rk-gold-700);font-weight:600}
171
+ .rk-aichat-fstate button{font-family:inherit;font-size:12px;font-weight:600;color:var(--rk-ink);cursor:pointer;
172
+ background:#fff;border:1px solid var(--rk-border);border-radius:var(--rk-r-full);padding:5px 12px}
173
+ .rk-aichat-fstate button:hover{background:var(--rk-n-100)}
174
+ /* upload dropzone footer (shown when inside My Files / Temp) */
175
+ .rk-aichat-drop{flex:none;margin:2px 10px 12px;padding:13px 12px;border:1.5px dashed var(--rk-border-strong);
176
+ border-radius:var(--rk-r-xl);background:#fff;display:grid;gap:9px;justify-items:center;text-align:center;
177
+ transition:border-color var(--rk-dur) var(--rk-ease),background var(--rk-dur) var(--rk-ease)}
178
+ .rk-aichat-drop[hidden]{display:none}
179
+ .rk-aichat-drop.is-drag{border-color:var(--rk-gold-600);background:var(--rk-gold-tint)}
180
+ .rk-aichat-drop-text{font-size:11.5px;color:var(--rk-text-muted);line-height:1.4;overflow-wrap:anywhere}
181
+ .rk-aichat-drop-btn{font-family:inherit;font-size:12px;font-weight:700;color:var(--rk-ink);cursor:pointer;
182
+ background:var(--rk-gold-tint);border:1px solid var(--rk-gold-600);border-radius:var(--rk-r-full);padding:6px 15px;
183
+ transition:background var(--rk-dur) var(--rk-ease)}
184
+ .rk-aichat-drop-btn:hover{background:var(--rk-gold-tint2)}
185
+ .rk-aichat-drop-btn:disabled{opacity:.6;cursor:default}
186
+
187
+ /* chat column */
188
+ .rk-aichat-main{flex:1;min-width:0;display:flex;flex-direction:column}
189
+ .rk-aichat-head{display:flex;align-items:center;gap:8px;padding:14px 14px;border-bottom:1px solid var(--rk-border);flex:none}
190
+ .rk-aichat-head-main{flex:1;min-width:0;display:grid;gap:1px}
191
+ .rk-aichat-title{font-family:var(--rk-font-display);font-weight:800;font-size:15px;color:var(--rk-ink);letter-spacing:-.01em}
192
+ .rk-aichat-sub{font-size:11.5px;color:var(--rk-text-muted)}
193
+ .rk-aichat-tool{width:30px;height:30px;border-radius:var(--rk-r-lg);border:1px solid var(--rk-border);background:#fff;
194
+ cursor:pointer;color:var(--rk-n-600);display:grid;place-items:center;font-size:13px;flex:none;
195
+ transition:background var(--rk-dur) var(--rk-ease),color var(--rk-dur) var(--rk-ease),border-color var(--rk-dur) var(--rk-ease)}
196
+ .rk-aichat-tool:hover{background:var(--rk-n-100);color:var(--rk-ink)}
197
+ .rk-aichat-tool svg{width:15px;height:15px}
198
+ .rk-aichat-tool.is-on{background:var(--rk-gold-tint);border-color:var(--rk-gold-600);color:var(--rk-ink)}
199
+ .rk-aichat-log{flex:1;min-height:0;overflow-y:auto;padding:16px;display:grid;gap:10px;align-content:start;background:var(--rk-n-50)}
200
+ .rk-aichat-msg{max-width:85%;padding:10px 14px;border-radius:var(--rk-r-2xl);font-size:13.5px;line-height:1.5;overflow-wrap:break-word}
201
+ .rk-aichat-msg.is-ai{background:#fff;border:1px solid var(--rk-border);color:var(--rk-text);justify-self:start;
202
+ border-bottom-left-radius:var(--rk-r-sm);box-shadow:var(--rk-shadow-xs)}
203
+ .rk-aichat-msg.is-user{background:var(--rk-gold-tint2);color:var(--rk-ink);justify-self:end;border-bottom-right-radius:var(--rk-r-sm)}
204
+ .rk-aichat-chips{display:flex;flex-wrap:wrap;gap:6px;padding:10px 12px 0;flex:none}
205
+ .rk-aichat-chips:empty{display:none}
206
+ .rk-aichat-chip{display:inline-flex;align-items:center;gap:4px;padding:4px 6px 4px 10px;border-radius:var(--rk-r-full);
207
+ background:var(--rk-gold-tint2);color:var(--rk-gold-700);font-size:11.5px;font-weight:600;max-width:190px}
208
+ .rk-aichat-chip span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
209
+ .rk-aichat-chip button{border:0;background:transparent;color:inherit;cursor:pointer;font-size:14px;line-height:1;padding:0 2px}
210
+ .rk-aichat-composer{display:flex;gap:8px;padding:12px;border-top:1px solid var(--rk-border);flex:none;background:#fff}
211
+ .rk-aichat-composer .rk-input{flex:1;border-radius:var(--rk-r-full)}
212
+
213
+ /* narrow: stack the files drawer above the chat so neither pane is cut off */
214
+ @media(max-width:700px){
215
+ .rk-aichat.has-files{flex-direction:column}
216
+ .rk-aichat.has-files .rk-aichat-files{width:auto;max-height:44%;border-right:0;border-bottom:1px solid var(--rk-border)}
217
+ }
218
+
219
+ /* brand + glass helpers (kept — reused by the sidebar brand + the login page) */
220
+ .rk-glass{background:rgba(255,255,255,.72);backdrop-filter:blur(var(--rk-glass-blur));
221
+ -webkit-backdrop-filter:blur(var(--rk-glass-blur));border:1px solid var(--rk-border);box-shadow:var(--rk-shadow-nav)}
222
+ .rk-brand{display:inline-flex;align-items:center;gap:8px;font-family:var(--rk-font-display);
223
+ font-weight:800;font-size:20px;color:var(--rk-ink);letter-spacing:-.02em;flex:none}
224
+ .rk-brand-mark{width:26px;height:26px;border-radius:8px;background:var(--rk-gold-500);
225
+ display:grid;place-items:center;font-family:var(--rk-font-display);font-weight:800;font-size:15px;
226
+ color:var(--rk-ink);box-shadow:var(--rk-shadow-xs);flex:none}
227
+ .rk-brand-tag{font-family:var(--rk-font-body);font-size:11px;font-weight:600;color:var(--rk-gold-700);
228
+ background:var(--rk-gold-tint2);padding:2px 8px;border-radius:var(--rk-r-full);letter-spacing:.02em}
229
+
230
+ /* narrow: sidebar collapses to a horizontal top strip */
231
+ @media(max-width:900px){
232
+ .rk-sidebar{position:static;width:auto;flex-direction:row;align-items:center;gap:6px;
233
+ padding:10px 14px;border-right:0;border-bottom:1px solid var(--rk-border);overflow-x:auto}
234
+ .rk-sidebar-brand{padding:6px 8px;flex:none}
235
+ .rk-sidebar-nav{flex-direction:row;gap:4px;flex:1}
236
+ .rk-sidebar-sep{display:none}
237
+ .rk-sidebar-item{padding:8px 12px}
238
+ .rk-content{margin-left:0}
239
+ .rk-chat-left .rk-sidebar{visibility:visible}
240
+ }
241
+
242
+ /* buttons */
243
+ .rk-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:11px 18px;
244
+ border-radius:var(--rk-r-full);font-family:var(--rk-font-body);font-size:14px;font-weight:600;
245
+ border:1px solid transparent;cursor:pointer;white-space:nowrap;text-align:center;
246
+ transition:transform var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease),background var(--rk-dur) var(--rk-ease),border-color var(--rk-dur) var(--rk-ease)}
247
+ .rk-btn .rk-arrow{transition:transform var(--rk-dur) var(--rk-ease)}
248
+ .rk-btn:hover .rk-arrow{transform:translateX(3px)}
249
+ .rk-btn-ink{background:var(--rk-ink);color:#fff;box-shadow:var(--rk-shadow-sm)}
250
+ .rk-btn-ink:hover{background:#000;box-shadow:var(--rk-shadow-md);transform:translateY(-1px)}
251
+ .rk-btn-gold{background:var(--rk-gold-500);color:var(--rk-ink);font-weight:700;box-shadow:var(--rk-shadow-sm)}
252
+ .rk-btn-gold:hover{background:var(--rk-gold-700);box-shadow:0 6px 18px -6px rgba(252,185,0,.6);transform:translateY(-1px)}
253
+ .rk-btn-ghost{background:#fff;color:var(--rk-ink);border-color:var(--rk-border);box-shadow:var(--rk-shadow-xs)}
254
+ .rk-btn-ghost:hover{border-color:var(--rk-border-strong);box-shadow:var(--rk-shadow-sm)}
255
+ .rk-btn-danger{background:#fff;color:var(--rk-red);border-color:var(--rk-red-tint)}
256
+ .rk-btn-danger:hover{background:var(--rk-red-tint)}
257
+ .rk-btn-sm{padding:7px 13px;font-size:13px}
258
+ .rk-btn-lg{padding:14px 24px;font-size:15px}
259
+ .rk-btn-block{width:100%}
260
+
261
+ /* badges + pills */
262
+ .rk-badge{display:inline-flex;align-items:center;gap:6px;padding:5px 12px;border-radius:var(--rk-r-full);
263
+ background:#fff;border:1px solid var(--rk-border);box-shadow:var(--rk-shadow-xs);
264
+ font-size:13px;font-weight:500;color:var(--rk-n-700);justify-self:start;width:fit-content}
265
+ .rk-pill{display:inline-flex;align-items:center;gap:6px;padding:4px 11px;border-radius:var(--rk-r-full);
266
+ font-size:12px;font-weight:600;background:var(--rk-n-100);color:var(--rk-n-600)}
267
+ .rk-pill-gold{background:var(--rk-gold-tint2);color:var(--rk-gold-700)}
268
+ .rk-pill-green{background:var(--rk-green-tint);color:#15803d}
269
+ .rk-pill-sky{background:var(--rk-sky-tint);color:#1d6fb8}
270
+ .rk-pill-violet{background:var(--rk-violet-tint);color:#7c3aed}
271
+ .rk-pill-red{background:var(--rk-red-tint);color:#b91c1c}
272
+
273
+ /* cards */
274
+ .rk-card{background:var(--rk-surface);border:1px solid var(--rk-border);border-radius:var(--rk-r-3xl);
275
+ padding:28px;box-shadow:var(--rk-shadow-card)}
276
+ .rk-card-hover{transition:transform var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease)}
277
+ .rk-card-hover:hover{transform:translateY(-2px);box-shadow:var(--rk-shadow-lg)}
278
+ .rk-card-pad-sm{padding:20px}
279
+ .rk-card h2{font-size:var(--rk-text-2xl);letter-spacing:-.02em}
280
+ .rk-card h3{font-size:var(--rk-text-lg);font-weight:700;font-family:var(--rk-font-display)}
281
+ .rk-card-head{display:grid;gap:6px;margin-bottom:20px}
282
+ .rk-eyebrow{display:inline-flex;align-items:center;gap:6px;font-size:13px;font-weight:600;
283
+ color:var(--rk-gold-700);text-transform:uppercase;letter-spacing:.04em;justify-self:start;width:fit-content}
284
+
285
+ /* icon tiles */
286
+ .rk-tile{width:40px;height:40px;border-radius:var(--rk-r-xl);display:grid;place-items:center;font-size:18px;flex:none}
287
+ .rk-tile-sm{width:32px;height:32px;font-size:15px;border-radius:var(--rk-r-lg)}
288
+ .rk-tile-lg{width:52px;height:52px;font-size:24px}
289
+ .rk-tile-gold{background:var(--rk-gold-tint2);color:var(--rk-gold-700)}
290
+ .rk-tile-sky{background:var(--rk-sky-tint);color:var(--rk-sky)}
291
+ .rk-tile-violet{background:var(--rk-violet-tint);color:var(--rk-violet)}
292
+ .rk-tile-green{background:var(--rk-green-tint);color:#16a34a}
293
+ .rk-tile-coral{background:var(--rk-coral-tint);color:var(--rk-coral)}
294
+ .rk-tile-ink{background:var(--rk-n-100);color:var(--rk-ink)}
295
+
296
+ /* forms */
297
+ .rk-field{display:grid;gap:7px}
298
+ .rk-label{font-size:13px;font-weight:600;color:var(--rk-n-700)}
299
+ .rk-hint{font-size:12px;color:var(--rk-text-muted)}
300
+ .rk-input,.rk-textarea,.rk-select{width:100%;font-family:var(--rk-font-body);font-size:14px;
301
+ color:var(--rk-ink);background:#fff;border:1px solid var(--rk-border-strong);border-radius:var(--rk-r-xl);
302
+ padding:11px 14px;transition:border-color var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease)}
303
+ .rk-input::placeholder,.rk-textarea::placeholder{color:var(--rk-n-400)}
304
+ .rk-textarea{min-height:110px;resize:vertical;line-height:1.5}
305
+ .rk-select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' stroke='%23737373' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 14px center;padding-right:36px}
306
+ .rk-input:focus,.rk-textarea:focus,.rk-select:focus{outline:none;border-color:var(--rk-gold-600);box-shadow:var(--rk-ring-gold)}
307
+ .rk-input-group{display:flex;align-items:stretch;gap:8px}
308
+ .rk-input-group .rk-input{flex:1}
309
+
310
+ /* notice / flash */
311
+ .rk-notice{display:flex;align-items:center;gap:10px;padding:13px 16px;border-radius:var(--rk-r-2xl);
312
+ font-size:14px;font-weight:500;border:1px solid transparent}
313
+ .rk-notice-ok{background:var(--rk-green-tint);color:#15803d;border-color:#bbf7d0}
314
+ .rk-notice-err{background:var(--rk-red-tint);color:#b91c1c;border-color:#fecaca}
315
+
316
+ /* two-column shell with sticky side rail (settings, etc.) */
317
+ .rk-shell{display:grid;grid-template-columns:248px minmax(0,1fr);gap:32px;align-items:start}
318
+ @media(max-width:860px){.rk-shell{grid-template-columns:1fr}}
319
+ .rk-side{position:sticky;top:88px;display:grid;gap:4px;background:#fff;border:1px solid var(--rk-border);
320
+ border-radius:var(--rk-r-2xl);padding:12px;box-shadow:var(--rk-shadow-card)}
321
+ @media(max-width:860px){.rk-side{position:static;grid-auto-flow:column;overflow:auto}}
322
+ .rk-side-item{display:flex;align-items:center;gap:10px;padding:11px 14px;border-radius:var(--rk-r-xl);
323
+ font-size:14px;font-weight:600;color:var(--rk-n-600);cursor:pointer;border:0;background:transparent;
324
+ box-sizing:border-box;text-decoration:none;
325
+ width:100%;text-align:left;white-space:nowrap;transition:background var(--rk-dur) var(--rk-ease),color var(--rk-dur) var(--rk-ease)}
326
+ .rk-side-item:hover{background:var(--rk-n-100);color:var(--rk-ink)}
327
+ .rk-side-item.is-active{background:var(--rk-gold-tint);color:var(--rk-ink)}
328
+ .rk-side-item.is-active .rk-side-ic{background:var(--rk-gold-500)}
329
+ .rk-side-ic{width:26px;height:26px;border-radius:8px;background:var(--rk-n-100);display:grid;place-items:center;font-size:14px;flex:none}
330
+
331
+ /* simple list rows */
332
+ .rk-list{display:grid;gap:10px;grid-template-columns:minmax(0,1fr)}
333
+ .rk-item{display:flex;align-items:center;gap:14px;padding:14px 16px;background:#fff;min-width:0;
334
+ border:1px solid var(--rk-border);border-radius:var(--rk-r-2xl);box-shadow:var(--rk-shadow-xs)}
335
+ .rk-item-main{flex:1;min-width:0}
336
+ .rk-item-title{font-weight:600;color:var(--rk-ink);font-size:14px}
337
+ .rk-item-sub{font-size:13px;color:var(--rk-text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
338
+
339
+ /* stat tiles */
340
+ .rk-stat{display:grid;gap:6px}
341
+ .rk-stat-label{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:600;color:var(--rk-text-muted)}
342
+ .rk-stat-num{font-family:var(--rk-font-display);font-size:var(--rk-text-4xl);font-weight:800;letter-spacing:-.02em;color:var(--rk-ink)}
343
+
344
+ /* footer — warm-dark charcoal */
345
+ .rk-footer{background:var(--rk-ink);color:var(--rk-n-400);padding:56px var(--rk-gutter) 40px;margin-top:64px}
346
+ .rk-footer-inner{width:min(var(--rk-container),100%);margin:0 auto;display:flex;flex-wrap:wrap;gap:24px;align-items:center;justify-content:space-between}
347
+ .rk-footer-brand{font-family:var(--rk-font-display);font-weight:800;font-size:22px;color:var(--rk-gold-500);display:inline-flex;align-items:center;gap:8px}
348
+ .rk-footer a{color:var(--rk-n-300)}.rk-footer a:hover{color:#fff}
349
+ .rk-footer-links{display:flex;gap:8px;flex-wrap:wrap}
350
+ .rk-trust-pill{display:inline-flex;align-items:center;gap:8px;padding:7px 14px;border-radius:var(--rk-r-full);background:#ffffff0d;color:var(--rk-n-400);font-size:13px}
351
+
352
+ /* hero band (sunny sky) — sits flush at the top of the content column */
353
+ .rk-hero-band{position:relative;overflow:hidden;margin-top:0}
354
+ .rk-hero-art{position:absolute;inset:0;z-index:0;background:
355
+ radial-gradient(58% 46% at 78% 20%,rgba(255,241,204,.9),transparent 60%),
356
+ linear-gradient(180deg,#3f9fe0 0%,#6cc0f5 55%,#a9dbfb 100%)}
357
+ .rk-hero{position:relative;z-index:1;text-align:center;padding:119px var(--rk-gutter) 72px}
358
+
359
+ :where(.rk-root a,.rk-root button,.rk-root input,.rk-root textarea,.rk-root select):focus-visible{outline:none;box-shadow:var(--rk-ring-gold)}
360
+ .rk-reveal[hidden]{display:none}
361
+ `;
362
+ //# sourceMappingURL=theme.js.map
@@ -654,6 +654,16 @@ class ServerlessRecordsServiceImpl {
654
654
  const updated = await this.putRecord("ready_post", { ...post, status: "deleted", deletedAt: nowIso(), updatedAt: nowIso() });
655
655
  return updated;
656
656
  }
657
+ async setReadyPostMedia(input) {
658
+ const post = await this.getReadyPost(input.postId);
659
+ if (!post || post.customerId !== input.customerId)
660
+ return null;
661
+ return this.putRecord("ready_post", {
662
+ ...post,
663
+ mediaAssets: input.mediaAssets,
664
+ updatedAt: nowIso()
665
+ });
666
+ }
657
667
  async setReadyPostZip(input) {
658
668
  const post = await this.getReadyPost(input.postId);
659
669
  if (!post || post.customerId !== input.customerId)
@@ -665,6 +675,50 @@ class ServerlessRecordsServiceImpl {
665
675
  updatedAt: nowIso()
666
676
  });
667
677
  }
678
+ async createSwipeCustomization(input) {
679
+ const timestamp = nowIso();
680
+ return this.putRecord("swipe_customization", {
681
+ id: input.id ?? createIdV7("swipe"),
682
+ customerId: input.customerId,
683
+ templateId: input.templateId,
684
+ forkId: input.forkId ?? null,
685
+ sourceTitle: input.sourceTitle ?? null,
686
+ status: input.status ?? "customizing",
687
+ pipelineVersion: input.pipelineVersion ?? null,
688
+ tailoredTitle: input.tailoredTitle ?? null,
689
+ tailoredCaption: input.tailoredCaption ?? "",
690
+ tailoredPinnedComment: input.tailoredPinnedComment ?? null,
691
+ captionStyleId: input.captionStyleId ?? null,
692
+ previewSourceUrl: input.previewSourceUrl ?? null,
693
+ durationSeconds: input.durationSeconds ?? null,
694
+ aspect: input.aspect ?? null,
695
+ jobId: input.jobId ?? null,
696
+ renderJobId: input.renderJobId ?? null,
697
+ readyPostId: input.readyPostId ?? null,
698
+ error: input.error ?? null,
699
+ decidedAt: input.decidedAt ?? null,
700
+ createdAt: input.createdAt ?? timestamp,
701
+ updatedAt: timestamp
702
+ });
703
+ }
704
+ async getSwipeCustomization(id) {
705
+ return this.getById("swipe_customization", id);
706
+ }
707
+ async listSwipeCustomizationsForCustomer(customerId) {
708
+ return this.listByCustomer("swipe_customization", customerId);
709
+ }
710
+ async updateSwipeCustomization(input) {
711
+ const existing = await this.getSwipeCustomization(input.id);
712
+ if (!existing || existing.customerId !== input.customerId)
713
+ return null;
714
+ return this.putRecord("swipe_customization", {
715
+ ...existing,
716
+ ...input.patch,
717
+ id: existing.id,
718
+ customerId: existing.customerId,
719
+ updatedAt: nowIso()
720
+ });
721
+ }
668
722
  async createPostSchedule(input) {
669
723
  const timestamp = nowIso();
670
724
  return this.putRecord("post_schedule", {