diff --git a/builder/mac-mini-dashboard/index.html b/builder/mac-mini-dashboard/index.html
index 72ec3ad..9afa1b5 100644
--- a/builder/mac-mini-dashboard/index.html
+++ b/builder/mac-mini-dashboard/index.html
@@ -52,6 +52,7 @@
.nav-pills::-webkit-scrollbar { display: none; }
.nav-pill { flex: 0 0 auto; padding: 10px 24px; border-radius: 10px; font-size: 14px; font-weight: 500; color: var(--text2); cursor: pointer; border: none; background: none; transition: all 0.2s; display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.nav-pill:hover { color: var(--text); }
+.nav-pill:focus-visible { outline: 3px solid rgba(234,179,8,0.38); outline-offset: 2px; }
.nav-pill.active { background: var(--card); color: var(--text); box-shadow: 0 1px 4px rgba(0,0,0,0.06); }
.nav-pill .pill-icon { font-size: 16px; }
.nav-pill .pill-badge { font-size: 11px; background: var(--accent-bg); color: var(--accent); padding: 2px 8px; border-radius: 6px; font-weight: 600; }
@@ -182,6 +183,165 @@
.section { display: none; }
.section.active { display: block; }
+/* Platforms */
+.platforms-header {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 20px;
+ align-items: end;
+ margin-bottom: 22px;
+ padding-bottom: 18px;
+ border-bottom: 1px solid var(--border2);
+}
+.platforms-eyebrow {
+ color: var(--accent);
+ font-size: 11px;
+ font-weight: 800;
+ letter-spacing: 0.9px;
+ text-transform: uppercase;
+}
+.platforms-title {
+ margin-top: 5px;
+ font-size: 26px;
+ font-weight: 800;
+ letter-spacing: -0.4px;
+}
+.platforms-copy {
+ max-width: 620px;
+ margin-top: 6px;
+ color: var(--text2);
+ font-size: 13px;
+ line-height: 1.55;
+}
+.platforms-legend {
+ display: flex;
+ gap: 8px;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+}
+.platforms-legend span,
+.platform-access {
+ display: inline-flex;
+ align-items: center;
+ width: fit-content;
+ border: 1px solid var(--border2);
+ border-radius: 6px;
+ background: var(--card);
+ color: var(--text2);
+ padding: 4px 7px;
+ font-size: 10px;
+ font-weight: 700;
+ letter-spacing: 0.25px;
+ text-transform: uppercase;
+}
+.platforms-legend .private,
+.platform-access.private { background: var(--accent-bg); color: #9A7100; border-color: rgba(234,179,8,0.28); }
+.platforms-legend .public,
+.platform-access.public { background: var(--green-bg); color: #16803A; border-color: rgba(34,197,94,0.24); }
+.platform-directory {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ column-gap: 32px;
+ row-gap: 0;
+ border-top: 1px solid var(--border2);
+}
+.platform-entry {
+ min-width: 0;
+ display: grid;
+ grid-template-columns: 38px minmax(0, 1fr);
+ gap: 14px;
+ padding: 19px 4px;
+ border-bottom: 1px solid var(--border2);
+}
+.platform-entry.priority {
+ position: relative;
+ padding-left: 14px;
+ background: linear-gradient(90deg, var(--accent-bg), transparent 62%);
+}
+.platform-entry.priority::before {
+ content: '';
+ position: absolute;
+ top: 14px;
+ bottom: 14px;
+ left: 0;
+ width: 3px;
+ border-radius: 2px;
+ background: var(--accent);
+}
+.platform-index {
+ color: var(--muted);
+ font-family: 'SF Mono', 'JetBrains Mono', monospace;
+ font-size: 11px;
+ font-weight: 700;
+ line-height: 22px;
+}
+.platform-entry.priority .platform-index { color: #9A7100; }
+.platform-content { min-width: 0; }
+.platform-name {
+ font-size: 15px;
+ font-weight: 750;
+ line-height: 1.4;
+}
+.platform-description {
+ margin-top: 3px;
+ color: var(--text2);
+ font-size: 12px;
+ line-height: 1.45;
+}
+.platform-links {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-top: 12px;
+}
+.platform-link {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ min-height: 34px;
+ border-bottom: 1px solid currentColor;
+ color: var(--text);
+ font-size: 12px;
+ font-weight: 700;
+ line-height: 1.25;
+ text-decoration: none;
+ transition: color 0.15s ease, transform 0.15s ease;
+}
+.platform-link::after { content: '\2197'; color: var(--muted); }
+.platform-link:hover { color: #9A7100; transform: translateY(-1px); }
+.platform-link:focus-visible {
+ border-radius: 4px;
+ outline: 3px solid rgba(234,179,8,0.34);
+ outline-offset: 4px;
+}
+.platform-note {
+ grid-column: 1 / -1;
+ margin-top: 18px;
+ color: var(--muted);
+ font-size: 11px;
+ line-height: 1.5;
+}
+
+@media (max-width: 760px) {
+ .platforms-header { grid-template-columns: 1fr; align-items: start; gap: 12px; }
+ .platforms-title { font-size: 22px; }
+ .platforms-legend { justify-content: flex-start; }
+ .platform-directory { grid-template-columns: 1fr; }
+ .platform-entry { padding-left: 2px; padding-right: 2px; }
+ .platform-entry.priority { padding-left: 14px; }
+ .platform-links { align-items: flex-start; flex-direction: column; }
+ .platform-link { max-width: 100%; overflow-wrap: anywhere; }
+}
+
+@media (max-width: 360px) {
+ .platform-entry { grid-template-columns: 28px minmax(0, 1fr); gap: 8px; }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .platform-link { transition: none; }
+ .platform-link:hover { transform: none; }
+}
+
/* Footer */
.footer { margin-top: 32px; text-align: center; font-size: 12px; color: var(--muted); display: flex; align-items: center; justify-content: center; gap: 8px; }
.live-dot { width: 6px; height: 6px; background: var(--green); border-radius: 50%; animation: pulse-green 2s infinite; }
@@ -2586,24 +2746,127 @@
Hello, Maxim
-
-
+
+
๐ฅ Mac Mini
offline
-
+
๐ป Air
-
-
+
๐ผ Pro
-
-
+
๐ค Agents
pixel
-
+
+ โ Platforms
+ 7
+
+
+
+
+
@@ -3179,18 +3442,26 @@
Hello, Maxim
// Navigation
function showSection(name) {
document.querySelectorAll('.section').forEach(s => s.classList.remove('active'));
- document.querySelectorAll('.nav-pill').forEach(p => p.classList.remove('active'));
- document.getElementById('section-' + name).classList.add('active');
+ document.querySelectorAll('.nav-pill').forEach(p => {
+ p.classList.remove('active');
+ p.setAttribute('aria-pressed', 'false');
+ });
+ const section = document.getElementById('section-' + name);
+ if (!section) return;
+ section.classList.add('active');
const trigger = (typeof event !== 'undefined' && event.currentTarget)
? event.currentTarget
: Array.from(document.querySelectorAll('.nav-pill'))
.find(p => p.getAttribute('onclick') === `showSection('${name}')`);
- if (trigger) trigger.classList.add('active');
+ if (trigger) {
+ trigger.classList.add('active');
+ trigger.setAttribute('aria-pressed', 'true');
+ }
if (name === 'logs' && !currentLogService) loadLogTabs();
}
const INITIAL_SECTION = new URLSearchParams(window.location.search).get('tab');
-if (['mac-mini', 'air', 'pro', 'agents'].includes(INITIAL_SECTION)) {
+if (['mac-mini', 'air', 'pro', 'agents', 'platforms'].includes(INITIAL_SECTION)) {
showSection(INITIAL_SECTION);
}
diff --git a/builder/tests/test_command_center_platforms.py b/builder/tests/test_command_center_platforms.py
new file mode 100644
index 0000000..e70cb28
--- /dev/null
+++ b/builder/tests/test_command_center_platforms.py
@@ -0,0 +1,207 @@
+from __future__ import annotations
+
+from html.parser import HTMLParser
+from pathlib import Path
+import re
+import unittest
+from urllib.parse import urlsplit
+
+
+DASHBOARD_PATH = (
+ Path(__file__).resolve().parents[1] / "mac-mini-dashboard" / "index.html"
+)
+
+EXPECTED_PLATFORMS = {
+ "financial": (
+ "JobRadar / Financial OS",
+ (
+ "http://127.0.0.1:8792",
+ "https://t.me/JobsRadarS_bot",
+ ),
+ ),
+ "mydictionary": (
+ "MyDictionary",
+ (
+ "http://127.0.0.1:8787/admin",
+ "https://t.me/max_context_bot",
+ ),
+ ),
+ "health": ("Health OS", ("https://health.meshly.fr/",)),
+ "ai-singularity": (
+ "AI Singularity",
+ ("http://127.0.0.1:8001",),
+ ),
+ "context-news": (
+ "Context News France",
+ (
+ "http://127.0.0.1:8002",
+ "https://t.me/croissantfr_bot",
+ ),
+ ),
+ "accountable": (
+ "Accountable OS",
+ ("http://127.0.0.1:4174",),
+ ),
+ "jarvis": ("JARVIS", ("https://t.me/max_jarvis_hoian_bot",)),
+}
+
+
+class _CommandCenterParser(HTMLParser):
+ def __init__(self) -> None:
+ super().__init__()
+ self.nav_targets: dict[str, str] = {}
+ self.platform_section_count = 0
+ self.platforms: dict[str, dict[str, object]] = {}
+ self._nav_target: str | None = None
+ self._nav_text: list[str] = []
+ self._platform_id: str | None = None
+ self._platform_depth = 0
+
+ def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None:
+ attributes = dict(attrs)
+ classes = (attributes.get("class") or "").split()
+
+ onclick = attributes.get("onclick") or ""
+ nav_target = re.fullmatch(r"showSection\(['\"]([^'\"]+)['\"]\)", onclick)
+ if tag == "button" and "nav-pill" in classes and nav_target:
+ self._nav_target = nav_target.group(1)
+ self._nav_text = []
+
+ if attributes.get("id") == "section-platforms":
+ self.platform_section_count += 1
+
+ platform_id = attributes.get("data-platform-id")
+ if platform_id is not None:
+ self._platform_id = platform_id
+ self._platform_depth = 1
+ self.platforms[platform_id] = {
+ "name": attributes.get("data-platform-name"),
+ "links": [],
+ }
+ elif self._platform_id is not None:
+ self._platform_depth += 1
+
+ if tag == "a" and self._platform_id is not None:
+ links = self.platforms[self._platform_id]["links"]
+ assert isinstance(links, list)
+ links.append(attributes)
+
+ def handle_data(self, data: str) -> None:
+ if self._nav_target is not None:
+ self._nav_text.append(data)
+
+ def handle_endtag(self, tag: str) -> None:
+ if tag == "button" and self._nav_target is not None:
+ self.nav_targets[self._nav_target] = " ".join(
+ "".join(self._nav_text).split()
+ )
+ self._nav_target = None
+ self._nav_text = []
+
+ if self._platform_id is not None:
+ self._platform_depth -= 1
+ if self._platform_depth == 0:
+ self._platform_id = None
+
+
+class CommandCenterPlatformsTests(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls) -> None:
+ cls.html = DASHBOARD_PATH.read_text(encoding="utf-8")
+ cls.parser = _CommandCenterParser()
+ cls.parser.feed(cls.html)
+
+ def test_historical_command_center_identity_is_preserved(self):
+ self.assertIn("Hello, Maxim", self.html)
+ for target, label in (
+ ("mac-mini", "Mac Mini"),
+ ("air", "Air"),
+ ("pro", "Pro"),
+ ("agents", "Agents"),
+ ):
+ self.assertIn(target, self.parser.nav_targets)
+ self.assertIn(label, self.parser.nav_targets[target])
+
+ def test_platforms_is_a_reachable_top_level_surface(self):
+ self.assertEqual(self.parser.platform_section_count, 1)
+ self.assertIn("platforms", self.parser.nav_targets)
+ self.assertIn("Platforms", self.parser.nav_targets["platforms"])
+
+ initial_guard = re.search(
+ r"\[([^\]]+)\]\.includes\(INITIAL_SECTION\)",
+ self.html,
+ )
+ self.assertIsNotNone(initial_guard, "INITIAL_SECTION needs a safe allowlist")
+ allowed = re.findall(r"['\"]([^'\"]+)['\"]", initial_guard.group(1))
+ self.assertIn("platforms", allowed)
+
+ def test_platform_directory_has_exact_registry_and_safe_destinations(self):
+ self.assertEqual(set(self.parser.platforms), set(EXPECTED_PLATFORMS))
+
+ for platform_id, (expected_name, expected_hrefs) in EXPECTED_PLATFORMS.items():
+ with self.subTest(platform=platform_id):
+ platform = self.parser.platforms[platform_id]
+ self.assertEqual(platform["name"], expected_name)
+ links = platform["links"]
+ assert isinstance(links, list)
+ self.assertEqual(
+ tuple(link.get("href") for link in links),
+ expected_hrefs,
+ )
+ for link in links:
+ self.assertEqual(link.get("target"), "_blank")
+ self.assertEqual(
+ set((link.get("rel") or "").split()),
+ {"noopener", "noreferrer"},
+ )
+
+ href = link.get("href") or ""
+ parsed = urlsplit(href)
+ self.assertIsNone(parsed.username)
+ self.assertIsNone(parsed.password)
+ self.assertEqual(parsed.query, "")
+ self.assertEqual(parsed.fragment, "")
+ self.assertNotIn("51.255.36.141", href)
+ self.assertNotRegex(
+ href,
+ r"(?i)(?:file:|/Users/|/home/|/srv/)",
+ )
+ if parsed.hostname == "127.0.0.1":
+ self.assertEqual(parsed.scheme, "http")
+ else:
+ self.assertEqual(parsed.scheme, "https")
+ self.assertIn(
+ parsed.hostname,
+ {"t.me", "health.meshly.fr"},
+ )
+
+ def test_platform_directory_is_responsive_keyboard_safe_and_motion_safe(self):
+ self.assertTrue(
+ 'class="platform-directory"' in self.html,
+ "Platforms needs the platform-directory layout hook",
+ )
+ self.assertTrue(
+ re.search(
+ r"@media\s*\([^)]*max-width[^)]*\)[\s\S]*?\.platform-directory",
+ self.html,
+ )
+ is not None,
+ "platform-directory needs a responsive breakpoint",
+ )
+ self.assertTrue(
+ re.search(r"\.platform-link:focus-visible\s*\{", self.html) is not None,
+ "platform links need a visible keyboard focus treatment",
+ )
+ self.assertTrue(
+ re.search(
+ r"@media\s*\(prefers-reduced-motion:\s*reduce\)\s*\{"
+ r"[\s\S]*?\.platform-link",
+ self.html,
+ )
+ is not None,
+ "platform link motion needs a reduced-motion override",
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/builder/tests/test_department_campus_visual_integration.py b/builder/tests/test_department_campus_visual_integration.py
index 4088ea1..3ff8a12 100644
--- a/builder/tests/test_department_campus_visual_integration.py
+++ b/builder/tests/test_department_campus_visual_integration.py
@@ -180,7 +180,7 @@ def _css_declarations(self, selector_fragment: str) -> str:
matches.append(declarations)
return "\n".join(matches)
- def test_ac_1_top_navigation_contains_only_the_four_public_surfaces(self):
+ def test_ac_1_top_navigation_contains_only_the_five_public_surfaces(self):
parser = self._dashboard()
self.assertEqual(
@@ -190,6 +190,7 @@ def test_ac_1_top_navigation_contains_only_the_four_public_surfaces(self):
("air", "Air"),
("pro", "Pro"),
("agents", "Agents"),
+ ("platforms", "Platforms"),
],
)
@@ -210,7 +211,10 @@ def test_ac_2_agents_is_default_and_legacy_tabs_cannot_be_selected(self):
"query-string tab restoration must retain an explicit safe allowlist",
)
allowed = re.findall(r"['\"]([^'\"]+)['\"]", initial_guard.group(1))
- self.assertEqual(allowed, ["mac-mini", "air", "pro", "agents"])
+ self.assertEqual(
+ allowed,
+ ["mac-mini", "air", "pro", "agents", "platforms"],
+ )
def test_ac_3_hq_keeps_its_id_but_uses_the_new_visible_russian_copy(self):
structure = self._campus_structure()