Skip to content

Commit 3c61d82

Browse files
UX/perf: scroll-progress bar, taller hero, async image decoding, keyboard focus styles, cleaner stat values
1 parent cad23c7 commit 3c61d82

1 file changed

Lines changed: 35 additions & 12 deletions

File tree

docs/index.html

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@
118118
}
119119
body.no-scroll{overflow:hidden}
120120
a{color:inherit;text-decoration:none}
121+
:focus-visible{outline:2px solid var(--blue);outline-offset:3px;border-radius:4px}
122+
::selection{background:color-mix(in srgb,var(--blue) 22%,transparent);color:var(--ink)}
121123
img{max-width:100%;height:auto;display:block}
122124
button,a,summary{-webkit-tap-highlight-color:transparent}
123125
button{font:inherit;cursor:pointer}
@@ -195,7 +197,7 @@
195197
.button-ghost:hover{background:var(--surface-2)}
196198

197199
/* Hero */
198-
.hero{position:relative;overflow:hidden;padding:70px 0 70px}
200+
.hero{position:relative;overflow:hidden;padding:70px 0 70px;min-height:calc(100svh - 74px);display:flex;align-items:center}
199201
.hero:before{
200202
content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
201203
background-image:
@@ -249,7 +251,7 @@
249251
}
250252
[data-theme="dark"] .device{background:#05070a;box-shadow:var(--shadow)}
251253
.device-notch{position:absolute;top:13px;left:50%;transform:translateX(-50%);width:120px;height:24px;background:#0c0f14;border-bottom-left-radius:14px;border-bottom-right-radius:14px;z-index:3}
252-
.device-screen{width:100%;border-radius:30px;display:block;background:#0c0f14}
254+
.device-screen{width:100%;aspect-ratio:9/19;object-fit:cover;border-radius:30px;display:block;background:#0c0f14}
253255
.bubble{
254256
position:absolute;display:flex;align-items:center;gap:9px;
255257
background:var(--card);border:1px solid var(--line);
@@ -348,6 +350,9 @@
348350
.shot.portrait .media-frame img{height:100%;object-fit:contain}
349351
.shot figcaption{font-size:13px;color:var(--muted);margin-top:10px;font-weight:600}
350352

353+
/* Scroll progress */
354+
.progress{position:fixed;top:0;left:0;height:3px;width:100%;transform:scaleX(0);transform-origin:0 50%;background:var(--blue);z-index:60}
355+
351356
/* Config */
352357
.config-layout{display:grid;grid-template-columns:.72fr 1.28fr;gap:50px;align-items:start}
353358
.config-copy{position:sticky;top:100px}
@@ -579,6 +584,7 @@
579584
</script>
580585
</head>
581586
<body>
587+
<div class="progress" id="progress" aria-hidden="true"></div>
582588
<!-- SVG sprite -->
583589
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
584590
<symbol id="i-reply" viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M8 10h8M8 13h5"/></symbol>
@@ -658,7 +664,7 @@ <h1>
658664
<div class="hero-device">
659665
<div class="device">
660666
<div class="device-notch"></div>
661-
<img class="device-screen" src="assets/showcase.jpg" alt="InstaReply Bot product showcase on an Android phone" width="660" height="1400" loading="eager">
667+
<img class="device-screen" src="assets/dashboard.jpg" alt="InstaReply Bot dashboard running on an Android phone" width="429" height="900" fetchpriority="high">
662668
</div>
663669
<div class="bubble bubble--in"><svg class="icon"><use href="#i-bell"/></svg> New DM detected</div>
664670
<div class="bubble bubble--out"><span class="dot"><i></i><i></i><i></i></span> AI drafting reply</div>
@@ -668,9 +674,9 @@ <h1>
668674

669675
<section class="stats" aria-label="Product summary">
670676
<div class="container stats-grid">
671-
<div class="stat reveal"><div class="stat-value">0<span class="accent">.</span>cost</div><div class="stat-label">Free, open-source APK</div></div>
677+
<div class="stat reveal"><div class="stat-value"><span class="accent">$</span>0</div><div class="stat-label">Free, open-source APK</div></div>
672678
<div class="stat reveal" style="--d:.08s"><div class="stat-value">4<span class="accent">+</span></div><div class="stat-label">AI providers supported</div></div>
673-
<div class="stat reveal" style="--d:.16s"><div class="stat-value">100<span class="accent">%</span></div><div class="stat-label">No Instagram login</div></div>
679+
<div class="stat reveal" style="--d:.16s"><div class="stat-value">0</div><div class="stat-label">Passwords required</div></div>
674680
<div class="stat reveal" style="--d:.24s"><div class="stat-value">24<span class="accent">/</span>7</div><div class="stat-label">Background automation</div></div>
675681
</div>
676682
</section>
@@ -759,7 +765,7 @@ <h2>One clear chain from message to response.</h2>
759765
<li class="step"><div class="step-node">05</div><div class="step-body"><strong>Reply sent</strong><span>The available Android reply mechanism sends the text.</span></div></li>
760766
<li class="step"><div class="step-node">06</div><div class="step-body"><strong>Logged</strong><span>The activity becomes available in the app's history.</span></div></li>
761767
</ol>
762-
<div class="workflow-image reveal" style="--d:.1s"><img src="assets/workflow.jpg" alt="InstaReply Bot seven-stage workflow infographic" width="1200" height="800" loading="lazy"></div>
768+
<div class="workflow-image reveal" style="--d:.1s"><img src="assets/workflow.jpg" alt="InstaReply Bot seven-stage workflow infographic" width="1200" height="800" loading="lazy" decoding="async"></div>
763769
</div>
764770
</div>
765771
</section>
@@ -772,10 +778,10 @@ <h2>See the actual app before you install it.</h2>
772778
<p class="section-lead">A Play Store-style screenshot rail using the supplied product screens. Swipe horizontally on smaller devices.</p>
773779
</div>
774780
<div class="screenshot-rail reveal" style="--d:.06s">
775-
<figure class="shot portrait"><div class="media-frame"><img src="assets/dashboard.jpg" alt="InstaReply Bot dashboard screen" width="429" height="900" loading="lazy"></div><figcaption>Dashboard and activity</figcaption></figure>
776-
<figure class="shot portrait"><div class="media-frame"><img src="assets/rule-engine.jpg" alt="InstaReply Bot Smart Rule Engine screen" width="416" height="900" loading="lazy"></div><figcaption>Smart Rule Engine</figcaption></figure>
777-
<figure class="shot portrait"><div class="media-frame"><img src="assets/ai-settings.jpg" alt="InstaReply Bot AI settings screen" width="416" height="900" loading="lazy"></div><figcaption>AI settings and providers</figcaption></figure>
778-
<figure class="shot portrait"><div class="media-frame"><img src="assets/poster.jpg" alt="InstaReply Bot promotional poster" width="506" height="900" loading="lazy"></div><figcaption>Product overview</figcaption></figure>
781+
<figure class="shot portrait"><div class="media-frame"><img src="assets/dashboard.jpg" alt="InstaReply Bot dashboard screen" width="429" height="900" loading="lazy" decoding="async"></div><figcaption>Dashboard and activity</figcaption></figure>
782+
<figure class="shot portrait"><div class="media-frame"><img src="assets/rule-engine.jpg" alt="InstaReply Bot Smart Rule Engine screen" width="416" height="900" loading="lazy" decoding="async"></div><figcaption>Smart Rule Engine</figcaption></figure>
783+
<figure class="shot portrait"><div class="media-frame"><img src="assets/ai-settings.jpg" alt="InstaReply Bot AI settings screen" width="416" height="900" loading="lazy" decoding="async"></div><figcaption>AI settings and providers</figcaption></figure>
784+
<figure class="shot portrait"><div class="media-frame"><img src="assets/poster.jpg" alt="InstaReply Bot promotional poster" width="506" height="900" loading="lazy" decoding="async"></div><figcaption>Product overview</figcaption></figure>
779785
</div>
780786
</div>
781787
</section>
@@ -798,8 +804,8 @@ <h2>Configure the behavior directly in the Android UI.</h2>
798804
</ul>
799805
</div>
800806
<div class="config-shots reveal" style="--d:.1s">
801-
<figure><div class="media-frame"><img src="assets/ai-settings.jpg" alt="Actual InstaReply Bot AI settings screen" width="416" height="900" loading="lazy"></div></figure>
802-
<figure><div class="media-frame"><img src="assets/rule-engine.jpg" alt="Actual InstaReply Bot rule editor screen" width="416" height="900" loading="lazy"></div></figure>
807+
<figure><div class="media-frame"><img src="assets/ai-settings.jpg" alt="Actual InstaReply Bot AI settings screen" width="416" height="900" loading="lazy" decoding="async"></div></figure>
808+
<figure><div class="media-frame"><img src="assets/rule-engine.jpg" alt="Actual InstaReply Bot rule editor screen" width="416" height="900" loading="lazy" decoding="async"></div></figure>
803809
</div>
804810
</div>
805811
</div>
@@ -936,6 +942,23 @@ <h4>Project</h4>
936942

937943
// Reveal on scroll
938944
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
945+
946+
// Scroll progress
947+
const progress = document.getElementById('progress');
948+
let ticking = false;
949+
function updateProgress(){
950+
const h = document.documentElement;
951+
const max = h.scrollHeight - h.clientHeight;
952+
const p = max > 0 ? (h.scrollTop || document.body.scrollTop) / max : 0;
953+
progress.style.transform = 'scaleX(' + p.toFixed(4) + ')';
954+
ticking = false;
955+
}
956+
if(!reduce){
957+
window.addEventListener('scroll', () => {
958+
if(!ticking){ ticking = true; window.requestAnimationFrame(updateProgress); }
959+
}, { passive:true });
960+
updateProgress();
961+
}
939962
const revealEls = document.querySelectorAll('.reveal');
940963
if(reduce || !('IntersectionObserver' in window)){
941964
revealEls.forEach(el => el.classList.add('in'));

0 commit comments

Comments
 (0)