Do a thorough audit of all 11 PHP pages in the Varaverk Unraid plugin at /boot/config/plugins/varaverk/Plugin/unraid/pages/. Also read the shared CSS at /boot/config/plugins/varaverk/Plugin/unraid/css/varaverk.css.

I need a page-by-page catalog of:

1. **Visual inconsistencies** — buttons, cards, badges, spacing, colors, fonts that don't match the design language used on other pages. Note which page does it "right" as the reference.

2. **UX gaps** — missing loading states, no empty state messages, missing error feedback, no confirmation on destructive actions, things that silently do nothing.

3. **Inline styles vs CSS** — how much styling is inline vs in varaverk.css? Which pages dump large <style> blocks inline vs sharing from the CSS file? Is the CSS file well-organized?

4. **Broken or incomplete flows** — pages or sections that appear unfinished, have placeholder text, dead buttons, or flows that don't complete correctly.

5. **Cross-page duplication** — identical JS functions, CSS class definitions, or HTML patterns repeated across multiple page files.

For each finding: page filename, what the issue is, and (where relevant) which other page has the "correct" version to copy from.

Be thorough — read each file fully. Report findings grouped by page. This audit will be used to plan a polishing pass, so concrete specifics matter more than summaries.


- update-config: Use this skill to configure the Claude Code harness via settings.json. Automated behaviors ("from now on when X", "each time X", "whenever X", "before/after X") require hooks configured in settings.json - the harness executes these, not Claude, so memory/preferences cannot fulfill them. Also use for: permissions ("allow X", "add permission", "move permission to"), env vars ("set X=Y"), hook troubleshooting, or any changes to settings.json/settings.local.json files. Examples: "allow npm commands", "add bq permission to global settings", "move permission to user settings", "set DEBUG=true", "when claude stops show X". For simple settings like theme/model, suggest the /config command.
- keybindings-help: Use when the user wants to customize keyboard shortcuts, rebind keys, add chord bindings, or modify ~/.claude/keybindings.json. Examples: "rebind ctrl+s", "add a chord shortcut", "change the submit key", "customize keybindings".
- verify: Verify that a code change actually does what it's supposed to by running the app and observing behavior. Use when asked to verify a PR, confirm a fix works, test a change manually, check that a feature works, or validate local changes before pushing.
- code-review: Review the current diff for correctness bugs and reuse/simplification/efficiency cleanups at the given effort level (low/medium: fewer, high-confidence findings; high→max: broader coverage, may include uncertain findings; ultra: deep multi-agent review in the cloud). Pass --comment to post findings as inline PR comments, or --fix to apply the findings to the working tree after the review.
- simplify: Review the changed code for reuse, simplification, efficiency, and altitude cleanups, then apply the fixes. Quality only — it does not hunt for bugs; use /code-review for that.
- fewer-permission-prompts: Scan your transcripts for common read-only Bash and MCP tool calls, then add a prioritized allowlist to project .claude/settings.json to reduce permission prompts.
- loop: Run a prompt or slash command on a recurring interval (e.g. /loop 5m /foo). Omit the interval to let the model self-pace. - When the user wants to set up a recurring task, poll for status, or run something repeatedly on an interval (e.g. "check the deploy every 5 minutes", "keep running /babysit-prs"). Do NOT invoke for one-off tasks.
- schedule: Create, update, list, or run scheduled remote agents (routines) that execute on a cron schedule. - When the user wants to schedule a recurring remote agent, set up automated tasks, create a cron job for Claude Code, or manage their scheduled agents/routines. Also use when the user wants a one-time scheduled run ("run this once at 3pm", "remind me to check X tomorrow").
- claude-api: Reference for the Claude API / Anthropic SDK — model ids, pricing, params, streaming, tool use, MCP, agents, caching, token counting, model migration.
TRIGGER — read BEFORE opening the target file; don't skip because it "looks like a one-liner" — whenever: the prompt names Claude/Anthropic in any form (Claude, Anthropic, Opus, Sonnet, Haiku, `anthropic`, `@anthropic-ai`, `claude-*`, `us.anthropic.*`, `[1m]`); the user asks about an LLM (pricing/model choice/limits/caching) — never answer from memory; OR the task is LLM-shaped with provider unstated (agent/MCP/tool-definition/multi-agent/RAG/LLM-judge/computer-use; generate/summarize/extract/classify/rewrite/converse over NL; debugging refusals/cutoffs/streaming/tool-calls/tokens).
SKIP only when another provider is being worked on (overrides all triggers): OpenAI/GPT/Gemini/Llama/Mistral/Cohere/Ollama named in the query; OR `grep -rE 'openai|langchain_openai|google.generativeai|genai|mistralai|cohere|ollama'` over the project hits (run this grep FIRST if no provider named — don't Read the file).
- run: Launch and drive this project's app to see a change working. Use when asked to run, start, or screenshot the app, or to confirm a change works in the real app (not just tests). First looks for a project skill that already covers launching the app; otherwise falls back to built-in patterns per project type (CLI, server, TUI, Electron, browser-driven, library).
- init: Initialize a new CLAUDE.md file with codebase documentation
- review: Review a pull request
- security-review: Complete a security review of the pending changes on the current branch

update-config keybindings-help verify code-review simplify fewer-permission-prompts loop schedule claude-api run init review security-review


I'll conduct a thorough audit of the Varaverk Unraid plugin pages. Let me start by exploring the structure and reading all the files.


Bash

find /boot/config/plugins/varaverk/Plugin/unraid/pages -type f -name "*.php" | sort


Perfect! I found all 11 pages. Now let me read each one along with the CSS file. I'll start with the CSS file to understand the design language, then read all PHP pages.


1	/* Varaverk plugin styles — inherits unRAID theme, adds plugin-specific layout */
2
3	#varaverk-wrap { padding: 10px; font-family: inherit; }
4
5	/* Tab bar */
6	#vv-tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 2px solid #444; align-items: flex-end; }
7	.vv-tab  { padding: 6px 16px; text-decoration: none; color: #aaa; border-radius: 4px 4px 0 0; }
8	.vv-tab:hover { color: #fff; background: #333; }
9	.vv-tab.active { color: #fff; background: #555; border-bottom: 2px solid #fff; }
10
11	/* Expand toggle button */
12	#vv-expand-btn {
13	  background: none; border: none; cursor: pointer;
14	  color: #333; font-size: 15px; padding: 2px 8px 4px;
15	  line-height: 1; border-radius: 3px; transition: color .15s;
16	  margin-left: 6px; flex-shrink: 0;
17	}
18	#vv-expand-btn:hover { color: #888; }
19	#vv-expand-btn.active { color: #aaa; }
20
21	/* Fullscreen mode — hide Unraid chrome, reclaim the space */
22	body.vv-fullscreen #header  { display: none !important; }
23	body.vv-fullscreen #menu    { display: none !important; }
24	body.vv-fullscreen #displaybox { padding-left: 1rem !important; padding-top: .5rem !important; }
25
26	/* Cards / layout */
27	.vv-row  { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
28	.vv-card { flex: 1; min-width: 200px; background: #1e1e1e; border: 1px solid #444;
29	           border-radius: 6px; padding: 12px; }
30	.vv-wide { flex: 100%; }
31	.vv-card h3 { margin: 0 0 10px; font-size: 13px; text-transform: uppercase;
32	              color: #888; letter-spacing: 0.05em; white-space: normal;
33	              overflow: hidden; min-width: 0;
34	              display: flex; align-items: center; justify-content: space-between; }
35
36	/* Cog icon — links to related Unraid page. Hidden until card hovered. */
37	.vv-card-cog { color: #2a2a2a; font-size: 13px; line-height: 1; text-decoration: none;
38	               padding: 1px 3px; border-radius: 3px; flex-shrink: 0;
39	               transition: color 0.15s, background 0.15s;
40	               font-style: normal; font-weight: normal; text-transform: none;
41	               letter-spacing: 0; cursor: pointer; }
42	.vv-card:hover .vv-card-cog { color: #4a4a4a; }
43	.vv-card-cog:hover { color: #aaa !important; background: #333; }
44
45	/* Card header icon wrapper */
46	.vv-ico { display:inline-flex; align-items:center; opacity:0.38; flex-shrink:0; }
47
48	/* Status accent — left border colour for state-driven cards */
49	.vv-accent-ok   { border-left-color: #2a5a2a !important; }
50	.vv-accent-warn { border-left-color: #5a4000 !important; }
51	.vv-accent-err  { border-left-color: #5a1e1e !important; }
52	#vv-monitor .vv-card { transition: border-left-color 0.5s; }
53
54	/* Status banner — coloured strip at top of card body */
55	.vv-banner { border-radius: 4px; padding: 5px 10px; margin-bottom: 10px;
56	             display: flex; align-items: center; justify-content: space-between;
57	             font-size: 12px; font-weight: 600; }
58	.vv-banner-ok   { background: #061306; border: 1px solid #1a401a; color: #4caf50; }
59	.vv-banner-warn { background: #130e00; border: 1px solid #3d2e00; color: #ff9800; }
60	.vv-banner-err  { background: #140404; border: 1px solid #3d1010; color: #f44336; }
61	.vv-banner-off  { background: #0d0d0d; border: 1px solid #252525; color: #555; }
62
63	/* System card — no h3, no top padding waste */
64	#vv-system { padding-top: 14px; }
65
66	/* System action buttons */
67	.vv-sys-btn { background: #2a2a2a; border: 1px solid #e65100; color: #ff9800; border-radius: 3px;
68	              padding: 3px 0; font-size: 6px; cursor: pointer; line-height: 1;
69	              width: 50px; min-width: 0; text-align: center; }
70	.vv-sys-btn:hover { background: #3a2000; color: #ffb74d; border-color: #ff9800; }
71
72	/* Fallback state badge */
73	.vv-state-badge { font-size: 20px; font-weight: bold; padding: 4px 0; margin-bottom: 2px; }
74	.vv-state-normal    { color: #4caf50; }
75	.vv-state-failover  { color: #f44336; }
76	.vv-state-no_internet { color: #ff9800; }
77	.vv-state-dark      { color: #9e9e9e; }
78	.vv-state-unknown   { color: #666; }
79
80	/* Docker table */
81	#vv-docker-table { width: 100%; border-collapse: collapse; font-size: 13px; }
82	#vv-docker-table th { text-align: left; padding: 4px 8px; color: #888;
83	                      border-bottom: 1px solid #444; }
84	#vv-docker-table td { padding: 4px 8px; border-bottom: 1px solid #2a2a2a; }
85	.vv-status-up   { color: #4caf50; }
86	.vv-status-down { color: #f44336; }
87
88	/* Scheduler */
89	.vv-hint { color: #888; font-size: 13px; margin-bottom: 16px; }
90	.vv-sched-card { margin-bottom: 10px; }
91	.vv-script { background: #161616; border: 1px solid #333; border-radius: 4px;
92	             padding: 6px 10px; margin: 4px 0; margin-left: 20px; }
93	.vv-job-row   { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
94	                transition: background 0.1s, box-shadow 0.1s; }
95	/* Orchestrator top row — clickable, show pointer + hover feedback */
96	.vv-orch-row  { cursor: pointer; border-radius: 4px; }
97	.vv-orch-row:hover { background: rgba(255,255,255,0.04); }
98	.vv-job-label { flex: 1; font-size: 16px; font-weight: bold;
99	                color: #6fcf97; min-width: 80px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
100	.vv-job-actions { display: flex; align-items: center; gap: 8px; padding-left: 44px; margin-top: 6px; }
101	.vv-job-desc  { font-size: 14px; color: #777; margin: 3px 0 2px 0;
102	                padding-left: 44px; box-sizing: border-box; width: 100%;
103	                white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
104	                cursor: default; }
105	.vv-cron { flex: 0 0 80px; width: 80px; background: #111; border: 1px solid #444; color: #ddd;
106	           padding: 4px 6px; border-radius: 4px; font-family: monospace; font-size: 11px; }
107	.vv-event-badge { flex: 0 0 auto; padding: 3px 8px; border-radius: 4px; font-size: 12px;
108	                  background: #1a3a1a; border: 1px solid #2e6b2e; color: #6fcf6f;
109	                  white-space: nowrap; font-weight: 500; }
110	.vv-flag-badge  { flex: 0 0 auto; padding: 2px 6px; border-radius: 3px; font-size: 11px;
111	                  background: #2e2200; border: 1px solid #6b4e00; color: #d4a017;
112	                  white-space: nowrap; font-family: monospace; }
113	.vv-log-label { display: flex; align-items: center; gap: 4px; font-size: 12px; color: #888;
114	                cursor: pointer; white-space: nowrap; flex-shrink: 0; }
115	.vv-log-label input { cursor: pointer; accent-color: #4caf50; }
116	.vv-log-label:has(input:checked) { color: #4caf50; }
117	.vv-children { padding-top: 8px; border-top: 1px solid #333; margin-top: 8px; }
118	.vv-advanced-toggle { background: none; border: 1px solid #555; color: #aaa;
119	                      padding: 2px 8px; border-radius: 4px; cursor: pointer; font-size: 12px; }
120	.vv-advanced-toggle:hover { border-color: #888; color: #fff; }
121	.vv-btn-sm { padding: 3px 10px; background: #2a2a2a; border: 1px solid #555; color: #ccc;
122	             border-radius: 4px; cursor: pointer; font-size: 12px; white-space: nowrap; }
123	.vv-btn-sm:hover { border-color: #888; color: #fff; }
124	.vv-btn-sm.active { border-color: #4caf50; color: #4caf50; }
125
126	/* Save checkmark */
127	.vv-save-check { color: #4caf50; font-size: 13px; width: 14px; flex-shrink: 0;
128	                 opacity: 0; text-align: center; }
129	@keyframes vv-check-fade { 0%,60% { opacity: 1; } 100% { opacity: 0; } }
130	.vv-save-check.vv-check-show { animation: vv-check-fade 2s forwards; }
131
132	/* Running dot */
133	.vv-job-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
134	.vv-dot-running { background: #4caf50; animation: vv-pulse-dot 1s ease-in-out infinite; }
135	#vv-log-dot { animation: vv-pulse-dot 1s ease-in-out infinite; }
136	@keyframes vv-pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } }
137
138	/* Selected job row — editor-style left accent + blue tint */
139	.vv-row-selected { background: rgba(100,149,237,0.1); border-radius: 4px;
140	                   outline: 1px solid rgba(100,149,237,0.35);
141	                   box-shadow: inset 3px 0 0 #6495ed; }
142
143	/* Two-panel layout */
144	#vv-sched-layout { display: flex; gap: 16px; align-items: stretch; }
145	#vv-sched-left   { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-self: flex-start; }
146	#vv-sched-cards  { flex: 1; }
147	#vv-sched-right  { display: none; flex: 1 1 0; min-width: 0; flex-direction: column; overflow: hidden; align-self: flex-start; }
148	#vv-sched-right.vv-panel-visible { display: flex; }
149	.vv-log-card { flex: 1; display: flex; flex-direction: column; padding-bottom: 0; }
150	.vv-log-right-pre { max-height: none; overflow-y: auto; }
151
152	/* Scheduler stacked layout (narrow viewport) */
153	@media (max-width: 900px) {
154	  #vv-sched-layout { flex-direction: column; align-items: stretch; }
155	  #vv-sched-left   { flex: none; width: 100%; }
156	  #vv-sched-right  { flex-direction: column; width: 100%; overflow: visible; }
157	  .vv-log-right-pre { min-height: 520px; max-height: 680px; }
158	  /* Toolbar: stack title row above buttons row, let buttons wrap */
159	  .vv-log-toolbar { flex-direction: column; align-items: flex-start; gap: 6px; }
160	  .vv-log-toolbar > div { flex-wrap: wrap; gap: 6px !important; }
161	  /* Array-event rows: badge already shows the event, cron input is redundant */
162	  .vv-job-row:has(.vv-event-badge) .vv-cron { display: none; }
163	}
164
165	/* Plugin settings row (Advanced mode) */
166	.vv-nb-settings { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
167	                  padding: 5px 10px; background: #101010; border-bottom: 1px solid #1a1a1a; }
168
169	/* ── Monitor: locked row height + scrollable cards ────────────────────────── */
170
171	/* Cards on the monitor grid are flex columns — h3 pins, body scrolls */
172	#vv-monitor .vv-card {
173	  display: flex;
174	  flex-direction: column;
175	  overflow: hidden;
176	}
177	#vv-monitor .vv-card h3 { flex-shrink: 0; }
178	#vv-monitor .vv-card > div {
179	  flex: 1;
180	  min-height: 0;
181	  overflow-y: auto;
182	  -ms-overflow-style: none;
183	  scrollbar-width: none;
184	}
185	#vv-monitor .vv-card > div::-webkit-scrollbar { display: none; }
186	/* Hide scrollbars on any nested scrollable div inside monitor cards */
187	#vv-monitor .vv-card div::-webkit-scrollbar { display: none; }
188
189	/* Dynamic row heights capped per screen tier — rows size to content, never exceed the cap.
190	   minmax(0, Xpx): track is content-driven but capped; align-items:stretch makes all cards
191	   in a row fill the track, so short cards (Pools, Watchdog) match tall ones (Array).
192	   Breakpoints are viewport height (after browser chrome), not screen height. */
193
194	/* ~720p  (viewport ≤ 700px) */
195	@media (min-width: 481px) and (max-height: 700px) {
196	  #vv-monitor { grid-auto-rows: minmax(0, calc((100vh - 160px) / 4)); }
197	}
198	/* ~1080p (viewport 701–1100px) */
199	@media (min-width: 481px) and (min-height: 701px) and (max-height: 1100px) {
200	  #vv-monitor { grid-auto-rows: minmax(0, calc((100vh - 240px) / 4)); }
201	}
202	/* ~1440p (viewport 1101–1450px) — calibrated on 15" 1440p display */
203	@media (min-width: 481px) and (min-height: 1101px) and (max-height: 1450px) {
204	  #vv-monitor { grid-auto-rows: minmax(0, calc((100vh - 335px) / 4)); }
205	}
206	/* ~4K    (viewport > 1450px) */
207	@media (min-width: 481px) and (min-height: 1451px) {
208	  #vv-monitor { grid-auto-rows: minmax(0, calc((100vh - 500px) / 4)); }
209	}
210
211	/* Mobile: natural heights, let page scroll */
212	@media (max-width: 480px) {
213	  #vv-monitor { grid-auto-rows: auto !important; }
214	  #vv-monitor .vv-card { overflow: visible !important; }
215	  #vv-monitor .vv-card > div { overflow-y: visible; min-height: auto; }
216	}
217
218	/* Monitor responsive — 4-column grid at medium width */
219	@media (max-width: 1400px) {
220	  /* CPU core bars — reduce gap/min-width at intermediate widths before cores get clipped */
221	  .vv-cpu-cores { gap: 2px !important; }
222	  .vv-cpu-core  { min-width: 7px !important; }
223	}
224
225	@media (max-width: 1024px) {
226	  #vv-monitor { grid-template-columns: repeat(4, 1fr) !important; }
227	  #vv-docker  { grid-column: span 4 !important; }
228	  /* Reset explicit placements so cards reflow in the 4-col grid */
229	  #vv-docker-folders { grid-column: span 4 !important; }
230	  #vv-parity-card    { grid-column: auto !important; }
231	  #vv-storage-card   { grid-column: auto !important; }
232	  #vv-array-card     { grid-column: auto !important; }
233	  /* Streams header: hide right chip group entirely, keep server badges + media type */
234	  .vv-stream-right { display: none; }
235	}
236
237	/* Containers+VMs: single column when viewport is narrow */
238	@media (max-width: 900px) {
239	  .vv-df-cols  { flex-direction: column; align-items: stretch; }
240	}
241
242	/* Phone layout — scheduler row/actions fixes + monitor single-column */
243	@media (max-width: 480px) {
244	  /* Phone portrait — hint gone, cron stays inline but compact */
245	  .vv-cron-hint { display: none !important; }
246	  .vv-job-row .vv-cron { flex: 0 0 68px; width: 68px; font-size: 10px; margin-left: 30px; }
247	}
248
249	@media (max-width: 600px) {
250	  /* Allow action buttons to wrap rather than overflow the card */
251	  .vv-job-actions { flex-wrap: wrap; padding-left: 0; }
252	  /* Kill the inline margin-left:auto that pushes Advanced off-screen */
253	  .vv-advanced-toggle { margin-left: 0 !important; width: auto !important; }
254	  /* Keep cron from growing — label owns remaining row space */
255	  .vv-cron { flex: 0 0 75px; width: 75px; }
256	  /* Slightly tighter label on narrow screens */
257	  .vv-job-label { font-size: 14px; }
258	  /* Footer buttons wrap instead of overflowing */
259	  .vv-sched-footer { flex-wrap: wrap; }
260	  /* Log toolbar search — narrow on small screens */
261	  #vv-log-search  { width: 80px; }
262	  /* Snapshot footer — smaller on mobile */
263	  .vv-snap-footer  { gap: 10px !important; }
264	  .vv-snap-item    { gap: 4px; }
265	  .vv-snap-label   { font-size: 10px; }
266	  .vv-snap-bar     { width: 44px; height: 5px; }
267	  .vv-snap-val     { font-size: 11px; min-width: 26px; }
268	  .vv-snap-div     { font-size: 11px; }
269	  .vv-snap-state   { font-size: 11px; }
270	  #vv-snap-partner { font-size: 11px; }
271	  .vv-snap-media   { font-size: 11px; }
272
273	  /* CPU core bars — shrink gap and min-width so many cores don't overflow */
274	  .vv-cpu-cores { gap: 2px !important; }
275	  .vv-cpu-core  { min-width: 6px !important; }
276
277	  /* Monitor single-column — explicit placement cards need override too */
278	  #vv-monitor { grid-template-columns: 1fr !important; }
279	  #vv-monitor > .vv-card { grid-column: 1 / -1 !important; }
280	  #vv-docker-folders { grid-column: 1 / -1 !important; }
281	}
282
283	/* Shared footer (Save Schedule left, info right) — same min-height so log card ends level with script cards */
284	.vv-sched-footer { display: flex; align-items: center; gap: 10px;
285	                   margin-top: 12px; padding: 10px 0; border-top: 1px solid #333;
286	                   flex-shrink: 0; min-height: 72px; box-sizing: border-box; }
287	.vv-sched-info { color: #666; font-size: 14px; display: flex; flex-direction: column; gap: 9px; }
288	.vv-save-btn { padding: 5px 18px; background: #4caf50; border: none; color: #fff;
289	               border-radius: 4px; cursor: pointer; font-size: 13px; }
290	.vv-save-btn:hover { background: #388e3c; }
291	.vv-save-status { font-size: 12px; color: #aaa; }
292	.vv-run-btn { border-color: #2196f3 !important; color: #2196f3 !important; }
293	.vv-run-btn:hover { background: #0d47a1 !important; color: #fff !important;
294	                    border-color: #2196f3 !important; }
295	.vv-dry-btn { border-color: #ff9800 !important; color: #ff9800 !important; }
296	.vv-dry-btn:hover { background: #e65100 !important; color: #fff !important;
297	                    border-color: #ff9800 !important; }
298	.vv-log-btn { border-color: #555 !important; color: #666 !important; }
299	.vv-log-btn:hover { background: #333 !important; color: #aaa !important; border-color: #777 !important; }
300	.vv-log-btn.vv-has-log { border-color: #4caf50 !important; color: #4caf50 !important; }
301	.vv-log-btn.vv-has-log:hover { background: #1b5e20 !important; color: #fff !important;
302	                                border-color: #4caf50 !important; }
303	.vv-edit-btn { border-color: #7b1fa2 !important; color: #ce93d8 !important; }
304	.vv-edit-btn:hover { background: #4a148c !important; color: #fff !important; border-color: #7b1fa2 !important; }
305	.vv-add-script-btn { background: #1565c0 !important; border: none !important; color: #fff !important; margin-left: 8px; }
306	.vv-add-script-btn:hover { background: #0d47a1 !important; }
307	.vv-save-script-btn-style { background: #1565c0 !important; border: none !important; color: #fff !important; }
308	.vv-save-script-btn-style:hover { background: #0d47a1 !important; }
309	.vv-delete-btn { background: #b71c1c !important; border: none !important; color: #fff !important; margin-left: 4px; }
310	.vv-delete-btn:hover { background: #7f0000 !important; }
311	.vv-conf-btn { border-color: #00838f !important; color: #4dd0e1 !important; }
312	.vv-conf-btn:hover { background: #006064 !important; color: #fff !important; border-color: #00838f !important; }
313
314	/* Config form */
315	#vv-confform { padding: 2px 4px; }
316	.vv-cf-group { border-bottom: 1px solid #252525; padding-bottom: 14px; margin-bottom: 14px; }
317	.vv-cf-group:last-child { border-bottom: none; margin-bottom: 0; }
318	.vv-cf-group-header { display: flex; align-items: center; gap: 8px; font-size: 11px; font-weight: bold;
319	                      color: #7a9eb5; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 10px; }
320	.vv-cf-file { font-size: 10px; color: #555; background: #1a1a1a; border: 1px solid #2e2e2e;
321	              padding: 1px 6px; border-radius: 3px; font-weight: normal; text-transform: none;
322	              letter-spacing: 0; }
323	.vv-cf-field { margin-bottom: 10px; }
324	.vv-cf-key  { font-family: monospace; font-size: 12px; color: #ccc; margin-bottom: 3px; }
325	.vv-cf-desc { font-size: 11px; color: #666; margin-bottom: 4px; font-style: italic; line-height: 1.4; }
326	.vv-cf-scalar { display: block; width: 100%; box-sizing: border-box; background: #111; border: 1px solid #333;
327	                color: #ddd; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; }
328	.vv-cf-scalar:focus { border-color: #555; outline: none; }
329	.vv-cf-array { display: block; width: 100%; box-sizing: border-box; background: #0d0d0d; border: 1px solid #333;
330	               color: #ccc; padding: 8px; border-radius: 4px; font-family: monospace; font-size: 11px;
331	               line-height: 1.6; resize: vertical; min-height: 60px; }
332	.vv-cf-array:focus { border-color: #555; outline: none; }
333	.vv-cf-empty { color: #555; font-size: 13px; font-style: italic; padding: 20px 4px; text-align: center; margin: 0; }
334	.vv-custom-empty { color: #666; font-size: 13px; padding: 8px 4px; margin: 0; font-style: italic; }
335	.vv-custom-count { font-size: 12px; color: #666; margin-left: 8px; flex-shrink: 0; }
336	.vv-section-sep { font-size: 11px; font-weight: bold; color: #666; text-transform: uppercase;
337	                  letter-spacing: 0.08em; padding: 10px 4px 4px; border-top: 1px solid #222; margin-top: 8px; }
338	#vv-editor { flex-direction: column; gap: 0; }
339	.vv-editor-body { font-family: monospace; font-size: 12px; background: #0d0d0d; color: #ccc;
340	                  border: 1px solid #333; border-radius: 4px; padding: 10px 12px; resize: none;
341	                  line-height: 1.5; scroll-behavior: auto; tab-size: 2; width: 100%; box-sizing: border-box;
342	                  white-space: pre; overflow-x: auto; }
343
344	/* Editor layout: gutter + inner area — unified bordered block */
345	#vv-editor-wrap  { display: flex; border: 1px solid #2e2e2e; border-radius: 4px 4px 0 0;
346	                   overflow: hidden; background: #0d0d0d; }
347	#vv-ln-gutter    { width: 46px; min-width: 46px; flex-shrink: 0;
348	                   background: #0a0a0a; border-right: 1px solid #1c1c1c;
349	                   font-family: monospace; font-size: 12px; line-height: 1.5; tab-size: 2;
350	                   color: #3a3a3a; text-align: right; padding: 10px 8px 10px 0;
351	                   overflow: hidden; user-select: none; white-space: pre; }
352	.vv-gln-cur { color: #ccc; font-weight: bold; }
353	#vv-editor-inner { position: relative; flex: 1; overflow: hidden; background: #0d0d0d; }
354
355	/* Current line highlight — sits behind overlay */
356	#vv-cur-line { position: absolute; left: 0; right: 0; height: 18px;
357	               background: rgba(255,255,255,0.04);
358	               border-top: 1px solid rgba(255,255,255,0.03);
359	               border-bottom: 1px solid rgba(255,255,255,0.03);
360	               pointer-events: none; display: none; }
361
362	/* Syntax-highlight overlay — transparent bg so cur-line shows through */
363	#vv-hl-overlay { display: none; position: absolute; top: 0; left: 0; right: 0; bottom: 0;
364	                 margin: 0; padding: 10px 12px; box-sizing: border-box;
365	                 font-family: monospace; font-size: 12px; line-height: 1.5; tab-size: 2;
366	                 white-space: pre; overflow: hidden;
367	                 pointer-events: none; user-select: none;
368	                 background: transparent; border: none; border-radius: 0; }
369	.vv-editor-hl #vv-hl-overlay { display: block; }
370	.vv-editor-hl #vv-editor-body { color: transparent; caret-color: #ddd; background: transparent;
371	                                  border: none !important; border-radius: 0 !important; }
372
373	/* Visible selection — works even when text is transparent */
374	.vv-editor-hl #vv-editor-body::selection     { background: rgba(100,149,237,0.35); color: transparent; }
375	.vv-editor-hl #vv-editor-body::-moz-selection{ background: rgba(100,149,237,0.35); color: transparent; }
376
377	/* Word match and search marks in the overlay */
378	.vv-word-mark          { background: rgba(255,220,60,0.14); outline: 1px solid rgba(255,220,60,0.35); border-radius: 2px; }
379	.vv-search-mark        { background: rgba(255,140,20,0.22); outline: 1px solid rgba(255,140,20,0.45); border-radius: 2px; }
380	.vv-search-mark-current{ background: rgba(255,90,0,0.40);   outline: 2px solid rgba(255,100,0,0.7);   border-radius: 2px; }
381
382	/* Slim scrollbar for editor */
383	#vv-editor-body::-webkit-scrollbar       { width: 8px; height: 8px; }
384	#vv-editor-body::-webkit-scrollbar-track { background: #0a0a0a; }
385	#vv-editor-body::-webkit-scrollbar-thumb { background: #2a2a2a; border-radius: 4px; }
386	#vv-editor-body::-webkit-scrollbar-thumb:hover { background: #444; }
387
388	/* Editor find bar — two-row (find + optional replace) */
389	#vv-editor-find { display: none; flex-direction: column; gap: 0; padding: 5px 8px;
390	                  margin-bottom: 5px; background: #161616; border: 1px solid #333;
391	                  border-radius: 4px; font-size: 12px; }
392	#vv-editor-find.vv-find-open { display: flex; }
393	.vv-find-row    { display: flex; align-items: center; gap: 6px; }
394	.vv-replace-row { display: none; align-items: center; gap: 6px;
395	                  margin-top: 4px; padding-top: 4px; border-top: 1px solid #222; }
396	.vv-replace-row.vv-repl-open { display: flex; }
397	.vv-find-expand { font-size: 10px; color: #555; cursor: pointer; flex-shrink: 0;
398	                  width: 14px; text-align: center; user-select: none;
399	                  transition: transform 0.15s; line-height: 1; }
400	.vv-find-expand:hover { color: #aaa; }
401	.vv-find-expand.open { transform: rotate(90deg); color: #888; }
402	#vv-find-input, #vv-replace-input {
403	  flex: 1; min-width: 0; background: #0d0d0d; border: 1px solid #333;
404	  color: #ddd; padding: 4px 8px; border-radius: 3px;
405	  font-family: monospace; font-size: 12px; }
406	#vv-find-input:focus, #vv-replace-input:focus {
407	  border-color: #6495ed; outline: none; box-shadow: 0 0 0 1px rgba(100,149,237,0.25); }
408	#vv-find-input.vv-find-no-match { border-color: #c62828; box-shadow: 0 0 0 1px rgba(198,40,40,0.3); }
409	.vv-find-count  { font-size: 11px; color: #555; white-space: nowrap; flex-shrink: 0; min-width: 64px; text-align: right; }
410	.vv-find-nav-btn{ padding: 2px 8px !important; }
411	.vv-repl-btn    { border-color: #444 !important; color: #777 !important; }
412	.vv-repl-btn:hover { border-color: #777 !important; color: #ddd !important; }
413	.vv-find-x      { color: #555; cursor: pointer; font-size: 16px; line-height: 1;
414	                  padding: 0 2px; flex-shrink: 0; }
415	.vv-find-x:hover { color: #aaa; }
416
417	/* Editor status bar */
418	#vv-editor-status { display: none; align-items: center; gap: 10px; padding: 3px 10px;
419	                    background: #0e0e0e; border: 1px solid #2e2e2e; border-top: none;
420	                    border-radius: 0 0 4px 4px; font-family: monospace;
421	                    font-size: 10px; color: #444; user-select: none; flex-shrink: 0; }
422	#vv-editor-status.vv-ed-active { display: flex; }
423	.vv-es-pos  { color: #666; }
424	.vv-es-sel  { color: #555; }
425	.vv-es-lang { margin-left: auto; color: #4a6a7a; }
426	/* Status bar action buttons */
427	.vv-es-btn { background: none; border: none; cursor: pointer; color: #555;
428	             font-size: 10px; padding: 1px 4px; border-radius: 2px; font-family: monospace; }
429	.vv-es-btn:hover { color: #aaa; background: rgba(255,255,255,0.05); }
430	.vv-es-btn.active { color: #6495ed; }
431	#vv-es-fontsize  { color: #444; font-size: 10px; min-width: 26px; text-align: center; }
432
433	/* Word wrap mode — applied to #vv-editor-wrap when wrap is enabled */
434	#vv-editor-wrap.vv-ed-wrap .vv-editor-body { white-space: pre-wrap !important; overflow-x: hidden !important; }
435	#vv-editor-wrap.vv-ed-wrap #vv-hl-overlay  { white-space: pre-wrap !important; word-break: break-word !important; }
436	#vv-editor-wrap.vv-ed-wrap #vv-ln-gutter   { display: none; }
437	#vv-editor-wrap.vv-ed-wrap #vv-cur-line    { display: none !important; }
438
439	/* Indent guides — 1px lines every 2 chars, starting at indent level 1 */
440	#vv-editor-inner {
441	  position: relative; flex: 1; overflow: hidden;
442	  background-color: #0d0d0d;
443	  background-image: repeating-linear-gradient(
444	    90deg,
445	    rgba(255,255,255,0.045) 0 1px,
446	    transparent 1px 2ch
447	  );
448	  background-position: calc(12px + 2ch) 0;
449	}
450
451	/* Go to line bar */
452	#vv-goto-bar { display: none; align-items: center; gap: 8px; padding: 5px 8px;
453	               margin-bottom: 5px; background: #161616; border: 1px solid #333;
454	               border-radius: 4px; font-size: 12px; }
455	#vv-goto-bar.vv-goto-open { display: flex; }
456	#vv-goto-input { width: 68px; background: #0d0d0d; border: 1px solid #333; color: #ddd;
457	                 padding: 4px 8px; border-radius: 3px; font-family: monospace; font-size: 12px; }
458	#vv-goto-input:focus { border-color: #6495ed; outline: none; }
459	.vv-goto-info { font-size: 11px; color: #555; white-space: nowrap; flex-shrink: 0; }
460
461	/* Undo / Redo buttons */
462	.vv-undo-redo-btn { border-color: #444 !important; color: #666 !important; }
463	.vv-undo-redo-btn:not([disabled]):hover { border-color: #777 !important; color: #ccc !important; background: #1e1e1e !important; }
464	.vv-undo-redo-btn[disabled] { opacity: 0.28 !important; cursor: default !important; pointer-events: none; }
465	.vv-undo-count { font-size: 10px; opacity: 0.7; margin-left: 2px; }
466
467	/* Suggestions panel — accordion */
468	#vv-suggestions { overflow-y: auto; }
469	.vv-sug-block { border-bottom: 1px solid #1e1e1e; }
470	.vv-sug-header { display: flex; align-items: center; gap: 8px; padding: 7px 4px;
471	                 cursor: pointer; user-select: none; flex-wrap: wrap; }
472	.vv-sug-header:hover { background: rgba(255,255,255,0.03); }
473	.vv-sug-chevron { color: #555; font-size: 11px; flex-shrink: 0; width: 10px; }
474	.vv-sug-title   { color: #7a9eb5; font-weight: bold; font-size: 13px; flex: 1; min-width: 120px; }
475	.vv-sug-cron    { color: #ddd; background: #111; border: 1px solid #333; padding: 1px 6px;
476	                  border-radius: 3px; font-size: 11px; font-family: monospace; white-space: nowrap; flex-shrink: 0; }
477	.vv-sug-label   { color: #666; font-size: 12px; flex: 1; min-width: 0; white-space: nowrap;
478	                  overflow: hidden; text-overflow: ellipsis; }
479	.vv-sug-status  { font-size: 11px; flex-shrink: 0; margin-left: auto; }
480	.vv-sug-on      { color: #4caf50; }
481	.vv-sug-off     { color: #777; }
482	.vv-sug-none    { color: #444; }
483	.vv-sug-body    { padding: 0 14px 10px; }
484	.vv-sug-desc    { font-size: 12px; color: #888; white-space: pre-wrap; word-break: break-word;
485	                  background: none; border: none; margin: 4px 0 8px; padding: 0;
486	                  font-family: inherit; line-height: 1.6; }
487	.vv-sug-scripts { display: flex; flex-direction: column; gap: 4px; }
488	.vv-sug-script-row { display: flex; align-items: center; gap: 8px; font-size: 12px; }
489	.vv-sug-inline-cron { color: #aaa; background: #111; padding: 1px 5px; border-radius: 3px;
490	                      font-size: 11px; white-space: nowrap; }
491	.vv-sug-path    { color: #888; font-family: monospace; }
492	.vv-sug-configured { color: #4caf50; font-size: 11px; }
493	/* Info sections inside Scheduler Information panel */
494	.vv-info-block .vv-sug-title { color: #9ab; }
495	.vv-info-body  { padding: 2px 10px 10px; }
496	.vv-info-cols  { margin: 0; padding-left: 16px; columns: 2; column-gap: 20px; column-fill: balance; }
497	.vv-info-cols li { font-size: 12px; color: #aaa; margin-bottom: 5px; break-inside: avoid; line-height: 1.5; }
498	.vv-info-cols .vv-info-sep { column-span: all; list-style: none; margin: 10px -4px 6px;
499	                              padding: 4px 8px; background: #161a1d; border-left: 2px solid #1e6fa5;
500	                              font-size: 10px; font-weight: bold; text-transform: uppercase;
501	                              letter-spacing: .08em; color: #4a8ab5; break-inside: avoid; }
502	.vv-info-cols li strong { color: #ccc; }
503	.vv-info-cols code { background: #1a1a1a; padding: 0 4px; border-radius: 2px;
504	                     font-size: 11px; color: #9ab; border: 1px solid #333; }
505	.vv-info-divider { font-size: 10px; text-transform: uppercase; letter-spacing: 0.1em; color: #444;
506	                   padding: 10px 12px 4px; border-top: 1px solid #2a2a2a; margin-top: 2px; }
507
508	/* How do I use this — pinned at top of suggestions panel */
509	#vv-how-to-use {
510	  position: sticky;
511	  top: 0;
512	  z-index: 3;
513	  background: #1e1e1e;
514	  border-bottom: 1px solid #333;
515	}
516
517	/* Run-status dot colours (tree + activity list) */
518	.vv-stat-ok   { color: #4caf50; }
519	.vv-stat-warn { color: #ff9800; }
520	.vv-stat-error{ color: #f44336; }
521	.vv-stat-skip { color: #607d8b; }
522	.vv-stat-none { color: #444; }
523
524	/* Cron humanizer hint — left of cron input; first to collapse under space pressure */
525	.vv-cron-hint { font-size: 10px; color: #505050; white-space: nowrap;
526	                flex: 0 10 auto; min-width: 0; max-width: 130px;
527	                overflow: hidden; text-overflow: ellipsis;
528	                pointer-events: none; user-select: none; }
529
530	/* Recent Activity list */
531	.vv-activity-list { display: flex; flex-direction: column; }
532	.vv-activity-row  { display: flex; align-items: center; gap: 6px; padding: 4px 0;
533	                    border-bottom: 1px solid #1a1a1a; font-size: 11px; cursor: pointer; }
534	.vv-activity-row:last-child { border-bottom: none; }
535	.vv-activity-row:hover .vv-activity-label { color: #fff; }
536	.vv-activity-dot   { flex-shrink: 0; font-size: 9px; }
537	.vv-activity-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis;
538	                     white-space: nowrap; color: #ccc; }
539	.vv-activity-ago   { color: #555; font-size: 10px; white-space: nowrap; flex-shrink: 0; }
540	.vv-activity-dur   { color: #444; font-size: 10px; white-space: nowrap; flex-shrink: 0;
541	                     min-width: 32px; text-align: right; }
542
543	/* Log search */
544	#vv-log-search { width: 120px; font-size: 11px; padding: 2px 6px;
545	                 background: #111; border: 1px solid #333; color: #ccc;
546	                 border-radius: 3px; font-family: monospace; }
547	#vv-log-search:focus { border-color: #555; outline: none; }
548	mark            { background: #5d4037; color: #ffcc80; border-radius: 2px; }
549	.vv-log-dim     { opacity: 0.2; }
550
551	/* Cron Calculator */
552	.vv-calc-wrap     { display: flex; flex-direction: column; gap: 8px; }
553	.vv-calc-in       { width: 100%; background: #111; border: 1px solid #333; color: #ccc;
554	                    padding: 5px 8px; border-radius: 3px; font-family: monospace; font-size: 12px;
555	                    box-sizing: border-box; }
556	.vv-calc-in:focus { border-color: #555; outline: none; }
557	.vv-calc-expr     { font-family: monospace; font-size: 13px; color: #7cb8e8;
558	                    background: #0d1117; padding: 4px 8px; border-radius: 3px; }
559	.vv-calc-desc     { font-size: 12px; color: #aaa; padding: 2px 2px 0; }
560	.vv-calc-hint     { font-size: 11px; color: #555; font-style: italic; }
561	.vv-calc-runs-lbl { font-size: 10px; color: #555; text-transform: uppercase;
562	                    letter-spacing: .05em; margin-top: 4px; }
563	.vv-calc-runs     { display: flex; flex-direction: column; gap: 2px; }
564	.vv-calc-run-row  { display: flex; gap: 8px; font-size: 11px; }
565	.vv-calc-run-in   { color: #4caf50; white-space: nowrap; min-width: 56px; }
566	.vv-calc-run-at   { color: #666; }
567	.vv-calc-apply-btn { align-self: flex-start; margin-top: 2px; }
568
569	/* Board blocks — Next Runs, Errors, Locks, Partner, Disabled */
570	.vv-board-placeholder { color: #555; font-size: 11px; padding: 3px 0; }
571
572	.vv-hdr-badge       { display: inline-block; padding: 1px 7px; border-radius: 10px;
573	                       font-size: 10px; font-weight: bold; flex-shrink: 0; }
574	.vv-hdr-badge-red   { background: #7f0000; color: #ef9a9a; }
575	.vv-hdr-badge-orange { background: #5d2000; color: #ffcc80; }
576	.vv-hdr-badge-gray  { background: #2a2a2a; color: #aaa; }
577
578	/* Next Runs */
579	.vv-nextrun-list { display: flex; flex-direction: column; }
580	.vv-nextrun-row  { display: flex; align-items: center; gap: 8px; padding: 4px 0;
581	                   border-bottom: 1px solid #1a1a1a; font-size: 12px; }
582	.vv-nextrun-row:last-child { border-bottom: none; }
583	.vv-nr-label { color: #ccc; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
584	.vv-nr-cron  { color: #555; font-family: monospace; font-size: 10px; flex-shrink: 0; }
585	.vv-nr-in    { color: #4caf50; font-size: 11px; white-space: nowrap; flex-shrink: 0; }
586	.vv-nr-at    { color: #666; font-size: 11px; white-space: nowrap; flex-shrink: 0; }
587
588	/* Errors */
589	.vv-errors-list { display: flex; flex-direction: column; gap: 1px; }
590	.vv-err-row     { padding: 5px 0; border-bottom: 1px solid #1a1a1a; }
591	.vv-err-row:last-child { border-bottom: none; }
592	.vv-err-top     { display: flex; align-items: baseline; gap: 8px; margin-bottom: 2px; }
593	.vv-err-script  { color: #e07070; font-size: 11px; font-weight: bold; }
594	.vv-err-age     { color: #555; font-size: 10px; flex: 1; padding-left: 6px; white-space: nowrap; }
595	.vv-ack-btn     { margin-left: auto; font-size: 10px; padding: 1px 6px;
596	                  color: #555; border-color: #333; flex-shrink: 0; }
597	.vv-ack-btn:hover { color: #aaa; border-color: #555; }
598	.vv-err-line    { color: #888; font-size: 11px; word-break: break-all; line-height: 1.4; }
599
600	/* Locks */
601	.vv-locks-list { display: flex; flex-direction: column; }
602	.vv-lock-row   { display: flex; align-items: center; gap: 8px; padding: 4px 0;
603	                 border-bottom: 1px solid #1a1a1a; font-size: 12px; }
604	.vv-lock-row:last-child { border-bottom: none; }
605	.vv-lk-name  { color: #e8a87c; flex: 1; }
606	.vv-lk-age   { color: #777; font-size: 11px; white-space: nowrap; }
607	.vv-lock-clear { font-size: 11px !important; padding: 1px 7px !important;
608	                 border-color: #b71c1c !important; color: #ef9a9a !important; }
609	.vv-lock-clear:hover { background: #7f0000 !important; color: #fff !important; }
610
611	/* Partner */
612	.vv-partner-row  { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 12px; }
613	.vv-partner-name { color: #ccc; }
614	.vv-partner-detail { color: #666; font-size: 11px; }
615	.vv-partner-down   { color: #f44336 !important; }
616
617	/* Disabled scripts */
618	.vv-disabled-list { display: flex; flex-direction: column; gap: 1px; }
619	.vv-disabled-row  { display: flex; align-items: center; gap: 8px; padding: 3px 0;
620	                    border-bottom: 1px solid #1a1a1a; font-size: 12px; }
621	.vv-disabled-row:last-child { border-bottom: none; }
622	.vv-disabled-name { color: #888; flex: 1; }
623	.vv-disabled-grp  { color: #444; font-size: 10px; font-family: monospace; white-space: nowrap; }
624
625	/* Notification board */
626	.vv-nb-board { display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
627	               padding: 7px 10px; background: #141414; border-bottom: 1px solid #222;
628	               font-size: 12px; min-height: 34px; }
629	.vv-nb-stat   { color: #aaa; }
630	.vv-nb-sep    { color: #444; }
631	.vv-nb-running { color: #f0a040; }
632	.vv-nb-conf-btns { display: flex; gap: 6px; margin-left: auto; }
633	.vv-nb-conf-btn  { font-size: 11px; font-family: monospace; }
634
635	/* Advanced mode button */
636	.vv-adv-mode-btn { border: 1px solid #555; color: #999; transition: background 0.15s, color 0.15s, border-color 0.15s; }
637	.vv-adv-mode-btn:hover { border-color: #888; color: #fff; }
638	.vv-adv-mode-btn.vv-adv-mode-on { background: #1565c0; border-color: #1565c0; color: #fff; }
639
640	/* Script browser in suggestions panel */
641	.vv-sb-desc { font-size: 12px; color: #888; margin: 4px 0 6px; line-height: 1.5; }
642	.vv-sb-child-desc { margin-left: 16px; }
643	.vv-sb-hdr  { font-family: monospace; font-size: 11px; color: #666; white-space: pre-wrap;
644	              word-break: break-word; background: none; border: none; margin: 4px 0 8px;
645	              padding: 0; line-height: 1.5; border-left: 2px solid #222; padding-left: 8px; }
646	.vv-sb-full { font-family: monospace; font-size: 11px; color: #888; white-space: pre-wrap;
647	              word-break: break-word; background: #0a0a0a; border: 1px solid #222;
648	              border-radius: 3px; margin: 6px 0 8px; padding: 8px 10px; line-height: 1.5;
649	              max-height: 480px; overflow-y: auto; }
650	.vv-sb-child-block { border-top: 1px solid #1a1a1a; margin-top: 8px; padding-top: 8px; }
651	.vv-sb-child-name  { display: flex; align-items: center; gap: 6px; margin-bottom: 3px; flex-wrap: wrap; }
652
653	/* README content display */
654	.vv-readme-body { font-family: monospace; font-size: 11px; color: #777; white-space: pre-wrap;
655	                  word-break: break-word; background: none; border: none; margin: 0;
656	                  padding: 0 4px; line-height: 1.6; }
657
658	/* Script browser tree rows */
659	#vv-sb-tree { padding: 0; }
660	.vv-sb-entry { }
661	.vv-sb-row { display: flex; align-items: center; gap: 6px; padding: 5px 6px;
662	             cursor: pointer; border-radius: 3px; user-select: none;
663	             transition: background 0.1s, box-shadow 0.1s; }
664	.vv-sb-row:hover { background: rgba(255,255,255,0.04); }
665	.vv-sb-selected { background: rgba(100,149,237,0.14) !important;
666	                  outline: 1px solid rgba(100,149,237,0.4);
667	                  box-shadow: inset 3px 0 0 #6495ed; }
668	.vv-sb-orch-row { border-bottom: 1px solid #1c1c1c; }
669	.vv-sb-child-row { padding-left: 2px; }
670	.vv-sb-expand { width: 14px; flex-shrink: 0; color: #555; font-size: 10px; text-align: center; }
671	.vv-sb-expand:hover { color: #aaa; }
672	.vv-sb-leaf { cursor: default; pointer-events: none; }
673	.vv-sb-name { flex: 1; font-size: 13px; color: #b0c4d0; min-width: 0;
674	              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
675	.vv-sb-orch-row .vv-sb-name { font-weight: bold; color: #9ab; }
676	.vv-sb-children { padding-left: 10px; }
677	.vv-sb-child-indent { width: 14px; flex-shrink: 0; color: #333; font-size: 11px;
678	                      text-align: center; pointer-events: none; }
679	.vv-sb-badge { flex-shrink: 0; font-size: 11px; }
680	.vv-sb-cron { color: #555; background: #111; border: 1px solid #222;
681	              padding: 0 4px; border-radius: 2px; font-size: 10px;
682	              font-family: monospace; flex-shrink: 0; }
683	.vv-sb-status { font-size: 10px; flex-shrink: 0; }
684
685	/* Script info content area */
686	.vv-si-hdr { font-family: monospace; font-size: 12px; color: #4d894d; white-space: pre-wrap;
687	             word-break: break-word; background: none; border: none; margin: 0;
688	             padding: 8px 12px; line-height: 1.6; }
689	.vv-si-src { font-family: monospace; font-size: 11px; white-space: pre-wrap;
690	             word-break: break-word; background: none; border: none; margin: 0;
691	             padding: 8px 12px; line-height: 1.5; }
692
693	/* Cog settings button next to script name */
694	.vv-cog-btn { cursor:pointer; color:#444; font-size:.85em; margin-right:4px;
695	              line-height:1; vertical-align:middle; user-select:none; }
696	.vv-cog-btn:hover { color:#aaa; }
697
698	/* Enriched script info blocks (advanced mode: header + docs + config) */
699	.vv-sinfo-block { border-top: 1px solid #222; padding: 0; }
700	.vv-sinfo-block:first-child { border-top: none; }
701	.vv-sinfo-lbl   { font-size: 10px; font-weight: bold; text-transform: uppercase;
702	                  letter-spacing: .06em; color: #555; padding: 6px 12px 2px; }
703
704	/* Syntax highlight tokens — dark theme (VSCode-inspired) */
705	.vv-hl-sep      { color: #2d2d2d; }
706	.vv-hl-shebang  { color: #4a4a4a; }
707	.vv-hl-hash     { color: #4a7340; }
708	.vv-hl-comment  { color: #6a9955; }
709	.vv-hl-section  { color: #9cdcfe; font-weight: bold; letter-spacing: 0.04em; }
710	.vv-hl-key      { color: #9cdcfe; }
711	.vv-hl-value    { color: #ce9178; }
712	.vv-hl-cron     { color: #d7ba7d; font-weight: bold; }
713	.vv-hl-text     { color: #4d894d; }
714	.vv-hl-keyword  { color: #569cd6; }
715	.vv-hl-builtin  { color: #4ec9b0; }
716	.vv-hl-string   { color: #ce9178; }
717	.vv-hl-var      { color: #d7ba7d; }
718	.vv-hl-number   { color: #b5cea8; }
719	.vv-hl-op       { color: #808080; }
720
721	/* Log panel */
722	.vv-log-panel { margin-top: 10px; border-top: 1px solid #333; padding-top: 8px; }
723	.vv-log-toolbar { display: flex; justify-content: space-between; align-items: center;
724	                  flex-wrap: wrap; gap: 4px; margin-bottom: 4px; }
725	.vv-log-ts { font-size: 11px; color: #666; }
726	.vv-log-pre { background: #0d0d0d; border: 1px solid #333; border-radius: 4px;
727	              padding: 10px 12px; margin: 0; font-family: monospace; font-size: 12px;
728	              color: #ccc; white-space: pre-wrap; word-break: break-all;
729	              max-height: 340px; overflow-y: auto; line-height: 1.5;
730	              scroll-behavior: auto; }
731
732	/* Toggle switch */
733	.vv-toggle { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; }
734	.vv-toggle input { opacity: 0; width: 0; height: 0; }
735	.vv-slider { position: absolute; inset: 0; background: #444; border-radius: 20px; cursor: pointer;
736	             transition: 0.2s; }
737	.vv-slider:before { content: ''; position: absolute; width: 14px; height: 14px; left: 3px; bottom: 3px;
738	                    background: #fff; border-radius: 50%; transition: 0.2s; }
739	.vv-toggle input:checked + .vv-slider { background: #4caf50; }
740	.vv-toggle input:checked + .vv-slider:before { transform: translateX(16px); }
741
742	/* Config editor */
743	#vv-conf-tabs { display: flex; gap: 4px; margin-bottom: 8px; }
744	.vv-conf-tab  { padding: 4px 12px; text-decoration: none; color: #aaa;
745	                border: 1px solid #444; border-radius: 4px; font-size: 13px; }
746	.vv-conf-tab.active { color: #fff; background: #333; border-color: #666; }
747	#vv-conf-editor { width: 100%; min-height: 500px; background: #111; color: #ddd;
748	                  border: 1px solid #444; padding: 12px; font-family: monospace;
749	                  font-size: 13px; line-height: 1.5; border-radius: 4px; box-sizing: border-box; resize: vertical; }
750	#vv-conf-actions { margin-top: 8px; display: flex; align-items: center; gap: 10px; }
751	#vv-conf-actions button { padding: 6px 18px; background: #4caf50; border: none;
752	                          color: #fff; border-radius: 4px; cursor: pointer; font-size: 14px; }
753	#vv-conf-actions button:hover { background: #388e3c; }
754	#vv-conf-status { font-size: 13px; color: #aaa; }
755
756	/* Docs */
757	#vv-docs { display: flex; gap: 16px; }
758	#vv-docs-sidebar { width: 220px; flex-shrink: 0; }
759	#vv-docs-sidebar h3 { font-size: 12px; text-transform: uppercase; color: #888; margin: 0 0 8px; }
760	#vv-docs-sidebar ul { list-style: none; padding: 0; margin: 0; }
761	#vv-docs-sidebar li { margin: 2px 0; }
762	#vv-docs-sidebar a { display: block; padding: 3px 8px; font-size: 12px; color: #aaa;
763	                     text-decoration: none; border-radius: 3px; }
764	#vv-docs-sidebar a:hover { background: #222; color: #fff; }
765	#vv-docs-sidebar a.active { background: #333; color: #fff; }
766	#vv-docs-content { flex: 1; min-width: 0; }
767	.vv-doc-body { background: #1a1a1a; border: 1px solid #444; border-radius: 6px;
768	               padding: 20px; line-height: 1.7; }
769	.vv-doc-body h1, .vv-doc-body h2, .vv-doc-body h3 { color: #ddd; }
770	.vv-doc-body code { background: #111; padding: 1px 5px; border-radius: 3px; font-size: 12px; }
771	.vv-doc-body pre { background: #111; padding: 12px; border-radius: 4px; overflow-x: auto; }
772	.vv-doc-hint { font-size: 12px; color: #666; margin-top: 8px; }
773
774	/* Media stream sessions */
775	.vv-stream-servers { display: flex; justify-content: space-between; align-items: center;
776	                     flex-wrap: nowrap; gap: 8px; margin-bottom: 10px; }
777	/* Left side: server badges + media type */
778	.vv-stream-left  { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; flex-shrink: 0; }
779	/* Right side: device / resolution / codec chip groups */
780	.vv-stream-right { display: flex; align-items: center; gap: 0; flex-wrap: nowrap; flex-shrink: 0; }
781	.vv-server-badge { background: #333; border: 1px solid #555; color: #aaa;
782	                   font-size: 10px; padding: 1px 7px; border-radius: 10px; }
783	.vv-server-badge-sm { font-size: 9px; padding: 1px 6px; flex-shrink: 0; }
784	/* Chip groups — server badge row */
785	.vv-device-sep  { color: #2a2a2a; font-size: 12px; margin: 0 2px; user-select: none; }
786	/* shared chip geometry */
787	.vv-device-chip,
788	.vv-chip-device, .vv-chip-res, .vv-chip-codec, .vv-chip-mtype {
789	  font-size: 10px; padding: 1px 7px; border-radius: 10px;
790	  white-space: nowrap; border: 1px solid; }
791	/* media type — purple */
792	.vv-chip-mtype  { color: #9a6abf; background: #1a0d2e; border-color: #3a1e55; }
793	/* device — blue */
794	.vv-chip-device { color: #5a9ec8; background: #0d1e2e; border-color: #1c3f5c; }
795	/* resolution — teal */
796	.vv-chip-res    { color: #4aaa9a; background: #0b1e1c; border-color: #1a4540; }
797	/* codec — amber */
798	.vv-chip-codec  { color: #b38820; background: #201500; border-color: #483300; }
799	/* legacy fallback */
800	.vv-device-chip { color: #666; background: #181818; border-color: #252525; }
801	/* chip group wrappers — inline so they flow with the badge row */
802	.vv-chip-group-device, .vv-chip-group-res, .vv-chip-group-codec { display: contents; }
803	.vv-stream-empty { color: #555; font-style: italic; font-size: 12px; margin: 4px 0; }
804	.vv-stream-empty span { font-size: 11px; color: #444; }
805	.vv-stream-row { margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #282828; }
806	.vv-stream-row:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; }
807	.vv-stream-top { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
808	.vv-stream-icon { font-size: 10px; color: #888; flex-shrink: 0; }
809	.vv-stream-title { flex: 1; font-size: 12px; color: #ddd; font-weight: 500;
810	                   white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
811	.vv-stream-meta { display: flex; gap: 10px; flex-wrap: wrap; font-size: 10px;
812	                  color: #666; margin-bottom: 5px; }
813	.vv-stream-user   { color: #888; }
814	.vv-stream-client { color: #555; }
815	.vv-stream-method { font-weight: 500; }
816	.vv-stream-time   { color: #555; margin-left: auto; }
817	.vv-stream-bar { height: 3px; background: #1a1a1a; border-radius: 2px; overflow: hidden; }
818	.vv-stream-bar div { height: 100%; border-radius: 2px; transition: width 0.4s; }
819
820	/* Live var substitution colours */
821	code.vv-live-var    { color: #4caf50; background: #0d1f0d; }
822	code.vv-unknown-var { color: #ff9800; background: #1f130d; }
823
824	/* ── Arrange mode ─────────────────────────────────────────────────────────── */
825	.vv-drag-handle { cursor: grab; color: #555; font-size: 14px; padding: 0 5px 0 0; user-select: none; flex-shrink: 0; }
826	.vv-drag-handle:hover { color: #888; }
827	.vv-drag-handle:active { cursor: grabbing; color: #aaa; }
828	/* Dragged item: semi-transparent with a dashed ring so you still see what you grabbed */
829	.vv-drag-ghost { opacity: 0.4; outline: 1px dashed #555; border-radius: 4px; }
830	/* Drop insertion line: blue glow to match selection accent */
831	.vv-drop-line { height: 2px; background: #6495ed; border-radius: 2px; margin: 2px 0;
832	                pointer-events: none; box-shadow: 0 0 6px rgba(100,149,237,0.7); }
833	.vv-arrange-active .vv-children { min-height: 28px; border: 1px dashed #2a2a2a; border-radius: 4px;
834	                                   padding: 4px 2px; transition: border-color 0.12s, background 0.12s; }
835	/* Drop targets use blue to match selection theme */
836	.vv-arrange-active .vv-children.vv-drop-target { border-color: #6495ed; background: rgba(100,149,237,0.07); }
837	.vv-arrange-btn-active { background: #1a3a1e !important; color: #4caf50 !important; border-color: #2d5c33 !important; }
838	/* Grabbing cursor while dragging anything */
839	.vv-is-dragging, .vv-is-dragging * { cursor: grabbing !important; }
840	.vv-arrange-save-btn { background: #1a3a1e; border-color: #2d5c33; color: #4caf50; }
841	.vv-arrange-save-btn:hover { background: #22502a; }
842	#vv-arrange-btn { background: #7b1fa2; border-color: #7b1fa2; }
843	#vv-arrange-btn:hover { background: #4a148c; border-color: #4a148c; }
844
845	/* ── Arrange workspace panel ─────────────────────────────────────────────── */
846	.vv-arrange-ws-hdr { font-size: 11px; font-weight: bold; color: #888; text-transform: uppercase;
847	                     letter-spacing: 0.6px; margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
848	#vv-pending-badge { background: #ff9800; color: #000; font-size: 10px; padding: 1px 7px;
849	                    border-radius: 10px; font-weight: bold; }
850	.vv-arrange-pending-hdr { font-size: 10px; color: #555; text-transform: uppercase; letter-spacing: 0.5px;
851	                           margin-bottom: 5px; }
852	.vv-pending-row { display: flex; align-items: center; gap: 8px; padding: 3px 0;
853	                  font-size: 11px; border-bottom: 1px solid #1e1e1e; }
854	.vv-pending-script { color: #ddd; font-weight: 500; }
855	.vv-pending-arrow  { color: #555; font-size: 10px; }
856	.vv-library-zone { border: 1px dashed #2a2a2a; border-radius: 4px; padding: 6px;
857	                   min-height: 60px; transition: border-color 0.12s, background 0.12s; }
858	.vv-library-zone.vv-drop-target { border-color: #ef5350; background: rgba(239,83,80,0.09);
859	                                   box-shadow: inset 0 0 8px rgba(239,83,80,0.08); }
860	.vv-arrange-drop-hint { font-size: 10px; color: #444; text-align: center; padding: 2px 0 7px; }
861	.vv-lib-card { background: #1c1c1c; border: 1px solid #2e2e2e; border-radius: 3px;
862	               padding: 4px 8px; margin-bottom: 4px; cursor: grab; display: flex;
863	               align-items: center; justify-content: space-between; gap: 8px; }
864	.vv-lib-card:hover { border-color: #444; }
865	.vv-lib-card.vv-drag-ghost { opacity: 0.35; }
866	.vv-lib-card-name { font-size: 16px; color: #ccc; font-weight: bold; }
867	.vv-lib-card-path { font-size: 10px; color: #444; font-family: monospace; }
868
869	/* ── Custom script folders ────────────────────────────────────────────────── */
870	.vv-folder-group { margin-bottom: 1px; }
871	.vv-folder-row { display: flex; align-items: center; gap: 6px; padding: 3px 6px;
872	                 cursor: pointer; border-radius: 3px; color: #888; font-size: 12px; user-select: none; }
873	.vv-folder-row:hover { background: #1e1e1e; }
874	.vv-folder-chevron { font-size: 10px; color: #555; width: 10px; flex-shrink: 0; }
875	.vv-folder-name { flex: 1; font-weight: 500; color: #aaa; }
876	.vv-folder-count { font-size: 10px; color: #555; background: #1c1c1c;
877	                   padding: 0 5px; border-radius: 8px; border: 1px solid #2a2a2a; }
878	.vv-folder-children { padding-left: 12px; min-height: 4px; }
879	.vv-folder-children.vv-drop-target { background: rgba(100,149,237,0.07); border-radius: 4px;
880	                                      outline: 1px dashed rgba(100,149,237,0.4); }
881	.vv-folder-new-row { display: flex; align-items: center; gap: 6px; padding: 4px 6px; }
882	.vv-new-folder-btn { background: #0277bd !important; border: none !important; color: #fff !important; }
883	.vv-new-folder-btn:hover { background: #01579b !important; }
884
885	/* ── Snapshot footer (right panel status bar) ────────────────────────────── */
886	.vv-snap-footer  { display: flex !important; flex-direction: row !important;
887	                   align-items: center !important; justify-content: center; gap: 20px; flex-wrap: wrap; }
888	.vv-snap-item    { display: flex; align-items: center; gap: 7px; }
889	.vv-snap-label   { font-size: 12px; color: #555; text-transform: uppercase; letter-spacing: 0.05em; }
890	.vv-snap-bar     { width: 90px; height: 8px; background: #222; border-radius: 4px; overflow: hidden; flex-shrink: 0; }
891	.vv-snap-bar span { display: block; height: 100%; border-radius: 4px; width: 0;
892	                    transition: width 0.5s, background-color 0.5s; }
893	.vv-snap-val     { font-size: 15px; color: #aaa; font-family: monospace; min-width: 36px; }
894	.vv-snap-div     { color: #333; font-size: 15px; }
895	.vv-snap-state   { font-size: 15px; font-weight: bold; }
896	#vv-snap-partner { font-size: 15px; color: #666; }
897	.vv-snap-media   { font-size: 15px; color: #666; }
898
899	/* ── Containers and VMs card ──────────────────────────────────────────────── */
900	.vv-df-section-hdr  { font-size: 10px; font-weight: bold; color: #555; text-transform: uppercase;
901	                       letter-spacing: 0.08em; padding: 4px 2px 5px; border-bottom: 1px solid #222;
902	                       margin-bottom: 4px; }
903	.vv-df-empty        { font-size: 12px; color: #555; font-style: italic; padding: 4px 2px 8px; }
904	.vv-df-vm-row       { display: flex; align-items: center; gap: 8px; padding: 5px 2px;
905	                       border-bottom: 1px solid #1a1a1a; }
906	.vv-df-vm-row:last-of-type { border-bottom: none; }
907	.vv-df-vm-icon      { font-size: 15px; line-height: 1; flex-shrink: 0; }
908	.vv-df-vm-meta      { font-size: 10px; color: #555; }
909	.vv-df-cols         { display: flex; gap: 10px; align-items: flex-start; }
910	.vv-df-col          { flex: 1; min-width: 0; }
911	#vv-docker-folders-body { overflow-x: hidden; }
912	.vv-df-folder       { border-bottom: 1px solid #1a1a1a; }
913	.vv-df-folder:last-child { border-bottom: none; }
914	.vv-df-folder-hdr   { display: flex; align-items: center; gap: 6px; padding: 5px 4px;
915	                       cursor: pointer; user-select: none; border-radius: 3px; }
916	.vv-df-folder-hdr:hover { background: rgba(255,255,255,0.03); }
917	.vv-df-chevron      { color: #555; font-size: 10px; width: 10px; flex-shrink: 0; }
918	.vv-df-fname        { flex: 1; font-size: 12px; color: #aaa; font-weight: 500;
919	                       white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
920	.vv-df-folder-body  { padding-left: 10px; padding-bottom: 3px; }
921	.vv-df-container    { display: flex; align-items: center; gap: 7px; padding: 3px 6px;
922	                       cursor: pointer; border-radius: 3px; user-select: none; }
923	.vv-df-container:hover { background: rgba(255,255,255,0.04); }
924	.vv-df-active       { background: rgba(100,149,237,0.1) !important;
925	                      outline: 1px solid rgba(100,149,237,0.35);
926	                      box-shadow: inset 3px 0 0 #6495ed; }
927	.vv-df-dot          { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
928	.vv-df-cname        { flex: 1; font-size: 12px; color: #ccc;
929	                       white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
930	.vv-df-status       { font-size: 10px; color: #555; flex-shrink: 0; white-space: nowrap; }
931	.vv-df-actions      { display: flex; gap: 6px; padding: 3px 6px 5px 24px; flex-wrap: wrap; }
932
933	/* ── Rsync standalone controls ────────────────────────────────────────────── */
934	.vv-rsync-location { width: 120px; flex-shrink: 1; min-width: 60px; font-size: 11px; font-family: monospace;
935	                     background: #111; border: 1px solid #333; color: #aaa;
936	                     padding: 2px 6px; border-radius: 3px; }
937	.vv-rsync-location:focus { border-color: #555; outline: none; }
938	.vv-rsync-location::placeholder { color: #444; }
939	.vv-script-args { flex: 1 1 0; min-width: 60px; max-width: 180px; font-size: 11px; font-family: monospace;
940	                  background: #111; border: 1px solid #2a2a2a; color: #aaa;
941	                  padding: 2px 6px; border-radius: 3px;
942	                  opacity: 0.3; transition: opacity 0.15s; }
943	.vv-script-args:hover, .vv-script-args:focus { opacity: 1; border-color: #555; outline: none; }
944	.vv-script-args::placeholder { color: #3a3a3a; }
945	.vv-rsync-save-btn { background: #1a2e1a; border-color: #2a4a2a; color: #6aaa6a; }
946	.vv-rsync-save-btn:hover { background: #22382a; }
947


1
86
87

88	  Arrs
89
90

91
92

93
Loading…

94

95
96
471


1
75
76

77	  Docker
78	  <button class="vv-dk-btn warn" id="vv-dk-sync-c2j" title="Apply conf desired state to JSON">Sync conf → JSON</button>
79	  <button class="vv-dk-btn prim" id="vv-dk-sync-j2c" title="Capture JSON state into conf">Sync JSON → conf</button>
80	  <button class="vv-dk-btn" id="vv-dk-edit-toggle">Edit folders</button>
81
82
83

84
85

86
87

88
Loading…

89

90
91

92
93
390


1
35
36

37	  FallBack
38
39

40
41

42
Loading…

43

44
45
244


1
121
122	<?php
123	require_once __DIR__ . '/../include/auth.php';
124	$isOwner = vv_is_owner();
125	?>
126
127

128	  Auth Stack
129	  <button class="vv-au-tab active" data-tab="proxies">Proxies</button>
130	  <button class="vv-au-tab" data-tab="users">Users & Groups</button>
131	  <button class="vv-au-tab" data-tab="acl">Access Control</button>
132	  <button class="vv-au-tab" data-tab="certs">Certs</button>
133	  <button class="vv-au-btn" id="vv-au-refresh" title="Refresh current tab">↻ Refresh</button>
134

135
136
137

138

139
140	    <button class="vv-au-btn prim" id="vv-au-proxy-add">+ Add Proxy</button>
141

142

143
Loading…

144

145

146	        Domain	Forward	SSL	Status
147

148

149

150
No proxy hosts configured.

151

152

153
154
155

156

157
158

159

160	        Users
161	        <button class="vv-au-btn prim" id="vv-au-user-add">+ Add User</button>
162

163
Loading…

164

165
No users found.

166

167
168

169

170	        Groups
171	        <button class="vv-au-btn prim" id="vv-au-group-add">+ Add Group</button>
172

173
Loading…

174

175
No groups found.

176

177
178

179

180
181
182

183

184	    Default policy:
185	    <select id="vv-au-ac-defpol" <?= $isOwner ? '' : 'disabled' ?>>
186	      <option value="deny">deny</option>
187	      <option value="two_factor">two_factor</option>
188	      <option value="one_factor">one_factor</option>
189	      <option value="bypass">bypass</option>
190	    </select>
191	    <?php if (!$isOwner): ?>
192	      default policy editable on HOST1
193	    <?php endif; ?>
194	    <button class="vv-au-btn green" id="vv-au-ac-save" style="margin-left:auto">Save & Restart Authelia</button>
195

196

197
198	    <button class="vv-au-btn prim" id="vv-au-rule-add">+ Add Rule</button>
199

200

201
Loading…

202

203

204	        #
205	        Domain	Policy	Subject
206

207

208

209
No rules configured.

210

211

212
213
214

215

216
217	    <button class="vv-au-btn prim" id="vv-au-cert-run">Run now</button>
218

219

220
Loading…

221

222

225

226

227
228
229

230

231

232
233
1022


<system-reminder>[Truncated: PARTIAL view — showing lines 1-1074 of 2212 total (43758 tokens, cap 25000). Call Read with offset=1075 limit=1074 for the next page, or Grep to find a specific section. Do NOT answer from this page alone if the answer may be further in the file.]</system-reminder>

1	<?php require_once dirname(__DIR__) . '/include/monitor.php'; ?>
2
8
9

10
11

12
13
14

15
Loading...

16

17
18

19

20
21	          <svg width="9" height="14" viewBox="0 0 11 18" fill="none" style="opacity:0.4;flex-shrink:0;">
22	            <polygon points="9,0 2,10 6,10 3,18 11,6 6,6 8,0" fill="#ff9800"/>
23	          </svg>Power
24
25	        ⚙
26

27
Loading...

28

29
30

31

32
33	          <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><rect x="3" y="3" width="6" height="6" rx="0.8"/><line x1="4.5" y1="3" x2="4.5" y2="1.2"/><line x1="7.5" y1="3" x2="7.5" y2="1.2"/><line x1="4.5" y1="9" x2="4.5" y2="10.8"/><line x1="7.5" y1="9" x2="7.5" y2="10.8"/><line x1="3" y1="4.5" x2="1.2" y2="4.5"/><line x1="3" y1="7.5" x2="1.2" y2="7.5"/><line x1="9" y1="4.5" x2="10.8" y2="4.5"/><line x1="9" y1="7.5" x2="10.8" y2="7.5"/></svg>
34	          CPU
35
36	        ⚙
37

38
Loading...

39

40
41

42

43
44	          <svg width="14" height="8" viewBox="0 0 14 8" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><rect x="0.6" y="2.5" width="12.8" height="3" rx="0.5"/><line x1="3" y1="2.5" x2="3" y2="0.8"/><line x1="5.5" y1="2.5" x2="5.5" y2="0.8"/><line x1="8" y1="2.5" x2="8" y2="0.8"/><line x1="10.5" y1="2.5" x2="10.5" y2="0.8"/><line x1="3" y1="5.5" x2="3" y2="7.2"/><line x1="5.5" y1="5.5" x2="5.5" y2="7.2"/><line x1="8" y1="5.5" x2="8" y2="7.2"/><line x1="10.5" y1="5.5" x2="10.5" y2="7.2"/></svg>
45	          Memory
46
47	        ⚙
48

49
Loading...

50

51
52

53

54
55	          <svg width="13" height="12" viewBox="0 0 13 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><rect x="4.5" y="0.5" width="4" height="3" rx="0.7"/><rect x="0.5" y="8" width="4" height="3" rx="0.7"/><rect x="8.5" y="8" width="4" height="3" rx="0.7"/><line x1="6.5" y1="3.5" x2="6.5" y2="6"/><line x1="6.5" y1="6" x2="2.5" y2="6"/><line x1="2.5" y1="6" x2="2.5" y2="8"/><line x1="6.5" y1="6" x2="10.5" y2="6"/><line x1="10.5" y1="6" x2="10.5" y2="8"/></svg>
56	          Network
57
58	        ⚙
59

60
Loading...

61

62
63
64

65

66
67	          <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="1" width="10" height="10" rx="1.5"/><line x1="1" y1="4.5" x2="11" y2="4.5"/><polyline points="3.5,7 5,8 3.5,9"/><line x1="6" y1="9" x2="8.5" y2="9"/></svg>
68	          Scripts
69
70	        ⚙
71

72
Loading...

73

74
75

76

77
78	          <svg width="10" height="12" viewBox="0 0 10 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"><path d="M5 0.8L9.2 2.8V6.2C9.2 9 5 11.2 5 11.2C5 11.2 0.8 9 0.8 6.2V2.8Z"/></svg>
79	          Fallback
80
81

82
Loading...

83

84
85

86

87
88	          <svg width="14" height="10" viewBox="0 0 14 10" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><rect x="0.5" y="1.5" width="4" height="7" rx="0.8"/><rect x="9.5" y="1.5" width="4" height="7" rx="0.8"/><line x1="4.5" y1="5" x2="9.5" y2="5"/><circle cx="7" cy="5" r="1" fill="#888" stroke="none"/></svg>
89	          Partner
90
91
92

93
Loading...

94

95
96

97

98
99	          <svg width="14" height="10" viewBox="0 0 14 10" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"><rect x="1" y="0.5" width="12" height="2.5" rx="0.5"/><rect x="1" y="3.8" width="12" height="2.5" rx="0.5"/><rect x="1" y="7" width="12" height="2.5" rx="0.5"/></svg>
100	          Containers & VMs
101
102	        ⚙
103

104
Loading...

105

106
107
108

109

110
111	          <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"><polyline points="2,4 10,4 8,2"/><polyline points="10,8 2,8 4,10"/></svg>
112	          Rsync
113
114

115
Loading...

116

117
118

119

120
121	          <svg width="15" height="10" viewBox="0 0 16 10" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"><rect x="0.8" y="0.8" width="14.4" height="7" rx="1.2"/><rect x="2.5" y="2.5" width="3.5" height="3.5" rx="0.5"/><line x1="8" y1="3" x2="13" y2="3"/><line x1="8" y1="5" x2="11" y2="5"/><rect x="3" y="7.8" width="2" height="1.8" rx="0.3" stroke="none" fill="#666"/><rect x="6.5" y="7.8" width="2" height="1.8" rx="0.3" stroke="none" fill="#666"/><rect x="10" y="7.8" width="2" height="1.8" rx="0.3" stroke="none" fill="#666"/></svg>
122	          GPU
123
124	        ⚙
125

126
Loading...

127

128
129

130

131
132	          <svg width="14" height="12" viewBox="0 0 14 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"><rect x="0.5" y="1" width="4" height="10" rx="0.8"/><line x1="0.5" y1="3.5" x2="2.3" y2="3.5"/><line x1="0.5" y1="8.5" x2="2.3" y2="8.5"/><line x1="2.7" y1="3.5" x2="4.5" y2="3.5"/><line x1="2.7" y1="8.5" x2="4.5" y2="8.5"/><line x1="6" y1="6" x2="9.5" y2="6"/><polyline points="8.2,4.3 10.2,6 8.2,7.7"/><rect x="11" y="1" width="2.5" height="10" rx="0.5"/></svg>
133	          Transcode
134
135

136
Loading...

137

138
139

140

141
142	          <svg width="11" height="12" viewBox="0 0 11 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"><polygon points="1.5,1 1.5,11 10,6"/></svg>
143	          Streams
144
145

146
Loading...

147

148
149
150

151

152
153	          <svg width="14" height="9" viewBox="0 0 14 8" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><path d="M1 4C3.2 1 5 0.5 7 0.5C9 0.5 10.8 1 13 4C10.8 7 9 7.5 7 7.5C5 7.5 3.2 7 1 4Z"/><circle cx="7" cy="4" r="1.5"/></svg>
154	          Watchdog
155
156

157
Loading...

158

159
160

161

162
163	          <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round" stroke-linejoin="round"><circle cx="6" cy="6" r="5"/><polyline points="3.5,6 5.5,8 8.5,4"/></svg>
164	          Parity
165
166	        ⚙
167

168
Loading...

169

170
171

172

173
174	          <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><ellipse cx="6" cy="3" rx="4.5" ry="1.5"/><line x1="1.5" y1="3" x2="1.5" y2="9"/><line x1="10.5" y1="3" x2="10.5" y2="9"/><ellipse cx="6" cy="9" rx="4.5" ry="1.5"/></svg>
175	          Pools
176
177
178	        ⚙
179

180
Loading...

181

182
183

184

185
186	          <svg width="14" height="12" viewBox="0 0 14 12" fill="none" stroke="#aaa" stroke-width="1.1" stroke-linecap="round"><rect x="0.7" y="0.7" width="12.6" height="3" rx="0.8"/><rect x="0.7" y="4.5" width="12.6" height="3" rx="0.8"/><rect x="0.7" y="8.3" width="12.6" height="3" rx="0.8"/><circle cx="11.5" cy="2.2" r="0.8" fill="#888" stroke="none"/><circle cx="11.5" cy="6" r="0.8" fill="#888" stroke="none"/><circle cx="11.5" cy="9.8" r="0.8" fill="#888" stroke="none"/></svg>
187	          Array
188
189
190	        ⚙
191

192
Loading...

193

194
195
196

197
198


The monitor.php file is very large. Let me continue reading the remaining pages.


<system-reminder>[Truncated: PARTIAL view — showing lines 1-1133 of 1739 total (32599 tokens, cap 25000). Call Read with offset=1134 limit=1133 for the next page, or Grep to find a specific section. Do NOT answer from this page alone if the answer may be further in the file.]</system-reminder>

1
118
119

120	  Rsync
121
122

123
124
125

126

127

128	      Manual Rsync
129
130

131	    <button onclick="vvMsToggle()" style="font-size:10px;color:#4a6a4a;background:#0d1a0d;border:1px solid #1a3a1a;
132	                                          border-radius:3px;padding:2px 10px;cursor:pointer;" id="vv-ms-tog">▾ Show</button>
133

134

135
136
137

138
139
140

141
Local source

142

143	          <input class="vv-ms-inp" id="vv-ms-local" type="text" placeholder="/mnt/user/…"
144	                 style="flex:1;min-width:0;" onkeydown="if(event.key==='Enter')vvMsBrowseLocal()">
145	          <button onclick="vvMsLocalNavUp()" title="Parent"
146	                  style="background:#111;border:1px solid #222;color:#555;border-radius:3px;
147	                         padding:4px 8px;cursor:pointer;font-size:12px;flex-shrink:0;">↑</button>
148	          <button onclick="vvMsBrowseLocal()" id="vv-ms-lbrowse-btn"
149	                  style="background:#111;border:1px solid #222;color:#4a9eff;border-radius:3px;
150	                         padding:4px 9px;cursor:pointer;font-size:11px;white-space:nowrap;flex-shrink:0;">⟳ Browse</button>
151

152

153
154	        trailing / = sync contents · without / = sync the folder
155

156
157
158

159

160

161
Remote server

162	            <select class="vv-ms-sel" id="vv-ms-host" onchange="vvMsHostChanged()">
163	              <option value="">Loading hosts…</option>
164	            </select>
165
166

167

168
User

169	            <select class="vv-ms-sel" id="vv-ms-user">
170	              <option value="root">root</option>
171	            </select>
172

173

174
Remote path

175

176	          <input class="vv-ms-inp" id="vv-ms-rpath" type="text" placeholder="/mnt/user/…"
177	                 style="flex:1;min-width:0;" onkeydown="if(event.key==='Enter')vvMsBrowse()">
178	          <button onclick="vvMsNavUp()" title="Parent"
179	                  style="background:#111;border:1px solid #222;color:#555;border-radius:3px;
180	                         padding:4px 8px;cursor:pointer;font-size:12px;flex-shrink:0;">↑</button>
181	          <button onclick="vvMsBrowse()" id="vv-ms-browse-btn"
182	                  style="background:#111;border:1px solid #222;color:#4a9eff;border-radius:3px;
183	                         padding:4px 9px;cursor:pointer;font-size:11px;white-space:nowrap;flex-shrink:0;">⟳ Browse</button>
184

185

186
187

188

189
190
191

192
Rsync flags
193	        does not inherit defaults — check every desired flag
194

195

196	        <input type="checkbox" data-flag="-av" checked onchange="vvMsUpdatePreview()">-av
197	        <input type="checkbox" data-flag="--human-readable" checked onchange="vvMsUpdatePreview()">--human-readable
198	        <input type="checkbox" data-flag="--stats" checked onchange="vvMsUpdatePreview()">--stats
199
200	        <input type="checkbox" data-flag="--delete" onchange="vvMsUpdatePreview()">--delete
201	        <input type="checkbox" data-flag="--inplace" onchange="vvMsUpdatePreview()">--inplace
202	        <input type="checkbox" data-flag="--no-whole-file" onchange="vvMsUpdatePreview()">--no-whole-file
203	        <input type="checkbox" data-flag="--checksum" onchange="vvMsUpdatePreview()">--checksum
204	        <input type="checkbox" data-flag="--compress" onchange="vvMsUpdatePreview()">--compress
205
206	        <input type="checkbox" id="vv-ms-dryrun" data-flag="--dry-run" onchange="vvMsUpdatePreview()">--dry-run
207

208

210	        rsync
211
212
213	        …src host:dst
214

215

216
217
218

219

220	        BW limit
221	        <input class="vv-ms-inp" id="vv-ms-bw" type="number" min="0" value="0"
222	               style="width:72px;padding:3px 6px;" oninput="vvMsUpdatePreview()">
223	        KB/s (0 = unlimited)
224

225
226	        <input type="checkbox" id="vv-ms-usekey" checked>
227	        SSH key: loading…
229
230

231
232
233

234	      <button class="vv-ms-run" id="vv-ms-run-btn" onclick="vvMsRun()">▶ Run Rsync</button>
235	      <button id="vv-ms-show-btn" onclick="vvMsToggleOutput()"
236	              style="background:#111;border:1px solid #252525;color:#555;font-size:11px;
237	                     padding:5px 14px;border-radius:3px;cursor:pointer;">▾ Show Rsync</button>
238	      <button id="vv-ms-stop-btn" onclick="vvMsStop()"
239	              style="display:none;background:#2a1010;border:1px solid #5a2020;color:#ef5350;
240	                     font-size:11px;padding:5px 14px;border-radius:3px;cursor:pointer;font-weight:600;">■ Stop</button>
241
242

243
244
245

246

247

248
249

250
251
252

253
254
255

256

257	      Rsync Reference
258	      <button onclick="vvRpOpen()"
259	              style="background:#0a1a2a;border:1px solid #1a3a5a;color:#4a9eff;font-size:11px;
260	                     padding:4px 14px;border-radius:3px;cursor:pointer;font-weight:600;">⚙ Profile Editor</button>
261

262
263
264

265

266	        ▾ How to use this page
267

268

269

270
Status card — shows whether the global rsync gate is open. Red = all syncs blocked regardless of tier toggles.

271
Sync windows — per-tier enable/disable. A tier can be enabled here but still blocked by the global gate.

272
Settings → Global gate — RSYNC_ENABLED in master.conf. Master switch; turn off during rebuilds or maintenance.

273
Settings → Tier toggles — CRITICAL/DAILY/etc._RSYNC_ENABLED. Disable one tier without affecting others.

274
Bandwidth history — last 30 days of per-profile rsync runs. Bar = relative time spent. Click recent runs for detail.

275
Manual Rsync — one-off transfer to any partner host. Browse remote dirs via SSH. Runs in background, output streams below.

276
Profile Editor — create and edit named profiles used by appdata syncs. Each profile controls flags, BW limit, container stop lists, and excludes.

277

278

279

280
281
282

283

284	        ▸ Sync windows
285

286

287

288
Critical (30 min) — appdata (arrs, auth, databases), partnership health check, play state sync. Designed to be fast — uses dirty-sync profiles where possible.

289
Intermediate (4 hr) — arr sync between the nightly runs. Catches new indexer hits without waiting until midnight.

290
Daily (nightly) — media shares, arr maintenance, media cleaner, docker updates, daily container restarts.

291
Weekly — bulk media shares, update checks, weekly restarts, SMART health digest.

292
Fallback — fires when a server comes back online after being the active fallback. Syncs any changes that happened during downtime.

293
Two-tier toggle — global gate (RSYNC_ENABLED) blocks everything. Per-tier flags (e.g. DAILY_RSYNC_ENABLED) disable just that window. Both must be ON for syncs to run.

294

295

296

297
298
299

300

301	        ▸ Profile system
302

303

304

305
What is a profile? — A named set of rsync options applied to a specific appdata directory. Appdata shares match a profile by their directory basename (lowercased).

306
PROFILE_RSYNC_OPTS — Full rsync flag string for this profile. Does NOT inherit DEFAULT_RSYNC_OPTS — list every desired flag explicitly. Use $BW_LIMIT to reference the profile's bandwidth limit.

307
PROFILE_BW_LIMIT — Bandwidth cap in KB/s. Overrides the global BW_LIMIT for this profile.

308
PROFILE_RETRY_COUNT / SLEEP — How many times to retry on failure, and how long to wait between attempts.

309
PROFILE_CRITICAL_CONTAINER_NAMES — Containers stopped on BOTH hosts before rsync. Local stops first (flush DBs), then remote. Only running containers get restarted — stopped ones stay stopped.

310
PROFILE_DELAYED_CONTAINERS — Containers that need a delay after the others start (e.g. NextCloud waits for Postgres).

311
PROFILE_CONTAINER_DELAY — Seconds to wait before starting delayed containers.

312
PROFILE_EXCLUDE_DIRS — Space-separated patterns excluded from the rsync. Supports globs (e.g. logs *.tmp *.db-wal).

313
PROFILE_REMOTE_RESTART_CONTAINERS — Used by dirty-sync profiles. Restarts these containers on the remote after sync so it picks up the new data.

314
Clean vs dirty sync — Clean: stop containers, --delete, full mirror. Dirty: containers keep running, WAL files excluded, --inplace --no-whole-file for safe partial writes. Use dirty for frequent critical syncs.

315
App layer — Scripts add their appdata directory to HOST*_CRITICAL_SYNC_SHARES or HOST*_DAILY_SYNC_SHARES using /path/to/dir|profile-name syntax. Creating the profile here makes it available for that reference.

316

317

318

319
320
321

322

323	        ▸ Common flag combinations
324

325

326

327
Clean sync (weekly appdata)
-av --human-readable --bwlimit=$BW_LIMIT --delete
Full mirror — removes files on destination that no longer exist at source. Safe when containers are stopped.

328
Dirty sync (every 30 min)
-av --human-readable --bwlimit=$BW_LIMIT --delete --inplace --no-whole-file
Containers stay running. --inplace writes directly to destination file (avoids temp-file rename issues). --no-whole-file uses delta transfer. Exclude WAL files to avoid corrupt state.

329
Database sync (arrs)
-av --info=progress2 --human-readable --bwlimit=$BW_LIMIT --delete --inplace
Stop containers first. --info=progress2 gives cleaner progress output in logs. Lower BW limit to not starve other syncs running concurrently.

330
Large media (weekly)
-av --human-readable --bwlimit=$BW_LIMIT --delete --inplace --no-whole-file
High BW limit, inplace for large files, delete to keep mirror clean. No container stops — media files are read-only.

331
--delete — remove files at destination that no longer exist at source. Essential for a true mirror.

332
--inplace — write file data directly into destination file instead of creating a temp copy first. Faster for large files; required for some databases.

333
--no-whole-file — force delta transfer even over fast LAN. Reduces data sent for files that change incrementally.

334
--checksum — compare files by checksum rather than mtime+size. Slower but catches any corruption. Use for archive syncs, not frequent syncs.

335

336

337

338

339
340
341

342

343	      <button onclick="vvRpClose()"
344	              style="background:#111;border:1px solid #222;color:#555;font-size:11px;
345	                     padding:4px 12px;border-radius:3px;cursor:pointer;">← Rsync Info</button>
346	      Profile Editor
347

348	        <select id="vv-rp-selector"
349	                style="background:#111;border:1px solid #2a2a2a;color:#bbb;font-size:11px;
350	                       padding:3px 8px;border-radius:3px;outline:none;cursor:pointer;max-width:200px;"
351	                onchange="vvRpOnSelect(this.value)">
352	          <option value="">Loading…</option>
353	        </select>
354	        <button onclick="vvRpNew()"
355	                style="background:#0a1a0a;border:1px solid #1a3a1a;color:#4caf50;
356	                       font-size:11px;padding:3px 12px;border-radius:3px;cursor:pointer;font-weight:600;">＋ New</button>
357

358

359
360
361

362	      Select a profile above to edit, or click ＋ New to create one.
363

364
365
366

367

368
369
370

371	          Profile name
372	          <input id="vv-rp-name" type="text"
373	                 style="background:#0d0d0d;border:1px solid #2a2a2a;border-radius:3px;color:#ccc;
374	                        font-size:12px;padding:4px 8px;font-family:monospace;outline:none;width:200px;"
375	                 placeholder="e.g. my-app">
376
377

378

379
380
381

382

383	            Rsync opts
384	            does NOT inherit defaults — list every desired flag
385

386

387	            <input type="checkbox" data-flag="-av" onchange="vvRpBuildOpts()">-av
388	            <input type="checkbox" data-flag="--human-readable" onchange="vvRpBuildOpts()">--human-readable
389	            <input type="checkbox" data-flag="--info=progress2" onchange="vvRpBuildOpts()">--info=progress2
390
391	            <input type="checkbox" data-flag="--delete" onchange="vvRpBuildOpts()">--delete
392	            <input type="checkbox" data-flag="--inplace" onchange="vvRpBuildOpts()">--inplace
393	            <input type="checkbox" data-flag="--no-whole-file" onchange="vvRpBuildOpts()">--no-whole-file
394	            <input type="checkbox" data-flag="--checksum" onchange="vvRpBuildOpts()">--checksum
395
396	            <input type="checkbox" data-flag="--bwlimit=$BW_LIMIT" onchange="vvRpBuildOpts()">--bwlimit=$BW_LIMIT
397	            <input type="checkbox" data-flag="--compress" onchange="vvRpBuildOpts()">--compress
398

399

400	            Extra flags
401	            <input id="vv-rp-opts-extra" type="text"
402	                   style="background:#0d0d0d;border:1px solid #1e1e1e;border-radius:3px;color:#888;
403	                          font-size:11px;padding:3px 7px;font-family:monospace;outline:none;flex:1;"
404	                   placeholder="any additional flags"
405	                   oninput="vvRpBuildOpts()">
406

407

409	            rsync_opts =
410
411

412	          <input type="hidden" id="vv-rp-rsync_opts">
413

414

415
416
417

418

419
BW limit KB/s

420	            <input class="vv-ry-set-inp" id="vv-rp-bw_limit" type="number" min="0" style="width:80px;">
421

422

423
Retry count

424	            <input class="vv-ry-set-inp" id="vv-rp-retry_count" type="number" min="0" max="20" style="width:60px;">
425

426

427
Retry sleep s

428	            <input class="vv-ry-set-inp" id="vv-rp-sleep" type="number" min="0" style="width:70px;">
429

430

431
Container delay s

432	            <input class="vv-ry-set-inp" id="vv-rp-container_delay" type="number" min="0" style="width:70px;">
433

434

435

436
437
438

439

440
Stop containers space-separated — stopped on both hosts before rsync, restarted after

441	            <input class="vv-ry-set-inp" id="vv-rp-critical_containers" type="text" style="width:100%;box-sizing:border-box;font-family:monospace;">
442

443

444
Delayed containers start after delay (e.g. app waits for its database)

445	            <input class="vv-ry-set-inp" id="vv-rp-delayed_containers" type="text" style="width:100%;box-sizing:border-box;font-family:monospace;">
446

447

448
Exclude dirs space-separated globs — e.g. logs *.tmp *.db-wal *.db-shm

449	            <input class="vv-ry-set-inp" id="vv-rp-exclude_dirs" type="text" style="width:100%;box-sizing:border-box;font-family:monospace;">
450

451

452
Remote restart dirty-sync only — restarted on remote after sync so it picks up changes

453	            <input class="vv-ry-set-inp" id="vv-rp-remote_restart" type="text" style="width:100%;box-sizing:border-box;font-family:monospace;">
454

455

456
457

458	          <button class="vv-ry-save-btn" onclick="vvRpSave()">Save Profile</button>
459	          <button id="vv-rp-del-btn" onclick="vvRpDelete()"
460	                  style="background:#1a0a0a;border:1px solid #3a1a1a;color:#ef5350;font-size:11px;
461	                         padding:4px 12px;border-radius:3px;cursor:pointer;display:none;">Delete</button>
462
463

464

465

466

467
468

469
470


1
58
59

60	  Partnership
61
62

63
64
65

66
Loading…

67

68
69
70

71

72
Host Settings

73	    <button id="vv-pt-hosts-save" class="vv-pt-action-btn run"
74	            onclick="vvPtSaveHosts(this)" style="display:none;">Save</button>
75

76

77

78
79
80

81
82
83

84
Loading…

85

86
87
88

89
90
91

92

93
Mirror Sync

94
Loading…

95

96

97
Actions

98
Loading…

99

100

101
102
103

104

106
Settings

107

108	      <button id="vv-pt-settings-save" class="vv-pt-action-btn run"
109	              onclick="event.stopPropagation();vvPtSaveSettings(this)"
110	              style="display:none;">Save Changes</button>
111	      ▸ Show settings
114

115

116

117	    Partnership configuration for this server.
118

119

120

121
122
1268