| <!DOCTYPE html> |
| <html lang="ru"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"> |
| <title>VICKERS</title> |
| <link rel="icon" type="image/png" href="image/favicon-96x96.png" sizes="96x96" /> |
| <link rel="icon" type="image/svg+xml" href="image/favicon.svg" /> |
| <link rel="shortcut icon" href="image/favicon.ico" /> |
| <link rel="apple-touch-icon" sizes="180x180" href="image/apple-touch-icon.png" /> |
| <meta name="apple-mobile-web-app-title" content="VICKERS" /> |
| <link rel="manifest" href="/site.webmanifest" /> |
| <link href="https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;1,300&family=Outfit:wght@200;300;400;500;600;700&display=swap" rel="stylesheet"> |
| <style> |
| *,*::before,*::after{box-sizing:border-box;margin:0;padding:0} |
| html,body{height:100%;overflow-x:hidden} |
| body{ |
| min-height:100vh;display:flex;flex-direction:column;align-items:center; |
| justify-content:flex-start;padding:20px 0 70px; |
| font-family:'Outfit',sans-serif; |
| user-select:none;-webkit-user-select:none;-webkit-tap-highlight-color:transparent; |
| background:var(--page-bg,#0e0e10); |
| transition:background 600ms; |
| } |
| |
| |
| |
| |
| :root{--page-bg:#0e0e10} |
| .remote{ |
| --bg:#111316;--surf:#1a1c21;--surf2:#1e2026; |
| --hi:rgba(255,255,255,.045);--lo:rgba(0,0,0,.65); |
| --accent:#00e8ff;--accent2:#007a8a;--glow:rgba(0,232,255,.22); |
| --scr:#070a0d;--tdim:rgba(255,255,255,.18);--tmid:rgba(255,255,255,.45); |
| --tbright:rgba(255,255,255,.85); |
| --eye:#ff2d55;--eye-glow:rgba(255,45,85,.5); |
| --pwr:#ff3b5c;--pwr-glow:rgba(255,59,92,.35); |
| --r:28px;--btn-r:12px; |
| } |
| .remote.chalk{ |
| --surf:#dedad3;--surf2:#e2ddd6; |
| --hi:rgba(255,255,255,.75);--lo:rgba(0,0,0,.11); |
| --accent:#7c5cfc;--accent2:#b8a6f8;--glow:rgba(124,92,252,.18); |
| --scr:#130e24;--tdim:rgba(0,0,0,.17);--tmid:rgba(0,0,0,.4);--tbright:rgba(0,0,0,.72); |
| --eye:#7c5cfc;--eye-glow:rgba(124,92,252,.55); |
| --pwr:#7c5cfc;--pwr-glow:rgba(124,92,252,.3); |
| --r:36px;--btn-r:18px; |
| } |
| .remote.grove{ |
| --surf:#0f1f14;--surf2:#122318; |
| --hi:rgba(255,255,255,.04);--lo:rgba(0,0,0,.72); |
| --accent:#00e87a;--accent2:#007a40;--glow:rgba(0,232,122,.18); |
| --scr:#060d08;--tdim:rgba(255,255,255,.15);--tmid:rgba(255,255,255,.4);--tbright:rgba(255,255,255,.82); |
| --eye:#00e87a;--eye-glow:rgba(0,232,122,.55); |
| --pwr:#00e87a;--pwr-glow:rgba(0,232,122,.28); |
| --r:22px;--btn-r:8px; |
| } |
| .remote.lime{ |
| --surf:#171b0c;--surf2:#1a1f0f; |
| --hi:rgba(255,255,255,.04);--lo:rgba(0,0,0,.72); |
| --accent:#c8ff00;--accent2:#607800;--glow:rgba(200,255,0,.18); |
| --scr:#060800;--tdim:rgba(255,255,255,.16);--tmid:rgba(255,255,255,.44);--tbright:rgba(255,255,255,.84); |
| --eye:#c8ff00;--eye-glow:rgba(200,255,0,.55); |
| --pwr:#c8ff00;--pwr-glow:rgba(200,255,0,.22); |
| --r:6px;--btn-r:3px; |
| } |
| .remote.dusk{ |
| --surf:#1c1224;--surf2:#20162c; |
| --hi:rgba(255,255,255,.05);--lo:rgba(0,0,0,.65); |
| --accent:#ff6b9d;--accent2:#7a2040;--glow:rgba(255,107,157,.2); |
| --scr:#0a0612;--tdim:rgba(255,255,255,.17);--tmid:rgba(255,255,255,.44);--tbright:rgba(255,255,255,.84); |
| --eye:#ff6b9d;--eye-glow:rgba(255,107,157,.55); |
| --pwr:#ff6b9d;--pwr-glow:rgba(255,107,157,.3); |
| --r:32px;--btn-r:18px; |
| } |
| |
| |
| |
| |
| .remote{ |
| width:272px;background:var(--surf);border-radius:var(--r); |
| padding:20px 16px 24px;position:relative; |
| transition:background 500ms,border-radius 500ms,box-shadow 500ms; |
| box-shadow:-6px -6px 16px var(--hi),8px 8px 24px var(--lo),0 0 0 .5px rgba(255,255,255,.04); |
| } |
| .remote::before{ |
| content:'';position:absolute;inset:0;border-radius:var(--r); |
| background:linear-gradient(155deg,var(--hi) 0%,transparent 50%); |
| pointer-events:none;z-index:0; |
| } |
| |
| |
| |
| |
| .topbar{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;position:relative;z-index:1} |
| .eyes{display:flex;gap:8px} |
| .eye{ |
| width:8px;height:8px;border-radius:50%; |
| background:rgba(0,0,0,.65); |
| box-shadow:0 0 0 1.5px rgba(255,255,255,.05),inset 1px 1px 2px rgba(0,0,0,.9); |
| transition:background 60ms,box-shadow 60ms; |
| } |
| .eye.blink{background:var(--eye);box-shadow:0 0 5px 2px var(--eye),0 0 14px 4px var(--eye-glow)} |
| .brand{font-size:9px;letter-spacing:3.5px;font-weight:600;color:var(--tdim);text-transform:uppercase} |
| .power-btn{ |
| width:36px;height:36px;border-radius:50%;border:none;cursor:pointer; |
| background:var(--surf2); |
| display:flex;align-items:center;justify-content:center; |
| box-shadow:-3px -3px 8px var(--hi),4px 4px 10px var(--lo); |
| transition:box-shadow 80ms,transform 80ms; |
| } |
| .power-btn:active,.power-btn.pr{box-shadow:inset 3px 3px 8px var(--lo),inset -2px -2px 5px var(--hi);transform:scale(.93)} |
| .power-btn svg{width:15px;height:15px} |
| .power-btn.off svg path{stroke:var(--tdim)} |
| .power-btn.on svg path{stroke:var(--pwr);filter:drop-shadow(0 0 3px var(--pwr))} |
| |
| |
| |
| |
| .screen-wrap{margin-bottom:14px;position:relative;z-index:1} |
| .screen{ |
| background:var(--scr);border-radius:calc(var(--r)*.55); |
| padding:13px 13px 11px;position:relative;overflow:hidden; |
| box-shadow:inset 0 2px 10px rgba(0,0,0,.95),inset 0 0 28px rgba(0,0,0,.5),0 0 0 .5px rgba(255,255,255,.04); |
| min-height:110px; |
| } |
| .screen::after{ |
| content:'';position:absolute;inset:0; |
| background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,.11) 2px,rgba(0,0,0,.11) 3px); |
| pointer-events:none;z-index:8;border-radius:inherit; |
| } |
| .screen-shine{position:absolute;top:0;left:0;right:0;height:38%;background:linear-gradient(180deg,rgba(255,255,255,.04),transparent);border-radius:inherit;pointer-events:none;z-index:9} |
| .screen-glow{position:absolute;inset:-.5px;border-radius:inherit;opacity:0;transition:opacity 700ms;border:.5px solid var(--accent2);pointer-events:none;z-index:7} |
| .screen-glow.on{opacity:.7} |
| .sc{position:relative;z-index:5;opacity:0;transition:opacity 400ms} |
| .sc.on{opacity:1} |
| @keyframes crt{0%{opacity:0;transform:scaleY(.03)}20%{opacity:.8;transform:scaleY(.03)}32%{opacity:.2;transform:scaleY(1)}48%{opacity:.95;transform:scaleY(1)}58%{opacity:.25;transform:scaleY(1)}100%{opacity:1;transform:scaleY(1)}} |
| .sc.boot{animation:crt 360ms ease-out forwards} |
| .scr-row1{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1px} |
| .mode-txt{font-family:'DM Mono',monospace;font-size:9px;letter-spacing:2px;color:var(--accent2);text-shadow:0 0 6px var(--accent);font-style:italic} |
| .fan-dots{display:flex;gap:2.5px;align-items:flex-end} |
| .fd{width:2.5px;border-radius:2px;background:rgba(255,255,255,.07);transition:background 250ms,box-shadow 250ms} |
| .fd:nth-child(1){height:5px}.fd:nth-child(2){height:8px}.fd:nth-child(3){height:11px}.fd:nth-child(4){height:14px}.fd:nth-child(5){height:17px} |
| .fd.on{background:var(--accent);box-shadow:0 0 4px var(--accent)} |
| .temp-row{display:flex;align-items:flex-start;line-height:1;margin:1px 0 4px} |
| .tv{font-family:'DM Mono',monospace;font-size:58px;font-weight:400;color:var(--accent);letter-spacing:-3px;text-shadow:0 0 8px var(--accent),0 0 24px var(--glow);transition:color 200ms} |
| .tu{font-family:'DM Mono',monospace;font-size:17px;color:var(--accent2);margin-top:8px;margin-left:2px;text-shadow:0 0 5px var(--accent)} |
| @keyframes gp{0%,100%{text-shadow:0 0 8px var(--accent),0 0 24px var(--glow)}50%{text-shadow:0 0 14px var(--accent),0 0 38px var(--glow),0 0 50px var(--glow)}} |
| .tv.pulse{animation:gp 2.4s ease-in-out infinite} |
| .scr-bot{display:flex;justify-content:space-between;align-items:flex-end} |
| .mi-row{display:flex;gap:6px} |
| .mi{width:17px;height:17px;opacity:.13;transition:opacity 200ms,filter 200ms;color:var(--accent)} |
| .mi.on{opacity:1;filter:drop-shadow(0 0 3px var(--accent))} |
| .tmr{font-family:'DM Mono',monospace;font-size:10px;color:rgba(255,255,255,.18);letter-spacing:.5px;transition:color 200ms,text-shadow 200ms;cursor:pointer} |
| .tmr.on{color:#ffaa00;text-shadow:0 0 8px #ffaa00} |
| .tmr.active-countdown{color:#ff6b3d;text-shadow:0 0 8px #ff6b3d} |
| .ss-row{display:flex;gap:5px;margin-top:5px} |
| .ss{width:4px;height:4px;border-radius:50%;background:rgba(255,255,255,.06);transition:background 200ms,box-shadow 200ms} |
| .ss.on{background:var(--accent);box-shadow:0 0 4px var(--accent)} |
| |
| |
| |
| |
| .div{height:.5px;margin:11px 0;background:linear-gradient(90deg,transparent,rgba(255,255,255,.07),transparent);position:relative;z-index:1} |
| |
| |
| |
| |
| .ring-wrap{display:flex;justify-content:center;margin-bottom:13px;position:relative;z-index:1} |
| .ring-out{ |
| width:140px;height:140px;border-radius:50%;background:var(--surf); |
| box-shadow:-4px -4px 12px var(--hi),5px 5px 14px var(--lo),0 0 0 .5px rgba(255,255,255,.03); |
| position:relative;display:flex;align-items:center;justify-content:center; |
| } |
| .ring-in{ |
| width:122px;height:122px;border-radius:50%;background:var(--surf); |
| box-shadow:inset 3px 3px 9px var(--lo),inset -2px -2px 5px var(--hi); |
| position:relative;display:flex;align-items:center;justify-content:center; |
| } |
| .rbtn{ |
| position:absolute;width:36px;height:36px;border:none;cursor:pointer; |
| background:transparent;border-radius:50%; |
| display:flex;align-items:center;justify-content:center; |
| color:var(--tdim);transition:color 80ms; |
| } |
| .rbtn:active,.rbtn.pr{color:var(--accent)} |
| .rbtn svg{width:13px;height:13px;pointer-events:none} |
| .rbtn.up{top:5px;left:50%;transform:translateX(-50%)} |
| .rbtn.dn{bottom:5px;left:50%;transform:translateX(-50%)} |
| .rbtn.lt{left:5px;top:50%;transform:translateY(-50%)} |
| .rbtn.rt{right:5px;top:50%;transform:translateY(-50%)} |
| .rlabel{position:absolute;font-family:'DM Mono',monospace;font-size:7px;letter-spacing:.8px;color:var(--tdim);text-transform:uppercase;pointer-events:none} |
| .rlabel.t{top:-15px;left:50%;transform:translateX(-50%);white-space:nowrap} |
| .rlabel.b{bottom:-15px;left:50%;transform:translateX(-50%);white-space:nowrap} |
| .rlabel.l{left:-22px;top:50%;transform:translateY(-50%) rotate(-90deg);white-space:nowrap} |
| .rlabel.r{right:-22px;top:50%;transform:translateY(-50%) rotate(90deg);white-space:nowrap} |
| .rcenter{ |
| width:42px;height:42px;border-radius:50%;border:none;cursor:pointer; |
| background:var(--surf2); |
| box-shadow:-2px -2px 7px var(--hi),3px 3px 8px var(--lo); |
| display:flex;align-items:center;justify-content:center; |
| transition:box-shadow 80ms,transform 80ms; |
| } |
| .rcenter:active,.rcenter.pr{box-shadow:inset 2px 2px 6px var(--lo),inset -1px -1px 4px var(--hi);transform:scale(.92)} |
| .rcd{width:7px;height:7px;border-radius:50%;background:var(--accent2);box-shadow:0 0 5px var(--accent2);transition:background 300ms,box-shadow 300ms} |
| .rcenter.on .rcd{background:var(--accent);box-shadow:0 0 10px var(--accent),0 0 18px var(--glow)} |
| |
| |
| |
| |
| .btn-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;position:relative;z-index:1} |
| .fbtn{ |
| border:none;background:var(--surf2);border-radius:var(--btn-r); |
| padding:10px 4px 8px;cursor:pointer; |
| display:flex;flex-direction:column;align-items:center;gap:4px; |
| box-shadow:-2px -2px 6px var(--hi),3px 3px 8px var(--lo); |
| transition:box-shadow 80ms,transform 80ms,background 500ms; |
| position:relative;overflow:hidden; |
| } |
| .fbtn::before{content:'';position:absolute;top:0;left:0;right:0;height:.5px;background:linear-gradient(90deg,transparent,var(--hi),transparent)} |
| .fbtn:active,.fbtn.pr{box-shadow:inset 2px 2px 6px var(--lo),inset -1px -1px 4px var(--hi);transform:scale(.95)} |
| .ficon{width:20px;height:20px;color:var(--tdim);transition:color 200ms,filter 200ms} |
| .fbtn.act .ficon{color:var(--accent);filter:drop-shadow(0 0 4px var(--accent))} |
| .fbtn.turbo.act .ficon{color:#ff6b3d;filter:drop-shadow(0 0 4px #ff6b3d)} |
| .fbtn.eco.act .ficon{color:#00e87a;filter:drop-shadow(0 0 4px #00e87a)} |
| .fbtn.timer-btn.act .ficon{color:#ffaa00;filter:drop-shadow(0 0 4px #ffaa00)} |
| .flabel{font-size:8.5px;font-weight:600;letter-spacing:1.2px;color:var(--tdim);text-transform:uppercase;transition:color 200ms,text-shadow 200ms} |
| .fbtn.act .flabel{color:var(--accent);text-shadow:0 0 6px var(--glow)} |
| .fbtn.turbo.act .flabel{color:#ff6b3d;text-shadow:0 0 5px rgba(255,107,61,.4)} |
| .fbtn.eco.act .flabel{color:#00e87a;text-shadow:0 0 5px rgba(0,232,122,.4)} |
| .fbtn.timer-btn.act .flabel{color:#ffaa00;text-shadow:0 0 5px rgba(255,170,0,.4)} |
| .fdesc{font-size:7px;font-weight:300;color:var(--tdim);opacity:.65;text-align:center;line-height:1.2} |
| |
| |
| |
| |
| .book-trigger{ |
| position:absolute;bottom:-14px;right:18px; |
| width:30px;height:30px;border-radius:50%;border:none; |
| background:var(--surf2);cursor:pointer; |
| box-shadow:-2px -2px 6px var(--hi),3px 3px 8px var(--lo),0 0 0 .5px rgba(255,255,255,.05); |
| display:flex;align-items:center;justify-content:center; |
| transition:box-shadow 80ms,transform 80ms,background 400ms; |
| z-index:10;color:var(--tmid); |
| } |
| .book-trigger:active{box-shadow:inset 2px 2px 5px var(--lo);transform:scale(.9)} |
| .book-trigger svg{width:14px;height:14px} |
| |
| |
| |
| |
| .theme-switcher{display:flex;gap:10px;margin-top:28px;align-items:center;position:relative;z-index:1} |
| .tsw{width:22px;height:22px;border-radius:50%;border:2.5px solid transparent;cursor:pointer;transition:transform 200ms,border-color 200ms,box-shadow 200ms;box-shadow:0 2px 8px rgba(0,0,0,.4)} |
| .tsw:hover{transform:scale(1.15)} |
| .tsw.sel{border-color:rgba(255,255,255,.5);transform:scale(1.2)} |
| .tsw[data-t=noir]{background:#1a1c21} |
| .tsw[data-t=chalk]{background:#dedad3} |
| .tsw[data-t=grove]{background:#0f1f14} |
| .tsw[data-t=lime]{background:#171b0c} |
| .tsw[data-t=dusk]{background:#1c1224} |
| .theme-label{font-size:9px;letter-spacing:2px;color:rgba(255,255,255,.28);text-transform:uppercase;font-weight:500} |
| |
| |
| |
| |
| .sheet-overlay{ |
| position:fixed;inset:0;z-index:200; |
| display:flex;align-items:flex-end;justify-content:center; |
| pointer-events:none;opacity:0;transition:opacity 300ms; |
| } |
| .sheet-overlay.open{pointer-events:all;opacity:1} |
| .sheet-bg{position:absolute;inset:0;background:rgba(0,0,0,0);transition:background 350ms} |
| .sheet-overlay.open .sheet-bg{background:rgba(0,0,0,.62)} |
| .sheet{ |
| position:relative;z-index:2;width:300px; |
| background:#f5f0e8;border-radius:20px 20px 0 0; |
| transform:translateY(100%); |
| transition:transform 480ms cubic-bezier(.34,1.3,.64,1); |
| box-shadow:0 -8px 40px rgba(0,0,0,.4);overflow:hidden; |
| } |
| .sheet-overlay.open .sheet{transform:translateY(0)} |
| .sheet-spine{position:absolute;top:0;left:0;right:0;height:4px;background:linear-gradient(90deg,#c8b89a,#ead8c0,#c8b89a)} |
| .sheet-drag{width:36px;height:4px;background:rgba(0,0,0,.12);border-radius:2px;margin:14px auto 0} |
| .sheet-head{display:flex;justify-content:space-between;align-items:center;padding:12px 18px 10px} |
| .sheet-title{font-size:14px;font-weight:600;color:#3a2e1e} |
| .sheet-subtitle{font-size:10px;color:#9a8a74;margin-top:1px;font-weight:300} |
| .sheet-x{width:26px;height:26px;border-radius:50%;border:none;background:rgba(0,0,0,.07);cursor:pointer;display:flex;align-items:center;justify-content:center;color:#6a5a44;transition:background 150ms} |
| .sheet-x:hover{background:rgba(0,0,0,.12)} |
| .sheet-x svg{width:10px;height:10px} |
| .sheet-body{padding:10px 18px 28px;max-height:70vh;overflow-y:auto} |
| .sheet-body::-webkit-scrollbar{width:3px} |
| .sheet-body::-webkit-scrollbar-thumb{background:#c8b89a;border-radius:2px} |
| |
| |
| |
| |
| .timer-presets{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin-bottom:16px} |
| .tpre{ |
| border:.5px solid rgba(0,0,0,.12);border-radius:10px; |
| background:rgba(0,0,0,.04);padding:10px 4px; |
| font-size:13px;font-weight:600;color:#4a3a28; |
| cursor:pointer;transition:background 150ms,border-color 150ms; |
| display:flex;flex-direction:column;align-items:center;gap:2px; |
| } |
| .tpre small{font-size:9px;font-weight:300;color:#9a8a74;letter-spacing:.5px} |
| .tpre:active,.tpre.sel{background:rgba(60,30,10,.1);border-color:rgba(60,30,10,.3)} |
| .tpre.sel{background:rgba(80,50,20,.12);border-color:#8b6a3e} |
| |
| .timer-custom{margin-bottom:16px} |
| .tc-label{font-size:10px;letter-spacing:1px;text-transform:uppercase;color:#9a8a74;margin-bottom:8px;font-weight:500} |
| .tc-row{display:flex;align-items:center;gap:8px} |
| .tc-spin{display:flex;flex-direction:column;align-items:center;gap:4px;flex:1} |
| .tc-spin button{width:32px;height:32px;border-radius:8px;border:.5px solid rgba(0,0,0,.12);background:rgba(0,0,0,.04);cursor:pointer;font-size:16px;color:#4a3a28;display:flex;align-items:center;justify-content:center;transition:background 100ms} |
| .tc-spin button:active{background:rgba(0,0,0,.1)} |
| .tc-val{font-family:'DM Mono',monospace;font-size:28px;font-weight:400;color:#3a2e1e;width:48px;text-align:center} |
| .tc-sep{font-size:24px;color:#9a8a74;margin-top:-4px} |
| .timer-info{font-size:11px;color:#9a8a74;text-align:center;margin-bottom:14px;line-height:1.5} |
| .timer-confirm{ |
| width:100%;padding:13px;border-radius:12px;border:none;cursor:pointer; |
| background:linear-gradient(135deg,#5a3e1e,#8b6a3e); |
| color:#f5ede0;font-family:'Outfit',sans-serif;font-size:14px;font-weight:600; |
| transition:opacity 150ms,transform 80ms; |
| } |
| .timer-confirm:active{transform:scale(.97);opacity:.9} |
| .timer-cancel{ |
| width:100%;padding:10px;border-radius:12px;border:.5px solid rgba(0,0,0,.1);cursor:pointer; |
| background:transparent;color:#9a8a74;font-family:'Outfit',sans-serif; |
| font-size:13px;margin-top:6px;transition:background 150ms; |
| } |
| .timer-cancel:active{background:rgba(0,0,0,.05)} |
| |
| |
| |
| |
| .bi{width:28px;height:28px;flex-shrink:0;border-radius:7px;background:rgba(0,0,0,.06);display:flex;align-items:center;justify-content:center;color:#5a4a34} |
| .bi svg{width:14px;height:14px} |
| .book-item{display:flex;align-items:flex-start;gap:10px;margin-bottom:11px;opacity:0;transform:translateX(-10px);transition:opacity 280ms,transform 280ms} |
| .sheet-overlay.open .book-item{opacity:1;transform:translateX(0)} |
| .book-item:nth-child(1){transition-delay:80ms}.book-item:nth-child(2){transition-delay:130ms} |
| .book-item:nth-child(3){transition-delay:180ms}.book-item:nth-child(4){transition-delay:230ms} |
| .book-item:nth-child(5){transition-delay:280ms}.book-item:nth-child(6){transition-delay:330ms} |
| .book-item:nth-child(7){transition-delay:380ms}.book-item:nth-child(8){transition-delay:430ms} |
| .book-item:nth-child(9){transition-delay:480ms} |
| .bit-name{font-size:11.5px;font-weight:600;color:#3a2e1e;margin-bottom:2px} |
| .bit-desc{font-size:10px;font-weight:300;color:#6a5a44;line-height:1.5} |
| .bsec-title{font-size:8px;font-weight:600;letter-spacing:2px;color:#9a8a74;text-transform:uppercase;margin:14px 0 8px;border-bottom:.5px solid rgba(0,0,0,.07);padding-bottom:4px} |
| .ir-box{background:rgba(60,40,10,.07);border-radius:10px;padding:12px;margin-top:14px;border:.5px solid rgba(0,0,0,.08)} |
| .ir-title{font-size:11px;font-weight:600;color:#4a3a28;margin-bottom:6px} |
| .ir-item{font-size:10px;color:#6a5a44;margin-bottom:4px;padding-left:10px;position:relative;line-height:1.4} |
| .ir-item::before{content:'·';position:absolute;left:0;color:#9a8a74} |
| |
| |
| |
| |
| .onb-overlay{ |
| position:fixed;inset:0;z-index:500; |
| background:#0e0f13; |
| display:flex;flex-direction:column;align-items:center;justify-content:center; |
| padding:24px; |
| transition:opacity 400ms,transform 400ms; |
| } |
| .onb-overlay.hide{opacity:0;transform:scale(1.04);pointer-events:none} |
| .onb-step{display:none;flex-direction:column;align-items:center;width:100%;max-width:300px} |
| .onb-step.active{display:flex} |
| |
| .onb-logo{ |
| width:64px;height:64px;border-radius:20px;margin-bottom:24px; |
| background:linear-gradient(135deg,#1e2026,#252830); |
| box-shadow:-4px -4px 10px rgba(255,255,255,.05),5px 5px 14px rgba(0,0,0,.7); |
| display:flex;align-items:center;justify-content:center; |
| } |
| .onb-logo svg{width:28px;height:28px} |
| .onb-h{font-size:22px;font-weight:700;color:#f0f0f0;text-align:center;margin-bottom:8px;letter-spacing:-.5px} |
| .onb-sub{font-size:13px;font-weight:300;color:rgba(255,255,255,.4);text-align:center;line-height:1.6;margin-bottom:32px} |
| .onb-perm-card{ |
| width:100%;background:#1a1c22;border-radius:16px;padding:16px; |
| border:.5px solid rgba(255,255,255,.07);margin-bottom:12px; |
| display:flex;align-items:center;gap:14px; |
| } |
| .onb-perm-icon{width:40px;height:40px;border-radius:12px;flex-shrink:0;display:flex;align-items:center;justify-content:center} |
| .onb-perm-icon.vib{background:rgba(0,232,255,.1)} |
| .onb-perm-icon.vib svg{color:#00e8ff} |
| .onb-perm-icon.notif{background:rgba(255,107,157,.1)} |
| .onb-perm-icon.notif svg{color:#ff6b9d} |
| .onb-perm-text .name{font-size:13px;font-weight:600;color:#e0e0e0;margin-bottom:2px} |
| .onb-perm-text .desc{font-size:11px;color:rgba(255,255,255,.35);line-height:1.4} |
| .onb-perm-badge{margin-left:auto;padding:5px 10px;border-radius:8px;font-size:10px;font-weight:600;letter-spacing:.5px} |
| .onb-perm-badge.ok{background:rgba(0,232,122,.15);color:#00e87a} |
| .onb-perm-badge.pending{background:rgba(255,255,255,.06);color:rgba(255,255,255,.3)} |
| |
| .onb-brand-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;width:100%;margin-bottom:24px} |
| .onb-brand{ |
| padding:12px 8px;border-radius:12px;border:.5px solid rgba(255,255,255,.08); |
| background:#1a1c22;cursor:pointer;text-align:center; |
| font-size:12px;font-weight:500;color:rgba(255,255,255,.45); |
| transition:background 150ms,border-color 150ms,color 150ms; |
| } |
| .onb-brand:active,.onb-brand.sel{background:rgba(0,232,255,.08);border-color:rgba(0,232,255,.25);color:#00e8ff} |
| |
| .onb-test-card{ |
| width:100%;background:#1a1c22;border-radius:16px; |
| border:.5px solid rgba(255,255,255,.07);overflow:hidden;margin-bottom:16px; |
| } |
| .onb-test-demo{ |
| padding:20px;display:flex;flex-direction:column;align-items:center;gap:8px; |
| background:#111316; |
| } |
| .onb-demo-btn{ |
| width:52px;height:52px;border-radius:50%;border:none;cursor:pointer; |
| display:flex;align-items:center;justify-content:center; |
| background:#1e2026; |
| box-shadow:-3px -3px 8px rgba(255,255,255,.04),4px 4px 10px rgba(0,0,0,.7); |
| transition:box-shadow 80ms,transform 80ms; |
| color:rgba(255,255,255,.3); |
| } |
| .onb-demo-btn:active,.onb-demo-btn.pr{ |
| box-shadow:inset 3px 3px 8px rgba(0,0,0,.7),inset -2px -2px 5px rgba(255,255,255,.04); |
| transform:scale(.92); |
| } |
| .onb-demo-btn svg{width:22px;height:22px;pointer-events:none} |
| .onb-demo-label{font-size:11px;color:rgba(255,255,255,.3);letter-spacing:1px;font-weight:500} |
| .onb-test-q{padding:14px 16px;border-top:.5px solid rgba(255,255,255,.05)} |
| .onb-test-q p{font-size:12px;color:rgba(255,255,255,.55);margin-bottom:10px;line-height:1.5} |
| .onb-yn{display:flex;gap:8px} |
| .onb-y{flex:1;padding:10px;border-radius:10px;border:none;cursor:pointer;background:rgba(0,232,122,.12);border:.5px solid rgba(0,232,122,.2);color:#00e87a;font-size:13px;font-weight:600;font-family:'Outfit',sans-serif;transition:background 150ms} |
| .onb-n{flex:1;padding:10px;border-radius:10px;border:none;cursor:pointer;background:rgba(255,60,60,.08);border:.5px solid rgba(255,60,60,.15);color:#ff4444;font-size:13px;font-weight:600;font-family:'Outfit',sans-serif;transition:background 150ms} |
| .onb-y:active{background:rgba(0,232,122,.22)} |
| .onb-n:active{background:rgba(255,60,60,.15)} |
| |
| .onb-compat{ |
| width:100%;background:#1a1c22;border-radius:16px;padding:20px; |
| border:.5px solid rgba(255,255,255,.07);margin-bottom:24px;text-align:center; |
| } |
| .onb-score{font-size:48px;font-weight:700;color:#00e8ff;text-shadow:0 0 20px rgba(0,232,255,.4);font-family:'DM Mono',monospace} |
| .onb-score-label{font-size:12px;color:rgba(255,255,255,.4);margin-top:4px;margin-bottom:16px} |
| .onb-results{text-align:left} |
| .onb-res-item{display:flex;align-items:center;gap:8px;margin-bottom:8px;font-size:12px;color:rgba(255,255,255,.5)} |
| .onb-res-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0} |
| .onb-res-dot.y{background:#00e87a;box-shadow:0 0 6px #00e87a} |
| .onb-res-dot.n{background:#ff4444;box-shadow:0 0 6px #ff4444} |
| |
| .onb-step-dots{display:flex;gap:6px;margin-bottom:28px} |
| .onb-dot{width:6px;height:6px;border-radius:50%;background:rgba(255,255,255,.15);transition:background 300ms,width 300ms} |
| .onb-dot.a{background:#00e8ff;width:18px;border-radius:3px} |
| |
| .onb-btn{ |
| width:100%;padding:15px;border-radius:14px;border:none;cursor:pointer; |
| background:linear-gradient(135deg,#0a5a6a,#00e8ff); |
| color:#000e14;font-family:'Outfit',sans-serif;font-size:15px;font-weight:700; |
| transition:opacity 150ms,transform 80ms;letter-spacing:.3px; |
| box-shadow:0 4px 20px rgba(0,232,255,.25); |
| } |
| .onb-btn:active{transform:scale(.97);opacity:.9} |
| .onb-skip{font-size:12px;color:rgba(255,255,255,.25);cursor:pointer;margin-top:14px;transition:color 150ms} |
| .onb-skip:hover{color:rgba(255,255,255,.45)} |
| .onb-progress{width:100%;height:2px;background:rgba(255,255,255,.06);border-radius:1px;margin-bottom:28px} |
| .onb-progress-bar{height:100%;border-radius:1px;background:linear-gradient(90deg,#007a8a,#00e8ff);transition:width 400ms ease} |
| |
| |
| .vib-test-btn{ |
| width:100%;padding:12px;border-radius:12px;border:none;cursor:pointer;margin-top:16px; |
| background:rgba(0,232,255,.1);border:.5px solid rgba(0,232,255,.2); |
| color:#00e8ff;font-family:'Outfit',sans-serif;font-size:13px;font-weight:600; |
| transition:background 150ms; |
| } |
| .vib-test-btn:active{background:rgba(0,232,255,.2)} |
| </style> |
| </head> |
| <body> |
|
|
| |
| |
| |
| <div class="onb-overlay" id="onbOverlay"> |
|
|
| |
| <div class="onb-step active" id="onb0"> |
| <div class="onb-logo"> |
| <svg viewBox="0 0 32 32" fill="none" stroke="#00e8ff" stroke-width="1.6" stroke-linecap="round"> |
| <circle cx="16" cy="16" r="6"/> |
| <line x1="16" y1="2" x2="16" y2="7"/><line x1="16" y1="25" x2="16" y2="30"/> |
| <line x1="2" y1="16" x2="7" y2="16"/><line x1="25" y1="16" x2="30" y2="16"/> |
| <line x1="5.5" y1="5.5" x2="9.3" y2="9.3"/><line x1="22.7" y1="22.7" x2="26.5" y2="26.5"/> |
| <line x1="5.5" y1="26.5" x2="9.3" y2="22.7"/><line x1="22.7" y1="9.3" x2="26.5" y2="5.5"/> |
| </svg> |
| </div> |
| <div class="onb-step-dots"> |
| <div class="onb-dot a"></div><div class="onb-dot"></div> |
| <div class="onb-dot"></div><div class="onb-dot"></div> |
| </div> |
| <h1 class="onb-h">Добро пожаловать<br>в ARCTIQ</h1> |
| <p class="onb-sub">Умный пульт управления<br>кондиционером нового поколения.<br>Настроим всё за минуту.</p> |
| <button class="onb-btn" onclick="onbNext()">Начать настройку</button> |
| <div class="onb-skip" onclick="onbSkip()">Пропустить</div> |
| </div> |
|
|
| |
| <div class="onb-step" id="onb1"> |
| <div class="onb-progress"><div class="onb-progress-bar" style="width:25%"></div></div> |
| <div class="onb-step-dots"> |
| <div class="onb-dot"></div><div class="onb-dot a"></div> |
| <div class="onb-dot"></div><div class="onb-dot"></div> |
| </div> |
| <h1 class="onb-h" style="font-size:18px;margin-bottom:6px">Разрешения</h1> |
| <p class="onb-sub" style="margin-bottom:20px">Для максимального погружения<br>нам нужен доступ к:</p> |
| <div class="onb-perm-card"> |
| <div class="onb-perm-icon vib"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" width="20" height="20"> |
| <path d="M5 12a7 7 0 0 0 14 0"/> |
| <line x1="12" y1="3" x2="12" y2="6"/><line x1="12" y1="18" x2="12" y2="21"/> |
| <line x1="3" y1="12" x2="5" y2="12"/><line x1="19" y1="12" x2="21" y2="12"/> |
| </svg> |
| </div> |
| <div class="onb-perm-text"> |
| <div class="name">Вибрация</div> |
| <div class="desc">Тактильная отдача<br>при нажатии кнопок</div> |
| </div> |
| <div class="onb-perm-badge pending" id="vibBadge">ОЖИДАНИЕ</div> |
| </div> |
| <div class="onb-perm-card" style="opacity:.5"> |
| <div class="onb-perm-icon notif"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" width="20" height="20"> |
| <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/> |
| <path d="M13.73 21a2 2 0 0 1-3.46 0"/> |
| </svg> |
| </div> |
| <div class="onb-perm-text"> |
| <div class="name">Уведомления</div> |
| <div class="desc">Таймер и напоминания<br>о работе кондиционера</div> |
| </div> |
| <div class="onb-perm-badge pending" id="notifBadge">ОЖИДАНИЕ</div> |
| </div> |
| <button class="vib-test-btn" id="vibTestBtn" onclick="testVibration()"> |
| 📳 Проверить вибрацию |
| </button> |
| <button class="onb-btn" style="margin-top:16px" onclick="requestPermsAndNext()">Разрешить и продолжить</button> |
| <div class="onb-skip" onclick="onbNext()">Пропустить этот шаг</div> |
| </div> |
|
|
| |
| <div class="onb-step" id="onb2"> |
| <div class="onb-progress"><div class="onb-progress-bar" style="width:50%"></div></div> |
| <div class="onb-step-dots"> |
| <div class="onb-dot"></div><div class="onb-dot"></div> |
| <div class="onb-dot a"></div><div class="onb-dot"></div> |
| </div> |
| <h1 class="onb-h" style="font-size:18px;margin-bottom:6px">Ваш кондиционер</h1> |
| <p class="onb-sub" style="margin-bottom:20px">Выберите производителя для подбора протокола сигнала</p> |
| <div class="onb-brand-grid"> |
| <div class="onb-brand" data-brand="Daikin" onclick="selBrand(this)">🌀 Daikin</div> |
| <div class="onb-brand" data-brand="Samsung" onclick="selBrand(this)">📱 Samsung</div> |
| <div class="onb-brand" data-brand="LG" onclick="selBrand(this)">🌀 LG</div> |
| <div class="onb-brand" data-brand="Mitsubishi" onclick="selBrand(this)">⭐ Mitsubishi</div> |
| <div class="onb-brand" data-brand="Haier" onclick="selBrand(this)">❄️ Haier</div> |
| <div class="onb-brand" data-brand="Другой" onclick="selBrand(this)">🔧 Другой</div> |
| </div> |
| <button class="onb-btn" onclick="onbNext()">Продолжить</button> |
| <div class="onb-skip" onclick="onbNext()">Пропустить</div> |
| </div> |
|
|
| |
| <div class="onb-step" id="onb3"> |
| <div class="onb-progress"><div class="onb-progress-bar" style="width:75%"></div></div> |
| <div class="onb-step-dots"> |
| <div class="onb-dot"></div><div class="onb-dot"></div> |
| <div class="onb-dot"></div><div class="onb-dot a"></div> |
| </div> |
| <h1 class="onb-h" style="font-size:18px;margin-bottom:4px">Проверка сигналов</h1> |
| <p class="onb-sub" style="margin-bottom:16px">Нажимай кнопку и проверяй реакцию кондиционера</p> |
|
|
| <div class="onb-test-card" id="testCard"> |
| <div class="onb-test-demo"> |
| <button class="onb-demo-btn" id="testDemoBtn" onclick="pressTestBtn()"> |
| |
| </button> |
| <div class="onb-demo-label" id="testDemoLabel">ПИТАНИЕ</div> |
| </div> |
| <div class="onb-test-q"> |
| <p id="testQ">Направь телефон на кондиционер и нажми кнопку выше. Кондиционер включился или среагировал?</p> |
| <div class="onb-yn"> |
| <button class="onb-y" onclick="testAnswer(true)">✓ Да, работает</button> |
| <button class="onb-n" onclick="testAnswer(false)">✗ Нет реакции</button> |
| </div> |
| </div> |
| </div> |
| <div style="font-size:10px;color:rgba(255,255,255,.2);text-align:center;margin-top:8px">Тест <span id="testNum">1</span> из 4</div> |
| </div> |
|
|
| |
| <div class="onb-step" id="onb4"> |
| <div class="onb-step-dots"> |
| <div class="onb-dot"></div><div class="onb-dot"></div> |
| <div class="onb-dot"></div><div class="onb-dot"></div> |
| </div> |
| <div class="onb-compat"> |
| <div class="onb-score" id="onbScore">0/4</div> |
| <div class="onb-score-label">Совместимость сигналов</div> |
| <div class="onb-results" id="onbResults"></div> |
| </div> |
| <div id="onbCompatMsg" style="font-size:12px;color:rgba(255,255,255,.4);text-align:center;margin-bottom:24px;line-height:1.6"></div> |
| <button class="onb-btn" onclick="finishOnboarding()">Открыть пульт</button> |
| </div> |
|
|
| </div> |
|
|
|
|
| |
| |
| |
| <div class="sheet-overlay" id="timerSheet"> |
| <div class="sheet-bg" onclick="closeTimer()"></div> |
| <div class="sheet"> |
| <div class="sheet-spine"></div> |
| <div class="sheet-drag"></div> |
| <div class="sheet-head"> |
| <div> |
| <div class="sheet-title">⏱ Таймер</div> |
| <div class="sheet-subtitle">Авто-выключение кондиционера</div> |
| </div> |
| <button class="sheet-x" onclick="closeTimer()"> |
| <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="2" y1="2" x2="10" y2="10"/><line x1="10" y1="2" x2="2" y2="10"/></svg> |
| </button> |
| </div> |
| <div class="sheet-body"> |
| <div class="tc-label">Быстрый выбор</div> |
| <div class="timer-presets" id="timerPresets"> |
| <div class="tpre" data-h="0" data-m="30" onclick="selPreset(this)">30<small>мин</small></div> |
| <div class="tpre" data-h="1" data-m="0" onclick="selPreset(this)">1<small>час</small></div> |
| <div class="tpre" data-h="2" data-m="0" onclick="selPreset(this)">2<small>часа</small></div> |
| <div class="tpre" data-h="4" data-m="0" onclick="selPreset(this)">4<small>часа</small></div> |
| <div class="tpre" data-h="6" data-m="0" onclick="selPreset(this)">6<small>часов</small></div> |
| <div class="tpre" data-h="8" data-m="0" onclick="selPreset(this)">8<small>часов</small></div> |
| </div> |
|
|
| <div class="timer-custom"> |
| <div class="tc-label">Точная настройка</div> |
| <div class="tc-row"> |
| <div class="tc-spin"> |
| <button onclick="adjH(1)">▲</button> |
| <div class="tc-val" id="tcH">01</div> |
| <button onclick="adjH(-1)">▼</button> |
| </div> |
| <div class="tc-sep">:</div> |
| <div class="tc-spin"> |
| <button onclick="adjM(15)">▲</button> |
| <div class="tc-val" id="tcM">00</div> |
| <button onclick="adjM(-15)">▼</button> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="timer-info" id="timerInfoTxt">Кондиционер выключится автоматически через <b id="timerInfoH">1 ч 0 мин</b></div> |
|
|
| <button class="timer-confirm" id="timerConfirmBtn" onclick="confirmTimer()">Установить таймер</button> |
| <button class="timer-cancel" id="timerCancelBtn" onclick="cancelTimer()" style="display:none">Отменить таймер</button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| |
| |
| <div class="sheet-overlay" id="bookSheet"> |
| <div class="sheet-bg" onclick="closeBook()"></div> |
| <div class="sheet"> |
| <div class="sheet-spine"></div> |
| <div class="sheet-drag"></div> |
| <div class="sheet-head"> |
| <div> |
| <div class="sheet-title">📖 Руководство</div> |
| <div class="sheet-subtitle">ARCTIQ Remote Control</div> |
| </div> |
| <button class="sheet-x" onclick="closeBook()"> |
| <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="2" y1="2" x2="10" y2="10"/><line x1="10" y1="2" x2="2" y2="10"/></svg> |
| </button> |
| </div> |
| <div class="sheet-body"> |
|
|
| <div class="bsec-title">Управление кольцом</div> |
|
|
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="5 12 10 7 15 12"/></svg></div> |
| <div><div class="bit-name">▲ Вверх - Температура +1°C</div><div class="bit-desc">Нажатие повышает целевую температуру. Диапазон: 16–30°C.</div></div> |
| </div> |
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="5 8 10 13 15 8"/></svg></div> |
| <div><div class="bit-name">▼ Вниз - Температура −1°C</div><div class="bit-desc">Понижает целевую температуру с шагом 1 градус.</div></div> |
| </div> |
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><circle cx="10" cy="10" r="2"/><path d="M10 8C11 5.5 12.5 3.5 13.5 2.5C13.5 2.5 12 3.5 11.5 7"/><path d="M12 10C14.5 9 17 9.5 18.5 9C18.5 9 16.5 11 13.5 10.5"/><path d="M10 12C9 14.5 7.5 16.5 6.5 17.5C6.5 17.5 8 16.5 8.5 13"/><path d="M8 10C5.5 11 3 10.5 1.5 11C1.5 11 3.5 9 6.5 9.5"/></svg></div> |
| <div><div class="bit-name">● Центр - Смена режима</div><div class="bit-desc">Цикл: Охлаждение → Обогрев → Осушение → Вентиляция.</div></div> |
| </div> |
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="12 5 8 10 12 15"/></svg></div> |
| <div><div class="bit-name">◀ Влево / ▶ Вправо - Вентилятор</div><div class="bit-desc">Скорость потока: уровни 1–5. Нажимай циклически.</div></div> |
| </div> |
|
|
| <div class="bsec-title">Функциональные кнопки</div> |
|
|
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="currentColor" stroke="none"><polygon points="11,2 3,12 10,12 9,18 17,8 10,8"/></svg></div> |
| <div><div class="bit-name">ТУРБО - Максимальная мощность</div><div class="bit-desc">Скорость вентилятора 5. Отключает ЭКО и ТИХИЙ. Быстрый выход на заданную температуру.</div></div> |
| </div> |
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><path d="M14 6.5C7 8 5 13 3.5 17L5 17.5L5.8 15.5C6.5 15.8 7.3 16 8.2 16C15.5 16 18 3 18 3C17.2 4.5 12 7.5 12 7.5"/><path d="M9 9.5C8.5 11.5 8 13.5 8 15"/></svg></div> |
| <div><div class="bit-name">ЭКО - Энергосбережение</div><div class="bit-desc">Ограничивает вентилятор уровнем 2. Снижает потребление до 30%.</div></div> |
| </div> |
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><circle cx="10" cy="11" r="6.5"/><polyline points="10 8 10 11 12 13"/><path d="M8 3.5 L6.5 5"/><path d="M12 3.5 L13.5 5"/></svg></div> |
| <div><div class="bit-name">ТАЙМЕР - Авто-выключение</div><div class="bit-desc">Нажми для открытия настройки. Выбери время: 30 мин - 8 часов. Долгое нажатие отменяет таймер.</div></div> |
| </div> |
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><path d="M3 8L5 8L9 5L9 15L5 12L3 12Z"/><line x1="13" y1="8" x2="17" y2="12"/><line x1="17" y1="8" x2="13" y2="12"/></svg></div> |
| <div><div class="bit-name">ТИХИЙ - Ночной режим</div><div class="bit-desc">Вентилятор уровень 1, шум менее 20 дБ. Идеально для сна.</div></div> |
| </div> |
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M17 10A7 7 0 0 0 4 6.5"/><polyline points="3 3 4 6.5 7 6.5"/><path d="M3 10A7 7 0 0 0 16 13.5"/><polyline points="17 17 16 13.5 13 13.5"/></svg></div> |
| <div><div class="bit-name">SWING - Авто-жалюзи</div><div class="bit-desc">Горизонтальные жалюзи автоматически поворачиваются для равномерного обдува.</div></div> |
| </div> |
| <div class="book-item"> |
| <div class="bi"><svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"><line x1="5" y1="17" x2="5" y2="12"/><line x1="10" y1="17" x2="10" y2="4"/><line x1="15" y1="17" x2="15" y2="9"/><line x1="3.5" y1="12" x2="6.5" y2="12"/><line x1="8.5" y1="4" x2="11.5" y2="4"/><line x1="13.5" y1="9" x2="16.5" y2="9"/></svg></div> |
| <div><div class="bit-name">ПОТОК - Зоны воздуха</div><div class="bit-desc">Переключает направление: напольная зона > средняя > потолочная > авто.</div></div> |
| </div> |
|
|
| <div class="ir-box"> |
| <div class="ir-title">📡 Как работает пульт?</div> |
| <div class="ir-item">Веб-браузер не имеет прямого доступа к ИК-порту телефона</div> |
| <div class="ir-item">Телефоны с ИК: Xiaomi, Redmi, POCO, Samsung (до 2020), Huawei - используй нативное приложение (Mi Remote, SmartThings)</div> |
| <div class="ir-item">Через умный хаб: Broadlink RM Pro, SwitchBot Hub > управление через Wi-Fi/Bluetooth</div> |
| <div class="ir-item">Этот пульт - полноценный UI-слой: добавь WebSocket-соединение к хабу для реальной работы</div> |
| <div class="ir-item">API: navigator.bluetooth > BLE-хаб > ИК-сигнал > кондиционер</div> |
| </div> |
|
|
| </div> |
| </div> |
| </div> |
|
|
|
|
| |
| |
| |
| <div class="remote noir" id="remote"> |
|
|
| |
| <div class="topbar"> |
| <div class="eyes"><div class="eye" id="e1"></div><div class="eye" id="e2"></div></div> |
| <div class="brand">Arctiq</div> |
| <button class="power-btn off" id="pwrBtn"> |
| <svg viewBox="0 0 24 24" fill="none"> |
| <path d="M12 3v8" stroke-width="2.2" stroke-linecap="round"/> |
| <path d="M6 5.5A9 9 0 1 0 18 5.5" stroke-width="2.2" stroke-linecap="round"/> |
| </svg> |
| </button> |
| </div> |
|
|
| |
| <div class="screen-wrap"> |
| <div class="screen"> |
| <div class="screen-shine"></div> |
| <div class="screen-glow" id="scrGlow"></div> |
| <div id="scrOff" style="position:absolute;inset:0;z-index:6;display:flex;align-items:center;justify-content:center;transition:opacity 300ms"> |
| <div style="width:70px;height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,.04),transparent);transform:rotate(-10deg)"></div> |
| </div> |
| <div class="sc" id="sc"> |
| <div class="scr-row1"> |
| <span class="mode-txt" id="modeTxt">COOL ·</span> |
| <div class="fan-dots" id="fanDots"> |
| <div class="fd"></div><div class="fd"></div><div class="fd"></div><div class="fd"></div><div class="fd"></div> |
| </div> |
| </div> |
| <div class="temp-row"> |
| <span class="tv pulse" id="tv">22</span> |
| <span class="tu">°C</span> |
| </div> |
| <div class="scr-bot"> |
| <div class="mi-row"> |
| |
| <svg class="mi on" id="mi0" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"> |
| <line x1="10" y1="2" x2="10" y2="18"/><line x1="2" y1="10" x2="18" y2="10"/> |
| <line x1="4.3" y1="4.3" x2="15.7" y2="15.7"/><line x1="15.7" y1="4.3" x2="4.3" y2="15.7"/> |
| <circle cx="10" cy="10" r="1.8" fill="currentColor" stroke="none"/> |
| <line x1="10" y1="2" x2="8.5" y2="3.8"/><line x1="10" y1="2" x2="11.5" y2="3.8"/> |
| <line x1="10" y1="18" x2="8.5" y2="16.2"/><line x1="10" y1="18" x2="11.5" y2="16.2"/> |
| </svg> |
| |
| <svg class="mi" id="mi1" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"> |
| <circle cx="10" cy="10" r="3.5"/> |
| <line x1="10" y1="1.5" x2="10" y2="4"/><line x1="10" y1="16" x2="10" y2="18.5"/> |
| <line x1="1.5" y1="10" x2="4" y2="10"/><line x1="16" y1="10" x2="18.5" y2="10"/> |
| <line x1="4.2" y1="4.2" x2="6" y2="6"/><line x1="14" y1="14" x2="15.8" y2="15.8"/> |
| <line x1="4.2" y1="15.8" x2="6" y2="14"/><line x1="14" y1="6" x2="15.8" y2="4.2"/> |
| </svg> |
| |
| <svg class="mi" id="mi2" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"> |
| <path d="M10 3 Q13 7.5 13 11.5 A3 3 0 0 1 7 11.5 Q7 7.5 10 3Z"/> |
| <line x1="8.5" y1="13" x2="9.5" y2="14" opacity=".5"/> |
| </svg> |
| |
| <svg class="mi" id="mi3" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round"> |
| <circle cx="10" cy="10" r="1.6"/> |
| <path d="M10 8.4C10 5.8 11.3 3.5 12.5 2.5C12.5 2.5 11 3.8 10.5 7.2"/> |
| <path d="M11.6 10C14.2 10 16.5 11.3 17.5 12.5C17.5 12.5 16.2 11 12.8 10.5"/> |
| <path d="M10 11.6C10 14.2 8.7 16.5 7.5 17.5C7.5 17.5 9 16.2 9.5 12.8"/> |
| <path d="M8.4 10C5.8 10 3.5 8.7 2.5 7.5C2.5 7.5 3.8 9 7.2 9.5"/> |
| </svg> |
| </div> |
| <span class="tmr" id="tmrTxt" onclick="openTimer()" title="Нажми для настройки">--:--</span> |
| </div> |
| <div class="ss-row"> |
| <div class="ss" id="ss0"></div><div class="ss" id="ss1"></div> |
| <div class="ss" id="ss2"></div><div class="ss" id="ss3"></div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="div"></div> |
|
|
| |
| <div class="ring-wrap"> |
| <div class="ring-out"> |
| <span class="rlabel t">ТЕМП ▲</span> |
| <span class="rlabel b">ТЕМП ▼</span> |
| <span class="rlabel l">ПОТ.</span> |
| <span class="rlabel r">ПОТ.</span> |
| <div class="ring-in"> |
| <button class="rbtn up" id="rUp"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 10 8 6 12 10"/></svg></button> |
| <button class="rbtn lt" id="rLt"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="10 4 6 8 10 12"/></svg></button> |
| <button class="rcenter off" id="rCen"><div class="rcd"></div></button> |
| <button class="rbtn rt" id="rRt"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 4 10 8 6 12"/></svg></button> |
| <button class="rbtn dn" id="rDn"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 6 8 10 12 6"/></svg></button> |
| </div> |
| </div> |
| </div> |
|
|
| <div class="div"></div> |
|
|
| |
| <div class="btn-grid"> |
|
|
| <button class="fbtn turbo" id="bTurbo"> |
| <svg class="ficon" viewBox="0 0 24 24" fill="currentColor" stroke="none"><polygon points="13,2 3,14 12,14 11,22 21,10 12,10"/></svg> |
| <span class="flabel">Турбо</span> |
| <span class="fdesc">Макс. мощность</span> |
| </button> |
|
|
| <button class="fbtn eco" id="bEco"> |
| <svg class="ficon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"> |
| <path d="M17 8C8 10 6 16 4 21L6 21.5L7 19C8 19.6 9.2 20 10.5 20C19.5 20 22 3 22 3C21 5 14 9 14 9"/> |
| <path d="M10 11A8 8 0 0 0 8.5 16.5"/> |
| </svg> |
| <span class="flabel">ЭКО</span> |
| <span class="fdesc">Энергосбережение</span> |
| </button> |
|
|
| <button class="fbtn timer-btn" id="bTimer"> |
| <svg class="ficon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"> |
| <circle cx="12" cy="13" r="7.5"/> |
| <polyline points="12 9.5 12 13 14.5 15.5"/> |
| <path d="M9.5 3.5L7.5 5.5"/><path d="M14.5 3.5L16.5 5.5"/> |
| <line x1="12" y1="2" x2="12" y2="4"/> |
| </svg> |
| <span class="flabel">Таймер</span> |
| <span class="fdesc" id="timerBtnDesc">Авто-выключение</span> |
| </button> |
|
|
| <button class="fbtn quiet" id="bQuiet"> |
| <svg class="ficon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"> |
| <path d="M3 9L6 9L11 5L11 19L6 15L3 15Z" fill="currentColor" stroke="none" opacity=".35"/> |
| <path d="M3 9L6 9L11 5L11 19L6 15L3 15"/> |
| <line x1="16" y1="9.5" x2="21" y2="14.5"/><line x1="21" y1="9.5" x2="16" y2="14.5"/> |
| </svg> |
| <span class="flabel">Тихий</span> |
| <span class="fdesc">Ночной режим</span> |
| </button> |
|
|
| <button class="fbtn swing" id="bSwing"> |
| <svg class="ficon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"> |
| <path d="M21 12A9 9 0 0 0 4 7"/><polyline points="3.5 3.5 4 7 7.5 7"/> |
| <path d="M3 12A9 9 0 0 0 20 17"/><polyline points="20.5 20.5 20 17 16.5 17"/> |
| </svg> |
| <span class="flabel">Swing</span> |
| <span class="fdesc">Авто-жалюзи</span> |
| </button> |
|
|
| <button class="fbtn flow" id="bFlow"> |
| <svg class="ficon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"> |
| <line x1="6" y1="20" x2="6" y2="14"/><line x1="12" y1="20" x2="12" y2="4"/> |
| <line x1="18" y1="20" x2="18" y2="10"/> |
| <line x1="4.5" y1="14" x2="7.5" y2="14"/> |
| <line x1="10.5" y1="4" x2="13.5" y2="4"/> |
| <line x1="16.5" y1="10" x2="19.5" y2="10"/> |
| </svg> |
| <span class="flabel">Поток</span> |
| <span class="fdesc">Зоны воздуха</span> |
| </button> |
|
|
| </div> |
|
|
| |
| <button class="book-trigger" onclick="openBook()"> |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"> |
| <path d="M2 3H8A4 4 0 0 1 12 7V21A3 3 0 0 0 9 18H2Z"/> |
| <path d="M22 3H16A4 4 0 0 0 12 7V21A3 3 0 0 1 15 18H22Z"/> |
| </svg> |
| </button> |
|
|
| </div> |
|
|
| |
| <div class="theme-switcher"> |
| <span class="theme-label">Стиль</span> |
| <div class="tsw sel" data-t="noir" title="Noir" onclick="setTheme(this)"></div> |
| <div class="tsw" data-t="chalk" title="Chalk" onclick="setTheme(this)"></div> |
| <div class="tsw" data-t="grove" title="Grove" onclick="setTheme(this)"></div> |
| <div class="tsw" data-t="lime" title="Lime" onclick="setTheme(this)"></div> |
| <div class="tsw" data-t="dusk" title="Dusk" onclick="setTheme(this)"></div> |
| </div> |
|
|
|
|
| <script> |
| |
| |
| |
| const SK = 'arctiq_v3'; |
| function load(){ try{ return JSON.parse(localStorage.getItem(SK)||'{}') }catch(e){ return {} } } |
| function save(){ |
| try{ |
| localStorage.setItem(SK, JSON.stringify({ |
| onboarded, theme: curTheme, temp, fan, mode, on: pwrOn, |
| timerH: tmH, timerM: tmM, timerActive, timerEnd, |
| st, acBrand, vibOk, testResults |
| })); |
| }catch(e){} |
| } |
| |
| |
| |
| |
| const saved = load(); |
| let onboarded = saved.onboarded || false; |
| let curTheme = saved.theme || 'noir'; |
| let temp = saved.temp || 22; |
| let fan = saved.fan || 2; |
| let mode = saved.mode || 0; |
| let pwrOn = false; |
| let tmH = saved.timerH || 1; |
| let tmM = saved.timerM || 0; |
| let timerActive = false; |
| let timerEnd = null; |
| let timerInterval = null; |
| let st = saved.st || {turbo:0,eco:0,quiet:0,swing:0,flow:0}; |
| let acBrand = saved.acBrand || ''; |
| let vibOk = saved.vibOk || false; |
| let testResults = []; |
| let onbStep = 0; |
| let curTest = 0; |
| const pageBg = {noir:'#0e0e10',chalk:'#e8e4dc',grove:'#090f0c',lime:'#0d1006',dusk:'#0f0914'}; |
| const modes = ['COOL ·','HEAT ·','DRY ·','FAN ·']; |
| |
| |
| const tests = [ |
| { |
| label:'ПИТАНИЕ', |
| q:'Направь телефон на кондиционер и нажми кнопку выше. Кондиционер включился или среагировал?', |
| icon:`<svg viewBox="0 0 24 24" fill="none" width="22" height="22"><path d="M12 3v8" stroke="#00e8ff" stroke-width="2.2" stroke-linecap="round"/><path d="M6 5.5A9 9 0 1 0 18 5.5" stroke="#00e8ff" stroke-width="2.2" stroke-linecap="round"/></svg>` |
| }, |
| { |
| label:'ОХЛАЖДЕНИЕ', |
| q:'Активирован режим охлаждения (снежинка). Кондиционер переключился в режим COOL?', |
| icon:`<svg viewBox="0 0 24 24" fill="none" width="22" height="22" stroke="#00e8ff" stroke-width="1.6" stroke-linecap="round"><line x1="12" y1="3" x2="12" y2="21"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="5.5" y1="5.5" x2="18.5" y2="18.5"/><line x1="18.5" y1="5.5" x2="5.5" y2="18.5"/><circle cx="12" cy="12" r="2.5" fill="#00e8ff"/></svg>` |
| }, |
| { |
| label:'ВЕНТИЛЯТОР', |
| q:'Скорость вентилятора изменяется? Нажми кнопку несколько раз — слышны ли изменения шума?', |
| icon:`<svg viewBox="0 0 24 24" fill="none" width="22" height="22" stroke="#00e8ff" stroke-width="1.5" stroke-linecap="round"><circle cx="12" cy="12" r="2"/><path d="M12 10C12 7 14 4.5 15.5 3.5C15.5 3.5 13.5 5 13 9"/><path d="M14 12C17 11 20 11.5 21.5 10.5C21.5 10.5 19.5 13 16 12.5"/><path d="M12 14C12 17 10 19.5 8.5 20.5C8.5 20.5 10.5 19 11 15"/><path d="M10 12C7 13 4 12.5 2.5 13.5C2.5 13.5 4.5 11 8 11.5"/></svg>` |
| }, |
| { |
| label:'ТУРБО', |
| q:'Нажата кнопка ТУРБО (максимальная мощность). Ощущается ли усиление воздушного потока?', |
| icon:`<svg viewBox="0 0 24 24" fill="#00e8ff" width="22" height="22"><polygon points="13,2 3,14 12,14 11,22 21,10 12,10"/></svg>` |
| } |
| ]; |
| |
| |
| |
| |
| const remote = document.getElementById('remote'); |
| const pwrBtn = document.getElementById('pwrBtn'); |
| const sc = document.getElementById('sc'); |
| const scrOff = document.getElementById('scrOff'); |
| const scrGlow = document.getElementById('scrGlow'); |
| const tvEl = document.getElementById('tv'); |
| const modeTxtEl = document.getElementById('modeTxt'); |
| const tmrTxtEl = document.getElementById('tmrTxt'); |
| const fanDots = document.querySelectorAll('.fd'); |
| const modeIcons = [document.getElementById('mi0'),document.getElementById('mi1'),document.getElementById('mi2'),document.getElementById('mi3')]; |
| const ssEls = [document.getElementById('ss0'),document.getElementById('ss1'),document.getElementById('ss2'),document.getElementById('ss3')]; |
| const rCen = document.getElementById('rCen'); |
| const timerBtnDesc = document.getElementById('timerBtnDesc'); |
| |
| |
| |
| |
| let ac2 = null; |
| function beep(type){ |
| try{ |
| if(!ac2) ac2 = new(window.AudioContext||window.webkitAudioContext)(); |
| const o=ac2.createOscillator(),g=ac2.createGain(); |
| o.connect(g);g.connect(ac2.destination); |
| if(type==='pwr'){ |
| o.frequency.setValueAtTime(200,ac2.currentTime); |
| o.frequency.exponentialRampToValueAtTime(90,ac2.currentTime+.18); |
| g.gain.setValueAtTime(.07,ac2.currentTime); |
| g.gain.exponentialRampToValueAtTime(.001,ac2.currentTime+.18); |
| o.start();o.stop(ac2.currentTime+.18); |
| }else{ |
| o.frequency.setValueAtTime(1200,ac2.currentTime); |
| o.frequency.exponentialRampToValueAtTime(850,ac2.currentTime+.035); |
| g.gain.setValueAtTime(.03,ac2.currentTime); |
| g.gain.exponentialRampToValueAtTime(.001,ac2.currentTime+.035); |
| o.start();o.stop(ac2.currentTime+.035); |
| } |
| }catch(e){} |
| } |
| |
| function hap(p=[15]){ if(navigator.vibrate) navigator.vibrate(p) } |
| |
| |
| |
| |
| function blink(ms=110){ |
| const e1=document.getElementById('e1'),e2=document.getElementById('e2'); |
| e1.classList.add('blink');e2.classList.add('blink'); |
| setTimeout(()=>{e1.classList.remove('blink');e2.classList.remove('blink')},ms); |
| } |
| |
| |
| |
| |
| function press(el,cb){ |
| el.classList.add('pr'); |
| setTimeout(()=>el.classList.remove('pr'),160); |
| if(cb)cb(); |
| } |
| |
| |
| |
| |
| function updFan(){ fanDots.forEach((d,i)=>d.classList.toggle('on',i<fan)) } |
| function updModes(){ |
| modeTxtEl.textContent=modes[mode]; |
| modeIcons.forEach((m,i)=>m.classList.toggle('on',i===mode)); |
| } |
| function updSS(){ |
| ssEls[0].classList.toggle('on',!!st.swing); |
| ssEls[1].classList.toggle('on',!!st.quiet); |
| ssEls[2].classList.toggle('on',!!st.eco); |
| ssEls[3].classList.toggle('on',!!st.turbo); |
| } |
| function updTimer(){ |
| if(timerActive && timerEnd){ |
| const rem = Math.max(0, timerEnd - Date.now()); |
| const totalMin = Math.ceil(rem/60000); |
| const h = Math.floor(totalMin/60), m = totalMin%60; |
| const txt = h>0 ? `${h}:${String(m).padStart(2,'0')}` : `0:${String(m).padStart(2,'0')}`; |
| tmrTxtEl.textContent = txt; |
| tmrTxtEl.classList.add('on'); |
| timerBtnDesc.textContent = txt + ' осталось'; |
| document.getElementById('bTimer').classList.add('act','timer-btn'); |
| if(rem <= 0) cancelTimer(); |
| } else { |
| tmrTxtEl.textContent = '--:--'; |
| tmrTxtEl.classList.remove('on','active-countdown'); |
| timerBtnDesc.textContent = 'Авто-выключение'; |
| document.getElementById('bTimer').classList.remove('act'); |
| } |
| } |
| |
| |
| |
| |
| function togglePower(){ |
| hap([25,10,25]);beep('pwr');blink(200); |
| pwrOn=!pwrOn; |
| pwrBtn.classList.toggle('on',pwrOn); |
| pwrBtn.classList.toggle('off',!pwrOn); |
| scrGlow.classList.toggle('on',pwrOn); |
| rCen.classList.toggle('on',pwrOn); |
| if(pwrOn){ |
| scrOff.style.opacity='0'; |
| setTimeout(()=>scrOff.style.pointerEvents='none',300); |
| sc.classList.remove('boot');void sc.offsetWidth; |
| sc.classList.add('on','boot'); |
| updFan();updModes();updSS();updTimer(); |
| } else { |
| sc.classList.remove('on','boot'); |
| setTimeout(()=>{scrOff.style.opacity='1';scrOff.style.pointerEvents=''},300); |
| } |
| save(); |
| } |
| |
| |
| |
| |
| function changeTemp(d){ |
| if(!pwrOn)return; |
| const t=temp+d;if(t<16||t>30)return; |
| temp=t;tvEl.textContent=temp;hap([15]);beep();blink(); |
| save(); |
| } |
| function fanUp(){if(!pwrOn)return;fan=fan>=5?1:fan+1;updFan();hap([15]);beep();blink();save()} |
| function fanDn(){if(!pwrOn)return;fan=fan<=1?5:fan-1;updFan();hap([15]);beep();blink();save()} |
| function nextMode(){if(!pwrOn)return;mode=(mode+1)%4;updModes();hap([15]);beep();blink();save()} |
| |
| function toggle(key,el){ |
| if(!pwrOn){hap([5]);return} |
| st[key]=st[key]?0:1; |
| el.classList.toggle('act',!!st[key]); |
| hap([15]);beep();blink(); |
| if(key==='turbo'&&st.turbo){ st.eco=0;st.quiet=0;document.getElementById('bEco').classList.remove('act');document.getElementById('bQuiet').classList.remove('act');fan=5;updFan() } |
| if(key==='eco'&&st.eco){ st.turbo=0;document.getElementById('bTurbo').classList.remove('act');if(fan>2){fan=2;updFan()} } |
| if(key==='quiet'&&st.quiet){ st.turbo=0;document.getElementById('bTurbo').classList.remove('act');fan=1;updFan() } |
| updSS();save(); |
| } |
| |
| |
| |
| |
| let pickerH=1, pickerM=0; |
| |
| function openTimer(){ |
| if(!pwrOn){hap([5]);return} |
| hap([10]); |
| pickerH = timerActive ? tmH : 1; |
| pickerM = timerActive ? tmM : 0; |
| updatePickerUI(); |
| document.getElementById('timerSheet').classList.add('open'); |
| document.getElementById('timerCancelBtn').style.display = timerActive ? 'block' : 'none'; |
| |
| document.querySelectorAll('.tpre').forEach(p=>p.classList.remove('sel')); |
| } |
| function closeTimer(){ document.getElementById('timerSheet').classList.remove('open') } |
| |
| function updatePickerUI(){ |
| document.getElementById('tcH').textContent = String(pickerH).padStart(2,'0'); |
| document.getElementById('tcM').textContent = String(pickerM).padStart(2,'0'); |
| const total = pickerH*60+pickerM; |
| const h=Math.floor(total/60),m=total%60; |
| let txt=''; |
| if(h>0)txt+=h+' ч '; |
| if(m>0)txt+=m+' мин'; |
| if(!txt)txt='0 мин'; |
| document.getElementById('timerInfoH').textContent=txt; |
| } |
| function adjH(d){ pickerH=Math.max(0,Math.min(12,pickerH+d));updatePickerUI();document.querySelectorAll('.tpre').forEach(p=>p.classList.remove('sel')) } |
| function adjM(d){ pickerM=((pickerM+d)+60)%60;if(d>0&&pickerM===0&&pickerH<12)pickerH++;updatePickerUI();document.querySelectorAll('.tpre').forEach(p=>p.classList.remove('sel')) } |
| function selPreset(el){ |
| document.querySelectorAll('.tpre').forEach(p=>p.classList.remove('sel')); |
| el.classList.add('sel'); |
| pickerH=parseInt(el.dataset.h); |
| pickerM=parseInt(el.dataset.m); |
| updatePickerUI(); |
| hap([10]); |
| } |
| function confirmTimer(){ |
| const total=pickerH*60+pickerM; |
| if(total===0){cancelTimer();return} |
| tmH=pickerH;tmM=pickerM; |
| timerActive=true; |
| timerEnd=Date.now()+total*60*1000; |
| if(timerInterval)clearInterval(timerInterval); |
| timerInterval=setInterval(updTimer,10000); |
| updTimer(); |
| hap([15,10,15]); |
| closeTimer(); |
| save(); |
| } |
| function cancelTimer(){ |
| timerActive=false;timerEnd=null; |
| if(timerInterval){clearInterval(timerInterval);timerInterval=null} |
| updTimer(); |
| closeTimer(); |
| save(); |
| } |
| |
| |
| |
| |
| function openBook(){ hap([10]);document.getElementById('bookSheet').classList.add('open') } |
| function closeBook(){ document.getElementById('bookSheet').classList.remove('open') } |
| |
| |
| |
| |
| function setTheme(el){ |
| const t=el.dataset.t; |
| if(t===curTheme)return; |
| curTheme=t; |
| remote.className='remote '+t; |
| document.body.style.background=pageBg[t]||'#111'; |
| document.querySelectorAll('.tsw').forEach(x=>x.classList.remove('sel')); |
| el.classList.add('sel'); |
| hap([10]); |
| save(); |
| } |
| |
| |
| |
| |
| function showOnbStep(n){ |
| document.querySelectorAll('.onb-step').forEach(s=>s.classList.remove('active')); |
| const el=document.getElementById('onb'+n); |
| if(el) el.classList.add('active'); |
| onbStep=n; |
| } |
| function onbNext(){ showOnbStep(onbStep+1) } |
| function onbSkip(){ finishOnboarding() } |
| |
| function selBrand(el){ |
| document.querySelectorAll('.onb-brand').forEach(b=>b.classList.remove('sel')); |
| el.classList.add('sel'); |
| acBrand=el.dataset.brand; |
| hap([10]); |
| } |
| function testVibration(){ |
| if(navigator.vibrate){ navigator.vibrate([30,20,30,20,60]);vibOk=true;document.getElementById('vibBadge').textContent='ОК';document.getElementById('vibBadge').className='onb-perm-badge ok' } |
| else { document.getElementById('vibBadge').textContent='НЕТ';document.getElementById('vibBadge').className='onb-perm-badge pending' } |
| hap([30,20,30]); |
| document.getElementById('vibTestBtn').textContent='✓ Вибрация работает!'; |
| document.getElementById('vibTestBtn').style.opacity='.7'; |
| } |
| async function requestPermsAndNext(){ |
| if(navigator.vibrate){ navigator.vibrate([15]);vibOk=true;document.getElementById('vibBadge').textContent='ОК';document.getElementById('vibBadge').className='onb-perm-badge ok' } |
| if('Notification' in window && Notification.permission==='default'){ |
| try{ const p=await Notification.requestPermission();if(p==='granted'){ document.getElementById('notifBadge').textContent='ОК';document.getElementById('notifBadge').className='onb-perm-badge ok' } }catch(e){} |
| } |
| onbNext(); |
| } |
| |
| |
| curTest=0;testResults=[]; |
| function loadTest(i){ |
| const t=tests[i]; |
| document.getElementById('testDemoBtn').innerHTML=t.icon; |
| document.getElementById('testDemoLabel').textContent=t.label; |
| document.getElementById('testQ').textContent=t.q; |
| document.getElementById('testNum').textContent=i+1; |
| } |
| function pressTestBtn(){ |
| const el=document.getElementById('testDemoBtn'); |
| press(el,()=>{hap([20]);beep()}); |
| } |
| function testAnswer(yes){ |
| testResults.push({label:tests[curTest].label,ok:yes}); |
| hap(yes?[15,10,30]:[15]); |
| curTest++; |
| if(curTest<tests.length){ loadTest(curTest) } |
| else { showResults();showOnbStep(4) } |
| } |
| function showResults(){ |
| const score=testResults.filter(r=>r.ok).length; |
| document.getElementById('onbScore').textContent=score+'/4'; |
| const msgs=['Вероятно, телефон не поддерживает ИК или протокол не совпадает.','Частичная совместимость. Некоторые команды работают.','Хорошая совместимость! Большинство функций работает.','Отличная совместимость! Все сигналы распознаются.']; |
| document.getElementById('onbCompatMsg').textContent=msgs[score]; |
| const cont=document.getElementById('onbResults'); |
| cont.innerHTML=''; |
| testResults.forEach(r=>{ |
| const d=document.createElement('div'); |
| d.className='onb-res-item'; |
| d.innerHTML=`<div class="onb-res-dot ${r.ok?'y':'n'}"></div>${r.label}: ${r.ok?'Работает':'Нет реакции'}`; |
| cont.appendChild(d); |
| }); |
| } |
| function finishOnboarding(){ |
| onboarded=true;save(); |
| const ov=document.getElementById('onbOverlay'); |
| ov.classList.add('hide'); |
| setTimeout(()=>ov.style.display='none',400); |
| } |
| |
| |
| |
| |
| |
| document.querySelectorAll('.tsw').forEach(t=>t.classList.remove('sel')); |
| remote.className='remote '+curTheme; |
| document.body.style.background=pageBg[curTheme]||'#111'; |
| const savedTsw=document.querySelector(`.tsw[data-t="${curTheme}"]`); |
| if(savedTsw)savedTsw.classList.add('sel'); |
| |
| |
| if(onboarded){ |
| document.getElementById('onbOverlay').style.display='none'; |
| } else { |
| loadTest(0); |
| } |
| |
| |
| pwrBtn.addEventListener('click',()=>press(pwrBtn,togglePower)); |
| document.getElementById('rUp').addEventListener('click',e=>press(e.currentTarget,()=>changeTemp(1))); |
| document.getElementById('rDn').addEventListener('click',e=>press(e.currentTarget,()=>changeTemp(-1))); |
| document.getElementById('rLt').addEventListener('click',e=>press(e.currentTarget,fanDn)); |
| document.getElementById('rRt').addEventListener('click',e=>press(e.currentTarget,fanUp)); |
| document.getElementById('rCen').addEventListener('click',e=>press(e.currentTarget,nextMode)); |
| |
| [['bTurbo','turbo'],['bEco','eco'],['bSwing','swing'],['bFlow','flow'],['bQuiet','quiet']].forEach(([id,k])=>{ |
| const el=document.getElementById(id); |
| el.addEventListener('click',()=>press(el,()=>toggle(k,el))); |
| }); |
| |
| |
| const timerBtnEl = document.getElementById('bTimer'); |
| let timerLongPress; |
| timerBtnEl.addEventListener('pointerdown',()=>{ timerLongPress=setTimeout(()=>{ if(timerActive){cancelTimer();hap([30,15,30])} },600) }); |
| timerBtnEl.addEventListener('pointerup',()=>clearTimeout(timerLongPress)); |
| timerBtnEl.addEventListener('pointerleave',()=>clearTimeout(timerLongPress)); |
| timerBtnEl.addEventListener('click',()=>press(timerBtnEl,openTimer)); |
| |
| |
| document.addEventListener('keydown',e=>{ |
| if(e.key==='p'||e.key==='P')togglePower(); |
| if(e.key==='ArrowUp')changeTemp(1); |
| if(e.key==='ArrowDown')changeTemp(-1); |
| if(e.key==='ArrowRight')fanUp(); |
| if(e.key==='ArrowLeft')fanDn(); |
| if(e.key==='m'||e.key==='M')nextMode(); |
| }); |
| |
| document.addEventListener('contextmenu',e=>e.preventDefault()); |
| |
| </script> |
| </body> |
| </html> |