Three single-file HTML apps ported to Makepad 2.0 (dev b41e740) script_mod! DSL: - rider (ride.html): 21 unit + 9 integration + 9 headless UI tests - koboyo (koboyo.html): 29 + 14 + 8 - insurance (insurance.html): 28 + 14 + 8 All 140 tests green. Includes headless-Linux platform patch, full README, setup script, and three brutal codebase assessments with execution plans.
997 lines
56 KiB
HTML
997 lines
56 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
|
||
<title>InsurePay — Insurance App</title>
|
||
<style>
|
||
/* ================= RESET / TOKENS ================= */
|
||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||
html,body{height:100%}
|
||
:root{
|
||
--bg:#f3f3f6;
|
||
--ink:#191a24;
|
||
--muted:#8b8c99;
|
||
--line:#ececf1;
|
||
--purple:#7b5cf6;
|
||
--purple-deep:#6a48f0;
|
||
--purple-ink:#241a56;
|
||
--navy:#181b2e;
|
||
--green:#12b76a;
|
||
--orange:#f97316;
|
||
--pink:#f43f6e;
|
||
--blue:#0ea5e9;
|
||
--card-sh:0 10px 26px rgba(20,22,44,.06),0 1px 3px rgba(20,22,44,.04);
|
||
}
|
||
body{
|
||
margin:0;
|
||
font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display",Inter,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||
background:#d7d7dd;
|
||
color:var(--ink);
|
||
-webkit-font-smoothing:antialiased;
|
||
}
|
||
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;-webkit-tap-highlight-color:transparent}
|
||
img,svg{display:block}
|
||
.hide{display:none !important}
|
||
|
||
/* ================= PHONE SHELL ================= */
|
||
.stage{min-height:100dvh;display:flex;align-items:center;justify-content:center}
|
||
.phone{
|
||
width:390px;max-width:100vw;height:100dvh;position:relative;overflow:hidden;
|
||
background:var(--bg);display:flex;flex-direction:column;
|
||
}
|
||
@media(min-width:440px){
|
||
.stage{padding:26px;background:linear-gradient(180deg,#e2e2e8,#c4c4cc)}
|
||
.phone{
|
||
height:824px;border-radius:46px;
|
||
box-shadow:0 34px 90px rgba(10,10,25,.32),inset 0 0 0 10px #101116,inset 0 0 0 11px #2c2d34;
|
||
}
|
||
}
|
||
.island{position:absolute;top:12px;left:50%;transform:translateX(-50%);width:104px;height:30px;background:#0c0d12;border-radius:18px;z-index:80}
|
||
|
||
/* status bar */
|
||
.statusbar{
|
||
flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;
|
||
padding:14px 26px 4px;font-size:14.5px;font-weight:650;letter-spacing:-.2px;
|
||
}
|
||
.sb-icons{display:flex;align-items:center;gap:6px}
|
||
|
||
/* ================= SCREENS ================= */
|
||
.screens{flex:1;position:relative;overflow:hidden}
|
||
.screen{
|
||
position:absolute;inset:0;overflow-y:auto;scrollbar-width:none;display:none;
|
||
padding:6px 20px 132px;
|
||
animation:fadeUp .32s cubic-bezier(.22,1,.36,1);
|
||
}
|
||
.screen::-webkit-scrollbar{display:none}
|
||
.screen.on{display:block}
|
||
@keyframes fadeUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
|
||
|
||
/* top bar (sub pages) */
|
||
.topbar{display:flex;align-items:center;gap:12px;margin:8px 0 4px;position:relative}
|
||
.back-btn{
|
||
width:38px;height:38px;border-radius:50%;background:#fff;display:grid;place-items:center;
|
||
box-shadow:var(--card-sh);color:var(--ink);
|
||
}
|
||
.top-title{position:absolute;left:50%;transform:translateX(-50%);font-size:16px;font-weight:650;letter-spacing:-.2px;white-space:nowrap}
|
||
.bell-btn{margin-left:auto;width:38px;height:38px;border-radius:50%;background:#fff;display:grid;place-items:center;box-shadow:var(--card-sh);position:relative}
|
||
.bell-dot{position:absolute;top:9px;right:10px;width:7px;height:7px;border-radius:50%;background:#ff5d5d;border:1.5px solid #fff}
|
||
|
||
/* ================= HOME ================= */
|
||
.hi-row{display:flex;align-items:center;gap:13px;margin:6px 0 16px}
|
||
.ava-wrap{position:relative;width:54px;height:54px;flex:0 0 54px}
|
||
.ava-wrap svg{position:absolute;inset:0}
|
||
.ava{
|
||
position:absolute;inset:5px;border-radius:50%;
|
||
background:radial-gradient(circle at 32% 26%,#ffd9c3,#f7a982 62%,#e8875c);
|
||
display:grid;place-items:center;font-size:21px;
|
||
}
|
||
.ava-badge{
|
||
position:absolute;bottom:-3px;left:-3px;background:var(--purple);color:#fff;
|
||
font-size:8.5px;font-weight:800;padding:2.5px 5px;border-radius:999px;border:2px solid #fff;
|
||
}
|
||
.hi-name{font-size:19px;font-weight:750;letter-spacing:-.3px}
|
||
.hi-sub{font-size:12.5px;color:var(--muted);margin-top:2px}
|
||
.searchbar{
|
||
display:flex;align-items:center;gap:10px;background:#fff;border-radius:16px;
|
||
padding:14px 16px;box-shadow:var(--card-sh);color:var(--muted);font-size:14px;margin-bottom:16px;
|
||
}
|
||
.searchbar input{border:0;outline:0;font:inherit;flex:1;color:var(--ink);background:none}
|
||
.searchbar input::placeholder{color:#a6a7b3}
|
||
.filter-btn{width:30px;height:30px;display:grid;place-items:center;color:var(--ink)}
|
||
|
||
.hero-card{
|
||
border-radius:26px;padding:20px 20px 18px;color:#fff;position:relative;overflow:hidden;
|
||
background:
|
||
radial-gradient(140px 140px at 88% -10%,rgba(255,255,255,.28),transparent 60%),
|
||
radial-gradient(190px 190px at 110% 60%,rgba(255,255,255,.12),transparent 62%),
|
||
linear-gradient(150deg,#8a74ff 0%,#6f4ff2 52%,#5a3ee6 100%);
|
||
box-shadow:0 18px 40px rgba(110,80,240,.38);
|
||
}
|
||
.hero-top{display:flex;align-items:flex-start;gap:12px}
|
||
.hero-ic{width:42px;height:42px;border-radius:14px;background:rgba(255,255,255,.16);display:grid;place-items:center;backdrop-filter:blur(4px)}
|
||
.hero-title{font-size:21px;font-weight:800;letter-spacing:-.3px}
|
||
.hero-sub{font-size:12.5px;color:rgba(255,255,255,.72);margin-top:2px}
|
||
.hero-arrow{margin-left:auto;width:32px;height:32px;border-radius:50%;border:1.4px solid rgba(255,255,255,.5);display:grid;place-items:center}
|
||
.hero-mid{display:flex;justify-content:space-between;gap:12px;margin:18px 0 4px}
|
||
.lbl{font-size:10.5px;color:rgba(255,255,255,.62);letter-spacing:.2px}
|
||
.val{font-size:14.5px;font-weight:700;margin-top:3px;letter-spacing:-.1px}
|
||
.hero-right{text-align:right}
|
||
.hero-foot{display:flex;align-items:flex-end;justify-content:space-between;margin-top:14px}
|
||
.renew-pill{
|
||
background:#fff;color:var(--ink);font-size:12.5px;font-weight:750;padding:9px 16px;border-radius:999px;
|
||
box-shadow:0 6px 16px rgba(20,10,60,.28);transition:transform .15s;
|
||
}
|
||
.renew-pill:active{transform:scale(.95)}
|
||
|
||
.sec-head{display:flex;align-items:center;justify-content:space-between;margin:22px 0 12px}
|
||
.sec-title{font-size:18px;font-weight:780;letter-spacing:-.3px}
|
||
.sec-link{font-size:12.5px;color:var(--muted);font-weight:600}
|
||
.cat-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
|
||
.cat{
|
||
border-radius:20px;padding:14px 6px 12px;display:flex;flex-direction:column;align-items:center;gap:9px;
|
||
font-size:12px;font-weight:700;color:#3c3d4e;transition:transform .16s;
|
||
}
|
||
.cat:active{transform:scale(.94)}
|
||
.cat-ic{width:38px;height:38px;border-radius:13px;background:rgba(255,255,255,.75);display:grid;place-items:center;box-shadow:0 2px 6px rgba(30,20,60,.06)}
|
||
.c-health{background:#ffedf3}.c-bike{background:#fff1e6}.c-home{background:#eeeaff}.c-travel{background:#e7f4ff}
|
||
.dots{display:flex;gap:5px;justify-content:center;margin:16px 0 2px}
|
||
.dot{width:5px;height:5px;border-radius:999px;background:#cfcfd9}
|
||
.dot.on{width:16px;background:var(--ink)}
|
||
|
||
.qa-row{
|
||
display:flex;align-items:center;gap:13px;background:#fff;border-radius:20px;
|
||
padding:14px 16px;box-shadow:var(--card-sh);margin-bottom:11px;
|
||
}
|
||
.qa-ic{width:44px;height:44px;border-radius:15px;background:#f4f3fa;display:grid;place-items:center;flex:0 0 44px}
|
||
.qa-t{font-size:14.5px;font-weight:750;letter-spacing:-.2px}
|
||
.qa-s{font-size:11.5px;color:var(--muted);margin-top:3px}
|
||
.qa-amt{margin-left:auto;font-size:14px;font-weight:800;color:var(--green)}
|
||
|
||
/* ================= POLICIES / INSTANT SERVICES ================= */
|
||
.page-h{font-size:23px;font-weight:820;letter-spacing:-.45px;margin:14px 0 14px}
|
||
.duo{display:grid;grid-template-columns:1.35fr 1fr;gap:12px;margin-bottom:6px}
|
||
.mini-card{background:#fff;border-radius:22px;padding:16px;box-shadow:var(--card-sh)}
|
||
.agents-tag{display:inline-flex;align-items:center;gap:5px;font-size:14px;font-weight:750}
|
||
.agents-tag .star{color:#f6b93b;font-size:15px}
|
||
.mini-txt{font-size:11px;color:var(--muted);line-height:1.5;margin:8px 0 12px}
|
||
.ava-stack{display:flex;align-items:center}
|
||
.stk{width:32px;height:32px;border-radius:50%;border:2.5px solid #fff;margin-left:-10px;display:grid;place-items:center;font-size:14px;flex:0 0 32px}
|
||
.stk:first-child{margin-left:0}
|
||
.stk-plus{background:var(--ink);color:#fff;font-size:10.5px;font-weight:800}
|
||
.chat-ic{width:44px;height:44px;border-radius:50%;background:linear-gradient(145deg,#8d79ff,#6a48f0);display:grid;place-items:center;color:#fff;margin-bottom:10px;box-shadow:0 8px 18px rgba(110,80,240,.35)}
|
||
.chat-t{font-size:16.5px;font-weight:800;letter-spacing:-.2px;line-height:1.25}
|
||
.chat-link{display:inline-flex;align-items:center;gap:4px;font-size:11.5px;color:var(--purple);font-weight:650;margin-top:9px}
|
||
|
||
.pol-card{background:#fff;border-radius:24px;padding:18px;box-shadow:var(--card-sh);margin-bottom:13px}
|
||
.pol-row1{display:flex;align-items:flex-start;gap:12px}
|
||
.pol-ic{width:42px;height:42px;border-radius:50%;display:grid;place-items:center;flex:0 0 42px}
|
||
.pi-orange{background:#fff1e2}.pi-pink{background:#ffe9f0}
|
||
.pol-tag{margin-left:auto;font-size:10.5px;color:var(--muted);background:#f4f4f8;padding:4.5px 10px;border-radius:999px;font-weight:650}
|
||
.pol-title{font-size:20px;font-weight:820;letter-spacing:-.4px;margin:10px 0 6px}
|
||
.pol-sub{font-size:12px;color:var(--muted);line-height:1.55}
|
||
.pol-exp{font-size:12px;font-weight:700;color:#ff7a1a;font-style:italic;margin-top:3px}
|
||
.renew-dark{
|
||
margin-top:15px;width:100%;display:flex;align-items:center;gap:11px;background:var(--navy);
|
||
color:#fff;border-radius:999px;padding:8px 9px;box-shadow:0 12px 24px rgba(20,22,44,.3);
|
||
transition:transform .15s;
|
||
}
|
||
.renew-dark:active{transform:scale(.97)}
|
||
.renew-dark .rd-ic{width:40px;height:40px;border-radius:50%;background:linear-gradient(145deg,#8d79ff,#5f3df0);display:grid;place-items:center;flex:0 0 40px}
|
||
.renew-dark .rd-t{flex:1;text-align:left;font-size:14px;font-weight:750}
|
||
.renew-dark .rd-ar{color:rgba(255,255,255,.75);padding-right:8px}
|
||
|
||
/* ================= BENEFITS ================= */
|
||
.chips{display:flex;gap:9px;margin:14px 0 16px}
|
||
.chip{
|
||
padding:9px 20px;border-radius:999px;background:#fff;font-size:13.5px;font-weight:700;color:#3c3d4e;
|
||
box-shadow:var(--card-sh);transition:all .2s;
|
||
}
|
||
.chip.on{background:var(--ink);color:#fff}
|
||
.drive-card{
|
||
border-radius:30px;padding:22px 20px 20px;color:#fff;position:relative;overflow:hidden;
|
||
background:
|
||
radial-gradient(220px 220px at 100% 0%,rgba(255,255,255,.22),transparent 55%),
|
||
linear-gradient(155deg,#8f7dff 0%,#7248f6 55%,#5e35e6 100%);
|
||
box-shadow:0 22px 46px rgba(110,80,240,.4);
|
||
}
|
||
.drv-top{display:flex;align-items:flex-start;justify-content:space-between}
|
||
.drv-t{font-size:19px;font-weight:800;letter-spacing:-.3px}
|
||
.drv-s{font-size:12px;color:rgba(255,255,255,.75);margin-top:3px}
|
||
.batt-tag{display:inline-flex;align-items:center;gap:6px;background:rgba(255,255,255,.18);backdrop-filter:blur(6px);border-radius:999px;padding:6px 12px;font-size:11px;font-weight:700}
|
||
.car-box{margin:14px 0 2px}
|
||
.drv-num{text-align:center;font-size:44px;font-weight:850;letter-spacing:-1.5px;margin-top:4px}
|
||
.drv-num small{font-size:15px;font-weight:700;color:rgba(255,255,255,.8);margin-left:5px;letter-spacing:0}
|
||
.drv-ctrl{display:flex;align-items:center;gap:10px;margin-top:14px}
|
||
.dc{width:46px;height:46px;border-radius:50%;display:grid;place-items:center;transition:transform .15s}
|
||
.dc:active{transform:scale(.92)}
|
||
.dc-dark{background:rgba(15,10,40,.85)}
|
||
.dc-glass{background:rgba(255,255,255,.22);backdrop-filter:blur(6px)}
|
||
.dc-close{margin-left:auto;width:46px;height:46px;border-radius:50%;background:#fff;color:#3c3d4e;display:grid;place-items:center;font-size:17px;font-weight:700}
|
||
.mini-handle{width:46px;height:4.5px;border-radius:999px;background:#c6c6cf;margin:18px auto 14px}
|
||
|
||
.tip-card{background:#fff;border-radius:24px;padding:16px 18px;box-shadow:var(--card-sh)}
|
||
.tip-tag{display:inline-block;background:#ffedd9;color:#f2600c;font-size:11px;font-weight:800;padding:5.5px 12px;border-radius:999px;margin-bottom:9px}
|
||
.tip-txt{font-size:14px;color:#4a4b5c;line-height:1.55;font-weight:550;margin-bottom:14px}
|
||
.tip-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}
|
||
.tip-cell{background:#faf9fd;border-radius:16px;padding:11px 9px;text-align:center}
|
||
.tip-cell .tl{font-size:11px;font-weight:750;color:#3c3d4e;margin-top:7px;line-height:1.3}
|
||
.tip-cell .tv{font-size:13px;font-weight:850;margin-top:2px}
|
||
|
||
/* ================= BUYING ================= */
|
||
.id-hero{background:#fff;border-radius:26px;padding:18px;box-shadow:var(--card-sh);position:relative;overflow:hidden;margin-top:12px}
|
||
.idh-row{display:flex;align-items:flex-start;gap:14px}
|
||
.idh-name{font-size:22px;font-weight:830;letter-spacing:-.4px}
|
||
.idh-dob{font-size:12px;color:var(--muted);margin-top:4px}
|
||
.idh-ring{margin-left:auto;text-align:center;position:relative;width:60px;height:60px}
|
||
.idh-ring .rv{position:absolute;inset:0;display:grid;place-items:center;font-size:10px;font-weight:800;color:#7b8494}
|
||
.portrait{
|
||
width:118px;height:128px;border-radius:22px;margin:-4px auto 0;position:relative;overflow:hidden;
|
||
background:linear-gradient(180deg,#dfe8f5,#cfd9ea);
|
||
}
|
||
.idh-foot{display:flex;align-items:center;margin-top:12px}
|
||
.plus-2{
|
||
width:34px;height:34px;border-radius:50%;background:var(--ink);color:#fff;display:grid;place-items:center;
|
||
font-size:16px;margin-left:-10px;border:2.5px solid #fff;
|
||
}
|
||
.id-card{
|
||
border-radius:26px;margin-top:16px;padding:18px;color:#fff;position:relative;overflow:hidden;
|
||
background:
|
||
radial-gradient(180px 180px at 110% -10%,rgba(255,255,255,.2),transparent 60%),
|
||
linear-gradient(150deg,#7f68f7,#6a48f0 60%,#5b39e6);
|
||
box-shadow:0 18px 42px rgba(104,74,240,.4);
|
||
}
|
||
.id-top{display:flex;align-items:center;gap:9px}
|
||
.id-top .it-ic{width:32px;height:32px;border-radius:50%;background:rgba(255,255,255,.18);display:grid;place-items:center}
|
||
.id-top .it-dl{width:32px;height:32px;border-radius:50%;background:rgba(10,6,30,.55);display:grid;place-items:center}
|
||
.id-top .it-more{margin-left:2px;color:rgba(255,255,255,.85);font-weight:800;letter-spacing:2px;font-size:14px}
|
||
.id-top .it-lbl{margin-left:auto;text-align:right}
|
||
.id-top .it-lbl .a{font-size:10.5px;color:rgba(255,255,255,.65)}
|
||
.id-top .it-lbl .b{font-size:15px;font-weight:800;letter-spacing:-.2px}
|
||
.id-body{display:flex;gap:14px;margin-top:16px}
|
||
.id-fields{flex:1}
|
||
.id-f{margin-bottom:13px}
|
||
.id-f .l{font-size:10px;color:rgba(255,255,255,.62)}
|
||
.id-f .v{font-size:15px;font-weight:800;letter-spacing:.3px;margin-top:2px}
|
||
.qr{width:104px;height:104px;background:#fff;border-radius:14px;padding:9px;flex:0 0 104px;align-self:flex-start}
|
||
.buy-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}
|
||
.buy-card{border-radius:22px;padding:16px;box-shadow:var(--card-sh);transition:transform .16s}
|
||
.buy-card:active{transform:scale(.96)}
|
||
.bc-dark{background:var(--navy);color:#fff}
|
||
.bc-light{background:#fff}
|
||
.bc-top{display:flex;align-items:center;justify-content:space-between}
|
||
.bc-ic{width:36px;height:36px;border-radius:12px;display:grid;place-items:center}
|
||
.bc-dark .bc-ic{background:rgba(255,255,255,.12)}
|
||
.bc-light .bc-ic{background:#f0edfe}
|
||
.bc-ar{width:28px;height:28px;border-radius:50%;display:grid;place-items:center}
|
||
.bc-dark .bc-ar{background:rgba(255,255,255,.1);color:#fff}
|
||
.bc-light .bc-ar{background:#f2f2f7;color:#3c3d4e}
|
||
.bc-t{font-size:13px;font-weight:750;margin-top:26px}
|
||
.bc-dark .bc-t{color:rgba(255,255,255,.85)}
|
||
.bc-light .bc-t{color:#3c3d4e}
|
||
.bc-p{font-size:21px;font-weight:850;letter-spacing:-.4px;margin-top:2px}
|
||
.bc-p small{font-size:11px;font-weight:700;color:var(--muted)}
|
||
|
||
/* ================= TAB BAR ================= */
|
||
.tabbar{
|
||
position:absolute;left:14px;right:14px;bottom:14px;height:74px;z-index:60;
|
||
background:rgba(255,255,255,.94);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
|
||
border-radius:26px;display:flex;align-items:stretch;
|
||
box-shadow:0 14px 34px rgba(20,22,44,.14),inset 0 0 0 1px rgba(20,22,44,.04);
|
||
transition:opacity .25s,transform .25s,filter .25s;
|
||
}
|
||
.tabbar.ghost{opacity:0;transform:translateY(12px);filter:blur(3px);pointer-events:none}
|
||
.tb{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;color:#9a9ba8;position:relative;transition:color .18s}
|
||
.tb .tl{font-size:10.5px;font-weight:700}
|
||
.tb.on{color:var(--purple)}
|
||
.tb .tdot{width:4.5px;height:4.5px;border-radius:50%;background:var(--purple);opacity:0;transform:scale(.4);transition:all .2s}
|
||
.tb.on .tdot{opacity:1;transform:none}
|
||
.tb:active svg{transform:scale(.88)}
|
||
.tb svg{transition:transform .16s}
|
||
.fab-slot{flex:1;position:relative}
|
||
.fab{
|
||
position:absolute;left:50%;top:-21px;transform:translateX(-50%);
|
||
width:62px;height:62px;border-radius:50%;color:#fff;display:grid;place-items:center;
|
||
background:radial-gradient(circle at 34% 26%,#927cff,#6a48f0 62%,#5a34e8);
|
||
box-shadow:0 14px 30px rgba(104,72,240,.5),inset 0 1.5px 2px rgba(255,255,255,.35);
|
||
transition:transform .16s;
|
||
}
|
||
.fab:active{transform:translateX(-50%) scale(.93)}
|
||
.home-ind{position:absolute;bottom:4px;left:50%;transform:translateX(-50%);width:126px;height:5px;border-radius:999px;background:#15161f;z-index:90;pointer-events:none}
|
||
|
||
/* ================= SHEET (+ FAB) ================= */
|
||
.backdrop{
|
||
position:absolute;inset:0;background:rgba(16,16,26,.36);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
|
||
opacity:0;pointer-events:none;transition:opacity .28s;z-index:70;
|
||
}
|
||
.backdrop.open{opacity:1;pointer-events:auto}
|
||
.sheet{
|
||
position:absolute;left:12px;right:12px;bottom:12px;z-index:80;
|
||
background:#f4f3f8;border-radius:28px;
|
||
box-shadow:0 -16px 52px rgba(15,15,30,.24),inset 0 1px 0 rgba(255,255,255,.9);
|
||
transform:translateY(calc(100% + 30px));opacity:0;pointer-events:none;
|
||
transition:transform .38s cubic-bezier(.22,1,.36,1),opacity .3s;
|
||
display:flex;flex-direction:column;overflow:hidden;touch-action:none;max-height:calc(100% - 30px);
|
||
}
|
||
.sheet.open{transform:translateY(0);opacity:1;pointer-events:auto}
|
||
.sheet.peek{height:400px}
|
||
.sheet.expanded{height:640px}
|
||
.sheet.drag{transition:none !important}
|
||
.grab{flex:0 0 64px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;cursor:grab;user-select:none;-webkit-user-select:none}
|
||
.grab-pill{width:46px;height:5px;border-radius:999px;background:#c9c9d3}
|
||
.drag-hint{font-size:10.5px;color:#9a9ba8;font-weight:700;letter-spacing:.3px}
|
||
.stabs{
|
||
margin:0 18px;background:#e2e2ea;border-radius:14px;padding:4px;display:flex;gap:4px;
|
||
max-height:0;opacity:0;transform:translateY(-8px);overflow:hidden;pointer-events:none;
|
||
transition:max-height .34s cubic-bezier(.22,1,.36,1),opacity .24s,transform .28s,margin .24s;
|
||
}
|
||
.sheet.expanded .stabs{max-height:52px;opacity:1;transform:none;pointer-events:auto;margin-bottom:12px}
|
||
.stab{flex:1;text-align:center;padding:9.5px 0;border-radius:10.5px;font-size:13px;font-weight:750;color:#6b6c79;transition:all .2s}
|
||
.stab.on{background:#fff;color:var(--ink);box-shadow:0 3px 10px rgba(25,25,50,.12)}
|
||
.sbody{flex:1;overflow:hidden;position:relative}
|
||
.sheet.peek .sbody{overflow:hidden}
|
||
.sheet.expanded .sbody{overflow-y:auto;scrollbar-width:none}
|
||
.spage{display:none;padding:2px 18px 22px;animation:fadeUp .28s cubic-bezier(.22,1,.36,1)}
|
||
.spage.on{display:block}
|
||
.sh-title{font-size:19px;font-weight:820;letter-spacing:-.35px;margin:2px 0 14px}
|
||
.act-grid{display:grid;grid-template-columns:1fr 1fr;gap:11px}
|
||
.act{
|
||
background:#fff;border-radius:20px;padding:16px 14px;display:flex;flex-direction:column;gap:11px;
|
||
box-shadow:var(--card-sh);transition:transform .15s;
|
||
}
|
||
.act:active{transform:scale(.95)}
|
||
.act-ic{width:42px;height:42px;border-radius:14px;display:grid;place-items:center}
|
||
.ai-p{background:#efeaff}.ai-o{background:#fff0e2}.ai-g{background:#e7f8ef}.ai-b{background:#e7f2ff}
|
||
.act-t{font-size:14px;font-weight:780;letter-spacing:-.2px}
|
||
.act-s{font-size:11px;color:var(--muted);margin-top:-7px}
|
||
.ag-row{display:flex;align-items:center;gap:12px;background:#fff;border-radius:18px;padding:12px 14px;box-shadow:var(--card-sh);margin-bottom:10px}
|
||
.ag-ava{width:44px;height:44px;border-radius:50%;display:grid;place-items:center;font-size:20px;flex:0 0 44px}
|
||
.ag-n{font-size:14px;font-weight:780}
|
||
.ag-r{font-size:11px;color:var(--muted);margin-top:2px}
|
||
.ag-btn{margin-left:auto;background:#efeaff;color:var(--purple);font-size:12px;font-weight:800;padding:8px 15px;border-radius:999px}
|
||
.sup-row{display:flex;align-items:center;gap:13px;background:#fff;border-radius:18px;padding:15px 16px;box-shadow:var(--card-sh);margin-bottom:10px;font-size:14px;font-weight:750}
|
||
.sup-ic{width:40px;height:40px;border-radius:13px;display:grid;place-items:center;flex:0 0 40px}
|
||
.sup-row .chev{margin-left:auto;color:#b9bac6}
|
||
|
||
/* toast */
|
||
.toast{
|
||
position:absolute;left:50%;bottom:108px;transform:translateX(-50%) translateY(16px);z-index:95;
|
||
background:var(--ink);color:#fff;font-size:13px;font-weight:700;padding:12px 20px;border-radius:999px;
|
||
opacity:0;pointer-events:none;transition:all .3s cubic-bezier(.22,1,.36,1);white-space:nowrap;
|
||
box-shadow:0 12px 30px rgba(15,15,30,.35);
|
||
}
|
||
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="stage">
|
||
<div class="phone">
|
||
<div class="island"></div>
|
||
|
||
<!-- STATUS BAR -->
|
||
<div class="statusbar">
|
||
<span>9:41</span>
|
||
<span class="sb-icons">
|
||
<svg width="17" height="11" viewBox="0 0 17 11" fill="currentColor"><rect x="0" y="7" width="3" height="4" rx="1"/><rect x="4.5" y="4.8" width="3" height="6.2" rx="1"/><rect x="9" y="2.5" width="3" height="8.5" rx="1"/><rect x="13.5" y="0" width="3" height="11" rx="1"/></svg>
|
||
<svg width="16" height="11" viewBox="0 0 16 12" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M1.5 4.2a9.5 9.5 0 0 1 13 0"/><path d="M4 7a6 6 0 0 1 8 0"/><circle cx="8" cy="10" r="1.2" fill="currentColor" stroke="none"/></svg>
|
||
<svg width="25" height="12" viewBox="0 0 25 12" fill="none"><rect x=".7" y=".7" width="20" height="10.6" rx="3" stroke="currentColor" stroke-opacity=".45" stroke-width="1"/><rect x="2.5" y="2.5" width="13.5" height="7" rx="1.6" fill="currentColor"/><path d="M22.8 4v4a2.2 2.2 0 0 0 0-4z" fill="currentColor" fill-opacity=".45"/></svg>
|
||
</span>
|
||
</div>
|
||
|
||
<div class="screens">
|
||
|
||
<!-- ============ SCREEN: HOME ============ -->
|
||
<section class="screen on" id="scr-home">
|
||
<div class="hi-row">
|
||
<div class="ava-wrap">
|
||
<svg viewBox="0 0 54 54"><circle cx="27" cy="27" r="25.5" fill="none" stroke="#ececf1" stroke-width="3"/><circle cx="27" cy="27" r="25.5" fill="none" stroke="#7b5cf6" stroke-width="3" stroke-linecap="round" stroke-dasharray="160.2" stroke-dashoffset="64"/></svg>
|
||
<div class="ava">🧑🏽</div>
|
||
<div class="ava-badge">60%</div>
|
||
</div>
|
||
<div>
|
||
<div class="hi-name">Hello 👋 Thomson!</div>
|
||
<div class="hi-sub">Complete your profile easily</div>
|
||
</div>
|
||
<button class="bell-btn" id="bellHome" aria-label="Notifications">
|
||
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="#3c3d4e" stroke-width="1.9" stroke-linecap="round"><path d="M6 9.5a6 6 0 0 1 12 0c0 4 1.6 5.6 2.4 6.4H3.6C4.4 15.1 6 13.5 6 9.5Z"/><path d="M10 19.5a2.2 2.2 0 0 0 4 0"/></svg>
|
||
<span class="bell-dot"></span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="searchbar">
|
||
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="#a6a7b3" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="7"/><path d="m16.5 16.5 4 4"/></svg>
|
||
<input type="text" placeholder="Search" aria-label="Search">
|
||
<button class="filter-btn" aria-label="Filter" id="filterBtn">
|
||
<svg width="19" height="19" viewBox="0 0 24 24" stroke="#191a24" stroke-width="2" stroke-linecap="round"><path d="M4 7h10M18 7h2M4 12h4M12 12h8M4 17h13"/><circle cx="16" cy="7" r="1.6" fill="#191a24" stroke="none"/><circle cx="10" cy="12" r="1.6" fill="#191a24" stroke="none"/><circle cx="19.5" cy="17" r="1.6" fill="#191a24" stroke="none"/></svg>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- purple hero -->
|
||
<div class="hero-card">
|
||
<div class="hero-top">
|
||
<div class="hero-ic">
|
||
<svg width="21" height="21" viewBox="0 0 24 24" fill="#fff"><path d="M12 2.5 5 5v6c0 4.6 3 8.4 7 10.5 4-2.1 7-5.9 7-10.5V5l-7-2.5Z"/><path d="m9.5 11.8 1.8 1.8 3.4-3.6" stroke="#7b5cf6" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||
</div>
|
||
<div>
|
||
<div class="hero-title">Car Insurance</div>
|
||
<div class="hero-sub">Comprehensive</div>
|
||
</div>
|
||
<button class="hero-arrow" aria-label="Open policy">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8.5 7H17v8.5"/></svg>
|
||
</button>
|
||
</div>
|
||
<div class="hero-mid">
|
||
<div>
|
||
<div class="lbl">Policy holder</div>
|
||
<div class="val">Rahul Sharma</div>
|
||
</div>
|
||
<div class="hero-right">
|
||
<div class="lbl">Tata Altroz</div>
|
||
<div class="val">MP04CY9999</div>
|
||
</div>
|
||
</div>
|
||
<div class="hero-foot">
|
||
<div>
|
||
<div class="lbl">Third party validity</div>
|
||
<div class="val" style="font-size:16px">10/02/25</div>
|
||
</div>
|
||
<button class="renew-pill" data-toast="Renewal started for MP04CY9999 ✓">Renew Now</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sec-head">
|
||
<div class="sec-title">Health & Wellness</div>
|
||
<button class="sec-link" data-go="benefits">View All</button>
|
||
</div>
|
||
<div class="cat-grid">
|
||
<button class="cat c-health" data-go="benefits">
|
||
<span class="cat-ic"><svg width="19" height="19" viewBox="0 0 24 24" fill="#f43f6e"><path d="M12 20.5s-7.5-4.7-9.2-9A5.2 5.2 0 0 1 12 6.6a5.2 5.2 0 0 1 9.2 4.9c-1.7 4.3-9.2 9-9.2 9Z"/></svg></span>
|
||
Health
|
||
</button>
|
||
<button class="cat c-bike" data-go="buy">
|
||
<span class="cat-ic"><svg width="19" height="19" viewBox="0 0 24 24" fill="#f97316"><circle cx="12" cy="7" r="3"/><path d="M12 11c-3.6 0-6 2.6-6 6v4h12v-4c0-3.4-2.4-6-6-6Z"/></svg></span>
|
||
Bike
|
||
</button>
|
||
<button class="cat c-home" data-go="policies">
|
||
<span class="cat-ic"><svg width="19" height="19" viewBox="0 0 24 24" fill="#7b5cf6"><path d="m12 3.5 8.5 6.6V20a1 1 0 0 1-1 1h-5v-6h-5v6h-5a1 1 0 0 1-1-1v-9.9L12 3.5Z"/></svg></span>
|
||
Home
|
||
</button>
|
||
<button class="cat c-travel" data-go="policies">
|
||
<span class="cat-ic"><svg width="19" height="19" viewBox="0 0 24 24" fill="#0ea5e9"><rect x="5.5" y="8" width="13" height="12" rx="3"/><path d="M9.5 8V6.2A2.2 2.2 0 0 1 11.7 4h.6a2.2 2.2 0 0 1 2.2 2.2V8h-5Z" fill="#fff" opacity=".55"/><path d="M9.5 8V6.2A2.2 2.2 0 0 1 11.7 4h.6a2.2 2.2 0 0 1 2.2 2.2V8"/><rect x="3.5" y="8" width="2" height="3" rx="1" opacity=".7"/></svg></span>
|
||
Travel
|
||
</button>
|
||
</div>
|
||
<div class="dots"><span class="dot on"></span><span class="dot"></span></div>
|
||
|
||
<div class="sec-head">
|
||
<div class="sec-title">Quick Actions</div>
|
||
<button class="sec-link" data-go="policies">See All</button>
|
||
</div>
|
||
<div class="qa-row">
|
||
<div class="qa-ic"><svg width="20" height="20" viewBox="0 0 24 24" fill="#f2a541"><path d="M6.5 3.5h8L19 8v11a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 5 19V5a1.5 1.5 0 0 1 1.5-1.5Z"/><path d="M14.5 3.5V8H19" fill="#ffd9a0"/><path d="M8.5 12.5h7M8.5 16h5" stroke="#fff" stroke-width="1.7" stroke-linecap="round"/></svg></div>
|
||
<div>
|
||
<div class="qa-t">Register a Claim</div>
|
||
<div class="qa-s">Weekly Goal: 150 min</div>
|
||
</div>
|
||
<div class="qa-amt">+$234.00</div>
|
||
</div>
|
||
<div class="qa-row">
|
||
<div class="qa-ic"><svg width="20" height="20" viewBox="0 0 24 24" fill="#8b7cf6"><path d="M12 21s-6.8-5.7-6.8-11a6.8 6.8 0 0 1 13.6 0c0 5.3-6.8 11-6.8 11Z"/><circle cx="12" cy="10" r="2.4" fill="#fff"/></svg></div>
|
||
<div>
|
||
<div class="qa-t">Find Local Services</div>
|
||
<div class="qa-s">Weekly Goal: 60 min</div>
|
||
</div>
|
||
<div class="qa-amt">+$134.00</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ SCREEN: POLICIES (Instant Services) ============ -->
|
||
<section class="screen" id="scr-policies">
|
||
<div class="topbar">
|
||
<button class="back-btn" data-go="home" aria-label="Back">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5.5 8.5 12l6.5 6.5"/></svg>
|
||
</button>
|
||
<div class="top-title">Instant Services</div>
|
||
<button class="bell-btn" aria-label="Notifications">
|
||
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="#3c3d4e" stroke-width="1.9" stroke-linecap="round"><path d="M6 9.5a6 6 0 0 1 12 0c0 4 1.6 5.6 2.4 6.4H3.6C4.4 15.1 6 13.5 6 9.5Z"/><path d="M10 19.5a2.2 2.2 0 0 0 4 0"/></svg>
|
||
<span class="bell-dot"></span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="page-h">Live Well & Yield Rewards</div>
|
||
|
||
<div class="duo">
|
||
<div class="mini-card">
|
||
<div class="agents-tag"><span class="star">⭐</span> Our Agents</div>
|
||
<div class="mini-txt">Meet your exclusive insurance advisor and get advice</div>
|
||
<div class="ava-stack">
|
||
<span class="stk" style="background:#cfe0ff">🧔🏻</span>
|
||
<span class="stk" style="background:#ffd9e4">👩🏼</span>
|
||
<span class="stk" style="background:#ffe9c9">👱🏾</span>
|
||
<span class="stk stk-plus">+20</span>
|
||
</div>
|
||
</div>
|
||
<div class="mini-card">
|
||
<div class="chat-ic">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="#fff"><path d="M12 3.8c-4.7 0-8.5 3.1-8.5 7 0 2.3 1.3 4.3 3.3 5.6l-.9 3.3 3.6-1.7c.8.2 1.6.3 2.5.3 4.7 0 8.5-3.1 8.5-7s-3.8-7.5-8.5-7.5Z"/><circle cx="8.7" cy="10.8" r="1.1" fill="#7b5cf6"/><circle cx="12" cy="10.8" r="1.1" fill="#7b5cf6"/><circle cx="15.3" cy="10.8" r="1.1" fill="#7b5cf6"/></svg>
|
||
</div>
|
||
<div class="chat-t">Chat with expert</div>
|
||
<button class="chat-link" data-toast="Opening expert chat…">
|
||
Message Now
|
||
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8.5 7H17v8.5"/></svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sec-head">
|
||
<div class="sec-title">Quick Actions</div>
|
||
<button class="sec-link">View All</button>
|
||
</div>
|
||
|
||
<div class="pol-card">
|
||
<div class="pol-row1">
|
||
<div class="pol-ic pi-orange">
|
||
<svg width="19" height="19" viewBox="0 0 24 24" fill="#f2a03f"><path d="M6.5 3.5h8L19 8v11a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 5 19V5a1.5 1.5 0 0 1 1.5-1.5Z"/><path d="M9 13h6M9 16.5h4" stroke="#fff" stroke-width="1.7" stroke-linecap="round"/></svg>
|
||
</div>
|
||
<span class="pol-tag">Health</span>
|
||
</div>
|
||
<div class="pol-title">Edit Your Policy Details</div>
|
||
<div class="pol-sub">Your policy purchased on 27 Feb, 2025 will<br><span class="pol-exp">Expires in 15 Days</span></div>
|
||
<button class="renew-dark" data-toast="Policy renewal started ✓">
|
||
<span class="rd-ic">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"><path d="M20 12a8 8 0 1 1-2.3-5.6"/><path d="M20 3.8V7h-3.2"/></svg>
|
||
</span>
|
||
<span class="rd-t">Renew Now</span>
|
||
<span class="rd-ar">»</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="pol-card">
|
||
<div class="pol-row1">
|
||
<div class="pol-ic pi-pink">
|
||
<svg width="19" height="19" viewBox="0 0 24 24" fill="#f25a8a"><path d="M7 4h7l4 4v11a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1Z"/><path d="M9.2 12.5l2 2 3.6-3.8" stroke="#fff" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||
</div>
|
||
<span class="pol-tag">PUC Validity</span>
|
||
</div>
|
||
<div class="pol-title">Register a Claim Details</div>
|
||
<div class="pol-sub">Your policy purchased on 27 Feb, 2025 will<br><span class="pol-exp">Expires in 15 Days</span></div>
|
||
<button class="renew-dark" data-toast="Claim registration opened ✓">
|
||
<span class="rd-ic">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.2" stroke-linecap="round"><path d="M12 5v14M5 12h14"/></svg>
|
||
</span>
|
||
<span class="rd-t">Start Claim</span>
|
||
<span class="rd-ar">»</span>
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ SCREEN: BENEFITS ============ -->
|
||
<section class="screen" id="scr-benefits">
|
||
<div class="topbar">
|
||
<button class="back-btn" data-go="home" aria-label="Back">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5.5 8.5 12l6.5 6.5"/></svg>
|
||
</button>
|
||
<div class="top-title">Benefits</div>
|
||
<button class="bell-btn" aria-label="Notifications">
|
||
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="#3c3d4e" stroke-width="1.9" stroke-linecap="round"><path d="M6 9.5a6 6 0 0 1 12 0c0 4 1.6 5.6 2.4 6.4H3.6C4.4 15.1 6 13.5 6 9.5Z"/><path d="M10 19.5a2.2 2.2 0 0 0 4 0"/></svg>
|
||
<span class="bell-dot"></span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="chips" id="chips">
|
||
<button class="chip on">Featured</button>
|
||
<button class="chip">Health</button>
|
||
<button class="chip">Motor</button>
|
||
</div>
|
||
|
||
<div class="drive-card">
|
||
<div class="drv-top">
|
||
<div>
|
||
<div class="drv-t">Driving Score</div>
|
||
<div class="drv-s">Curious Driving Habits</div>
|
||
</div>
|
||
<span class="batt-tag">
|
||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#ffd66b" stroke-width="2"><rect x="2.5" y="8" width="16" height="9" rx="2.5"/><rect x="4.7" y="10.2" width="8" height="4.6" rx="1.2" fill="#ffd66b" stroke="none"/><path d="M20.5 10.8v3.4" stroke-linecap="round"/></svg>
|
||
89% Charged
|
||
</span>
|
||
</div>
|
||
|
||
<!-- car illustration -->
|
||
<div class="car-box">
|
||
<svg viewBox="0 0 300 110" width="100%" aria-hidden="true">
|
||
<ellipse cx="150" cy="98" rx="128" ry="9" fill="rgba(20,10,60,.28)"/>
|
||
<path d="M48 78c-6 0-10-4.4-10-10v-8c0-8 6-13 14-14l22-3 24-16c6-4 12-6 20-6h44c9 0 16 2 22 7l20 15 30 4c9 1.2 14 6 14 13v8c0 5.6-4 10-10 10H48Z" fill="#1b1e30"/>
|
||
<path d="M100 42l-18 12h56V32h-18c-8 0-14 2-20 10Z" fill="#8fa0b8" opacity=".92"/>
|
||
<path d="M146 32v22h60l-16-13c-4-5-9-9-14-9h-30Z" fill="#8fa0b8" opacity=".92"/>
|
||
<rect x="34" y="58" width="10" height="6" rx="3" fill="#ffd66b"/>
|
||
<rect x="232" y="58" width="12" height="6" rx="3" fill="#ff8a8a"/>
|
||
<circle cx="88" cy="78" r="17" fill="#0e1018"/><circle cx="88" cy="78" r="10" fill="#3a3f52"/><circle cx="88" cy="78" r="4.5" fill="#b9c2d4"/>
|
||
<circle cx="212" cy="78" r="17" fill="#0e1018"/><circle cx="212" cy="78" r="10" fill="#3a3f52"/><circle cx="212" cy="78" r="4.5" fill="#b9c2d4"/>
|
||
</svg>
|
||
</div>
|
||
|
||
<div class="drv-num">296<small>mi</small></div>
|
||
|
||
<div class="drv-ctrl">
|
||
<button class="dc dc-dark" data-toast="Car locked 🔒" aria-label="Lock">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"><rect x="5.5" y="10.5" width="13" height="9" rx="2.5" fill="#fff" stroke="none"/><path d="M8.5 10.5V8a3.5 3.5 0 0 1 7 0v2.5"/></svg>
|
||
</button>
|
||
<button class="dc dc-glass" data-toast="Car unlocked 🔓" aria-label="Unlock">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"><rect x="5.5" y="10.5" width="13" height="9" rx="2.5"/><path d="M8.5 10.5V8a3.5 3.5 0 0 1 6.9-.8"/></svg>
|
||
</button>
|
||
<button class="dc-close" data-toast="Card dismissed" aria-label="Close">✕</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mini-handle"></div>
|
||
|
||
<div class="tip-card">
|
||
<span class="tip-tag">Health Tip</span>
|
||
<div class="tip-txt">Regular checkups are your best defence against unexpected health challenges.</div>
|
||
<div class="tip-grid">
|
||
<div class="tip-cell">
|
||
<svg width="26" height="26" viewBox="0 0 24 24" style="margin:0 auto"><path d="M12 20.5s-7.5-4.7-9.2-9A5.2 5.2 0 0 1 12 6.6a5.2 5.2 0 0 1 9.2 4.9c-1.7 4.3-9.2 9-9.2 9Z" fill="#ffb167"/><path d="M7 12h2.4l1.2-2.4 2 4.6 1.2-2.2H17" stroke="#fff" stroke-width="1.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||
<div class="tl">Heart Rate</div><div class="tv">72 bpm</div>
|
||
</div>
|
||
<div class="tip-cell">
|
||
<svg width="26" height="26" viewBox="0 0 24 24" style="margin:0 auto" fill="none" stroke="#f2779f" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M9 4.5c-2 2.4-3 5-3 7a5 5 0 0 0 10 0c0-2-1-4.6-3-7"/><path d="M9 4.5c.8 1.4 2.2 2 3 2s2.2-.6 3-2"/></svg>
|
||
<div class="tl">Respiratory Rate</div><div class="tv">14 /min</div>
|
||
</div>
|
||
<div class="tip-cell">
|
||
<svg width="26" height="26" viewBox="0 0 24 24" style="margin:0 auto" fill="none" stroke="#4aa8f0" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M2.5 12h4l1.6-4.5 3 9 2-6 1.2 1.5h7.2"/></svg>
|
||
<div class="tl">Heart Rate Variability</div><div class="tv">58 ms</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ SCREEN: BUY ============ -->
|
||
<section class="screen" id="scr-buy">
|
||
<div class="topbar">
|
||
<button class="back-btn" data-go="home" aria-label="Back">
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M15 5.5 8.5 12l6.5 6.5"/></svg>
|
||
</button>
|
||
<div class="top-title">Buying Insurance</div>
|
||
<button class="bell-btn" aria-label="Notifications">
|
||
<svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="#3c3d4e" stroke-width="1.9" stroke-linecap="round"><path d="M6 9.5a6 6 0 0 1 12 0c0 4 1.6 5.6 2.4 6.4H3.6C4.4 15.1 6 13.5 6 9.5Z"/><path d="M10 19.5a2.2 2.2 0 0 0 4 0"/></svg>
|
||
<span class="bell-dot"></span>
|
||
</button>
|
||
</div>
|
||
|
||
<div class="id-hero">
|
||
<div class="idh-row">
|
||
<div style="flex:1">
|
||
<div class="idh-name">Alex Mandes</div>
|
||
<div class="idh-dob">24 Feb 2001</div>
|
||
</div>
|
||
<div class="idh-ring">
|
||
<svg viewBox="0 0 60 60" width="60" height="60">
|
||
<circle cx="30" cy="30" r="25" fill="none" stroke="#eceef5" stroke-width="5"/>
|
||
<circle cx="30" cy="30" r="25" fill="none" stroke="#7b8a9e" stroke-width="5" stroke-linecap="round" stroke-dasharray="157" stroke-dashoffset="52" transform="rotate(-90 30 30)"/>
|
||
</svg>
|
||
<span class="rv">112.22<br>(3 yr)</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- illustrated portrait -->
|
||
<div class="portrait">
|
||
<svg viewBox="0 0 118 128" width="118" height="128">
|
||
<rect width="118" height="128" fill="#dce6f2"/>
|
||
<ellipse cx="59" cy="140" rx="52" ry="42" fill="#9db6d4"/>
|
||
<path d="M40 122c4-14 10-20 19-20s15 6 19 20v10H40v-10Z" fill="#e9eef6"/>
|
||
<path d="M52 100h14v16a7 7 0 0 1-14 0v-16Z" fill="#e8b08c"/>
|
||
<ellipse cx="59" cy="72" rx="24" ry="27" fill="#f4c29c"/>
|
||
<path d="M35 66c-3-20 8-32 24-32s28 12 24 32c-1-8-4-13-6-14 1 4 0 7-1 9-2-10-8-14-17-14s-15 4-17 14c-1-2-2-5-1-9-2 1-5 6-6 14Z" fill="#b4551f"/>
|
||
<path d="M42 82c3 12 9 17 17 17s14-5 17-17c-2 9-8 13-17 13s-15-4-17-13Z" fill="#b4551f" opacity=".9"/>
|
||
<rect x="40" y="62" width="15" height="11" rx="5" fill="none" stroke="#39415c" stroke-width="2.2"/>
|
||
<rect x="63" y="62" width="15" height="11" rx="5" fill="none" stroke="#39415c" stroke-width="2.2"/>
|
||
<path d="M55 67h8" stroke="#39415c" stroke-width="2.2"/>
|
||
<path d="M45 68c2-2.5 5-2.5 7 0" stroke="#2c3350" stroke-width="2" fill="none" stroke-linecap="round"/>
|
||
<path d="M70 66l6 3-6 3" stroke="#2c3350" stroke-width="1.9" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
|
||
<path d="M53 86c4 2.4 8 2.4 12 0" stroke="#8a4a2a" stroke-width="2.2" fill="none" stroke-linecap="round"/>
|
||
<circle cx="97" cy="94" r="13" fill="#f4c29c"/>
|
||
<circle cx="93" cy="90" r="4.5" fill="none" stroke="#8a4a2a" stroke-width="2.4"/>
|
||
</svg>
|
||
</div>
|
||
|
||
<div class="idh-foot">
|
||
<div class="ava-stack">
|
||
<span class="stk" style="background:#ffe0c2">🧑🏻</span>
|
||
<span class="stk" style="background:#d5e6ff">👩🏽</span>
|
||
<span class="stk" style="background:#e9dcff">👨🏾</span>
|
||
<button class="plus-2" data-toast="2 more family members">+2</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ID card -->
|
||
<div class="id-card">
|
||
<div class="id-top">
|
||
<span class="it-ic"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M8.5 14a4.5 4.5 0 0 0 7 0" stroke-linecap="round"/><circle cx="9" cy="9.6" r="1.1" fill="#fff" stroke="none"/><circle cx="15" cy="9.6" r="1.1" fill="#fff" stroke="none"/></svg></span>
|
||
<button class="it-dl" data-toast="ID card downloaded ✓" aria-label="Download">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2.3" stroke-linecap="round" stroke-linejoin="round"><path d="M12 4v10.5M7.5 10.5 12 15l4.5-4.5M5 19.5h14"/></svg>
|
||
</button>
|
||
<span class="it-more">···</span>
|
||
<div class="it-lbl">
|
||
<div class="a">Personality Data</div>
|
||
<div class="b">ID Card</div>
|
||
</div>
|
||
</div>
|
||
<div class="id-body">
|
||
<div class="id-fields">
|
||
<div class="id-f"><div class="l">ID Number</div><div class="v">326547624</div></div>
|
||
<div class="id-f"><div class="l">Policy Number</div><div class="v">CA326547624</div></div>
|
||
<div class="id-f"><div class="l">Residence</div><div class="v">California, USA</div></div>
|
||
</div>
|
||
<div class="qr" aria-hidden="true">
|
||
<svg viewBox="0 0 86 86" width="100%" height="100%">
|
||
<g fill="#181a24">
|
||
<rect x="0" y="0" width="24" height="24" rx="3"/><rect x="6" y="6" width="12" height="12" fill="#fff"/><rect x="9" y="9" width="6" height="6"/>
|
||
<rect x="62" y="0" width="24" height="24" rx="3"/><rect x="68" y="6" width="12" height="12" fill="#fff"/><rect x="71" y="9" width="6" height="6"/>
|
||
<rect x="0" y="62" width="24" height="24" rx="3"/><rect x="6" y="68" width="12" height="12" fill="#fff"/><rect x="9" y="71" width="6" height="6"/>
|
||
<rect x="32" y="4" width="6" height="6"/><rect x="44" y="4" width="6" height="6"/><rect x="32" y="14" width="6" height="6"/><rect x="50" y="12" width="6" height="6"/>
|
||
<rect x="4" y="32" width="6" height="6"/><rect x="14" y="40" width="6" height="6"/><rect x="24" y="32" width="6" height="6"/><rect x="34" y="28" width="6" height="6"/>
|
||
<rect x="44" y="30" width="6" height="6"/><rect x="54" y="36" width="6" height="6"/><rect x="64" y="30" width="6" height="6"/><rect x="76" y="34" width="6" height="6"/>
|
||
<rect x="6" y="48" width="6" height="6"/><rect x="18" y="52" width="6" height="6"/><rect x="30" y="44" width="6" height="6"/><rect x="42" y="44" width="6" height="6"/>
|
||
<rect x="54" y="48" width="6" height="6"/><rect x="68" y="46" width="6" height="6"/><rect x="80" y="50" width="6" height="6"/><rect x="34" y="56" width="6" height="6"/>
|
||
<rect x="46" y="58" width="6" height="6"/><rect x="58" y="60" width="6" height="6"/><rect x="72" y="58" width="6" height="6"/><rect x="82" y="62" width="4" height="6"/>
|
||
<rect x="32" y="70" width="6" height="6"/><rect x="44" y="72" width="6" height="6"/><rect x="36" y="80" width="6" height="6"/><rect x="56" y="72" width="6" height="6"/>
|
||
<rect x="66" y="70" width="6" height="6"/><rect x="78" y="72" width="6" height="6"/><rect x="50" y="80" width="6" height="6"/><rect x="72" y="80" width="6" height="6"/>
|
||
</g>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="sec-head">
|
||
<div class="sec-title">Buy Insurance</div>
|
||
<button class="sec-link">View All</button>
|
||
</div>
|
||
<div class="buy-grid">
|
||
<button class="buy-card bc-dark" data-toast="Health Insurance selected — $214/mo">
|
||
<span class="bc-top">
|
||
<span class="bc-ic"><svg width="17" height="17" viewBox="0 0 24 24" fill="#fff"><path d="M12 20.5s-7.5-4.7-9.2-9A5.2 5.2 0 0 1 12 6.6a5.2 5.2 0 0 1 9.2 4.9c-1.7 4.3-9.2 9-9.2 9Z"/></svg></span>
|
||
<span class="bc-ar"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8.5 7H17v8.5"/></svg></span>
|
||
</span>
|
||
<div class="bc-t">Health Insurance</div>
|
||
<div class="bc-p">$214<small>/mo</small></div>
|
||
</button>
|
||
<button class="buy-card bc-light" data-toast="Bike Insurance selected — $112/mo">
|
||
<span class="bc-top">
|
||
<span class="bc-ic"><svg width="17" height="17" viewBox="0 0 24 24" fill="#7b5cf6"><circle cx="12" cy="7.5" r="3"/><path d="M12 11.5c-3.6 0-6 2.6-6 6V21h12v-3.5c0-3.4-2.4-6-6-6Z"/></svg></span>
|
||
<span class="bc-ar"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8.5 7H17v8.5"/></svg></span>
|
||
</span>
|
||
<div class="bc-t">Bike Insurance</div>
|
||
<div class="bc-p">$112<small>/mo</small></div>
|
||
</button>
|
||
</div>
|
||
</section>
|
||
|
||
</div><!-- /screens -->
|
||
|
||
<!-- BACKDROP -->
|
||
<div class="backdrop" id="backdrop"></div>
|
||
|
||
<!-- TAB BAR -->
|
||
<nav class="tabbar" id="tabbar" aria-label="Primary navigation">
|
||
<button class="tb on" data-go="home" aria-label="Home">
|
||
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m4 10.5 8-6.5 8 6.5V19a1.5 1.5 0 0 1-1.5 1.5H14v-6h-4v6H5.5A1.5 1.5 0 0 1 4 19v-8.5Z"/></svg>
|
||
<span class="tl">Home</span><span class="tdot"></span>
|
||
</button>
|
||
<button class="tb" data-go="policies" aria-label="Policies">
|
||
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2.8 5 5.2v5.6c0 4.6 3 8.7 7 10.7 4-2 7-6.1 7-10.7V5.2L12 2.8Z"/><path d="m9.2 11.6 2 2 3.6-3.8"/></svg>
|
||
<span class="tl">Policies</span><span class="tdot"></span>
|
||
</button>
|
||
<div class="fab-slot">
|
||
<button class="fab" id="fabBtn" aria-label="Quick actions">
|
||
<svg width="25" height="25" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"><path d="M12 5.8v12.4M5.8 12h12.4"/></svg>
|
||
</button>
|
||
</div>
|
||
<button class="tb" data-go="benefits" aria-label="Benefits">
|
||
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.5 4.5 15.6 8l3.5 1.1-3.5 1.1-1.1 3.5-1.1-3.5L9.9 9.1 13.4 8l1.1-3.5Z"/><path d="M19 14.2l.6 1.7 1.7.6-1.7.6-.6 1.7-.6-1.7-1.7-.6 1.7-.6.6-1.7Z"/><path d="M6.5 14.5l5 5M7.8 13.2l1.4 1.4" opacity=".9"/></svg>
|
||
<span class="tl">Benefits</span><span class="tdot"></span>
|
||
</button>
|
||
<button class="tb" data-go="buy" aria-label="Buy">
|
||
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 5h2l2.2 11h9.6l2-8H7.1"/><circle cx="10" cy="19.5" r="1.4"/><circle cx="17" cy="19.5" r="1.4"/></svg>
|
||
<span class="tl">Buy</span><span class="tdot"></span>
|
||
</button>
|
||
</nav>
|
||
|
||
<!-- SHEET -->
|
||
<div class="sheet" id="sheet" aria-hidden="true">
|
||
<div class="grab" id="grab">
|
||
<div class="grab-pill"></div>
|
||
<div class="drag-hint" id="dragHint">pull up · swipe down to close</div>
|
||
</div>
|
||
|
||
<div class="stabs" id="stabs">
|
||
<button class="stab on" data-stab="actions">Actions</button>
|
||
<button class="stab" data-stab="agents">Agents</button>
|
||
<button class="stab" data-stab="support">Support</button>
|
||
</div>
|
||
|
||
<div class="sbody">
|
||
<!-- ACTIONS (default) -->
|
||
<div class="spage on" id="spg-actions">
|
||
<div class="sh-title">Quick Actions</div>
|
||
<div class="act-grid">
|
||
<button class="act" data-toast="Starting a new policy…">
|
||
<span class="act-ic ai-p"><svg width="19" height="19" viewBox="0 0 24 24" fill="#7b5cf6"><path d="M12 2.8 5 5.2v5.6c0 4.6 3 8.7 7 10.7 4-2 7-6.1 7-10.7V5.2L12 2.8Z"/><path d="M12 8.5v6M9 11.5h6" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg></span>
|
||
<span class="act-t">New Policy</span><span class="act-s">Car, health, home</span>
|
||
</button>
|
||
<button class="act" data-toast="Claim form opened…">
|
||
<span class="act-ic ai-o"><svg width="19" height="19" viewBox="0 0 24 24" fill="#f2a03f"><path d="M6.5 3.5h8L19 8v11a1.5 1.5 0 0 1-1.5 1.5h-11A1.5 1.5 0 0 1 5 19V5a1.5 1.5 0 0 1 1.5-1.5Z"/><path d="M9 13h6M9 16.5h4" stroke="#fff" stroke-width="1.7" stroke-linecap="round"/></svg></span>
|
||
<span class="act-t">File a Claim</span><span class="act-s">Under 2 minutes</span>
|
||
</button>
|
||
<button class="act" data-toast="Renewal options…">
|
||
<span class="act-ic ai-g"><svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="#12b76a" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round"><path d="M20 12a8 8 0 1 1-2.3-5.6"/><path d="M20 3.8V7h-3.2"/></svg></span>
|
||
<span class="act-t">Renew Plan</span><span class="act-s">Expires in 15 days</span>
|
||
</button>
|
||
<button class="act" data-toast="Connecting to an expert…">
|
||
<span class="act-ic ai-b"><svg width="19" height="19" viewBox="0 0 24 24" fill="#3e9bf0"><path d="M12 3.8c-4.7 0-8.5 3.1-8.5 7 0 2.3 1.3 4.3 3.3 5.6l-.9 3.3 3.6-1.7c.8.2 1.6.3 2.5.3 4.7 0 8.5-3.1 8.5-7s-3.8-7.5-8.5-7.5Z"/></svg></span>
|
||
<span class="act-t">Chat Expert</span><span class="act-s">Online now</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- AGENTS -->
|
||
<div class="spage" id="spg-agents">
|
||
<div class="sh-title">Your Agents</div>
|
||
<div class="ag-row">
|
||
<span class="ag-ava" style="background:#ffe0ec">👩🏾</span>
|
||
<div><div class="ag-n">Sarah Kimani</div><div class="ag-r">Motor insurance · Online</div></div>
|
||
<button class="ag-btn" data-toast="Chatting with Sarah…">Chat</button>
|
||
</div>
|
||
<div class="ag-row">
|
||
<span class="ag-ava" style="background:#e3ecff">👨🏼</span>
|
||
<div><div class="ag-n">David Otieno</div><div class="ag-r">Health plans · Online</div></div>
|
||
<button class="ag-btn" data-toast="Chatting with David…">Chat</button>
|
||
</div>
|
||
<div class="ag-row">
|
||
<span class="ag-ava" style="background:#f1e7ff">👩🏻</span>
|
||
<div><div class="ag-n">Grace Wanjiru</div><div class="ag-r">Claims specialist · Away</div></div>
|
||
<button class="ag-btn" data-toast="Calling Grace…">Call</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SUPPORT -->
|
||
<div class="spage" id="spg-support">
|
||
<div class="sh-title">Support</div>
|
||
<button class="sup-row" data-toast="Opening help center…">
|
||
<span class="sup-ic ai-p"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#7b5cf6" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M9.6 9.4a2.6 2.6 0 0 1 5 .9c0 1.6-2.4 2-2.4 3.2M12.1 17h.01"/></svg></span>
|
||
Help Center <span class="chev">›</span>
|
||
</button>
|
||
<button class="sup-row" data-toast="Opening WhatsApp…">
|
||
<span class="sup-ic ai-g"><svg width="18" height="18" viewBox="0 0 24 24" fill="#12b76a"><path d="M12 3.8c-4.7 0-8.5 3.1-8.5 7 0 2.3 1.3 4.3 3.3 5.6l-.9 3.3 3.6-1.7c.8.2 1.6.3 2.5.3 4.7 0 8.5-3.1 8.5-7s-3.8-7.5-8.5-7.5Z"/></svg></span>
|
||
WhatsApp Us <span class="chev">›</span>
|
||
</button>
|
||
<button class="sup-row" data-toast="Composing email…">
|
||
<span class="sup-ic ai-b"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#3e9bf0" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3.5" y="5.5" width="17" height="13" rx="2.5"/><path d="m4.5 7.5 7.5 6 7.5-6"/></svg></span>
|
||
hello@insurepay.app <span class="chev">›</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="toast" id="toast">Done ✓</div>
|
||
<div class="home-ind"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
/* ============ SCREEN ROUTER ============ */
|
||
const screens = document.querySelectorAll('.screen');
|
||
const tabs = document.querySelectorAll('.tabbar .tb');
|
||
function go(name){
|
||
screens.forEach(s => s.classList.toggle('on', s.id === 'scr-' + name));
|
||
tabs.forEach(t => t.classList.toggle('on', t.dataset.go === name));
|
||
}
|
||
document.querySelectorAll('[data-go]').forEach(el => {
|
||
el.addEventListener('click', () => { go(el.dataset.go); closeSheet(); });
|
||
});
|
||
|
||
/* ============ TOAST ============ */
|
||
const toast = document.getElementById('toast');
|
||
let toastT;
|
||
function showToast(msg){
|
||
toast.textContent = msg;
|
||
toast.classList.add('show');
|
||
clearTimeout(toastT);
|
||
toastT = setTimeout(() => toast.classList.remove('show'), 2200);
|
||
}
|
||
document.querySelectorAll('[data-toast]').forEach(el => {
|
||
el.addEventListener('click', () => showToast(el.dataset.toast));
|
||
});
|
||
|
||
/* ============ CHIPS (Benefits) ============ */
|
||
document.querySelectorAll('#chips .chip').forEach(c => {
|
||
c.addEventListener('click', () => {
|
||
document.querySelectorAll('#chips .chip').forEach(x => x.classList.remove('on'));
|
||
c.classList.add('on');
|
||
});
|
||
});
|
||
|
||
/* ============ SHEET ============ */
|
||
const sheet = document.getElementById('sheet');
|
||
const backdrop = document.getElementById('backdrop');
|
||
const tabbar = document.getElementById('tabbar');
|
||
const fabBtn = document.getElementById('fabBtn');
|
||
const grab = document.getElementById('grab');
|
||
const dragHint = document.getElementById('dragHint');
|
||
let sheetMode = 'closed'; // closed | peek | expanded
|
||
|
||
function setMode(m){
|
||
sheetMode = m;
|
||
const open = m !== 'closed';
|
||
sheet.classList.toggle('open', open);
|
||
sheet.classList.toggle('peek', m === 'peek');
|
||
sheet.classList.toggle('expanded', m === 'expanded');
|
||
backdrop.classList.toggle('open', open);
|
||
tabbar.classList.toggle('ghost', open);
|
||
sheet.setAttribute('aria-hidden', String(!open));
|
||
if(m === 'expanded') switchStab('actions');
|
||
dragHint.textContent = m === 'peek' ? 'pull up · swipe down to close' : m === 'expanded' ? 'drag down to collapse' : '';
|
||
}
|
||
function openSheet(){ setMode('peek') }
|
||
function closeSheet(){ setMode('closed') }
|
||
fabBtn.addEventListener('click', () => sheetMode === 'closed' ? openSheet() : closeSheet());
|
||
backdrop.addEventListener('click', closeSheet);
|
||
|
||
/* sheet tabs */
|
||
function switchStab(k){
|
||
document.querySelectorAll('.stab').forEach(s => s.classList.toggle('on', s.dataset.stab === k));
|
||
document.querySelectorAll('.spage').forEach(p => p.classList.toggle('on', p.id === 'spg-' + k));
|
||
}
|
||
document.querySelectorAll('.stab').forEach(s => s.addEventListener('click', () => switchStab(s.dataset.stab)));
|
||
|
||
/* drag logic — Y only, sheet anchored left/right (no translateX) */
|
||
let dragging = false, sy = 0, cy = 0, ly = 0, vy = 0, lt = 0;
|
||
grab.addEventListener('pointerdown', e => {
|
||
dragging = true;
|
||
grab.setPointerCapture(e.pointerId);
|
||
sy = cy = ly = e.clientY; vy = 0; lt = performance.now();
|
||
sheet.classList.add('drag');
|
||
});
|
||
grab.addEventListener('pointermove', e => {
|
||
if(!dragging) return;
|
||
const now = performance.now();
|
||
cy = e.clientY;
|
||
vy = (cy - ly) / Math.max(1, now - lt);
|
||
ly = cy; lt = now;
|
||
const dy = cy - sy;
|
||
let ty = 0;
|
||
if(sheetMode === 'peek') ty = Math.max(dy, -140);
|
||
if(sheetMode === 'expanded') ty = Math.max(dy, 0);
|
||
sheet.style.transform = `translateY(${ty}px)`;
|
||
dragHint.textContent =
|
||
sheetMode === 'peek' && dy < -14 ? 'release to expand ↑' :
|
||
sheetMode === 'expanded' && dy > 14 ? 'release to collapse ↓' :
|
||
sheetMode === 'peek' ? 'pull up · swipe down to close' : 'drag down to collapse';
|
||
});
|
||
function endDrag(){
|
||
if(!dragging) return;
|
||
dragging = false;
|
||
sheet.classList.remove('drag');
|
||
sheet.style.transform = '';
|
||
const dy = cy - sy;
|
||
const up = dy < -26 || (dy < -12 && vy < -0.2);
|
||
const down = dy > 36 || (dy > 18 && vy > 0.28);
|
||
if(sheetMode === 'expanded' && down) return setMode('peek');
|
||
if(sheetMode === 'peek' && up) return setMode('expanded');
|
||
if(sheetMode === 'peek' && down) return closeSheet();
|
||
setMode(sheetMode); // snap back
|
||
}
|
||
grab.addEventListener('pointerup', endDrag);
|
||
grab.addEventListener('pointercancel', endDrag);
|
||
|
||
/* taps on handle = toggle */
|
||
let tapT, moved = false;
|
||
grab.addEventListener('pointerdown', () => { moved = false; });
|
||
grab.addEventListener('pointermove', () => { if(Math.abs(cy - sy) > 8) moved = true; });
|
||
grab.addEventListener('click', () => {
|
||
if(moved) return;
|
||
setMode(sheetMode === 'peek' ? 'expanded' : 'peek');
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|