deb04c9315
Sprint 0 completo del producto VMS-Sailor (Vessel Management System integrado para buques 30-40m). Brief de referencia en VMS_Sailor_v2_Parte_*.md (intacto). Core (vmssailor.core, 95.17% coverage, 99 tests verde): - ShipCoord: sistema naval x_pp/y_cl/z_bl frozen - Vessel, Deck, Bulkhead - Equipment, EquipmentModel, Sensor, EquipmentSpec - Tag, AlarmConfig, TagBinding, Scaling - CardInstance, Bus, Topology con validacion 21 puntos I/O AR-NMEA-IO-v1.0 - Alarm, PermissiveRule, Condition - Project agregado raiz con validacion cross-entity - Persistencia portable .vmsproj (SQLite) con roundtrip verificable Biblioteca curada seed (vmssailor.library): - systems_catalog.json completo (catalogo maestro Parte 1 sec 7) - 2 vessels: Sunseeker 76, Ferretti 850 - 2 motores: MTU 12V 2000 M96, Volvo D13-900 - 1 genset: Northern Lights M65C13 - yacht_motor_planeo.yaml (reglas heuristicas) - TODO marcado data_source=seed_estimate - requiere validacion datasheets Tools: - vms-validate-library: CLI valida biblioteca completa - vms-generate-test-project: CLI demo + verificacion roundtrip persistencia Design System + 8 mockups HTML estaticos: - docs/design_system.md (paleta Deep Ocean, gradientes, typography, motion) - docs/brand/ (logo + variantes SVG) - docs/mockups/splash, studio_main, runtime_overview, runtime_mimic_fuel (P&ID animado), runtime_alarms, runtime_trim (panel estrella con horizonte artificial), mobile_overview, mobile_trim - docs/mockups/index.html (galeria) Firmware (Sprint 12+ implementacion): - firmware/ar_nmea_io_v1/src/config/pinout.h con macros GPIO Decisiones autonomas documentadas en docs/decisions_sprint0.md. Stack: Python 3.11 + uv + Pydantic v2 + SQLite stdlib + hatchling + pytest 9 + ruff + mypy. Sin PySide6, FastAPI, Flutter ni firmware funcional (entran en sprints siguientes). Criterio de aceptacion Sprint 0: cumplido. - uv sync: OK - pytest: 99/99 verde - cov vmssailor.core: 95.17% (objetivo >=80%) - ruff: clean - vms-validate-library: OK - vms-generate-test-project: INTEGRIDAD OK Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
571 lines
20 KiB
HTML
571 lines
20 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="es">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>VMS-Sailor Mobile · Trim</title>
|
||
<link rel="icon" type="image/svg+xml" href="../brand/favicon.svg">
|
||
<link rel="stylesheet" href="_tokens.css">
|
||
<style>
|
||
body {
|
||
background:
|
||
radial-gradient(ellipse at top, rgba(255,59,71,0.10), transparent 60%),
|
||
radial-gradient(ellipse at bottom, rgba(0,217,255,0.10), transparent 60%),
|
||
var(--g-deep-sea);
|
||
min-height: 100vh;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--s-7) var(--s-5);
|
||
gap: var(--s-7);
|
||
}
|
||
.phone {
|
||
width: 390px;
|
||
height: 844px;
|
||
background: #000;
|
||
border-radius: 56px;
|
||
padding: 12px;
|
||
box-shadow: var(--e-5), 0 0 0 2px rgba(255,255,255,0.05), 0 0 0 14px #1a1a1a;
|
||
position: relative;
|
||
flex-shrink: 0;
|
||
}
|
||
.phone::before {
|
||
content: ""; position: absolute;
|
||
top: 16px; left: 50%; transform: translateX(-50%);
|
||
width: 124px; height: 36px;
|
||
background: #000; border-radius: 18px; z-index: 10;
|
||
}
|
||
.screen {
|
||
width: 100%; height: 100%;
|
||
background: var(--c-abyss);
|
||
border-radius: 44px;
|
||
overflow: hidden;
|
||
display: flex; flex-direction: column;
|
||
position: relative;
|
||
}
|
||
.ios-status {
|
||
display: flex; justify-content: space-between; align-items: center;
|
||
padding: 16px 32px 6px;
|
||
font-size: 14px; font-weight: 600;
|
||
color: var(--c-foam);
|
||
height: 56px;
|
||
}
|
||
.indicators { display: flex; gap: 6px; align-items: center; }
|
||
.ios-bars { display: inline-flex; align-items: flex-end; gap: 1.5px; height: 11px; }
|
||
.ios-bars i { width: 3px; background: var(--c-foam); border-radius: 1px; }
|
||
.ios-bars i:nth-child(1) { height: 4px; }
|
||
.ios-bars i:nth-child(2) { height: 6px; }
|
||
.ios-bars i:nth-child(3) { height: 8px; }
|
||
.ios-bars i:nth-child(4) { height: 11px; }
|
||
.ios-battery { width: 25px; height: 12px; border: 1px solid var(--c-foam); border-radius: 3px; padding: 1px; position: relative; }
|
||
.ios-battery::after { content: ""; position: absolute; top: 3px; right: -3px; width: 2px; height: 6px; background: var(--c-foam); border-radius: 1px; }
|
||
.ios-battery div { width: 88%; height: 100%; background: var(--c-foam); border-radius: 1px; }
|
||
|
||
/* Header */
|
||
.m-head {
|
||
padding: var(--s-3) var(--s-5);
|
||
display: flex; align-items: center; gap: var(--s-3);
|
||
border-bottom: 1px solid var(--c-steel);
|
||
}
|
||
.back {
|
||
width: 36px; height: 36px;
|
||
border-radius: 50%;
|
||
background: var(--c-steel);
|
||
border: 1px solid var(--c-iron);
|
||
display: flex; align-items: center; justify-content: center;
|
||
color: var(--c-sand);
|
||
}
|
||
.m-head h1 {
|
||
flex: 1;
|
||
margin: 0;
|
||
font-family: var(--f-display);
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: var(--c-foam);
|
||
}
|
||
.m-head h1 small {
|
||
display: block;
|
||
font-family: var(--f-ui);
|
||
font-size: 10px;
|
||
color: var(--c-fog);
|
||
font-weight: 400;
|
||
letter-spacing: 1px;
|
||
text-transform: uppercase;
|
||
margin-top: 2px;
|
||
}
|
||
.m-head .badge-ok {
|
||
padding: 4px 10px;
|
||
background: rgba(0,224,138,0.14);
|
||
border: 1px solid rgba(0,224,138,0.4);
|
||
border-radius: var(--r-pill);
|
||
color: var(--c-ok);
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 1px;
|
||
}
|
||
|
||
.body {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: var(--s-4) var(--s-4) calc(var(--s-9) + 12px);
|
||
display: flex; flex-direction: column; gap: var(--s-4);
|
||
}
|
||
|
||
/* Big horizon */
|
||
.horizon-card {
|
||
padding: var(--s-4) var(--s-4);
|
||
background: linear-gradient(180deg, rgba(91,192,235,0.08), rgba(91,192,235,0.0)),
|
||
var(--c-midnight);
|
||
border: 1px solid var(--c-steel);
|
||
border-radius: var(--r-4);
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
.horizon-card svg {
|
||
width: 100%;
|
||
max-width: 320px;
|
||
aspect-ratio: 1;
|
||
display: block;
|
||
margin: 0 auto;
|
||
}
|
||
.att-row {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: var(--s-3);
|
||
margin-top: var(--s-4);
|
||
}
|
||
.att-cell {
|
||
padding: var(--s-3);
|
||
background: var(--c-abyss);
|
||
border: 1px solid var(--c-steel);
|
||
border-radius: var(--r-3);
|
||
text-align: center;
|
||
}
|
||
.att-cell .l { font-size: 10px; color: var(--c-fog); letter-spacing: 1.5px; text-transform: uppercase; font-weight: 700; }
|
||
.att-cell .v {
|
||
font-family: var(--f-mono);
|
||
font-size: 34px;
|
||
color: var(--c-foam);
|
||
font-weight: 600;
|
||
margin-top: 4px;
|
||
letter-spacing: -1px;
|
||
line-height: 1;
|
||
}
|
||
.att-cell .s { font-size: 10px; color: var(--c-fog); margin-top: 4px; font-family: var(--f-mono); }
|
||
|
||
/* Sliders */
|
||
.sliders-card {
|
||
padding: var(--s-4);
|
||
background: var(--c-midnight);
|
||
border: 1px solid var(--c-steel);
|
||
border-radius: var(--r-4);
|
||
}
|
||
.sliders-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: var(--s-4);
|
||
margin-top: var(--s-3);
|
||
}
|
||
.slider-block {
|
||
display: flex; flex-direction: column; align-items: center; gap: var(--s-2);
|
||
}
|
||
.slider-block .name {
|
||
font-family: var(--f-mono);
|
||
font-size: 11px;
|
||
color: var(--c-cyan);
|
||
font-weight: 700;
|
||
}
|
||
.v-slider {
|
||
width: 38px;
|
||
height: 200px;
|
||
background: linear-gradient(180deg,
|
||
rgba(255,59,71,0.10) 0%,
|
||
rgba(255,176,32,0.10) 20%,
|
||
rgba(0,224,138,0.10) 40%,
|
||
rgba(0,224,138,0.10) 60%,
|
||
rgba(255,176,32,0.10) 80%,
|
||
rgba(255,59,71,0.10) 100%
|
||
);
|
||
border: 1px solid var(--c-iron);
|
||
border-radius: var(--r-pill);
|
||
box-shadow: inset 0 2px 8px rgba(0,0,0,0.4);
|
||
position: relative;
|
||
}
|
||
.v-slider::after {
|
||
content: ""; position: absolute;
|
||
left: -4px; right: -4px; top: 50%;
|
||
height: 1px; background: var(--c-cyan); opacity: 0.5;
|
||
}
|
||
.v-handle {
|
||
position: absolute;
|
||
left: 50%; transform: translateX(-50%);
|
||
width: 54px; height: 28px;
|
||
background: var(--g-cyan);
|
||
border-radius: var(--r-2);
|
||
box-shadow: var(--glow-cyan), 0 4px 8px rgba(0,0,0,0.5);
|
||
display: flex; align-items: center; justify-content: center;
|
||
color: #04111F;
|
||
font-family: var(--f-mono);
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
}
|
||
.slider-block .pct {
|
||
font-family: var(--f-mono);
|
||
font-size: 17px;
|
||
font-weight: 600;
|
||
color: var(--c-foam);
|
||
}
|
||
|
||
/* Envelope */
|
||
.env-card {
|
||
padding: var(--s-4);
|
||
background: var(--c-midnight);
|
||
border: 1px solid var(--c-steel);
|
||
border-radius: var(--r-4);
|
||
}
|
||
.env-card h4 {
|
||
font-size: 11px; letter-spacing: 1.5px; color: var(--c-fog);
|
||
text-transform: uppercase; font-weight: 700;
|
||
margin: 0 0 var(--s-3);
|
||
}
|
||
.env-bar {
|
||
height: 14px;
|
||
background: linear-gradient(90deg,
|
||
#FF3B47 0%, #FF3B47 12%,
|
||
#FF8030 12%, #FF8030 25%,
|
||
#FFB020 25%, #FFB020 38%,
|
||
#00E08A 38%, #00E08A 62%,
|
||
#FFB020 62%, #FFB020 75%,
|
||
#FF8030 75%, #FF8030 88%,
|
||
#FF3B47 88%, #FF3B47 100%
|
||
);
|
||
border-radius: var(--r-pill);
|
||
position: relative;
|
||
box-shadow: inset 0 2px 4px rgba(0,0,0,0.4);
|
||
}
|
||
.env-pointer {
|
||
position: absolute;
|
||
top: -8px;
|
||
left: 47%;
|
||
transform: translateX(-50%);
|
||
width: 0; height: 0;
|
||
border-left: 8px solid transparent;
|
||
border-right: 8px solid transparent;
|
||
border-top: 12px solid var(--c-foam);
|
||
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.6));
|
||
}
|
||
.env-scale {
|
||
display: flex; justify-content: space-between;
|
||
margin-top: 6px;
|
||
font-family: var(--f-mono); font-size: 9px;
|
||
color: var(--c-fog);
|
||
}
|
||
.env-msg {
|
||
margin-top: var(--s-3);
|
||
font-size: 12px;
|
||
color: var(--c-ok);
|
||
font-family: var(--f-mono);
|
||
display: flex; align-items: center; gap: 6px;
|
||
}
|
||
|
||
/* Owner manual toggle */
|
||
.manual-card {
|
||
padding: var(--s-4);
|
||
background: var(--c-abyss);
|
||
border: 1px solid var(--c-steel);
|
||
border-radius: var(--r-3);
|
||
display: flex; align-items: center; gap: var(--s-3);
|
||
}
|
||
.manual-card .label { flex: 1; }
|
||
.manual-card .ttl { font-size: 13px; color: var(--c-foam); font-weight: 600; }
|
||
.manual-card .desc { font-size: 11px; color: var(--c-fog); margin-top: 2px; }
|
||
.toggle {
|
||
width: 52px; height: 30px;
|
||
border-radius: var(--r-pill);
|
||
background: var(--c-steel);
|
||
border: 1px solid var(--c-iron);
|
||
position: relative;
|
||
cursor: pointer;
|
||
}
|
||
.toggle::after {
|
||
content: ""; position: absolute;
|
||
left: 3px; top: 3px;
|
||
width: 22px; height: 22px;
|
||
background: var(--c-fog);
|
||
border-radius: 50%;
|
||
transition: all 200ms;
|
||
}
|
||
.biometric {
|
||
font-size: 10px;
|
||
color: var(--c-cyan);
|
||
margin-top: 6px;
|
||
display: flex; align-items: center; gap: 4px;
|
||
}
|
||
|
||
/* Emergency button */
|
||
.em-btn {
|
||
background: var(--g-emergency);
|
||
border: none;
|
||
border-radius: var(--r-4);
|
||
padding: var(--s-5);
|
||
color: var(--c-foam);
|
||
font-family: var(--f-display);
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
letter-spacing: 1.5px;
|
||
text-transform: uppercase;
|
||
cursor: pointer;
|
||
box-shadow: var(--glow-emergency);
|
||
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||
gap: var(--s-2);
|
||
}
|
||
.em-btn .ic-big { width: 36px; height: 36px; stroke: currentColor; fill: none; stroke-width: 2.5; }
|
||
.em-btn .sub { font-size: 11px; font-weight: 400; letter-spacing: 0.5px; text-transform: none; opacity: 0.9; }
|
||
|
||
.tab-bar {
|
||
position: absolute;
|
||
bottom: 0; left: 0; right: 0;
|
||
background: rgba(10,26,46,0.92);
|
||
border-top: 1px solid var(--c-steel);
|
||
backdrop-filter: blur(20px);
|
||
-webkit-backdrop-filter: blur(20px);
|
||
display: flex;
|
||
padding: var(--s-2) var(--s-3) calc(var(--s-3) + 18px);
|
||
}
|
||
.tab {
|
||
flex: 1; display: flex; flex-direction: column; align-items: center;
|
||
gap: 4px; padding: 6px 4px;
|
||
color: var(--c-fog); font-size: 10px; font-weight: 600;
|
||
}
|
||
.tab.active { color: var(--c-cyan); }
|
||
.tab .ic { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 2; }
|
||
|
||
.desc-panel {
|
||
max-width: 320px;
|
||
color: var(--c-sand);
|
||
}
|
||
.desc-panel h2 {
|
||
font-family: var(--f-display);
|
||
font-size: 28px;
|
||
font-weight: 600;
|
||
margin: 0 0 var(--s-3);
|
||
color: var(--c-foam);
|
||
}
|
||
.desc-panel p {
|
||
font-size: 14px; line-height: 1.7;
|
||
}
|
||
.desc-panel .quote {
|
||
padding: var(--s-4);
|
||
border-left: 3px solid var(--c-cyan);
|
||
background: rgba(0,217,255,0.05);
|
||
border-radius: 0 var(--r-3) var(--r-3) 0;
|
||
font-style: italic;
|
||
color: var(--c-foam);
|
||
margin-top: var(--s-5);
|
||
}
|
||
.ic { stroke: currentColor; fill: none; stroke-width: 2; width: 18px; height: 18px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="phone">
|
||
<div class="screen">
|
||
<div class="ios-status">
|
||
<span>03:42</span>
|
||
<div class="indicators">
|
||
<span class="ios-bars"><i></i><i></i><i></i><i></i></span>
|
||
<svg width="16" height="11" viewBox="0 0 16 11" style="color: var(--c-foam);"><path d="M8 4a5 5 0 0 1 5 5M8 1a8 8 0 0 1 8 8M8 7a2 2 0 0 1 2 2" stroke="currentColor" stroke-width="1.4" fill="none" stroke-linecap="round"/></svg>
|
||
<span class="ios-battery"><div></div></span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="m-head">
|
||
<div class="back">
|
||
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
|
||
</div>
|
||
<h1>
|
||
Trim & Maniobra
|
||
<small>Authority MÁQUINAS</small>
|
||
</h1>
|
||
<span class="badge-ok">SAFE</span>
|
||
</div>
|
||
|
||
<div class="body">
|
||
|
||
<div class="horizon-card">
|
||
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
|
||
<defs>
|
||
<linearGradient id="msky2" x1="0" y1="0" x2="0" y2="1">
|
||
<stop offset="0%" stop-color="#5BC0EB"/>
|
||
<stop offset="100%" stop-color="#1B3E6E"/>
|
||
</linearGradient>
|
||
<linearGradient id="msea2" x1="0" y1="0" x2="0" y2="1">
|
||
<stop offset="0%" stop-color="#0A1A2E"/>
|
||
<stop offset="100%" stop-color="#04111F"/>
|
||
</linearGradient>
|
||
<clipPath id="mclip2"><circle cx="150" cy="150" r="128"/></clipPath>
|
||
</defs>
|
||
<!-- Color bands roll scale -->
|
||
<g fill="none" stroke-width="5" stroke-linecap="butt">
|
||
<path d="M 100 32 A 128 128 0 0 1 200 32" stroke="#00E08A" opacity="0.7"/>
|
||
<path d="M 60 55 A 128 128 0 0 1 100 32" stroke="#FFB020" opacity="0.65"/>
|
||
<path d="M 200 32 A 128 128 0 0 1 240 55" stroke="#FFB020" opacity="0.65"/>
|
||
<path d="M 36 90 A 128 128 0 0 1 60 55" stroke="#FF8030" opacity="0.65"/>
|
||
<path d="M 240 55 A 128 128 0 0 1 264 90" stroke="#FF8030" opacity="0.65"/>
|
||
<path d="M 22 150 A 128 128 0 0 1 36 90" stroke="#FF3B47" opacity="0.75"/>
|
||
<path d="M 264 90 A 128 128 0 0 1 278 150" stroke="#FF3B47" opacity="0.75"/>
|
||
</g>
|
||
<circle cx="150" cy="150" r="140" fill="none" stroke="#1A2B42" stroke-width="2"/>
|
||
<g clip-path="url(#mclip2)">
|
||
<g transform="rotate(-4 150 150)">
|
||
<g transform="translate(0,8)">
|
||
<rect x="0" y="-100" width="300" height="250" fill="url(#msky2)"/>
|
||
<rect x="0" y="150" width="300" height="200" fill="url(#msea2)"/>
|
||
<line x1="0" y1="150" x2="300" y2="150" stroke="#00D9FF" stroke-width="2.5"/>
|
||
<line x1="0" y1="150" x2="300" y2="150" stroke="#00D9FF" stroke-width="5" opacity="0.35"/>
|
||
<g font-family="JetBrains Mono" font-size="11" fill="#E6EAF0" font-weight="600">
|
||
<line x1="115" y1="130" x2="185" y2="130" stroke="#E6EAF0" stroke-width="1.4"/>
|
||
<text x="105" y="134" text-anchor="end">10</text>
|
||
<text x="195" y="134">10</text>
|
||
<line x1="125" y1="115" x2="175" y2="115" stroke="#E6EAF0" stroke-width="1" opacity="0.7"/>
|
||
<line x1="115" y1="170" x2="185" y2="170" stroke="#E6EAF0" stroke-width="1.4"/>
|
||
<text x="105" y="174" text-anchor="end">10</text>
|
||
<text x="195" y="174">10</text>
|
||
</g>
|
||
</g>
|
||
</g>
|
||
</g>
|
||
<!-- Boat symbol -->
|
||
<g stroke="#00D9FF" stroke-width="3" fill="none" stroke-linecap="round">
|
||
<line x1="100" y1="150" x2="130" y2="150"/>
|
||
<line x1="170" y1="150" x2="200" y2="150"/>
|
||
<line x1="130" y1="150" x2="130" y2="158"/>
|
||
<line x1="170" y1="150" x2="170" y2="158"/>
|
||
</g>
|
||
<circle cx="150" cy="150" r="3.5" fill="#00D9FF"/>
|
||
<!-- Top reference -->
|
||
<path d="M 150 24 L 144 14 L 156 14 Z" fill="#FFB020"/>
|
||
<!-- Live roll triangle on outer -->
|
||
<g transform="translate(150,150) rotate(-4)">
|
||
<path d="M 0 -140 L -5 -148 L 5 -148 Z" fill="#00D9FF"/>
|
||
</g>
|
||
</svg>
|
||
<div class="att-row">
|
||
<div class="att-cell">
|
||
<div class="l">Roll</div>
|
||
<div class="v">-4.1°</div>
|
||
<div class="s">babor</div>
|
||
</div>
|
||
<div class="att-cell">
|
||
<div class="l">Pitch</div>
|
||
<div class="v">+1.8°</div>
|
||
<div class="s">popa abajo</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sliders-card">
|
||
<h4 style="font-size:11px; letter-spacing:1.5px; color:var(--c-fog); margin:0; text-transform:uppercase; font-weight:700;">Sliders de trim</h4>
|
||
<div class="sliders-grid">
|
||
<div class="slider-block">
|
||
<span class="name">ME_PORT</span>
|
||
<div class="v-slider"><div class="v-handle" style="top: 38%;">+12</div></div>
|
||
<span class="pct">+12%</span>
|
||
</div>
|
||
<div class="slider-block">
|
||
<span class="name">ME_STBD</span>
|
||
<div class="v-slider"><div class="v-handle" style="top: 42%;">+8</div></div>
|
||
<span class="pct">+8%</span>
|
||
</div>
|
||
<div class="slider-block">
|
||
<span class="name">TAB_PORT</span>
|
||
<div class="v-slider"><div class="v-handle" style="top: 65%;">−30</div></div>
|
||
<span class="pct">−30%</span>
|
||
</div>
|
||
<div class="slider-block">
|
||
<span class="name">TAB_STBD</span>
|
||
<div class="v-slider"><div class="v-handle" style="top: 50%;">0</div></div>
|
||
<span class="pct">0%</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="env-card">
|
||
<h4>Safety envelope</h4>
|
||
<div class="env-bar">
|
||
<div class="env-pointer" style="left: 46%;"></div>
|
||
</div>
|
||
<div class="env-scale">
|
||
<span>−18°</span>
|
||
<span>−12°</span>
|
||
<span>−8°</span>
|
||
<span>0°</span>
|
||
<span>+8°</span>
|
||
<span>+12°</span>
|
||
<span>+18°</span>
|
||
</div>
|
||
<div class="env-msg">
|
||
<svg class="ic" viewBox="0 0 24 24" style="color: var(--c-ok);"><polyline points="20 6 9 17 4 12"/></svg>
|
||
Roll dentro del rango seguro
|
||
</div>
|
||
</div>
|
||
|
||
<div class="manual-card">
|
||
<div class="label">
|
||
<div class="ttl">Modo manual del owner</div>
|
||
<div class="desc">Desactiva L1/L2. Mantiene L3 + envelope ±10°.</div>
|
||
<div class="biometric">
|
||
<svg class="ic" viewBox="0 0 24 24" style="width:12px;height:12px;"><path d="M12 2a4 4 0 0 0-4 4v6a4 4 0 0 0 8 0V6a4 4 0 0 0-4-4z"/><path d="M5 18s2 3 7 3 7-3 7-3"/></svg>
|
||
Requiere FaceID + TOTP
|
||
</div>
|
||
</div>
|
||
<div class="toggle"></div>
|
||
</div>
|
||
|
||
<button class="em-btn pulse-emergency">
|
||
<svg class="ic-big" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v6M12 16h.01"/></svg>
|
||
RESET TRIMS
|
||
<span class="sub">Lleva todos a neutral · acción cubierta por log book</span>
|
||
</button>
|
||
|
||
</div>
|
||
|
||
<nav class="tab-bar">
|
||
<div class="tab">
|
||
<svg class="ic" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
|
||
Overview
|
||
</div>
|
||
<div class="tab">
|
||
<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3v18"/></svg>
|
||
Mímicos
|
||
</div>
|
||
<div class="tab">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/></svg>
|
||
Alarmas
|
||
</div>
|
||
<div class="tab active">
|
||
<svg class="ic" viewBox="0 0 24 24"><path d="M6 3v18M18 3v18"/><circle cx="12" cy="12" r="3"/></svg>
|
||
Trim
|
||
</div>
|
||
<div class="tab">
|
||
<svg class="ic" viewBox="0 0 24 24"><circle cx="5" cy="12" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="19" cy="12" r="2"/></svg>
|
||
Más
|
||
</div>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="desc-panel">
|
||
<span class="overline">Panel destacado</span>
|
||
<h2>Trim desde la palma de la mano</h2>
|
||
<p>El owner ajusta el trim desde el flybridge mientras conduce. Botones grandes pensados para manos mojadas y guantes. Touch-targets ≥44pt.</p>
|
||
<p>El sistema mantiene <strong>L3 + envelope ±10°</strong> incluso en modo manual. La predicción del envelope bloquea movimientos peligrosos antes de ejecutarse.</p>
|
||
<div class="quote">
|
||
"El RESET es físico en consola + virtual en cada UI. Un toque, sin doble confirmación — es emergencia."
|
||
<div style="margin-top: 6px; font-style: normal; font-size: 11px; color: var(--c-fog); letter-spacing: 1px;">— Parte 1 sec 8, Reset de Emergencia</div>
|
||
</div>
|
||
</div>
|
||
|
||
</body>
|
||
</html>
|