@@ -2727,7 +3146,56 @@ function syncUnitsToggle(){
});
}
-document.querySelectorAll('.tab').forEach(t=>{t.addEventListener('click',()=>{document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active'));document.querySelectorAll('.panel').forEach(x=>x.classList.remove('active'));t.classList.add('active');document.getElementById('panel-'+t.dataset.panel).classList.add('active');document.getElementById('fab').style.display=['trips','maintenance','pending','zones'].includes(t.dataset.panel)?'flex':'none';if(t.dataset.panel==='export'){updateStorageInfo();bindCloudInputs();renderCloudStatus();renderShareList();bindWeatherInputs();renderAuthBox();refreshGoogleStatus()}if(t.dataset.panel==='pending'&&_gcalConnected&&Date.now()-_gcalLastPullAt>GCAL_PULL_INTERVAL_MS)googlePullNow();if(t.dataset.panel==='zones')renderZones();window.scrollTo(0,0)})});
+function switchPanel(name){
+ document.querySelectorAll('.tab').forEach(x=>x.classList.toggle('active',x.dataset.panel===name));
+ document.querySelectorAll('.bn-item').forEach(x=>x.classList.toggle('active',x.dataset.panel===name));
+ document.querySelectorAll('.panel').forEach(x=>x.classList.remove('active'));
+ const p=document.getElementById('panel-'+name);
+ if(p)p.classList.add('active');
+ // FAB visível em panels que têm "criar item"
+ document.getElementById('fab').style.display=['trips','maintenance','pending','zones','overview'].includes(name)?'flex':'none';
+ if(name==='export'){updateStorageInfo();bindCloudInputs();renderCloudStatus();renderShareList();bindWeatherInputs();renderAuthBox();refreshGoogleStatus()}
+ if(name==='pending'&&_gcalConnected&&Date.now()-_gcalLastPullAt>GCAL_PULL_INTERVAL_MS)googlePullNow();
+ if(name==='zones')renderZones();
+ window.scrollTo(0,0);
+}
+// Compat: top tabs (escondidos via CSS mas mantém handlers caso re-exibidos)
+document.querySelectorAll('.tab').forEach(t=>{t.addEventListener('click',()=>switchPanel(t.dataset.panel))});
+
+// Safety bar: atualiza bateria, GPS, anchor a cada 10s
+function updateSafetyBar(){
+ const bat=document.getElementById('battery-indicator');
+ const sbBat=document.getElementById('sb-battery');
+ if(sbBat&&bat){sbBat.textContent=bat.textContent.trim()||'—'}
+ const sbGps=document.getElementById('sb-gps');
+ const sbGpsDot=document.getElementById('sb-gps-dot');
+ if(sbGps&&sbGpsDot){
+ if(tracking?.active||(typeof lastGpsPos!=='undefined'&&lastGpsPos)){
+ sbGps.textContent='GPS ativo';sbGpsDot.className='safety-bar-dot ok';
+ }else{
+ sbGps.textContent='GPS aguardando';sbGpsDot.className='safety-bar-dot';
+ }
+ }
+ const sbAnchorWrap=document.getElementById('sb-anchor-wrap');
+ const sbAnchorDot=document.getElementById('sb-anchor-dot');
+ const sbAnchor=document.getElementById('sb-anchor');
+ if(sbAnchorWrap&&anchorWatch){
+ if(anchorWatch.active){
+ sbAnchorWrap.style.display='inline-flex';
+ const breach=anchorWatch.currentDist>anchorWatch.radius;
+ sbAnchorDot.className='safety-bar-dot '+(breach?'danger':'ok');
+ sbAnchor.textContent=breach?'⚠ DERIVANDO!':`Fundeado · raio ${Math.round(anchorWatch.currentDist||0)}/${anchorWatch.radius}m`;
+ }else{
+ sbAnchorWrap.style.display='none';
+ }
+ }
+ // Bottom nav badge pendências
+ const overdue=(state.pending||[]).filter(p=>!p.done&&p.dueDate&&p.dueDate0?'flex':'none';bnBadge.textContent=overdue}
+}
+setInterval(updateSafetyBar,5000);
+setTimeout(updateSafetyBar,1500);
function quickAdd(){const a=document.querySelector('.tab.active').dataset.panel;if(a==='maintenance')openMaintModal();else if(a==='pending')openPendingModal();else if(a==='zones')openZoneEditor();else openTripModal()}
function openModal(id){document.getElementById(id).classList.add('show')}
function closeModal(id){document.getElementById(id).classList.remove('show')}
diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle
index 4948964..42376e7 100644
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -7,8 +7,8 @@ android {
applicationId "br.com.pontualtech.shivao"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 9
- versionName "1.6.2"
+ versionCode 10
+ versionName "1.7.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
aaptOptions {
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
diff --git a/mobile/package.json b/mobile/package.json
index 3c5e443..5aa9d0e 100644
--- a/mobile/package.json
+++ b/mobile/package.json
@@ -1,6 +1,6 @@
{
"name": "shivao-mobile",
- "version": "1.6.2",
+ "version": "1.7.0",
"description": "Shivao app nativo (Capacitor wrapper Android/iOS)",
"main": "index.js",
"type": "module",
diff --git a/server/public/index.html b/server/public/index.html
index c8dd2b1..89f2b28 100644
--- a/server/public/index.html
+++ b/server/public/index.html
@@ -15,7 +15,7 @@
Diário de Bordo
-
+
@@ -1405,6 +1405,393 @@ header{
/* ── TOOLBAR refinada ── */
.toolbar{gap:10px; margin-bottom:18px}
+
+/* ════════════════════════════════════════════════════════════════════
+ v3 — "MARINE PRO DARK" REDESIGN (override completo)
+ Bottom nav · Inter + Mono · Dark navy + cyan · Cards modernos
+ ════════════════════════════════════════════════════════════════════ */
+:root{
+ /* Tipografia — sem Fraunces editorial */
+ --f-display:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
+ --f-body:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;
+ --f-mono:'JetBrains Mono','SF Mono','Consolas',monospace;
+ /* Paleta marine pro dark */
+ --m-bg:#0d2538; /* deep navy (canvas) */
+ --m-bg-2:#0f2a40; /* surface 1 */
+ --m-bg-3:#163a55; /* surface 2 (cards) */
+ --m-bg-4:#1d4a6b; /* surface elevated */
+ --m-border:rgba(255,255,255,.08);
+ --m-border-strong:rgba(255,255,255,.18);
+ --m-text:#e8f1f8; /* primary text */
+ --m-text-mid:#b3c5d6; /* secondary */
+ --m-text-soft:#7d97ad; /* tertiary */
+ --m-accent:#06b6d4; /* cyan accent */
+ --m-accent-2:#22d3ee; /* cyan brighter */
+ --m-accent-glow:rgba(6,182,212,.20);
+ --m-ok:#10b981; /* anchored / safe */
+ --m-warn:#f59e0b; /* drift / soon */
+ --m-danger:#ef4444; /* alarm */
+ --m-info:#3b82f6; /* info */
+ /* Spacing scale */
+ --sp-1:4px;--sp-2:8px;--sp-3:12px;--sp-4:16px;--sp-5:24px;--sp-6:32px;--sp-7:48px;
+ /* Radius */
+ --m-r-sm:6px;--m-r-md:10px;--m-r-lg:14px;--m-r-xl:20px;--m-r-pill:9999px;
+ /* Shadows (subtle, marine) */
+ --m-sh-1:0 1px 2px rgba(0,0,0,.32);
+ --m-sh-2:0 2px 6px rgba(0,0,0,.28),0 1px 2px rgba(0,0,0,.24);
+ --m-sh-3:0 8px 20px rgba(0,0,0,.32),0 2px 6px rgba(0,0,0,.24);
+}
+
+html,body{
+ background:var(--m-bg);
+ color:var(--m-text);
+ font-family:var(--f-body);
+ font-feature-settings:'cv11','ss03';
+ font-size:15px;line-height:1.5;
+}
+body{
+ background-image:
+ radial-gradient(ellipse 800px 600px at top right,rgba(34,211,238,.04) 0%,transparent 70%),
+ radial-gradient(ellipse 700px 500px at bottom left,rgba(6,182,212,.03) 0%,transparent 70%),
+ linear-gradient(180deg,#0a1f30 0%,#0d2538 100%);
+ background-attachment:fixed;
+ padding-bottom:calc(76px + env(safe-area-inset-bottom));
+}
+
+/* Mata o italic editorial em TUDO */
+.boat-name,.entry-title,.empty-title,.modal-head h3,
+.entry-notes,.field textarea,.export-card-title,
+.export-card-text,.field-hint,h1,h2,h3,h4,h5,
+.gps-card,.anchor-card,.fleet-name,.welcome-tagline{
+ font-family:var(--f-body)!important;
+ font-style:normal!important;
+ font-variation-settings:normal!important;
+}
+
+/* ── HEADER COMPACTO ── */
+header{
+ background:linear-gradient(180deg,var(--m-bg-2) 0%,var(--m-bg) 100%);
+ border-bottom:1px solid var(--m-border);
+ padding:max(10px,env(safe-area-inset-top)) 14px 10px;
+ box-shadow:var(--m-sh-1);
+}
+.header-row{gap:10px;max-width:760px}
+.compass-mark{display:none} /* compact: avatar é suficiente */
+.boat-tagline{
+ font-family:var(--f-mono);font-size:9px;color:var(--m-accent);
+ letter-spacing:.18em;opacity:.85;margin-bottom:1px;
+}
+.boat-name,.boat-selector{
+ font-family:var(--f-body)!important;font-style:normal!important;
+ font-size:17px!important;font-weight:600;letter-spacing:-.01em;
+ color:var(--m-text)!important;line-height:1.2;
+}
+.boat-meta{
+ font-family:var(--f-body);font-size:11px;color:var(--m-text-soft);
+ text-transform:none;letter-spacing:0;
+}
+.boat-edit-btn{display:none}
+.boat-header-avatar{
+ width:38px;height:38px;border:2px solid var(--m-accent);
+ background:var(--m-bg-3);color:var(--m-accent);
+ box-shadow:0 0 0 3px var(--m-accent-glow);
+}
+
+/* ── SAFETY STATUS BAR (logo abaixo do header) ── */
+.safety-bar{
+ display:flex;justify-content:space-between;align-items:center;
+ background:var(--m-bg-2);border-bottom:1px solid var(--m-border);
+ padding:6px 14px;font-family:var(--f-mono);font-size:10.5px;
+ color:var(--m-text-mid);letter-spacing:.04em;
+ position:sticky;top:0;z-index:39;
+}
+.safety-bar-item{display:inline-flex;align-items:center;gap:5px}
+.safety-bar-dot{width:7px;height:7px;border-radius:50%;background:var(--m-text-soft)}
+.safety-bar-dot.ok{background:var(--m-ok);box-shadow:0 0 6px var(--m-ok)}
+.safety-bar-dot.warn{background:var(--m-warn);box-shadow:0 0 6px var(--m-warn);animation:pulseDot 1.5s infinite}
+.safety-bar-dot.danger{background:var(--m-danger);box-shadow:0 0 8px var(--m-danger);animation:pulseDot .8s infinite}
+@keyframes pulseDot{50%{opacity:.4}}
+
+/* ── TOP TABS REMOVIDAS (substituídas pela bottom nav) ── */
+.tabs{display:none!important}
+
+/* ── CONTAINER ── */
+.container{padding:14px 12px 20px;max-width:760px}
+.panel{padding:0;background:transparent}
+
+/* ── CARDS DARK MODERNOS ── */
+.export-card,.gps-card,.anchor-card,.empty,.contact-card{
+ background:var(--m-bg-3);
+ border:1px solid var(--m-border);
+ border-radius:var(--m-r-lg);
+ box-shadow:var(--m-sh-2);
+ padding:16px;margin-bottom:12px;
+ color:var(--m-text);
+}
+.export-card-title{
+ color:var(--m-text)!important;font-weight:600;font-size:15px;
+ letter-spacing:-.005em;margin-bottom:6px;
+}
+.export-card-text{
+ color:var(--m-text-mid)!important;font-size:13px;line-height:1.5;
+}
+.gps-card,.anchor-card{
+ background:linear-gradient(165deg,var(--m-bg-3),var(--m-bg-2));
+ border:1px solid var(--m-border-strong);
+}
+.gps-card.idle{
+ background:var(--m-bg-3);
+ color:var(--m-text);
+}
+.gps-stats{gap:14px}
+.gps-stat-value,.t-stat-value{
+ color:var(--m-accent)!important;
+ font-family:var(--f-mono);font-weight:700;
+ font-variant-numeric:tabular-nums;
+}
+.gps-stat-label,.t-stat-label{
+ color:var(--m-text-soft)!important;
+ font-size:9.5px;letter-spacing:.14em;
+}
+
+.entry{
+ background:var(--m-bg-3);
+ border:1px solid var(--m-border);
+ border-left:3px solid var(--m-accent);
+ border-radius:var(--m-r-md);
+ box-shadow:var(--m-sh-1);
+ padding:14px;margin-bottom:10px;
+ color:var(--m-text);
+}
+.entry-title{color:var(--m-text)!important;font-weight:600;font-size:15px}
+.entry-meta{color:var(--m-text-mid)}
+.entry.maint{border-left-color:var(--m-warn)}
+.entry.pending{border-left-color:var(--m-warn)}
+.entry.pending.overdue{border-left-color:var(--m-danger)}
+.entry.pending.done{border-left-color:var(--m-ok);opacity:.7}
+.entry-grid dt{color:var(--m-text-soft)}
+.entry-grid dd{color:var(--m-text)}
+.entry-notes{
+ background:var(--m-bg-2)!important;border-left-color:var(--m-accent)!important;
+ color:var(--m-text-mid)!important;border-radius:var(--m-r-sm);
+ font-style:normal!important;
+}
+
+/* ── STATS DASHBOARD ── */
+.stats{gap:8px}
+.stat{
+ background:var(--m-bg-3);
+ border:1px solid var(--m-border);
+ border-radius:var(--m-r-md);
+ padding:14px 12px;
+ position:relative;overflow:hidden;
+}
+.stat::before{
+ content:'';position:absolute;top:0;left:0;right:0;height:2px;
+ background:linear-gradient(90deg,var(--m-accent),var(--m-accent-2));
+ opacity:.7;
+}
+.stat-value{
+ color:var(--m-accent)!important;
+ font-family:var(--f-mono);font-weight:700;
+ font-variant-numeric:tabular-nums;
+ font-size:24px;
+}
+.stat-label{
+ color:var(--m-text-soft)!important;
+ font-size:9.5px;letter-spacing:.14em;
+}
+.stat-sub{color:var(--m-text-mid)!important;font-style:normal!important;font-size:11px}
+
+/* ── BUTTONS ── */
+.btn{
+ background:var(--m-bg-3);border:1px solid var(--m-border-strong);
+ color:var(--m-text);font-family:var(--f-body);
+ font-size:14px;font-weight:500;
+ border-radius:var(--m-r-md);
+ min-height:44px;padding:11px 18px;
+ text-transform:none;letter-spacing:0;
+ transition:all .15s;
+}
+.btn:hover{background:var(--m-bg-4);border-color:var(--m-accent)}
+.btn-primary,.btn-brass{
+ background:var(--m-accent);color:#001a25;border-color:var(--m-accent);
+ font-weight:600;
+}
+.btn-primary:hover,.btn-brass:hover{background:var(--m-accent-2);color:#001a25;border-color:var(--m-accent-2)}
+.btn-danger{background:transparent;color:var(--m-danger);border-color:var(--m-danger)}
+.btn-danger:hover{background:rgba(239,68,68,.1);color:var(--m-danger)}
+.btn-block{width:100%}
+.btn-sm{min-height:34px;padding:7px 14px;font-size:12.5px}
+.btn-big{min-height:54px;padding:14px 22px;font-size:15px;font-weight:600}
+
+/* ── FAB acima da bottom nav ── */
+.fab{
+ bottom:calc(86px + env(safe-area-inset-bottom))!important;
+ right:18px!important;
+ background:linear-gradient(135deg,var(--m-accent),var(--m-accent-2))!important;
+ color:#001a25!important;
+ width:56px!important;height:56px!important;
+ box-shadow:0 6px 20px var(--m-accent-glow),0 2px 8px rgba(0,0,0,.5)!important;
+}
+.fab:hover{transform:scale(1.06) translateY(-2px)!important}
+.fab svg{stroke:#001a25!important}
+
+/* ── BOTTOM NAVIGATION ── */
+.bottom-nav{
+ position:fixed;bottom:0;left:0;right:0;z-index:48;
+ background:var(--m-bg-2);
+ border-top:1px solid var(--m-border);
+ padding:6px 0 max(6px,env(safe-area-inset-bottom));
+ display:flex;justify-content:space-around;align-items:stretch;
+ backdrop-filter:blur(18px);
+ -webkit-backdrop-filter:blur(18px);
+ background:rgba(15,42,64,.92);
+}
+.bn-item{
+ flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
+ gap:3px;padding:6px 4px;
+ background:none;border:none;cursor:pointer;
+ color:var(--m-text-soft);
+ font-family:var(--f-body);font-size:10px;font-weight:500;
+ transition:color .15s;
+ min-height:54px;
+}
+.bn-item:hover{color:var(--m-text-mid)}
+.bn-item.active{color:var(--m-accent)}
+.bn-item svg{width:22px;height:22px;stroke-width:2;transition:stroke-width .15s}
+.bn-item.active svg{stroke-width:2.4}
+.bn-badge{
+ position:absolute;top:4px;right:50%;transform:translate(14px,0);
+ background:var(--m-danger);color:#fff;
+ font-family:var(--f-mono);font-size:9px;font-weight:700;
+ min-width:16px;height:16px;border-radius:8px;
+ display:flex;align-items:center;justify-content:center;padding:0 4px;
+}
+.bn-item{position:relative}
+
+/* ── MODAIS dark ── */
+.modal{
+ background:var(--m-bg-3);
+ color:var(--m-text);
+ border:1px solid var(--m-border-strong);
+ border-radius:var(--m-r-xl) var(--m-r-xl) 0 0;
+ border-top:1px solid var(--m-border-strong);
+}
+@media(min-width:600px){
+ .modal{border-radius:var(--m-r-xl);}
+}
+.modal-head{border-bottom:1px solid var(--m-border)}
+.modal-head h3{color:var(--m-text);font-style:normal;font-weight:600;font-size:17px}
+.modal-foot{border-top:1px solid var(--m-border);background:var(--m-bg-2)}
+.modal-backdrop{background:rgba(0,0,0,.7);backdrop-filter:blur(6px)}
+.icon-btn{color:var(--m-text-mid);background:transparent;border:none}
+.icon-btn:hover{color:var(--m-text);background:var(--m-bg-2)}
+
+/* ── FORM FIELDS dark ── */
+.field-label{color:var(--m-text-soft);font-size:10px;letter-spacing:.12em;font-weight:600;text-transform:uppercase}
+.field input,.field textarea,.field select{
+ background:var(--m-bg-2)!important;
+ border:1px solid var(--m-border-strong)!important;
+ color:var(--m-text)!important;
+ border-radius:var(--m-r-sm);
+ font-family:var(--f-body);font-style:normal!important;
+ font-size:15px;padding:11px 13px;
+}
+.field input:focus,.field textarea:focus,.field select:focus{
+ outline:none!important;
+ border-color:var(--m-accent)!important;
+ box-shadow:0 0 0 3px var(--m-accent-glow)!important;
+ background:var(--m-bg-3)!important;
+}
+.field-hint{color:var(--m-text-soft);font-style:normal!important}
+
+/* ── SECTION HEADERS / TOOLBARS ── */
+.section-header h2{color:var(--m-text-soft);text-transform:uppercase;letter-spacing:.12em;font-size:10.5px}
+.toolbar{margin-bottom:14px}
+
+/* ── EMPTY STATES ── */
+.empty{text-align:center;padding:32px 20px;color:var(--m-text-soft)}
+.empty-title{color:var(--m-text);font-weight:600;font-size:16px;font-style:normal!important}
+.empty-text{color:var(--m-text-soft);font-size:13.5px;line-height:1.55}
+
+/* ── SYNC INDICATOR ── */
+.sync-indicator{font-size:10px;margin-left:5px}
+
+/* ── WELCOME SCREEN dark ── */
+.welcome-screen{background:linear-gradient(135deg,var(--m-bg) 0%,var(--m-bg-2) 50%,#06151f 100%)}
+.welcome-card{
+ background:var(--m-bg-3);
+ border:1px solid var(--m-border-strong);
+ border-radius:var(--m-r-xl);
+ box-shadow:var(--m-sh-3);
+ color:var(--m-text);
+}
+.welcome-title{color:var(--m-text);font-style:normal;font-weight:700;font-size:24px}
+.welcome-tagline{color:var(--m-text-mid);font-style:normal;font-size:14px}
+.welcome-btn{
+ background:var(--m-bg-2);border:1px solid var(--m-border-strong);
+ color:var(--m-text);border-radius:var(--m-r-md);
+ font-family:var(--f-body);font-weight:500;
+}
+.welcome-btn:hover{background:var(--m-bg-4);border-color:var(--m-accent)}
+.welcome-btn-google{background:#fff;color:#3c4043;border-color:#dadce0}
+.welcome-btn-google:hover{background:#f1f3f4;color:#3c4043;border-color:#dadce0}
+.welcome-btn-primary{background:var(--m-accent);color:#001a25;border-color:var(--m-accent)}
+.welcome-btn-primary:hover{background:var(--m-accent-2);color:#001a25;border-color:var(--m-accent-2)}
+.welcome-btn-text{color:var(--m-text-soft);background:transparent;border:none}
+.welcome-tab{color:var(--m-text-soft);text-transform:uppercase;letter-spacing:.12em}
+.welcome-tab.active{color:var(--m-accent);border-bottom-color:var(--m-accent)}
+
+/* ── FLEET & ANCHOR CALC dark ── */
+.fleet-item{background:var(--m-bg-2);border:1px solid var(--m-border)}
+.fleet-item:hover{background:var(--m-bg-4);border-color:var(--m-accent)}
+.fleet-item.active{border-left:3px solid var(--m-accent);background:var(--m-bg-4)}
+.fleet-name{color:var(--m-text);font-style:normal;font-weight:600;font-size:15px}
+.fleet-meta{color:var(--m-text-soft);text-transform:uppercase;letter-spacing:.06em}
+.fleet-active-badge{background:var(--m-accent);color:#001a25;font-weight:700}
+.fleet-edit-icon{background:transparent;border:1px solid var(--m-border-strong);color:var(--m-text-mid)}
+.fleet-units-toggle{border:1px solid var(--m-border-strong);background:var(--m-bg-2)}
+.fleet-units-toggle button{background:transparent;color:var(--m-text-mid)}
+.fleet-units-toggle button.active{background:var(--m-accent);color:#001a25}
+
+.anchor-calc{background:var(--m-bg-2);border:1px solid var(--m-border);border-left:3px solid var(--m-accent)}
+.anchor-calc-head{color:var(--m-accent);font-weight:600}
+.anchor-calc-stat{background:var(--m-bg-3);border:1px solid var(--m-border)}
+.anchor-calc-stat-label{color:var(--m-text-soft)}
+.anchor-calc-stat-value{color:var(--m-text);font-style:normal;font-weight:700;font-family:var(--f-mono);font-variant-numeric:tabular-nums}
+.anchor-calc-stat-value.ok{color:var(--m-ok)}
+.anchor-calc-stat-value.warn{color:var(--m-warn)}
+.anchor-calc-stat-value.danger{color:var(--m-danger)}
+.anchor-calc-advice{background:rgba(6,182,212,.08);border-left-color:var(--m-accent);color:var(--m-text-mid);font-style:normal}
+
+/* ── BADGES & TAGS ── */
+.badge{background:var(--m-danger);color:#fff;font-family:var(--f-mono);font-weight:700}
+.pax-tag{background:var(--m-bg-3);border:1px solid var(--m-border);color:var(--m-text);border-radius:var(--m-r-pill)}
+
+/* ── ALERTS ── */
+.alert-overdue,.alert-danger{background:rgba(239,68,68,.08);border-left:3px solid var(--m-danger);color:var(--m-text)}
+.alert-soon,.alert-warn{background:rgba(245,158,11,.08);border-left:3px solid var(--m-warn);color:var(--m-text)}
+.alert-info{background:rgba(59,130,246,.08);border-left:3px solid var(--m-info);color:var(--m-text)}
+
+/* ── TOAST ── */
+.toast{
+ background:var(--m-bg-3);color:var(--m-text);
+ border:1px solid var(--m-border-strong);
+ border-radius:var(--m-r-md);
+ box-shadow:var(--m-sh-3);
+ font-family:var(--f-body);font-style:normal;font-weight:500;
+}
+
+/* ── pax/checklist/tags ajustes ── */
+.checklist-card{background:var(--m-bg-3);border:1px solid var(--m-border);border-radius:var(--m-r-md);color:var(--m-text)}
+.weather-widget{background:var(--m-bg-3)!important;border:1px solid var(--m-border)!important;color:var(--m-text)!important;border-radius:var(--m-r-md)}
+
+/* ── SCROLLBAR thin estilo iOS ── */
+::-webkit-scrollbar{width:6px;height:6px}
+::-webkit-scrollbar-thumb{background:var(--m-border-strong);border-radius:3px}
+::-webkit-scrollbar-track{background:transparent}
+
@@ -1450,6 +1837,13 @@ header{
+
+
+ GPS aguardando
+ Fundeado
+ —
+
+
@@ -1951,6 +2345,31 @@ Hora: {HORA}
+
+
+
@@ -2727,7 +3146,56 @@ function syncUnitsToggle(){
});
}
-document.querySelectorAll('.tab').forEach(t=>{t.addEventListener('click',()=>{document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active'));document.querySelectorAll('.panel').forEach(x=>x.classList.remove('active'));t.classList.add('active');document.getElementById('panel-'+t.dataset.panel).classList.add('active');document.getElementById('fab').style.display=['trips','maintenance','pending','zones'].includes(t.dataset.panel)?'flex':'none';if(t.dataset.panel==='export'){updateStorageInfo();bindCloudInputs();renderCloudStatus();renderShareList();bindWeatherInputs();renderAuthBox();refreshGoogleStatus()}if(t.dataset.panel==='pending'&&_gcalConnected&&Date.now()-_gcalLastPullAt>GCAL_PULL_INTERVAL_MS)googlePullNow();if(t.dataset.panel==='zones')renderZones();window.scrollTo(0,0)})});
+function switchPanel(name){
+ document.querySelectorAll('.tab').forEach(x=>x.classList.toggle('active',x.dataset.panel===name));
+ document.querySelectorAll('.bn-item').forEach(x=>x.classList.toggle('active',x.dataset.panel===name));
+ document.querySelectorAll('.panel').forEach(x=>x.classList.remove('active'));
+ const p=document.getElementById('panel-'+name);
+ if(p)p.classList.add('active');
+ // FAB visível em panels que têm "criar item"
+ document.getElementById('fab').style.display=['trips','maintenance','pending','zones','overview'].includes(name)?'flex':'none';
+ if(name==='export'){updateStorageInfo();bindCloudInputs();renderCloudStatus();renderShareList();bindWeatherInputs();renderAuthBox();refreshGoogleStatus()}
+ if(name==='pending'&&_gcalConnected&&Date.now()-_gcalLastPullAt>GCAL_PULL_INTERVAL_MS)googlePullNow();
+ if(name==='zones')renderZones();
+ window.scrollTo(0,0);
+}
+// Compat: top tabs (escondidos via CSS mas mantém handlers caso re-exibidos)
+document.querySelectorAll('.tab').forEach(t=>{t.addEventListener('click',()=>switchPanel(t.dataset.panel))});
+
+// Safety bar: atualiza bateria, GPS, anchor a cada 10s
+function updateSafetyBar(){
+ const bat=document.getElementById('battery-indicator');
+ const sbBat=document.getElementById('sb-battery');
+ if(sbBat&&bat){sbBat.textContent=bat.textContent.trim()||'—'}
+ const sbGps=document.getElementById('sb-gps');
+ const sbGpsDot=document.getElementById('sb-gps-dot');
+ if(sbGps&&sbGpsDot){
+ if(tracking?.active||(typeof lastGpsPos!=='undefined'&&lastGpsPos)){
+ sbGps.textContent='GPS ativo';sbGpsDot.className='safety-bar-dot ok';
+ }else{
+ sbGps.textContent='GPS aguardando';sbGpsDot.className='safety-bar-dot';
+ }
+ }
+ const sbAnchorWrap=document.getElementById('sb-anchor-wrap');
+ const sbAnchorDot=document.getElementById('sb-anchor-dot');
+ const sbAnchor=document.getElementById('sb-anchor');
+ if(sbAnchorWrap&&anchorWatch){
+ if(anchorWatch.active){
+ sbAnchorWrap.style.display='inline-flex';
+ const breach=anchorWatch.currentDist>anchorWatch.radius;
+ sbAnchorDot.className='safety-bar-dot '+(breach?'danger':'ok');
+ sbAnchor.textContent=breach?'⚠ DERIVANDO!':`Fundeado · raio ${Math.round(anchorWatch.currentDist||0)}/${anchorWatch.radius}m`;
+ }else{
+ sbAnchorWrap.style.display='none';
+ }
+ }
+ // Bottom nav badge pendências
+ const overdue=(state.pending||[]).filter(p=>!p.done&&p.dueDate&&p.dueDate0?'flex':'none';bnBadge.textContent=overdue}
+}
+setInterval(updateSafetyBar,5000);
+setTimeout(updateSafetyBar,1500);
function quickAdd(){const a=document.querySelector('.tab.active').dataset.panel;if(a==='maintenance')openMaintModal();else if(a==='pending')openPendingModal();else if(a==='zones')openZoneEditor();else openTripModal()}
function openModal(id){document.getElementById(id).classList.add('show')}
function closeModal(id){document.getElementById(id).classList.remove('show')}
diff --git a/server/public/sw.js b/server/public/sw.js
index 33a5734..b05bae6 100644
--- a/server/public/sw.js
+++ b/server/public/sw.js
@@ -1,7 +1,7 @@
// Shivao Service Worker — offline real
// Estratégia: shell precachado, tiles cache-first, windy network-first, /api passa direto.
// Versão usada nos cache names — bumpa essa string pra invalidar caches antigos em deploys.
-const VERSION = 'shivao-v1.6.0';
+const VERSION = 'shivao-v1.7.0';
const SHELL_CACHE = `shivao-shell-${VERSION}`;
const TILES_CACHE = 'shivao-tiles-v1'; // separado pra não invalidar tiles em update do shell
const WINDY_CACHE = `shivao-windy-${VERSION}`;
diff --git a/server/src/index.js b/server/src/index.js
index c7443a2..38a3f0d 100644
--- a/server/src/index.js
+++ b/server/src/index.js
@@ -347,7 +347,7 @@ app.get('/.well-known/assetlinks.json', (req, res) => {
});
// Atalho: /apk redireciona pra última APK release no Forgejo
-const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.6.2/Shivao-v1.6.2.apk';
+const LATEST_APK_URL = 'https://git.pontualtech.work/karlao/shivao-projeto/releases/download/v1.7.0/Shivao-v1.7.0.apk';
app.get('/apk', (req, res) => res.redirect(302, LATEST_APK_URL));
// Página A4 imprimível com QR Code + instruções (cola no barco/marina)