makepad-ports/nav.html
andodeki 7ddd75fb70 Makepad 2.0 ports: rider, koboyo, insurance (+ HTML sources, assessments)
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.
2026-08-04 05:07:18 +00:00

1196 lines
No EOL
53 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
<title>WWDC 4-icon pill nav + FAB · pull sheet</title>
<style>
/* ========== RESET / TOKENS ========== */
*,*::before,*::after{box-sizing:border-box;margin:0}
html,body{height:100%}
body{
margin:0;
font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display",Inter,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
background:#cecfd4;
color:#18181e;
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
}
button{font:inherit;color:inherit}
a{color:inherit}
/* ========== MOBILE APP SHELL 390px ========== */
.app-shell{
width:390px;
max-width:100vw;
min-height:100dvh;
margin:0 auto;
background:#f2f2f5;
position:relative;
overflow:hidden;
display:flex;
flex-direction:column;
}
@media(min-width:440px){
body{background:linear-gradient(180deg,#dddde2,#b8b8be);display:flex;align-items:center;justify-content:center;padding:22px}
.app-shell{
height:812px;
min-height:auto;
border-radius:40px;
box-shadow:0 30px 80px rgba(0,0,0,.26), inset 0 0 0 9px #111217, inset 0 0 0 10px #2a2a30;
}
.island{display:block}
}
.island{display:none;position:absolute;top:10px;left:50%;transform:translateX(-50%);width:96px;height:30px;background:#111;border-radius:18px;z-index:90}
@media(min-width:440px){.island{display:block}}
.statusbar{
height:50px;
flex:0 0 50px;
display:flex;align-items:flex-end;justify-content:space-between;
padding:0 22px 7px;
font-size:14.5px;font-weight:600;color:#2b2b32;
}
/* ---------- article / feed ---------- */
.feed{
flex:1;
overflow-y:auto;
-webkit-overflow-scrolling:touch;
padding:8px 18px 128px;
}
.feed::-webkit-scrollbar{display:none}
.feed-top{
display:flex;justify-content:space-between;align-items:center;
margin:2px 2px 14px;
font-size:15px;color:#8a8a92;
}
.feed-brand{color:#e52b2b;font-weight:800;font-size:20px;letter-spacing:-.3px}
.hero{display:flex;gap:13px;align-items:flex-start}
.thumb{
width:108px;height:108px;flex:0 0 108px;
border-radius:24px;
background:#0f1015;
position:relative;
overflow:hidden;
box-shadow:0 8px 24px rgba(0,0,0,.14);
}
.thumb i{
position:absolute;left:13px;top:16px;
font-style:normal;font-weight:800;font-size:28px;line-height:.92;
color:#b8b8bf;opacity:.5;letter-spacing:-1px;
}
.thumb b{
position:absolute;bottom:13px;left:13px;
font-weight:800;font-size:38px;color:#fff;
text-shadow:0 0 16px rgba(255,255,255,.9);
letter-spacing:-1.5px;
}
h1.headline{
font-size:20.8px;line-height:1.26;font-weight:750;letter-spacing:-.4px;
color:#1b1b20;
}
.byline{
display:flex;align-items:center;gap:9px;
margin-top:11px;font-size:13.2px;color:#74747c;
}
.ava{width:30px;height:30px;border-radius:50%;background:linear-gradient(140deg,#705035,#2a1810);flex:0 0 30px}
.byline strong{color:#2a2a32;font-weight:600}
/* =====================================================
1) BOTTOM NAV — nav1.png / nav2.png
4 ICONS — pill left — FAB right — SAME ROW
===================================================== */
.nav-dock{
position:absolute;
left:14px; right:14px; bottom:20px;
z-index:30;
}
.nav-row{
display:flex;
flex-direction:row;
flex-wrap:nowrap;
align-items:center;
justify-content:space-between;
gap:13px;
width:100%;
}
/* pill white, heavily styled */
.nav-pill{
flex:1 1 0%;
min-width:0;
display:flex;
align-items:center;
gap:3px;
background:#ffffff;
border-radius:9999px;
padding:8px 9px;
box-shadow:
0 10px 32px rgba(0,0,0,.10),
0 1px 4px rgba(0,0,0,.05),
inset 0 0 0 1px rgba(0,0,0,.035);
overflow-x:auto;
scrollbar-width:none;
}
.nav-pill::-webkit-scrollbar{display:none}
/* ——— nav buttons — heavily styled ——— */
.nav-btn{
appearance:none;
-webkit-appearance:none;
border:2px solid transparent;
outline:0;
margin:0;
background:transparent;
color:#6b6b74;
cursor:pointer;
display:inline-flex;
align-items:center;
justify-content:center;
gap:0;
padding:12px 13px;
border-radius:9999px;
flex-shrink:0;
white-space:nowrap;
font-weight:550;
font-size:15px;
line-height:1;
letter-spacing:-.15px;
transition:
background .20s cubic-bezier(.22,1,.36,1),
color .18s ease,
padding .24s cubic-bezier(.22,1,.36,1),
transform .12s ease,
box-shadow .18s ease,
border-color .15s;
position:relative;
user-select:none;
}
.nav-btn:hover{ background:#f4f4f6; color:#3a3a44 }
.nav-btn:active{ transform:scale(.95) }
.nav-btn:focus-visible{
border-color:#7adfff;
box-shadow:0 0 0 3px rgba(80,210,255,.28);
}
/* ACTIVE unmistakable background color */
.nav-btn.is-active{
background:#e8e8ea;
color:#111217;
padding-left:17px;
padding-right:18px;
gap:9px;
box-shadow:
inset 0 1px 2px rgba(0,0,0,.035),
inset 0 0 0 1px rgba(0,0,0,.03);
}
.nav-btn.is-active:hover{ background:#e2e2e5 }
.nav-btn svg{
width:23px;height:23px;
display:block;flex:0 0 23px;
transition:transform .18s ease;
}
.nav-btn.is-active svg{ transform:scale(1.04) }
/* label expand / collapse */
.nav-label{
display:inline-block;
max-width:0;
opacity:0;
overflow:hidden;
transform:translateX(-6px);
white-space:nowrap;
font-weight:640;
font-size:15px;
transition:
max-width .34s cubic-bezier(.22,1,.36,1),
opacity .22s ease,
transform .28s cubic-bezier(.22,1,.36,1),
margin .22s ease;
}
.nav-btn.is-active .nav-label{
max-width:110px;
opacity:1;
transform:translateX(0);
margin-left:2px;
}
/* icon fill swap outline → filled on active */
.ico-fill{display:none}
.nav-btn.is-active .ico-stroke{display:none}
.navbtn.is-active .ico-stroke, .nav-btn.is-active .ico-stroke{display:none !important}
.navbtn.is-active .ico-fill, .nav-btn.is-active .ico-fill{display:block !important}
/* FAB SEPARATE SAME ROW HEAVILY STYLED */
.fab-btn{
flex:0 0 62px;
width:62px;
height:62px;
border-radius:50%;
border:0;
margin:0;
background:radial-gradient(circle at 32% 28%, #23232a 0%, #0f0f14 72%);
color:#fff;
display:grid;
place-items:center;
cursor:pointer;
box-shadow:
0 14px 34px rgba(0,0,0,.24),
0 3px 10px rgba(0,0,0,.12),
inset 0 1px 1px rgba(255,255,255,.09),
inset 0 -1px 2px rgba(0,0,0,.35);
transition: transform .16s ease, box-shadow .16s ease, background .15s, filter .15s;
flex-shrink:0;
position:relative;
z-index:2;
-webkit-tap-highlight-color:transparent;
}
.fab-btn:hover{
transform:translateY(-2px) scale(1.035);
box-shadow:0 18px 44px rgba(0,0,0,.28), 0 3px 10px rgba(0,0,0,.14), inset 0 1px 1px rgba(255,255,255,.09);
background:radial-gradient(circle at 32% 28%, #282832, #14141c 72%);
}
.fab-btn:active{ transform:scale(.93); filter:brightness(.96) }
.fab-btn:focus-visible{ outline:none; box-shadow:0 0 0 3px rgba(90,220,255,.35), 0 12px 30px rgba(0,0,0,.22) }
.fab-btn svg{ width:28px; height:28px; stroke-width:2.3; pointer-events:none }
/* hide nav+fabs when sheet open sheet covers them */
.navrow.sheet-open .nav-pill,
.navrow.sheet-open .fab-btn{
opacity:0;
transform:translateY(10px) scale(.97);
filter:blur(3px);
pointer-events:none;
transition:opacity .22s ease, transform .22s ease, filter .22s ease;
}
/* narrow screens keep 4 icons + FAB on ONE row */
@media (max-width:390px){
.navbtn{ padding:10px 11px }
.navbtn.is-active{ padding-left:14px; padding-right:15px }
.navbtn svg{width:21px;height:21px}
.fab-btn{ width:56px !important; height:56px !important; flex:0 0 56px !important }
.navrow{ gap:10px !important }
.nav-pill{ padding:6px 7px }
}
@media (max-width:350px){
.navb, .navbtn{ padding:9px 9px }
.fab-btn{ width:52px !important; height:52px !important; flex:0 0 52px !important }
}
/* =====================================================
2) PULL CARD — covers bottom — opens via + button
3) PULL HANDLE — pull up reveals 3-tab bar
tabs HIDDEN until pull-up
===================================================== */
.sheet-backdrop{
position:absolute;
inset:0;
background:rgba(18,18,24,.32);
backdrop-filter:blur(5px);
-webkit-backdrop-filter:blur(5px);
opacity:0;
pointer-events:none;
transition:opacity .26s ease;
z-index:40;
border-radius:inherit;
}
.sheet-backdrop.open{ opacity:1; pointer-events:auto }
/* sheet centered, left:12px right:12px NO translateX bug */
.sheet-card{
position:absolute;
left:12px;
right:12px;
bottom:12px;
background:#e9e9ee;
border-radius:26px;
z-index:50;
box-shadow:
0 -14px 50px rgba(0,0,0,.16),
0 -2px 12px rgba(0,0,0,.06),
inset 0 1px 0 rgba(255,255,255,.92);
/* closed below screen */
transform:translateY(calc(100% + 30px));
opacity:0;
pointer-events:none;
transition:transform .38s cubic-bezier(.22,1,.36,1), opacity .28s ease;
display:flex;
flex-direction:column;
overflow:hidden;
touch-action:none;
max-height:calc(100% - 28px);
}
.sheet-card.open{
transform:translateY(0);
opacity:1;
pointer-events:auto;
}
.sheet-card.peek{ height:420px; }
.sheet-card.expanded{ height:650px; }
.sheet-card.dragging{ transition:none !important }
/* drag handle 68px tall */
.sheet-handle{
flex:0 0 auto;
padding:18px 0 10px;
display:flex;
flex-direction:column;
align-items:center;
gap:7px;
cursor:grab;
touch-action:none;
user-select:none;
-webkit-user-select:none;
position:relative;
background:linear-gradient(180deg, rgba(255,255,255,.55), transparent 75%);
}
.sheet-handle:active{ cursor:grabbing }
.grab-pill{
width:44px; height:5px;
border-radius:99px;
background:#c9c9cf;
transition:width .15s ease, background .15s ease;
box-shadow:inset 0 1px 1px rgba(0,0,0,.06);
}
.sheet-card.dragging .grab-pill,
.sheet-handle:hover .grab-pill{ width:60px; background:#b5b5bc }
.drag-hint{
font-size:12px;
font-weight:600;
color:#9a9aa2;
letter-spacing:.01em;
transition:opacity .18s;
}
.sheet-card.dragging .drag-hint{ opacity:.55 }
/* close X inside sheet */
.sheet-close{
position:absolute;
top:13px; right:13px;
width:36px; height:36px;
border-radius:50%;
border:0;
background:rgba(0,0,0,.045);
color:#7a7a82;
cursor:pointer;
display:grid;
place-items:center;
z-index:10;
transition: background .15s, transform .1s, color .15s;
font-size:17px; font-weight:600;
}
.sheet-close:hover{ background:rgba(0,0,0,.09); color:#333 }
.sheet-close:active{ transform:scale(.92) }
/* ===== 3) TABS HIDDEN UNTIL PULL-UP ===== */
.sheet-tabs{
margin:0 16px;
background:#d9d9df;
border-radius:13px;
padding:4px;
display:flex;
gap:4px;
/* hidden in peek */
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 ease,
transform .28s ease,
margin .24s ease;
}
.sheet-card.expanded .sheet-tabs{
max-height:56px;
opacity:1;
transform:translateY(0);
pointer-events:auto;
margin-bottom:10px;
}
.tab-btn{
flex:1;
border:2px solid transparent;
background:transparent;
padding:10px 8px;
border-radius:9px;
font:650 13.8px/1.15 "Inter", system-ui, sans-serif;
color:#6f6f77;
cursor:pointer;
text-align:center;
transition: background .16s ease, color .16s ease, box-shadow .16s ease, transform .1s ease, border-color .15s;
user-select:none;
white-space:nowrap;
}
.tab-btn:hover{ color:#3a3a42 }
.tab-btn:active{ transform:scale(.97) }
.tab-btn:focus-visible{ outline:none; border-color:#7adff5; box-shadow:0 0 0 3px rgba(90,220,255,.28) }
.tab-btn.active{
background:#ffffff;
color:#18181d;
box-shadow:0 2px 8px rgba(0,0,0,.07), 0 1px 2px rgba(0,0,0,.05);
}
/* sheet body */
.sheet-body{
flex:1;
overflow:hidden;
padding:0 18px 20px;
position:relative;
}
.sheet-card.expanded .sheet-body{
overflow-y:auto;
-webkit-overflow-scrolling:touch;
overscroll-behavior:contain;
}
.sheet-body::-webkit-scrollbar{width:0}
/* tab panels */
.tab-panel{ display:none }
.tab-panel.active{ display:block; animation:tabIn .24s cubic-bezier(.22,1,.36,1) }
@keyframes tabIn{ from{ opacity:0; transform:translateY(7px) } to{ opacity:1; transform:translateY(0) } }
/* ===== 4a) 4-GRID MENU BUTTONS default sheet content ===== */
.menu-grid{
display:grid;
grid-template-columns:1fr 1fr;
gap:12px;
padding-top:4px;
}
.menu-card{
appearance:none;
-webkit-appearance:none;
border:1.5px solid #e5e5e8;
background:#ffffff;
border-radius:20px;
padding:20px 14px 16px;
text-align:center;
cursor:pointer;
color:#2a2a32;
font-family:inherit;
box-shadow:0 4px 16px rgba(0,0,0,.045), 0 1px 2px rgba(0,0,0,.03);
transition:
transform .14s ease,
box-shadow .18s ease,
background .15s ease,
border-color .15s ease;
user-select:none;
}
.menu-card:hover{
transform:translateY(-2px);
box-shadow:0 10px 28px rgba(0,0,0,.09), 0 2px 6px rgba(0,0,0,.04);
background:#fcfcfe;
border-color:#d8d8de;
}
.menu-card:active{ transform:translateY(0) scale(.97) }
.menu-card:focus-visible{
outline:none;
border-color:#6adff5;
box-shadow:0 0 0 3px rgba(80,210,255,.28), 0 4px 16px rgba(0,0,0,.06);
}
.menu-card .mi{
width:36px;height:36px;
margin:0 auto 10px;
display:grid;place-items:center;
border-radius:12px;
background:#f3f3f6;
transition:background .15s;
}
.menu-card:hover .mi{ background:#ececf0 }
.menu-card strong{
display:block;
font-size:15px;
font-weight:680;
letter-spacing:-.2px;
margin-bottom:3px;
}
.menu-card span{
font-size:12.5px;
color:#8a8a92;
font-weight:500;
}
/* profile */
.profile-top{display:flex;align-items:center;gap:14px;margin:4px 0 16px}
.p-avatar{
width:68px;height:68px;border-radius:20px;
background:linear-gradient(145deg,#6d3f26,#2b1710);
display:grid;place-items:center;
color:#f7ddd0;font-weight:750;font-size:22px;
flex:0 0 68px;
box-shadow:0 6px 20px rgba(90,45,20,.18);
position:relative;overflow:hidden;
}
.p-avatar::after{content:"";position:absolute;inset:0;background:radial-gradient(55px 36px at 30% 28%, rgba(255,220,190,.22), transparent 70%)}
.profile-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:9px;margin:12px 0 16px}
.stat-card{
background:#fff;border-radius:16px;padding:13px 8px;text-align:center;
box-shadow:0 1px 4px rgba(0,0,0,.045);
border:1px solid #ececee;
}
.stat-card b{display:block;font-size:18.5px;font-weight:760;letter-spacing:-.2px}
.stat-card i{font-style:normal;font-size:11.8px;color:#8a8a92;font-weight:500}
/* profile list heavily styled buttons */
.plist{display:flex;flex-direction:column;gap:9px}
.plist-btn{
appearance:none;-webkit-appearance:none;
width:100%;
text-align:left;
background:#ffffff;
border:1px solid #e6e6ea;
border-radius:15px;
padding:14px 15px;
font:520 14.8px/1.35 inherit;
color:#22222a;
cursor:pointer;
display:flex;
align-items:center;
justify-content:space-between;
box-shadow:0 1px 3px rgba(0,0,0,.035);
transition:background .14s ease, transform .1s ease, border-color .15s ease, box-shadow .15s ease;
}
.plist-btn:hover{ background:#f7f7f9; border-color:#dcdce2; transform:translateY(-1px); box-shadow:0 4px 14px rgba(0,0,0,.06) }
.plist-btn:active{ transform:translateY(0) scale(.985) }
.plist-btn:focus-visible{ outline:none; border-color:#6adff5; box-shadow:0 0 0 3px rgba(80,210,255,.25), 0 1px 4px rgba(0,0,0,.05) }
.plist-btn em{ font-style:normal; color:#a9a9b3; font-size:13px; font-weight:500 }
.plist-btn.danger{
color:#d92d20;
border-color:#f2c7c5;
background:#fffafa;
}
.plist-btn.danger:hover{ background:#fff0ef; border-color:#ebb4b1 }
/* preferences sheet1.png match */
.pref-head{
display:flex;align-items:center;justify-content:space-between;
margin-bottom:6px;padding-right:4px;
}
.pref-title{ font-size:21px; font-weight:650; color:#6f6f76; letter-spacing:-.15px }
.pref-tune{
color:#a6a6ae; background:transparent; border:0; cursor:pointer;
padding:6px; border-radius:10px; transition:background .15s;
font-size:20px; line-height:1;
}
.pref-tune:hover{ background:#dedee3; color:#555 }
.theme3{ display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-bottom:18px }
.theme-opt{
appearance:none; -webkit-appearance:none;
border:2px solid transparent;
background:#f1f1f4;
border-radius:20px;
padding:20px 10px 16px;
text-align:center;
cursor:pointer;
color:#8e8e96;
font-family:inherit;
transition: all .18s ease;
user-select:none;
}
.theme-opt:hover{ background:#e6e6ea; color:#5a5a62; transform:translateY(-1px) }
.theme-opt:active{ transform:translateY(0) scale(.97) }
.theme-opt:focus-visible{ outline:none; border-color:#6adff5; box-shadow:0 0 0 3px rgba(80,210,255,.25) }
.theme-opt.active{
background:#ffffff;
color:#18181c;
border-color:#ececec;
box-shadow:0 6px 22px rgba(0,0,0,.07), 0 1px 3px rgba(0,0,0,.04);
transform:translateY(-1px);
}
.theme-opt .ti{ font-size:28px; line-height:1; margin-bottom:10px; display:block }
.theme-opt .tn{ font-size:17.5px; font-weight:550; letter-spacing:-.2px }
/* toggle rows iOS style heavily styled */
.pref-list{ display:flex; flex-direction:column; gap:22px; margin-top:6px }
.pref-row{
display:flex; align-items:center; justify-content:space-between; gap:16px;
padding:3px 2px;
border-radius:12px;
transition:background .14s;
cursor:pointer;
}
.pref-row:hover{ background:rgba(0,0,0,.018) }
.pref-row b{ display:block; font-size:20px; font-weight:720; letter-spacing:-.25px; color:#1b1b20; margin-bottom:2px }
.pref-row span{ color:#9a9aa1; font-size:14.8px; font-weight:450; line-height:1.35 }
/* toggle switch prominent */
.sw{
appearance:none; -webkit-appearance:none;
width:60px; height:32px;
flex:0 0 60px;
background:#d1d1d6;
border-radius:999px;
position:relative;
cursor:pointer;
transition: background .22s ease, box-shadow .2s;
outline:none;
border:2px solid transparent;
box-shadow: inset 0 1px 3px rgba(0,0,0,.1);
}
.sw::after{
content:"";
position:absolute;
top:2px; left:2px;
width:26px; height:26px;
background:linear-gradient(180deg,#fff,#f5f5f7);
border-radius:50%;
box-shadow:0 2px 5px rgba(0,0,0,.14), 0 0 0 1px rgba(0,0,0,.04);
transition: transform .26s cubic-bezier(.22,1,.36,1), width .15s;
}
.sw:checked{
background:linear-gradient(135deg,#3be9f5 0%, #2dd4bf 55%, #2ad8e0 100%);
box-shadow: inset 0 1px 3px rgba(0,120,120,.12), 0 0 0 1px rgba(45,212,191,.18);
}
.sw:checked::after{ transform:translateX(28px) }
.sw:focus-visible{ border-color:#6adff5; box-shadow:0 0 0 3px rgba(58,239,245,.30), inset 0 1px 3px rgba(0,0,0,.09) }
.sw:active::after{ width:29px }
/* pull-up CTA */
.pull-cta{
display:block;width:100%;
margin:2px 0 14px;
background:linear-gradient(180deg,#f7f7f9,#f0f0f3);
border:1.5px dashed #c8c8ce;
border-radius:14px;
padding:12px 14px;
text-align:center;
font:650 13.5px/1.4 inherit;
color:#5a5a62;
cursor:pointer;
transition: background .15s, transform .1s, border-color .15s, color .15s;
user-select:none;
}
.pull-cta:hover{ background:#efeff3; border-color:#b8b8be; color:#3a3a42 }
.pull-cta:active{ transform:scale(.97) }
.sheet.expanded .pull-cta{ display:none }
</style>
</head>
<body>
<div class="app" id="app">
<div class="notch" aria-hidden="true"></div>
<div style="height:50px;display:flex;align-items:flex-end;justify-content:space-between;padding:0 20px 6px;font-size:14.5px;font-weight:600;color:#2a2a30"><span>9:41</span><span style="font-size:12.5px;opacity:.78">◴ ● ●</span></div>
<main class="feed" style="flex:1;overflow-y:auto;padding:8px 18px 130px;-webkit-overflow-scrolling:touch">
<!-- CNET / WWDC card nav2.png -->
<div style="display:flex;justify-content:space-between;align-items:center;margin:4px 2px 12px;font-size:14.8px;color:#8a8a92">
<span>Tech</span>
<span style="color:#e52b2b;font-weight:800;font-size:20px;letter-spacing:-.3px">CNET</span>
</div>
<div style="display:flex;gap:13px;align-items:flex-start">
<div style="width:108px;height:108px;flex:0 0 108px;border-radius:22px;background:#0f1015;position:relative;overflow:hidden;box-shadow:0 8px 22px rgba(0,0,0,.14)">
<div style="position:absolute;left:13px;top:15px;color:#b9b9c0;font-weight:800;font-size:26px;line-height:.92;opacity:.5;letter-spacing:-1px">WW<br>DC</div>
<div style="position:absolute;bottom:12px;left:13px;color:#fff;font-weight:800;font-size:36px;text-shadow:0 0 14px rgba(255,255,255,.9);letter-spacing:-1.5px">26</div>
</div>
<div style="min-width:0;flex:1">
<h1>WWDC 2026: News on Siri, iOS 27, Tim Cook and More (Live)</h1>
<div style="display:flex;align-items:center;gap:9px;margin-top:10px;font-size:13px;color:#6f6f76">
<div style="width:30px;height:30px;border-radius:50%;background:linear-gradient(140deg,#705035,#281610);flex:0 0 30px"></div>
<div><strong style="color:#2b2b32">David Lumb</strong> • June 7, 2026 10:06 p.m</div>
</div>
</div>
</div>
<div style="color:#8d8d95;font-size:13.6px;line-height:1.55;margin-top:16px">
<p style="margin-bottom:9px">Live from Apple Park — iOS 27 Liquid Glass, on-device Siri 2.0.</p>
<p style="color:#9a9aa1;font-size:12.6px;line-height:1.55">
<b style="color:#5a5a62">4-icon pill</b> Home • Explore • Saved • Reading — <b style="color:#5a5a62">FAB separate, same row</b><br>
Tap any icon → active pill background <b>#e8e8ea</b> moves, label expands, icon fills.<br>
Tap <b>+</b> → pull-card covers nav.<br>
Pull handle up → 3 tabs appear: Menu • Profile • Preferences.
</p>
</div>
</main>
<!-- =========================================================
1) BOTTOM NAV — nav1.png / nav2.png
4 ICONS — PILL + SEPARATE FAB — SAME ROW
========================================================= -->
<div style="position:absolute;left:12px;right:12px;bottom:20px;z-index:30" id="navDockWrap">
<!-- FLEX ROW !important never wraps guarantees FAB stays right of pill -->
<div id="navRow"
style="display:flex;flex-direction:row;flex-wrap:nowrap;align-items:center;justify-content:space-between;gap:12px;width:100%">
<!-- PILL — 4 ICONS -->
<nav aria-label="Primary navigation"
style="flex:1 1 0%;min-width:0;display:flex;align-items:center;gap:3px;background:#ffffff;border-radius:9999px;padding:8px 8px;box-shadow:0 10px 30px rgba(0,0,0,.10),0 1px 3px rgba(0,0,0,.05),inset 0 0 0 1px rgba(0,0,0,.035);overflow-x:auto;scrollbar-width:none"
id="pillNav">
<!-- 1 — HOME — active matches nav1.png / nav2.png left -->
<button type="button" class="navb nav-btn is-active" data-nav="home" aria-current="page"
style="border:2px solid transparent;outline:none;margin:0;background:#e8e8ea;color:#111217;cursor:pointer;display:inline-flex;align-items:center;gap:8px;padding:12px 16px 12px 16px;border-radius:9999px;flex-shrink:0;white-space:nowrap;font:600 15px/1 inherit;letter-spacing:-.15px;transition:all .2s cubic-bezier(.22,1,.36,1);box-shadow:inset 0 1px 2px rgba(0,0,0,.035)">
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" style="flex:0 0 22px"><path d="M11.45 3.25a1.6 1.6 0 0 1 1.1 0l7.9 4.8a1.5 1.5 0 0 1 .8 1.35V19a2 2 0 0 1-2 2H4.75a2 2 0 0 1-2-2V9.35c0-.56.32-1.1.82-1.37l8.03-4.73Z"/><rect x="9.2" y="13.6" width="5.6" height="1.9" rx=".95" fill="#f2f2f4"/></svg>
<span style="font-weight:650">Home</span>
</button>
<!-- 2 — EXPLORE / decider — nav1.png middle, nav2.png second -->
<button class="navb nav-btn" type="button" aria-label="Explore" data-nav="explore"
style="border:2px solid transparent;outline:0;margin:0;background:transparent;color:#5b5b66;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:12px 13px;border-radius:9999px;flex-shrink:0;transition:all .18s">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.95" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M15.4 8.6l-4.6 2.1-2.1 4.7 4.6-2.1 2.1-4.6z"/></svg>
<span style="max-width:0;opacity:0;overflow:hidden;white-space:nowrap;font-weight:600">Explore</span>
</button>
<!-- 3 — SAVED / bookmark — nav1.png right, nav2.png third -->
<button class="navb nav-btn" type="button" aria-label="Saved" data-nav="saved"
style="border:2px solid transparent;outline:0;margin:0;background:transparent;color:#5b5b66;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:12px 13px;border-radius:9999px;flex-shrink:0;transition:all .18s;white-space:nowrap">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 3.7h10a1.3 1.3 0 0 1 1.3 1.3v15.4l-6.3-3.9-6.3 3.9V5A1.3 1.3 0 0 1 7 3.7Z"/><path d="M10 9.3h4"/></svg>
<span style="max-width:0;opacity:0;overflow:hidden;white-space:nowrap;font-weight:600">Saved</span>
</button>
<!-- 4 — READING / book-open — nav2.png fourth -->
<button class="navb nav-btn" type="button" aria-label="Reading" data-nav="reading"
style="border:2px solid transparent;outline:0;margin:0;background:transparent;color:#5b5b66;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:12px 13px;border-radius:9999px;flex-shrink:0;white-space:nowrap;font:500 15px/1 inherit;transition:all .18s">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.85" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4.4 5.5C4.4 4.35 5.45 3.5 6.6 3.75l3.7.78A2.7 2.7 0 0 1 12.6 7.1v13.2a2.3 2.3 0 0 0-2.15-1.25H5.9A1.7 1.7 0 0 1 4.2 17.35V5.5Z"/><path d="M12.6 7v13.4c.65-.25 1.4-.25 2.05-.07l3.5.72c1.15.25 2.15-.6 2.15-1.75V7.2"/></svg>
<span style="max-width:0;opacity:0;overflow:hidden;white-space:nowrap;font-weight:600">Reading</span>
</button>
</nav>
<!-- FAB — SEPARATE — SAME ROW — RIGHT -->
<button id="fabBtn" type="button" aria-expanded="false" aria-label="Open menu sheet"
style="flex:0 0 60px;width:60px;height:60px;border-radius:50%;border:0;margin:0;background:radial-gradient(circle at 32% 28%,#23232c,#0f0f14 70%);color:#fff;display:grid;place-items:center;cursor:pointer;flex-shrink:0;box-shadow:0 12px 30px rgba(0,0,0,.24),0 2px 8px rgba(0,0,0,.12),inset 0 1px 1px rgba(255,255,255,.07);transition:transform .15s,box-shadow .16s;z-index:2;-webkit-tap-highlight-color:transparent">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3" stroke-linecap="round" width="26" height="26" aria-hidden="true"><path d="M12 5.8v12.4M5.8 12h12.4"/></svg>
</button>
</div>
</div>
<!-- ===== 2) PULL CARD — covers bottom — opens via + button ===== -->
<!-- backdrop sits ABOVE nav (z 40 > nav 30), BELOW sheet (z 50) -->
<div id="sheetBackdrop" aria-hidden="true"
style="position:absolute;inset:0;background:rgba(18,18,24,.32);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);opacity:0;pointer-events:none;transition:opacity .26s ease;z-index:40;border-radius:inherit"></div>
<!-- sheet ALWAYS centered, NEVER cut off left -->
<div id="sheet" role="dialog" aria-modal="true" aria-hidden="true"
style="position:absolute;left:10px;right:10px;bottom:10px;background:#e9e9ee;border-radius:26px;z-index:50;box-shadow:0 -14px 50px rgba(0,0,0,.18),inset 0 1px 0 rgba(255,255,255,.9);transform:translateY(calc(100% + 28px));opacity:0;pointer-events:none;transition:transform .36s cubic-bezier(.22,1,.36,1),opacity .28s;display:flex;flex-direction:column;overflow:hidden;touch-action:none;max-height:calc(100% - 28px)">
<!-- 3) PULL HANDLE — pull up to reveal tabs -->
<div id="sheetHandle"
style="flex:0 0 auto;padding:18px 0 10px;display:flex;flex-direction:column;align-items:center;gap:7px;cursor:grab;touch-action:none;user-select:none;background:linear-gradient(180deg,rgba(255,255,255,.55),transparent)">
<span id="grabBar" style="display:block;width:44px;height:5px;border-radius:99px;background:#c9c9cf;transition:width .15s,background .15s;box-shadow:inset 0 1px 1px rgba(0,0,0,.06)"></span>
<div id="dragText" style="font-size:12px;font-weight:600;color:#9a9aa2;letter-spacing:.01em;transition:opacity .18s">pull up • swipe down to close</div>
<button id="sheetClose" aria-label="Close sheet"
style="position:absolute;top:12px;right:12px;width:34px;height:34px;border-radius:50%;border:0;background:rgba(0,0,0,.05);color:#777;cursor:pointer;display:grid;place-items:center;font-size:16px;font-weight:700">×</button>
</div>
<!-- 3) TABBED BAR — HIDDEN UNTIL PULL-UP -->
<div id="sheetTabs" role="tablist" aria-label="Sheet sections"
style="margin:0 16px;background:#d9d9df;border-radius:13px;padding:4px;display:flex;gap:4px;max-height:0;opacity:0;transform:translateY(-6px);overflow:hidden;pointer-events:none;transition:max-height .32s cubic-bezier(.22,1,.36,1),opacity .24s,transform .24s,margin .24s">
<button role="tab" aria-selected="true" data-stab="menu"
class="stab active"
style="flex:1;border:2px solid transparent;background:#fff;padding:10px;border-radius:9px;font:650 14px/1 inherit;color:#18181c;cursor:pointer;box-shadow:0 1px 5px rgba(0,0,0,.07);transition:all .15s">Menu</button>
<button role="tab" aria-selected="false" data-stab="profile"
class="stab"
style="flex:1;border:2px solid transparent;background:transparent;padding:10px;border-radius:9px;font:650 14.5px/1 inherit;color:#6f6f77;cursor:pointer;transition:all .15s">Profile</button>
<button role="tab" aria-selected="false" data-stab="prefs"
class="stab"
style="flex:1;border:2px solid transparent;background:transparent;padding:10px;border-radius:9px;font:650 14.5px/1 inherit;color:#6f6f77;cursor:pointer;transition:all .15s">Preferences</button>
</div>
<div id="sheetBody" style="flex:1;overflow:hidden;padding:0 18px 20px;position:relative">
<!-- 4a) 4-GRID MENU BUTTONS — DEFAULT when + clicked -->
<div id="tp-menu" class="tpan active">
<!-- pull-up CTA — heavily styled button -->
<button id="pullUpBtn" type="button"
style="display:block;width:100%;margin:2px 0 14px;background:linear-gradient(180deg,#f7f7f9,#f0f0f3);border:1.5px dashed #c8c8ce;border-radius:14px;padding:13px 14px;text-align:center;font:650 13.5px/1.4 inherit;color:#5a5a64;cursor:pointer;transition:background .15s,transform .1s,user-select:none">
↑ Pull up — reveal Profile / Preferences tabs
</button>
<div style="font-size:11.5px;font-weight:750;color:#8b8b93;text-transform:uppercase;letter-spacing:.09em;margin:2px 2px 12px">Quick actions</div>
<!-- 4-grid styled buttons -->
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px">
<button type="button" class="menu-card" data-act="new"
style="appearance:none;border:1.5px solid #e6e6ea;background:#ffffff;border-radius:20px;padding:20px 14px 16px;text-align:center;cursor:pointer;color:#22222a;font-family:inherit;box-shadow:0 4px 16px rgba(0,0,0,.045),0 1px 2px rgba(0,0,0,.03);transition:transform .13s ease,box-shadow .18s ease,background .15s,border-color .15s">
<div style="width:38px;height:38px;margin:0 auto 10px;border-radius:12px;background:#f3f3f6;display:grid;place-items:center;font-size:20px;font-weight:700"></div>
<strong style="display:block;font-size:15px;font-weight:680;letter-spacing:-.2px">New Post</strong>
<span style="font-size:12.5px;color:#8a8a92">Share update</span>
</button>
<button type="button" class="menu-card" data-act="explore"
style="appearance:none;border:1.5px solid #e6e6ea;background:#ffffff;border-radius:20px;padding:20px 14px 16px;text-align:center;cursor:pointer;color:#22222a;font-family:inherit;box-shadow:0 4px 16px rgba(0,0,0,.045),0 1px 2px rgba(0,0,0,.03);transition:transform .13s ease,box-shadow .18s ease,background .15s,border-color .15s">
<div style="width:38px;height:38px;margin:0 auto 10px;border-radius:12px;background:#f3f3f6;display:grid;place-items:center">🧭</div>
<strong style="display:block;font-size:15px;font-weight:680;letter-spacing:-.2px">Explore</strong>
<span style="font-size:12.5px;color:#8a8a92">Discover</span>
</button>
<button type="button" class="menu-card" data-act="saved"
style="appearance:none;border:1.5px solid #e6e6ea;background:#ffffff;border-radius:20px;padding:20px 14px 16px;text-align:center;cursor:pointer;color:#22222a;font-family:inherit;box-shadow:0 4px 16px rgba(0,0,0,.045),0 1px 2px rgba(0,0,0,.03);transition:transform .13s ease,box-shadow .18s ease,background .15s,border-color .15s">
<div style="width:38px;height:38px;margin:0 auto 10px;border-radius:12px;background:#f3f3f6;display:grid;place-items:center">🔖</div>
<strong style="display:block;font-size:15px;font-weight:680;letter-spacing:-.2px">Saved</strong>
<span style="font-size:12.5px;color:#8a8a92">Bookmarks</span>
</button>
<button type="button" class="menu-card" data-act="reading"
style="appearance:none;border:1.5px solid #e6e6ea;background:#ffffff;border-radius:20px;padding:20px 14px 16px;text-align:center;cursor:pointer;color:#22222a;font-family:inherit;box-shadow:0 4px 16px rgba(0,0,0,.045),0 1px 2px rgba(0,0,0,.03);transition:transform .13s ease,box-shadow .18s ease,background .15s,border-color .15s">
<div style="width:38px;height:38px;margin:0 auto 10px;border-radius:12px;background:#f3f3f6;display:grid;place-items:center">📖</div>
<strong style="display:block;font-size:15px;font-weight:680;letter-spacing:-.2px">Reading</strong>
<span style="font-size:12.5px;color:#8a8a92">Continue</span>
</button>
</div>
<p style="text-align:center;font-size:11.8px;color:#a9a9b2;margin-top:12px">Pull up for Profile & Preferences tabs →</p>
</div>
<!-- 4b) PROFILE TAB -->
<div id="tp-profile" class="tpan" hidden>
<div style="display:flex;gap:13px;align-items:center;margin:4px 0 14px">
<div style="width:62px;height:62px;border-radius:18px;background:linear-gradient(145deg,#6d3f26,#2b1710);display:grid;place-items:center;color:#f7ddd0;font-weight:750;font-size:20px;flex:0 0 62px;box-shadow:0 6px 18px rgba(90,45,20,.18)">DL</div>
<div>
<div style="font-size:20px;font-weight:760;letter-spacing:-.2px">David Lumb</div>
<div style="font-size:13px;color:#7b7b84;line-height:1.45;margin-top:2px">david.lumb@cnet.com<br>San Francisco • Tech Editor</div>
<span style="display:inline-block;margin-top:6px;background:#e6fbf6;color:#149985;font-size:11px;font-weight:700;padding:3px 9px;border-radius:999px">PRO • WWDC Live</span>
</div>
</div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:10px 0 14px">
<div style="background:#fff;border-radius:15px;padding:12px 8px;text-align:center;box-shadow:0 1px 5px rgba(0,0,0,.045)"><b style="font-size:17px;font-weight:750;display:block">128</b><span style="font-size:11.5px;color:#8a8a92">Articles</span></div>
<div style="background:#fff;border-radius:15px;padding:12px 8px;text-align:center;box-shadow:0 1px 5px rgba(0,0,0,.045)"><b style="font-size:17px;font-weight:750;display:block">4.2k</b><span style="font-size:11.5px;color:#8a8a92">Followers</span></div>
<div style="background:#fff;border-radius:15px;padding:12px 8px;text-align:center;box-shadow:0 1px 5px rgba(0,0,0,.045)"><b style="font-size:17px;font-weight:750;display:block">27</b><span style="font-size:11.5px;color:#8a8a92">Following</span></div>
</div>
<div style="display:flex;flex-direction:column;gap:8px">
<button type="button" style="width:100%;text-align:left;background:#fff;border:1px solid #e6e6ea;border-radius:13px;padding:13px 14px;font:520 14.5px inherit;cursor:pointer;display:flex;justify-content:space-between;transition:background .13s">Edit profile <span style="color:#b0b0b6"></span></button>
<button type="button" style="width:100%;text-align:left;background:#fff;border:1px solid #e6e6ea;border-radius:13px;padding:13px 14px;font:520 14.5px inherit;cursor:pointer;display:flex;justify-content:space-between">Notifications <span style="color:#39d6c5;font-weight:650;font-size:12.8px">On</span></button>
<button type="button" style="width:100%;text-align:left;background:#fff;border:1px solid #e6e6ea;border-radius:13px;padding:13px 14px;font:520 14.5px inherit;cursor:pointer;display:flex;justify-content:space-between">Reading history <span style="color:#a9a9b3;font-size:12.8px">142</span></button>
<button type="button" style="width:100%;text-align:left;background:#fffbfb;border:1px solid #f2c9c7;border-radius:13px;padding:13px 14px;font:600 14.5px inherit;color:#d92d20;cursor:pointer">Sign out</button>
</div>
</div>
<!-- 4c) PREFERENCES TAB — sheet1.png UI -->
<div id="tp-prefs" class="tpan" hidden>
<!-- header like sheet1.png -->
<div style="display:flex;align-items:center;justify-content:space-between;margin:2px 2px 14px;padding-right:4px">
<div style="font-size:20px;font-weight:550;color:#8f8f96;letter-spacing:-.15px">Preferences</div>
<button type="button" aria-label="Tune"
style="border:0;background:transparent;color:#a9a9b0;cursor:pointer;padding:5px;border-radius:9px;font-size:20px;line-height:1">⚙️</button>
</div>
<!-- theme selector exactly sheet1.png: System / Dark / [Light white card] -->
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:20px">
<button type="button" class="theme-btn" data-theme="system"
style="border:0;background:transparent;border-radius:20px;padding:20px 10px 16px;text-align:center;color:#9a9aa0;cursor:pointer;transition:all .16s;font-family:inherit">
<div style="font-size:28px;margin-bottom:8px;opacity:.75">🖥️</div>
<div style="font-size:17px;font-weight:500">System</div>
</button>
<button type="button" class="theme-btn" data-theme="dark"
style="border:0;background:transparent;border-radius:20px;padding:20px 10px 16px;text-align:center;color:#9a9aa0;cursor:pointer;transition:all .16s;font-family:inherit">
<div style="font-size:28px;margin-bottom:8px;opacity:.75">🌙</div>
<div style="font-size:17px;font-weight:500">Dark</div>
</button>
<button type="button" class="theme-btn active" data-theme="light" aria-pressed="true"
style="border:0;background:#ffffff;border-radius:20px;padding:20px 10px 16px;text-align:center;color:#18181c;cursor:pointer;box-shadow:0 6px 22px rgba(0,0,0,.07),0 1px 3px rgba(0,0,0,.04);transition:all .18s;font-family:inherit">
<div style="font-size:28px;margin-bottom:8px">☀️</div>
<div style="font-size:17px;font-weight:600">Light</div>
</button>
</div>
<!-- Sound ON cyan toggle like sheet1.png -->
<div style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:6px 2px;margin-bottom:18px">
<div>
<div style="font-size:21px;font-weight:720;letter-spacing:-.25px">Sound</div>
<div style="color:#9a9aa1;font-size:15px;margin-top:2px">Enable sound effects</div>
</div>
<button type="button" class="tgl on" data-tog="sound" aria-pressed="true"
style="width:60px;height:34px;border-radius:999px;border:0;cursor:pointer;position:relative;flex:0 0 60px;background:linear-gradient(135deg,#3ae9f5,#2fd4bf);box-shadow:inset 0 1px 3px rgba(0,100,100,.12);transition:background .2s">
<span style="position:absolute;top:3px;left:30px;width:28px;height:28px;background:#f6f8fa;border-radius:50%;box-shadow:0 1px 5px rgba(0,0,0,.16);transition:left .24s cubic-bezier(.22,1,.36,1)"></span>
</button>
</div>
<!-- Compact mode OFF gray toggle -->
<div style="display:flex;align-items:center;justify-content:space-between;gap:16px;padding:6px 2px">
<div>
<div style="font-size:21px;font-weight:720;letter-spacing:-.25px">Compact mode</div>
<div style="color:#9a9aa1;font-size:15px;margin-top:2px">More content, less space</div>
</div>
<button type="button" class="tgl" data-tog="compact" aria-pressed="false" id="compactToggleBtn"
style="width:60px;height:34px;border-radius:999px;border:0;cursor:pointer;position:relative;flex:0 0 60px;background:#d1d1d6;box-shadow:inset 0 1px 3px rgba(0,0,0,.09);transition:background .22s">
<span style="position:absolute;top:3px;left:3px;width:28px;height:28px;background:#fff;border-radius:50%;box-shadow:0 1px 4px rgba(0,0,0,.16);transition:left .24s cubic-bezier(.22,1,.36,1)"></span>
</button>
</div>
</div>
</div>
</div>
</div>
<script>
/* ===== 4 ICON NAV — active background color swap ===== */
const navBtns = document.querySelectorAll('.navb, .nav-btn, [data-n]');
function activateNav(btn){
document.querySelectorAll('#pillNav button, .navb, .nav-btn').forEach(n=>{
n.classList.remove('active','is-active');
n.removeAttribute('aria-current');
// reset styles STYLED BUTTONS
n.style.background='transparent';
n.style.color='#6b6b74';
const lb=n.querySelector('.nav-label, span:last-child');
if(lb && lb.textContent.trim().length>2){ lb.style.maxWidth='0'; lb.style.opacity='0'; lb.style.marginLeft='0'; }
// icon outline on / fill off
const s=n.querySelector('.ico-stroke'); const f=n.querySelector('.ico-fill');
if(s) s.style.display='';
if(f) f.style.display='none';
});
// activate clicked
btn.classList.add('active','is-active');
btn.setAttribute('aria-current','page');
btn.style.background='#e7e7ea';
btn.style.color='#111217';
const label=btn.querySelector('.nav-label') || btn.querySelector('span:last-child');
if(label && label.textContent.trim().length>2){ label.style.maxWidth='90px'; label.style.opacity='1'; label.style.marginLeft='6px' }
const fs=btn.querySelector('.ico-stroke'); const ff=btn.querySelector('.ico-fill');
if(fs) fs.style.display='none';
if(ff) ff.style.display='block';
}
document.querySelectorAll('#pillNav button').forEach(b=> b.addEventListener('click', ()=> activateNav(b)));
// ensure initial Home is styled active
activateNav(document.querySelector('#pillNav button[data-n="home"]')||document.querySelector('#pillNav .navb'));
/* ===== SHEET — pull card — covers bottom — opens via + =====
- sheet is position:absolute left:10px;right:10px;bottom:10px
→ centered, never cut off left fixes “cut off vertically on left”
- z-index: sheet 50 > backdrop 35 > nav 30 → always ON TOP of navbar
- + button opens it
*/
const sheet = document.getElementById('sheet');
const backdrop = document.getElementById('sheetBackdrop');
const fabBtn = document.getElementById('fabBtn');
let sheetState = 'closed'; // closed | peek | expanded
function setSheetState(m){
sheetMode = sMode = m;
sheetMode = m; // alias for drag code
sMode = m;
const open = m !== 'closed';
// backdrop
backdrop.style.opacity = open ? '1' : '0';
backdrop.style.pointerEvents = open ? 'auto' : 'none';
// hide nav under sheet
const navRow = document.getElementById('navRow') || document.querySelector('.navrow') || document.querySelector('#bottomNav');
if(navRow){ navRow.style.opacity = open ? '0' : ''; navRow.style.transform = open ? 'translateY(8px)' : ''; navRow.style.filter = open ? 'blur(2px)' : ''; navRow.style.pointerEvents = open ? 'none' : '' }
// sheet transform NO translateX left/right anchor keeps it centered
if(!open){
sheet.style.transform='translateY(calc(100% + 30px))';
sheet.style.opacity='0';
sheet.style.pointerEvents='none';
sheet.setAttribute('aria-hidden','true');
fabBtn.setAttribute('aria-expanded','false');
return;
}
sheet.style.opacity='1';
sheet.style.pointerEvents='auto';
sheet.style.transform='translateY(0)';
sheet.setAttribute('aria-hidden','false');
fabBtn.setAttribute('aria-expanded','true');
// height + tabs visibility TABS ONLY VISIBLE WHEN PULLED UP
const tabs = document.getElementById('sheetTabs');
const body = document.getElementById('sheetBody');
if(m==='expanded'){
sheet.style.height='610px';
if(tabs){ tabs.style.maxHeight='54px'; tabs.style.opacity='1'; tabs.style.transform='translateY(0)'; tabs.style.pointerEvents='auto'; tabs.style.marginBottom='10px' }
if(body) body.style.overflowY='auto';
} else { // peek
sheet.style.height='410px';
if(tabs){ tabs.style.maxHeight='0'; tabs.style.opacity='0'; tabs.style.transform='translateY(-6px)'; tabs.style.pointerEvents='none'; tabs.style.marginBottom='0' }
if(body) body.style.overflow='hidden';
}
}
let sheetMode = 'closed';
let sMode = 'closed';
function openSheet(m){ setSheet(m||'peek') }
function openPeek(){ setSheet('peek') }
function openExpanded(){ setSheet('expanded') }
function closeSheet(){ setSheet('closed') }
fabBtn.addEventListener('click', ()=> sheetMode==='closed' ? openSheet('peek') : closeSheet());
backdrop.addEventListener('click', closeSheet);
document.getElementById('sheetClose').addEventListener('click', closeSheet);
document.getElementById('pullUpBtn')?.addEventListener('click', openExpanded);
document.addEventListener('keydown', e=>{ if(e.key==='Escape' && sheetMode!=='closed') closeSheet() });
/* ===== 3-tab bar — only visible after pull-up =====
a) Menu — 4 grid buttons — DEFAULT
b) Profile
c) Preferences — sheet1.png UI
*/
function switchTab(which){
document.querySelectorAll('.stab').forEach(t=>{
const on = t.dataset.stab===which;
t.classList.toggle('active', on);
t.setAttribute('aria-selected', on);
t.style.background = on ? '#fff' : 'transparent';
t.style.color = on ? '#18181c' : '#6f6f77';
t.style.boxShadow = on ? '0 1px 5px rgba(0,0,0,.07)' : 'none';
});
const panels = {menu:'tp-menu', profile:'tp-profile', prefs:'tp-prefs'};
Object.entries(panels).forEach(([k,id])=>{
const p=document.getElementById(id);
if(!p) return;
const show = k===which;
p.classList.toggle('active', show);
p.hidden = !show;
p.style.display = show ? 'block' : 'none';
});
}
document.querySelectorAll('.stab').forEach(tab=>{
tab.addEventListener('click', ()=>{
const t = tab.dataset.stab;
if(sheetMode!=='expanded'){ openExpanded(); setTimeout(()=>switchTab(t), 120); return; }
switchTab(t);
});
});
// default to menu grid
switchTab('prefs'); // keep preferences as initial inner default? spec: 4a menu is default when + clicked
// actually per spec 4a: 4 grid menu buttons - default content when + clicked
// so override:
switchTab('menu');
document.querySelectorAll('.stab').forEach((t,i)=>{
const isMenu = t.dataset.stab==='menu';
t.classList.toggle('active', isMenu);
t.style.background = isMenu ? '#fff' : 'transparent';
t.style.color = isMenu ? '#18181c' : '#6f6f77';
});
/* theme buttons styled sheet1.png */
document.querySelectorAll('.theme-btn, .thb').forEach(b=>{
b.addEventListener('mouseenter', ()=> { if(!b.classList.contains('active')) b.style.background='#e8e8eb' });
b.addEventListener('mouseleave', ()=> { if(!b.classList.contains('active')) b.style.background='transparent' });
b.addEventListener('click', ()=>{
const g=b.closest('.theme3') || b.parentElement;
g.querySelectorAll('button').forEach(x=>{
x.classList.remove('active');
x.style.background='transparent';
x.style.color='#8b8b93';
x.style.boxShadow='none';
x.style.transform='none';
x.style.borderColor='transparent';
});
b.classList.add('active');
b.style.background='#ffffff';
b.style.color='#15151a';
b.style.boxShadow='0 6px 20px rgba(0,0,0,.06)';
b.style.transform='translateY(-1px)';
});
});
/* toggle switches styled cyan / gray like sheet1.png */
function bindToggle(btn){
if(!btn) return;
btn.addEventListener('click', ()=>{
const on = btn.getAttribute('aria-pressed') === 'true';
const next = !on;
btn.setAttribute('aria-pressed', String(next));
btn.classList.toggle('on', next);
// move knob
const knob = btn.querySelector('span');
if(knob){ knob.style.left = next ? '27px' : '3px'; knob.style.transform = next ? 'scale(1)' : 'scale(1)'; }
btn.style.background = next
? 'linear-gradient(135deg,#3be7f2,#2fd4be)'
: '#d1d1d6';
// haptics demo
if(navigator.vibrate && next) try{ navigator.vibrate(8) }catch(e){}
});
}
document.querySelectorAll('.tgl, [data-tog]').forEach(bindToggle);
// compact mode actually shrinks nav
document.querySelector('[data-tog="compact"]')?.addEventListener('click', function(){
setTimeout(()=>{
const on = this.getAttribute('aria-pressed')==='true';
document.querySelectorAll('.navb').forEach(n=>{
n.style.paddingTop = on ? '9px' : '';
n.style.paddingBottom = on ? '9px' : '';
});
}, 10);
});
/* menu grid card hover rich button styling */
document.querySelectorAll('.menu-card').forEach(c=>{
c.addEventListener('mouseenter', ()=>{ c.style.transform='translateY(-2px)'; c.style.boxShadow='0 10px 28px rgba(0,0,0,.09)'; c.style.borderColor='#d8d8de' });
c.addEventListener('mouseleave', ()=>{ c.style.transform=''; c.style.boxShadow='0 4px 16px rgba(0,0,0,.045)'; c.style.borderColor='#e6e6ea' });
c.addEventListener('mousedown', ()=> c.style.transform='scale(.97)');
c.addEventListener('mouseup', ()=> c.style.transform='translateY(-2px)');
c.addEventListener('click', ()=>{
const act=c.dataset.act;
if(act==='explore') { closeSheet(); setTimeout(()=> document.querySelector('[data-n="explore"]')?.click(), 220) }
if(act==='saved') { closeSheet(); setTimeout(()=> document.querySelector('[data-n="saved"]')?.click(), 220) }
if(act==='reading') { closeSheet(); setTimeout(()=> document.querySelector('[data-n="reading"]')?.click(), 220) }
});
});
/* ===== PULL HANDLE — pull up shows tabs =====
sheet is left:10px right:10px — NO translateX — never cut off left
*/
let dragging=false, sy=0, cy=0, vy=0, lt=0, ly=0;
const handleEl = document.getElementById('sheetHandle');
function pd(y, e){
if(sheetMode==='closed') return;
dragging='maybe';
sy=cy=ly=y; lt=performance.now(); vy=0;
if(e && e.cancelable) e.preventDefault();
}
function pm(y, e){
if(!dragging) return;
const dy = y - sy;
if(dragging==='maybe' && Math.abs(dy) < 5){ return }
if(dragging==='maybe'){
dragging=true;
sheet.classList.add('dragging');
const gb=document.getElementById('grabBar'); if(gb){gb.style.width='60px';gb.style.background='#b5b5bc'}
}
const now=performance.now();
vy = (y - ly) / Math.max(1, now - lt);
ly=y; lt=now; cy=y;
// move sheet NO translateX safe, centered
let ty = dy * (dy < 0 ? 0.92 : 1);
sheet.style.transform = `translateY(${ty}px)`;
sheet.style.transition='none';
const ht=document.getElementById('dragText');
if(ht) ht.textContent = sheetMode==='peek' && dy < -14 ? 'release to expand ↑' : sheetMode==='expanded' && dy > 14 ? 'release to collapse ↓' : 'pull up • swipe down to close';
if(e && e.cancelable) e.preventDefault();
}
function pu(){
if(!dragging) return;
const was = dragging===true;
dragging=false;
sheet.classList.remove('dragging');
const dy = cy - sy;
sheet.style.transition='transform .28s cubic-bezier(.22,1,.36,1), opacity .22s ease';
if(was){
const up = dy < -26 || (dy < -12 && vy < -0.2);
const down = dy > 36 || (dy > 18 && vy > 0.28);
if(sheetMode==='expanded' && down){ openPeek(); return; }
if(sheetMode==='peek' && up){ openExpanded(); return; }
if(sheetMode==='peek' && down){ closeSheet(); return; }
}
sheet.style.transform='translateY(0)';
setTimeout(()=>{ sheet.style.transition=''; }, 300);
const ht=document.getElementById('dragText'); if(ht) ht.textContent='pull up • swipe down to close';
const gb=document.getElementById('grabBar'); if(gb){ gb.style.width=''; gb.style.background=''; }
}
// big drag area handle + top 96px
handleEl.addEventListener('pointerdown', e=>{ pd(e.clientY, e); try{handleEl.setPointerCapture(e.pointerId)}catch{} });
sheet.addEventListener('pointerdown', e=>{
const r=sheet.getBoundingClientRect();
const y=e.clientY - r.top;
const interactive=e.target.closest('button,input,a,select,textarea,label');
if(y < 96 || !interactive) pd(e.clientY, e);
});
window.addEventListener('pointermove', e=> moveDrag(e), {passive:false});
function moveDrag(e){ const y=e.clientY ?? (e.touches && e.touches[0].clientY); if(y!=null) pm(y, e) }
window.addEventListener('pointerup', pu);
window.addEventListener('pointercancel', pu);
// touch
handleEl.addEventListener('touchstart', e=> pd(e.touches[0].clientY, e), {passive:false});
sheet.addEventListener('touchstart', e=>{
const rect=sheet.getBoundingClientRect();
const y=e.touches[0].clientY-rect.top;
const t=e.target;
if(y < 100 || !t.closest('button,input,label,a,select,textarea')) pd(e.touches[0].clientY, e);
}, {passive:false});
window.addEventListener('touchmove', e=>{ if(dragging){ pm(e.touches[0].clientY, e); e.preventDefault() }}, {passive:false});
window.addEventListener('touchend', pu);
window.addEventListener('touchcancel', pu);
// start closed
closeSheet();
</script>
</body>
</html>