Files
bambuddy/mockup/control-page-v16.html
T

1207 lines
36 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BambuTrack Control - v16</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
:root {
--bg-main: #f5f5f5;
--bg-white: #ffffff;
--bg-light: #fafafa;
--bg-panel: #f8f8f8;
--bg-hover: #e8e8e8;
--text-primary: #333333;
--text-secondary: #666666;
--text-muted: #999999;
--border: #e0e0e0;
--border-light: #eeeeee;
--accent: #00ae42;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg-main);
color: var(--text-primary);
font-size: 13px;
}
.main-layout {
display: grid;
grid-template-columns: 1fr 620px;
height: 100vh;
}
/* Left Panel - Camera */
.left-panel {
display: flex;
flex-direction: column;
background: var(--bg-main);
}
.camera-header {
display: flex;
align-items: center;
padding: 8px 12px;
background: var(--bg-white);
border-bottom: 1px solid var(--border);
gap: 8px;
}
.camera-title {
font-size: 13px;
color: var(--text-primary);
margin-right: auto;
}
.icon-btn {
width: 28px;
height: 28px;
border: none;
background: none;
cursor: pointer;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.icon-btn:hover { background: var(--bg-hover); }
.icon-btn img { width: 18px; height: 18px; opacity: 0.6; }
.camera-feed {
flex: 1;
background: #1a1a1a;
display: flex;
align-items: center;
justify-content: center;
color: #555;
font-size: 14px;
position: relative;
}
.camera-overlay {
position: absolute;
top: 10px;
left: 10px;
}
.camera-overlay img {
width: 24px;
height: 24px;
opacity: 0.7;
filter: invert(1);
}
/* Status bar */
.status-bar {
background: var(--accent);
padding: 4px 12px;
}
/* Print Progress */
.print-progress {
background: var(--bg-white);
padding: 16px 20px;
}
.progress-label { font-size: 12px; color: var(--text-muted); margin-bottom: 12px; }
.progress-row { display: flex; gap: 16px; align-items: center; }
.progress-thumb {
width: 80px; height: 80px;
background: var(--bg-light);
border: 1px solid var(--border);
border-radius: 8px;
display: flex; align-items: center; justify-content: center;
flex-direction: column;
font-size: 11px;
color: var(--text-muted);
overflow: hidden;
}
.progress-info { flex: 1; }
.progress-name { font-weight: 500; font-size: 14px; margin-bottom: 2px; }
.progress-status { color: var(--accent); font-size: 13px; margin-bottom: 8px; }
.progress-bar-bg { height: 4px; background: var(--border-light); border-radius: 2px; margin-bottom: 8px; }
.progress-bar-fill { height: 100%; background: var(--accent); border-radius: 2px; width: 0%; }
.progress-meta { font-size: 12px; color: var(--text-muted); margin-bottom: 4px; }
.progress-btns { display: flex; gap: 6px; }
.progress-btn {
width: 32px; height: 32px;
border: 1px solid var(--border);
background: var(--bg-white);
border-radius: 6px;
cursor: pointer;
font-size: 14px;
color: var(--text-muted);
}
.progress-btn:hover { background: var(--bg-hover); }
/* Right Panel - Control */
.right-panel {
background: var(--bg-white);
border-left: 1px solid var(--border);
overflow-y: auto;
overflow-x: hidden;
display: flex;
flex-direction: column;
}
.control-header {
display: flex;
align-items: center;
padding: 10px 16px;
border-bottom: 1px solid var(--border);
gap: 8px;
}
.control-title { font-size: 13px; margin-right: auto; color: var(--text-secondary); }
.header-btn {
padding: 7px 16px;
font-size: 12px;
border: none;
border-radius: 6px;
cursor: pointer;
background: var(--accent);
color: white;
}
.header-btn:hover { background: #009938; }
.control-body {
padding: 16px 20px;
flex: 1;
overflow-y: auto;
overflow-x: hidden;
}
/* Top Section: Temp + Movement side by side */
.top-section {
display: flex;
gap: 30px;
margin-bottom: 16px;
}
/* Temperature Column */
.temp-column {
flex: 0 0 auto;
min-width: 160px;
}
.temp-row {
display: flex;
align-items: center;
gap: 8px;
padding: 5px 0;
}
.temp-icon { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; }
.temp-icon img { width: 18px; opacity: 0.5; }
.temp-badge {
font-size: 11px;
font-weight: 600;
color: var(--accent);
background: #e8f5e9;
padding: 2px 8px;
border-radius: 4px;
min-width: 24px;
text-align: center;
}
.temp-badge-spacer {
min-width: 24px;
padding: 2px 8px;
}
.temp-value { font-size: 18px; font-weight: 500; }
.temp-target { font-size: 15px; color: var(--text-muted); }
/* Air Condition */
.air-section {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 0;
margin-top: 10px;
border-top: 1px solid var(--border-light);
}
.air-label {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: var(--text-secondary);
}
.air-label img { width: 18px; opacity: 0.5; }
.air-values {
display: flex;
align-items: center;
gap: 16px;
margin-top: 8px;
}
.air-value {
display: flex;
align-items: center;
gap: 5px;
font-size: 13px;
color: var(--text-secondary);
}
.air-value img { width: 16px; opacity: 0.5; }
.lamp-section {
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: var(--text-secondary);
}
.lamp-dot { width: 14px; height: 14px; border-radius: 50%; background: var(--accent); }
/* Movement Column */
.movement-column {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-end;
}
.nozzle-toggle {
display: flex;
border-radius: 6px;
overflow: hidden;
border: 1px solid var(--border);
margin-bottom: 12px;
}
.nozzle-toggle button {
padding: 7px 20px;
border: none;
background: var(--bg-white);
font-size: 13px;
cursor: pointer;
color: var(--text-secondary);
}
.nozzle-toggle button:first-child { border-right: 1px solid var(--border); }
.nozzle-toggle button.active { background: var(--accent); color: white; }
.movement-row {
display: flex;
gap: 24px;
align-items: flex-start;
}
.jog-section { display: flex; flex-direction: column; align-items: center; }
.jog-pad {
position: relative;
width: 120px;
height: 120px;
margin-bottom: 12px;
}
.jog-ring {
width: 100%;
height: 100%;
border-radius: 50%;
background: linear-gradient(135deg, #f8f8f8 0%, #ebebeb 100%);
border: 1px solid var(--border);
position: relative;
}
.jog-label {
position: absolute;
font-size: 11px;
color: var(--text-muted);
}
.jog-label.top { top: 8px; left: 50%; transform: translateX(-50%); }
.jog-label.bottom { bottom: 8px; left: 50%; transform: translateX(-50%); }
.jog-label.left { left: 8px; top: 50%; transform: translateY(-50%); }
.jog-label.right { right: 8px; top: 50%; transform: translateY(-50%); }
.jog-btn {
position: absolute;
width: 24px;
height: 24px;
background: var(--bg-white);
border: 1px solid var(--border);
border-radius: 4px;
cursor: pointer;
font-size: 10px;
color: var(--text-muted);
display: flex;
align-items: center;
justify-content: center;
}
.jog-btn:hover { background: var(--bg-hover); }
.jog-btn.up { top: 20px; left: 50%; transform: translateX(-50%); }
.jog-btn.down { bottom: 20px; left: 50%; transform: translateX(-50%); }
.jog-btn.left { left: 20px; top: 50%; transform: translateY(-50%); }
.jog-btn.right { right: 20px; top: 50%; transform: translateY(-50%); }
.jog-home {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--accent);
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.jog-home:hover { background: #009938; }
.jog-home img { width: 20px; filter: brightness(0) invert(1); }
/* Bed Controls */
.bed-controls {
display: flex;
align-items: center;
gap: 8px;
}
.bed-btn {
padding: 8px 14px;
background: var(--bg-white);
border: 1px solid var(--border);
border-radius: 6px;
cursor: pointer;
font-size: 12px;
color: var(--text-secondary);
}
.bed-btn:hover { background: var(--bg-hover); }
.bed-label { font-size: 12px; color: var(--text-muted); padding: 0 8px; }
/* Extruder Section */
.extruder-section {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
}
.extruder-btn {
width: 36px;
height: 36px;
background: var(--bg-white);
border: 1px solid var(--border);
border-radius: 6px;
cursor: pointer;
font-size: 14px;
color: var(--text-muted);
display: flex;
align-items: center;
justify-content: center;
}
.extruder-btn:hover { background: var(--bg-hover); }
.extruder-graphic {
height: 80px;
margin: 8px 0;
}
.extruder-graphic img { height: 100%; }
.extruder-label { font-size: 12px; color: var(--text-muted); }
/* ========== AMS SECTION ========== */
.ams-section {
background: var(--bg-panel);
border-radius: 12px;
padding: 16px;
margin-bottom: 12px;
}
/* Dual nozzle: two panels side by side */
.ams-dual-layout {
display: flex;
gap: 12px;
}
.ams-panel {
flex: 1;
display: flex;
flex-direction: column;
}
.ams-panel-label {
font-size: 11px;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
margin-bottom: 8px;
text-align: center;
}
/* AMS Selector Row - colored boxes */
.ams-selector-row {
display: flex;
gap: 6px;
margin-bottom: 12px;
flex-wrap: wrap;
}
.ams-selector-box {
display: flex;
align-items: center;
gap: 4px;
padding: 8px 10px;
background: var(--bg-white);
border: 2px solid var(--border);
border-radius: 6px;
cursor: pointer;
}
.ams-selector-box:hover { border-color: #ccc; }
.ams-selector-box.active { border-color: var(--accent); }
.ams-selector-box .color-dots {
display: flex;
gap: 3px;
}
.ams-selector-box .color-dot {
width: 14px;
height: 14px;
border-radius: 3px;
border: 1px solid rgba(0,0,0,0.1);
}
.ams-selector-box .color-dot.empty {
background: #e0e0e0;
}
.ams-selector-box .separator {
width: 1px;
height: 14px;
background: #ccc;
margin: 0 2px;
}
.ams-selector-box .count {
font-size: 12px;
color: var(--text-muted);
margin-left: 4px;
}
/* AMS Content Area */
.ams-content {
background: var(--bg-white);
border-radius: 10px;
padding: 14px;
display: flex;
gap: 12px;
}
/* AMS Slots Area */
.ams-slots-area {
flex: 1;
}
/* AMS Header */
.ams-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 10px;
font-size: 13px;
color: var(--text-secondary);
}
.ams-stat {
display: flex;
align-items: center;
gap: 4px;
}
.ams-stat img { width: 16px; opacity: 0.5; }
.ams-stat .sun { font-size: 16px; color: #f5a623; }
/* Slot Labels */
.slot-labels {
display: flex;
gap: 6px;
margin-bottom: 8px;
}
.slot-label {
flex: 1;
text-align: center;
font-size: 11px;
color: var(--text-muted);
padding: 4px 0;
background: var(--bg-panel);
border: 1px solid var(--border);
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
gap: 2px;
}
.slot-label .arrow {
font-size: 10px;
}
/* AMS Slots */
.ams-slots {
display: flex;
gap: 6px;
margin-bottom: 10px;
}
.ams-slot {
flex: 1;
height: 70px;
border-radius: 10px;
overflow: hidden;
cursor: pointer;
border: 2px solid var(--border);
background: var(--bg-white);
}
.ams-slot:hover { border-color: #bbb; }
.ams-slot.active { border-color: #d4a84b; }
.ams-slot-fill {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-end;
padding-bottom: 6px;
}
.ams-slot-type {
font-size: 10px;
font-weight: 600;
color: white;
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
margin-bottom: 4px;
}
.ams-slot-type.dark { color: #333; text-shadow: none; }
.ams-slot-eye { width: 14px; height: 14px; }
.ams-slot-eye img { width: 12px; height: 12px; opacity: 0.8; }
.ams-slot-eye.invert img { filter: invert(1); }
/* Slot Connectors */
.slot-connectors {
display: flex;
padding: 0 10px;
position: relative;
height: 20px;
}
.connector-line {
flex: 1;
display: flex;
justify-content: center;
}
.connector-line .vline {
width: 2px;
height: 12px;
background: #c0c0c0;
}
.connector-hbar {
position: absolute;
bottom: 8px;
left: 15%;
right: 15%;
height: 2px;
background: #c0c0c0;
}
.connector-down {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 2px;
height: 10px;
background: #c0c0c0;
}
/* External Spool Section */
.ext-section {
display: flex;
flex-direction: column;
align-items: center;
min-width: 100px;
}
.ext-label {
font-size: 14px;
font-weight: 500;
color: var(--text-secondary);
margin-bottom: 10px;
}
.ext-content {
display: flex;
gap: 8px;
align-items: flex-start;
}
.ext-slot-wrapper {
display: flex;
flex-direction: column;
align-items: center;
}
.ext-slot {
width: 55px;
height: 70px;
border-radius: 10px;
border: 2px solid var(--border);
background: var(--bg-white);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
cursor: pointer;
}
.ext-slot:hover { border-color: #bbb; }
.ext-slot .question {
font-size: 22px;
color: var(--text-muted);
}
.ext-slot .slash {
font-size: 18px;
color: var(--text-muted);
margin-top: -4px;
}
.ext-connector {
width: 2px;
height: 20px;
background: #c0c0c0;
margin-top: 0;
}
/* Spool Holder Illustration */
.spool-holder {
width: 70px;
height: 80px;
}
.spool-holder svg {
width: 100%;
height: 100%;
}
/* Hub Connector */
.hub-row {
display: flex;
align-items: center;
justify-content: center;
padding: 8px 0;
margin-top: 4px;
}
.hub-line {
flex: 1;
height: 2px;
background: #c0c0c0;
}
.hub-graphic {
display: flex;
gap: 4px;
padding: 6px 12px;
background: #e8e8e8;
border-radius: 4px;
border: 1px solid var(--border);
}
.hub-port {
width: 12px;
height: 18px;
background: var(--accent);
border-radius: 2px;
}
/* AMS Actions */
.ams-actions {
display: flex;
align-items: center;
gap: 12px;
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid var(--border-light);
}
.auto-refill-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 10px 18px;
background: var(--bg-white);
border: 1px solid var(--border);
border-radius: 8px;
cursor: pointer;
font-size: 13px;
color: var(--text-secondary);
}
.auto-refill-btn:hover { background: var(--bg-hover); }
.ams-settings-btn {
width: 40px;
height: 40px;
background: var(--bg-white);
border: 1px solid var(--border);
border-radius: 8px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.ams-settings-btn:hover { background: var(--bg-hover); }
.ams-settings-btn img { width: 22px; opacity: 0.5; }
.ams-spacer { flex: 1; }
.ams-action-btn {
padding: 10px 28px;
border-radius: 8px;
font-size: 13px;
cursor: pointer;
border: none;
background: #e8e8e8;
color: var(--text-secondary);
}
.ams-action-btn:hover { background: #ddd; }
</style>
</head>
<body>
<div class="main-layout">
<!-- Left Panel - Camera -->
<div class="left-panel">
<div class="camera-header">
<span class="camera-title">Camera</span>
<button class="icon-btn"><img src="icons/video-camera.svg"></button>
<button class="icon-btn"><img src="icons/webcam.svg"></button>
<button class="icon-btn"><img src="icons/settings.svg"></button>
</div>
<div class="camera-feed">
<div class="camera-overlay">
<img src="icons/micro-sd.svg">
</div>
Camera Feed
</div>
<div class="status-bar"></div>
<div class="print-progress">
<div class="progress-label">Printing Progress</div>
<div class="progress-row">
<div class="progress-thumb">
Bambu<br>Lab
</div>
<div class="progress-info">
<div class="progress-name">N/A</div>
<div class="progress-status">N/A</div>
<div class="progress-bar-bg"><div class="progress-bar-fill"></div></div>
<div class="progress-meta">Layer: N/A &nbsp;&nbsp; N/A</div>
<div class="progress-meta">Estimated finish time: N/A</div>
</div>
<div class="progress-btns">
<button class="progress-btn">&#8962;</button>
<button class="progress-btn">&#9208;</button>
<button class="progress-btn">&#9632;</button>
</div>
</div>
</div>
</div>
<!-- Right Panel - Control -->
<div class="right-panel">
<div class="control-header">
<span class="control-title">Control</span>
<button class="header-btn">Printer Parts</button>
<button class="header-btn">Print Options</button>
<button class="header-btn">Calibration</button>
</div>
<div class="control-body">
<!-- Top Section: Temp + Movement side by side -->
<div class="top-section">
<!-- Temperature Column -->
<div class="temp-column">
<div class="temp-row">
<div class="temp-icon"><img src="icons/hotend.svg"></div>
<span class="temp-badge">L</span>
<span class="temp-value">24</span>
<span class="temp-target">/0 °C</span>
</div>
<div class="temp-row">
<div class="temp-icon"><img src="icons/hotend.svg"></div>
<span class="temp-badge">R</span>
<span class="temp-value">23</span>
<span class="temp-target">/0 °C</span>
</div>
<div class="temp-row">
<div class="temp-icon"><img src="icons/heatbed.svg"></div>
<span class="temp-badge-spacer"></span>
<span class="temp-value">23</span>
<span class="temp-target">/0 °C</span>
</div>
<div class="temp-row">
<div class="temp-icon"><img src="icons/chamber.svg"></div>
<span class="temp-badge-spacer"></span>
<span class="temp-value">23</span>
<span class="temp-target">/0 °C</span>
</div>
<!-- Air Condition -->
<div class="air-section">
<div class="air-label"><img src="icons/ventilation.svg"> Air Condition</div>
</div>
<div class="air-values">
<div class="air-value"><img src="icons/ventilation.svg"> 100%</div>
<div class="lamp-section">Lamp <div class="lamp-dot"></div></div>
</div>
</div>
<!-- Movement Column -->
<div class="movement-column">
<div class="nozzle-toggle">
<button class="active">Left</button>
<button>Right</button>
</div>
<div class="movement-row">
<div class="jog-section">
<div class="jog-pad">
<div class="jog-ring">
<span class="jog-label top">Y</span>
<span class="jog-label bottom">-Y</span>
<span class="jog-label left">-X</span>
<span class="jog-label right">X</span>
<button class="jog-btn up">&#9650;</button>
<button class="jog-btn down">&#9660;</button>
<button class="jog-btn left">&#9664;</button>
<button class="jog-btn right">&#9654;</button>
<button class="jog-home"><img src="icons/home.svg"></button>
</div>
</div>
<div class="bed-controls">
<button class="bed-btn">&#8593;10</button>
<button class="bed-btn">&#8593;1</button>
<span class="bed-label">Bed</span>
<button class="bed-btn">&#8595;1</button>
<button class="bed-btn">&#8595;10</button>
</div>
</div>
<div class="extruder-section">
<button class="extruder-btn">&#9650;</button>
<div class="extruder-graphic"><img src="icons/dual-extruder.png"></div>
<button class="extruder-btn">&#9660;</button>
<span class="extruder-label">Extruder</span>
</div>
</div>
</div>
</div>
<!-- AMS Section - Dual Nozzle Layout -->
<div class="ams-section">
<div class="ams-dual-layout">
<!-- LEFT NOZZLE PANEL -->
<div class="ams-panel">
<div class="ams-panel-label">Left Nozzle</div>
<!-- AMS Selector Boxes -->
<div class="ams-selector-row">
<div class="ams-selector-box active">
<div class="color-dots">
<div class="color-dot" style="background: #FFD700;"></div>
<div class="color-dot" style="background: #333;"></div>
<div class="color-dot" style="background: #8B4513;"></div>
<div class="color-dot" style="background: #666;"></div>
</div>
</div>
<div class="ams-selector-box">
<div class="color-dots">
<div class="color-dot" style="background: #FF6600;"></div>
<div class="color-dot" style="background: #00AA00;"></div>
</div>
<div class="separator"></div>
<div class="color-dots">
<div class="color-dot" style="background: #0066FF;"></div>
<div class="color-dot" style="background: #FF0000;"></div>
</div>
<span class="count">0</span>
</div>
<div class="ams-selector-box">
<div class="color-dots">
<div class="color-dot empty"></div>
<div class="color-dot empty"></div>
<div class="color-dot empty"></div>
<div class="color-dot empty"></div>
</div>
<span class="count">0</span>
</div>
</div>
<!-- AMS Content: Slots + Ext -->
<div class="ams-content">
<!-- AMS Slots Area -->
<div class="ams-slots-area">
<div class="ams-header">
<div class="ams-stat"><img src="icons/water.svg"> 18 %</div>
<div class="ams-stat"><span class="sun">&#9788;</span></div>
</div>
<div class="slot-labels">
<div class="slot-label">A1<span class="arrow">↓</span></div>
<div class="slot-label">A2<span class="arrow">↓</span></div>
<div class="slot-label">A3<span class="arrow">↓</span></div>
<div class="slot-label">A4<span class="arrow">↓</span></div>
</div>
<div class="ams-slots">
<div class="ams-slot active">
<div class="ams-slot-fill" style="background: #FFD700;">
<span class="ams-slot-type dark">PLA</span>
<div class="ams-slot-eye"><img src="icons/eye.svg"></div>
</div>
</div>
<div class="ams-slot">
<div class="ams-slot-fill" style="background: #333;">
<span class="ams-slot-type">PETG</span>
<div class="ams-slot-eye invert"><img src="icons/eye.svg"></div>
</div>
</div>
<div class="ams-slot">
<div class="ams-slot-fill" style="background: #8B4513;">
<span class="ams-slot-type">PETG</span>
<div class="ams-slot-eye invert"><img src="icons/eye.svg"></div>
</div>
</div>
<div class="ams-slot">
<div class="ams-slot-fill" style="background: #666;">
<span class="ams-slot-type">PLA</span>
<div class="ams-slot-eye invert"><img src="icons/eye.svg"></div>
</div>
</div>
</div>
<!-- Slot Connectors -->
<div class="slot-connectors">
<div class="connector-line"><div class="vline"></div></div>
<div class="connector-line"><div class="vline"></div></div>
<div class="connector-line"><div class="vline"></div></div>
<div class="connector-line"><div class="vline"></div></div>
<div class="connector-hbar"></div>
<div class="connector-down"></div>
</div>
</div>
<!-- External Spool Section -->
<div class="ext-section">
<div class="ext-label">Ext</div>
<div class="ext-content">
<div class="ext-slot-wrapper">
<div class="ext-slot">
<span class="question">?</span>
<span class="slash">⁄</span>
</div>
<div class="ext-connector"></div>
</div>
<div class="spool-holder">
<svg viewBox="0 0 70 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<!-- Spool holder box -->
<path d="M5 25 L40 12 L65 25 L65 65 L40 78 L5 65 Z" fill="#f0f0f0" stroke="#ccc" stroke-width="1.5"/>
<path d="M5 25 L40 38 L65 25" fill="none" stroke="#ccc" stroke-width="1.5"/>
<path d="M40 38 L40 78" fill="none" stroke="#ccc" stroke-width="1.5"/>
<!-- Vent lines -->
<line x1="48" y1="45" x2="60" y2="40" stroke="#ddd" stroke-width="1"/>
<line x1="48" y1="52" x2="60" y2="47" stroke="#ddd" stroke-width="1"/>
<line x1="48" y1="59" x2="60" y2="54" stroke="#ddd" stroke-width="1"/>
<!-- Spool -->
<ellipse cx="25" cy="28" rx="15" ry="6" fill="#00ae42" stroke="#008833" stroke-width="1"/>
<rect x="10" y="28" width="30" height="10" fill="#00ae42"/>
<ellipse cx="25" cy="38" rx="15" ry="6" fill="#009938" stroke="#008833" stroke-width="1"/>
<!-- Spool center -->
<ellipse cx="25" cy="28" rx="6" ry="2.5" fill="#e0e0e0"/>
<ellipse cx="25" cy="38" rx="6" ry="2.5" fill="#ccc"/>
<!-- PTFE tube -->
<path d="M25 44 Q25 52 35 56 L40 54" fill="none" stroke="#00ae42" stroke-width="2.5"/>
</svg>
</div>
</div>
</div>
</div>
<!-- Hub Row -->
<div class="hub-row">
<div class="hub-line"></div>
<div class="hub-graphic">
<div class="hub-port"></div>
<div class="hub-port"></div>
</div>
<div class="hub-line"></div>
</div>
</div>
<!-- RIGHT NOZZLE PANEL -->
<div class="ams-panel">
<div class="ams-panel-label">Right Nozzle</div>
<!-- AMS Selector Boxes -->
<div class="ams-selector-row">
<div class="ams-selector-box active">
<div class="color-dots">
<div class="color-dot" style="background: #FFFFFF; border-color: #999;"></div>
<div class="color-dot" style="background: #222;"></div>
<div class="color-dot" style="background: #666;"></div>
<div class="color-dot" style="background: #999;"></div>
</div>
</div>
<div class="ams-selector-box">
<div class="color-dots">
<div class="color-dot empty"></div>
<div class="color-dot empty"></div>
<div class="color-dot empty"></div>
<div class="color-dot empty"></div>
</div>
<span class="count">0</span>
</div>
</div>
<!-- AMS Content: Slots + Ext -->
<div class="ams-content">
<!-- AMS Slots Area -->
<div class="ams-slots-area">
<div class="ams-header">
<div class="ams-stat"><img src="icons/water.svg"> 14 %</div>
<div class="ams-stat"><span class="sun">&#9788;</span></div>
</div>
<div class="slot-labels">
<div class="slot-label">B1<span class="arrow">↓</span></div>
<div class="slot-label">B2<span class="arrow">↓</span></div>
<div class="slot-label">B3<span class="arrow">↓</span></div>
<div class="slot-label">B4<span class="arrow">↓</span></div>
</div>
<div class="ams-slots">
<div class="ams-slot">
<div class="ams-slot-fill" style="background: #FFFFFF;">
<span class="ams-slot-type dark">PLA</span>
<div class="ams-slot-eye"><img src="icons/eye.svg"></div>
</div>
</div>
<div class="ams-slot">
<div class="ams-slot-fill" style="background: #222;">
<span class="ams-slot-type">PLA</span>
<div class="ams-slot-eye invert"><img src="icons/eye.svg"></div>
</div>
</div>
<div class="ams-slot">
<div class="ams-slot-fill" style="background: #666;">
<span class="ams-slot-type">PLA</span>
<div class="ams-slot-eye invert"><img src="icons/eye.svg"></div>
</div>
</div>
<div class="ams-slot">
<div class="ams-slot-fill" style="background: #999;">
<span class="ams-slot-type">PLA</span>
<div class="ams-slot-eye invert"><img src="icons/eye.svg"></div>
</div>
</div>
</div>
<!-- Slot Connectors -->
<div class="slot-connectors">
<div class="connector-line"><div class="vline"></div></div>
<div class="connector-line"><div class="vline"></div></div>
<div class="connector-line"><div class="vline"></div></div>
<div class="connector-line"><div class="vline"></div></div>
<div class="connector-hbar"></div>
<div class="connector-down"></div>
</div>
</div>
<!-- External Spool Section -->
<div class="ext-section">
<div class="ext-label">Ext</div>
<div class="ext-content">
<div class="ext-slot-wrapper">
<div class="ext-slot">
<span class="question">?</span>
<span class="slash">⁄</span>
</div>
<div class="ext-connector"></div>
</div>
<div class="spool-holder">
<svg viewBox="0 0 70 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 25 L40 12 L65 25 L65 65 L40 78 L5 65 Z" fill="#f0f0f0" stroke="#ccc" stroke-width="1.5"/>
<path d="M5 25 L40 38 L65 25" fill="none" stroke="#ccc" stroke-width="1.5"/>
<path d="M40 38 L40 78" fill="none" stroke="#ccc" stroke-width="1.5"/>
<line x1="48" y1="45" x2="60" y2="40" stroke="#ddd" stroke-width="1"/>
<line x1="48" y1="52" x2="60" y2="47" stroke="#ddd" stroke-width="1"/>
<line x1="48" y1="59" x2="60" y2="54" stroke="#ddd" stroke-width="1"/>
<ellipse cx="25" cy="28" rx="15" ry="6" fill="#00ae42" stroke="#008833" stroke-width="1"/>
<rect x="10" y="28" width="30" height="10" fill="#00ae42"/>
<ellipse cx="25" cy="38" rx="15" ry="6" fill="#009938" stroke="#008833" stroke-width="1"/>
<ellipse cx="25" cy="28" rx="6" ry="2.5" fill="#e0e0e0"/>
<ellipse cx="25" cy="38" rx="6" ry="2.5" fill="#ccc"/>
<path d="M25 44 Q25 52 35 56 L40 54" fill="none" stroke="#00ae42" stroke-width="2.5"/>
</svg>
</div>
</div>
</div>
</div>
<!-- Hub Row -->
<div class="hub-row">
<div class="hub-line"></div>
<div class="hub-graphic">
<div class="hub-port"></div>
<div class="hub-port"></div>
</div>
<div class="hub-line"></div>
</div>
</div>
</div>
<!-- AMS Actions -->
<div class="ams-actions">
<button class="auto-refill-btn">Auto-refill</button>
<button class="ams-settings-btn"><img src="icons/ams-settings.svg"></button>
<div class="ams-spacer"></div>
<button class="ams-action-btn">Unload</button>
<button class="ams-action-btn">Load</button>
</div>
</div>
</div>
</div>
</div>
</body>
</html>