diff --git a/dashboard/css/apdetection.css b/dashboard/css/apdetection.css
new file mode 100644
index 0000000..bfdb287
--- /dev/null
+++ b/dashboard/css/apdetection.css
@@ -0,0 +1,211 @@
+/**
+ * Spaxel Dashboard - AP Detection Panel Styles
+ *
+ * Styles for the router AP detection banner and placement UI.
+ */
+
+/* ============================================
+ AP Detection Banner
+ ============================================ */
+
+.ap-detection-banner {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 1000;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
+ transform: translateY(-100%);
+ transition: transform 0.3s ease-out;
+}
+
+.ap-detection-banner-visible {
+ transform: translateY(0);
+}
+
+.ap-detection-content {
+ display: flex;
+ align-items: center;
+ padding: 16px 24px;
+ max-width: 800px;
+ margin: 0 auto;
+ color: white;
+}
+
+.ap-detection-icon {
+ font-size: 28px;
+ margin-right: 16px;
+ animation: pulse 2s ease-in-out infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ transform: scale(1);
+ opacity: 1;
+ }
+ 50% {
+ transform: scale(1.1);
+ opacity: 0.8;
+ }
+}
+
+.ap-detection-message {
+ flex: 1;
+}
+
+.ap-detection-title {
+ font-size: 18px;
+ font-weight: 600;
+ margin-bottom: 4px;
+}
+
+.ap-detection-subtitle {
+ font-size: 14px;
+ opacity: 0.9;
+}
+
+.ap-detection-actions {
+ display: flex;
+ gap: 12px;
+ margin-left: 16px;
+}
+
+/* ============================================
+ AP Placement Content
+ ============================================ */
+
+.ap-placement-content {
+ padding: 16px 0;
+}
+
+.ap-placement-list {
+ list-style: none;
+ padding: 0;
+ margin: 16px 0;
+}
+
+.ap-placement-list li {
+ padding: 8px 0;
+ padding-left: 24px;
+ position: relative;
+}
+
+.ap-placement-list li:before {
+ content: "•";
+ position: absolute;
+ left: 0;
+ color: #667eea;
+ font-weight: bold;
+}
+
+.ap-placement-tips {
+ margin-top: 20px;
+}
+
+.ap-placement-tip {
+ background: #f0f4ff;
+ border-left: 4px solid #667eea;
+ padding: 12px;
+ border-radius: 4px;
+ font-size: 14px;
+ color: #444;
+}
+
+/* ============================================
+ Responsive Design
+ ============================================ */
+
+@media (max-width: 768px) {
+ .ap-detection-content {
+ flex-direction: column;
+ text-align: center;
+ }
+
+ .ap-detection-icon {
+ margin-right: 0;
+ margin-bottom: 12px;
+ }
+
+ .ap-detection-actions {
+ margin-left: 0;
+ margin-top: 16px;
+ width: 100%;
+ }
+
+ .ap-detection-actions button {
+ flex: 1;
+ }
+
+ .ap-placement-list li {
+ padding-left: 0;
+ }
+
+ .ap-placement-list li:before {
+ display: none;
+ }
+}
+
+/* ============================================
+ Button Styles
+ ============================================ */
+
+.ap-btn {
+ padding: 10px 20px;
+ border: none;
+ border-radius: 6px;
+ font-size: 14px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.ap-btn-primary {
+ background: white;
+ color: #667eea;
+}
+
+.ap-btn-primary:hover {
+ background: #f0f0f0;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+}
+
+.ap-btn-secondary {
+ background: rgba(255, 255, 255, 0.2);
+ color: white;
+ border: 1px solid rgba(255, 255, 255, 0.3);
+}
+
+.ap-btn-secondary:hover {
+ background: rgba(255, 255, 255, 0.3);
+}
+
+.ap-btn:active {
+ transform: translateY(0);
+}
+
+/* ============================================
+ 3D View Router Icon
+ ============================================ */
+
+/* Distinct router icon for virtual AP nodes in 3D view */
+.virtual-node-router {
+ fill: #667eea;
+ stroke: #764ba2;
+ stroke-width: 1;
+}
+
+.virtual-node-router-glow {
+ opacity: 0.5;
+ animation: glow-pulse 2s ease-in-out infinite;
+}
+
+@keyframes glow-pulse {
+ 0%, 100% {
+ opacity: 0.3;
+ }
+ 50% {
+ opacity: 0.6;
+ }
+}
diff --git a/dashboard/index.html b/dashboard/index.html
index 946a31a..2e9a3f3 100644
--- a/dashboard/index.html
+++ b/dashboard/index.html
@@ -7,6 +7,7 @@
+