1<!DOCTYPE html> 2<html lang="en"> 3<head> 4<meta charset="UTF-8"> 5<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"> 6<meta name="description" content="Bloom - Handcrafted bouquets, pre-ordered for every moment. WCAG 2.1 AA accessible. "> 7<meta name="theme-color" content="#0B0516" media="(prefers-color-scheme: dark)"> 8<meta name="theme-color" content="#0B0516"> 9<meta name="color-scheme" content="dark"> 10<meta property="og:title" content="Bloom - Pre-Order Flowers & Gifts"> 11<meta property="og:description" content="Custom bouquets for every moment. WCAG 2.1 AA accessible. "> 12<meta property="og:type" content="website"> 13<meta property="og:image" content="/img/hero-flowers.webp"> 14<meta name="twitter:card" content="summary_large_image"> 15<title>Bloom - Pre-Order Flowers & Gifts</title> 16<link rel="canonical" href="https://capstonetechno.onrender.com/"> 17<link rel="alternate" hreflang="en" href="https://capstonetechno.onrender.com/"> 18<link rel="alternate" hreflang="en-PH" href="https://capstonetechno.onrender.com/?lang=en-PH"> 19<link rel="alternate" hreflang="fil-PH" href="https://capstonetechno.onrender.com/?lang=fil"> 20<link rel="alternate" hreflang="es" href="https://capstonetechno.onrender.com/?lang=es"> 21<link rel="alternate" hreflang="ja" href="https://capstonetechno.onrender.com/?lang=ja"> 22<link rel="alternate" hreflang="x-default" href="https://capstonetechno.onrender.com/"> 23<link rel="preconnect" href="https://fonts.googleapis.com"> 24<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 25<link rel="dns-prefetch" href="https://fonts.googleapis.com"> 26<link rel="preload" href="/img/hero-flowers.webp" as="image" fetchpriority="high"> 27<link rel="preload" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,700;0,900&family=Barlow+Condensed:wght@700;900&family=DM+Sans:opsz,[email protected],400;9..40,500&display=swap" as="style"> 28<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,700;0,900&family=Barlow+Condensed:wght@700;900&family=DM+Sans:opsz,[email protected],400;9..40,500&display=swap">
29<script type="application/ld+json"> 30{"@context":"https://schema.org","@type":"Organization","name":"Bloom","url":"/","logo":"/img/hero-flowers.webp","description":"Handcrafted bouquets, pre-ordered for every moment. WCAG 2.1 AA accessible. A BSIT Capstone project by STI College Lipa.","sameAs":["https://instagram.com/","https://facebook.com/"],"address":{"@type":"PostalAddress","addressCountry":"PH","addressRegion":"Batangas","addressLocality":"Lipa City"},"areaServed":["Metro Manila","Batangas","Cebu"]} 31</script>
vendor: 2 bytes, line 31
31
32<script type="application/ld+json"> 33{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"/"},{"@type":"ListItem","position":2,"name":"Catalog","item":"/catalog.html"}]} 34</script>
vendor: 2 bytes, line 34
34
35<script type="application/ld+json"> 36{"@context":"https://schema.org","@type":"Product","name":"Bloom Handcrafted Bouquets","image":"/img/hero-flowers.webp","description":"Pre-order handcrafted bouquets and floral arrangements with careful handling and dedicated delivery windows across our service areas.","brand":{"@type":"Brand","name":"Bloom"},"offers":{"@type":"AggregateOffer","priceCurrency":"PHP","lowPrice":"1650","highPrice":"4200","offerCount":"40"},"aggregateRating":{"@type":"AggregateRating","ratingValue":"4.86","reviewCount":"487","bestRating":"5","worstRating":"1"}} 37</script>
vendor: 2 bytes, line 37
37
38<script type="application/ld+json"> 39{"@context":"https://schema.org","@type":"WebSite","name":"Bloom","url":"/","potentialAction":{"@type":"SearchAction","target":"/catalog.html?search={search_term_string}","query-input":"required name=search_term_string"}} 40</script>
vendor: 2 bytes, line 40
40
41<script type="application/ld+json"> 42{"@context":"https://schema.org","@type":"LocalBusiness","name":"Bloom Florist","image":"/img/hero-flowers.webp","priceRange":"â±â±","telephone":"+63","address":{"@type":"PostalAddress","addressCountry":"PH","addressRegion":"Batangas","addressLocality":"Lipa City"},"openingHoursSpecification":[{"@type":"OpeningHoursSpecification","dayOfWeek":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],"opens":"08:00","closes":"20:00"}],"aggregateRating":{"@type":"AggregateRating","ratingValue":"4.86","reviewCount":"487"}} 43</script>
43 44<link rel="stylesheet" href="/css/landing.min.css"> 45<link rel="stylesheet" href="/css/phase8.css"> 46<link rel="stylesheet" href="/css/wabi-sabi.min.css"> 47<link rel="stylesheet" href="/css/atelier-persona.css"> 48<link rel="manifest" href="/manifest.json"> 49<link rel="apple-touch-icon" href="/img/hero-flowers.webp"> 50<style> 51@property --sh { syntax: '<angle>'; inherits: false; initial-value: 0deg; } 52@property --px { syntax: '<number>'; inherits: true; initial-value: 0; } 53@property --py { syntax: '<number>'; inherits: true; initial-value: 0; } 54:root { 55 --p5: #E61A1A; 56 --p5d: #A81010; 57 --p5l: #FF3B3B; 58 --pk: oklch(58% .22 348); 59 --pk2: oklch(48% .22 340); 60 --pu: oklch(40% .24 292); 61 --pu2: oklch(26% .18 292); 62 --gd: oklch(84% .17 86); 63 --mn: oklch(76% .15 172); 64 --bg: oklch(11% .06 292); 65 --bg2: oklch(15% .07 292); 66 --bg3: oklch(19% .08 292); 67 --ink: #0B0516; 68 --paper: #F8F3E8; 69 --cr: oklch(68% .22 27); 70 --gl: rgba(255,255,255,.055); 71 --glb: rgba(255,255,255,.09); 72 --gls: rgba(255,255,255,.025); 73 --r: 20px; 74 --rs: 12px; 75 --rx: 8px; 76 --ease: cubic-bezier(.23,1,.32,1); 77 --spring: cubic-bezier(.34,1.56,.64,1); 78 --p5ease: cubic-bezier(.17,.67,.32,1.27); 79 --fd: 'Playfair Display', Georgia, serif; 80 --fc: 'Barlow Condensed', Impact, sans-serif; 81 --fb: 'DM Sans', system-ui, sans-serif; 82 --text: #fff; 83 --text-muted: rgba(255,255,255,.6); 84 --text-dim: rgba(255,255,255,.50); 85} 86[data-theme="light"] { 87 --bg: #FEFCF9; 88 --bg2: #F5F0EB; 89 --bg3: #EDE6DF; 90 --ink: #1A1220; 91 --paper: #FFFFFF; 92 --gl: rgba(0,0,0,.04); 93 --glb: rgba(0,0,0,.08); 94 --gls: rgba(0,0,0,.02); 95 --text: #1A1220; 96 --text-muted: rgba(26,18,32,.6); 97 --text-dim: rgba(26,18,32,.4); 98 --nav-bg: rgba(254,252,249,.92); 99 --card-bg: rgba(0,0,0,.03); 100 --card-border: rgba(0,0,0,.08); 101 --input-bg: rgba(0,0,0,.04); 102 --input-border: rgba(0,0,0,.12); 103 --shadow-color: rgba(0,0,0,.08); 104} 105* { box-sizing: border-box; margin: 0; padding: 0; } 106*::before, *::after { box-sizing: border-box; } 107html { scroll-behavior: smooth; -webkit-font-smoothing: antialiased; color-scheme: dark; interpolate-size: allow-keywords; scrollbar-width: none; -ms-overflow-style: none; } 108html::-webkit-scrollbar { display: none !important; } 109html { overflow-x: clip; max-width: 100%; width: 100%; } 110body { background: var(--bg); color: var(--text, #fff); font-family: var(--fb); overflow-x: clip; min-height: 100dvh; width: 100%; max-width: 100vw; margin: 0; padding: 0; } 111body.modal-open { overflow: hidden; } 112@media (pointer: fine) { body { cursor: none; } button, a, input, textarea, [role="button"] { cursor: none; } } 113@media (prefers-reduced-motion: reduce) { 114 *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } 115} 116::selection { background: rgba(230,26,26,.35); color: #fff; } 117[data-theme="light"] { color-scheme: light; } 118[data-theme="light"] body { color: var(--text); } 119[data-theme="light"] #nav { background: rgba(254,252,249,.92); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); } 120[data-theme="light"] #nav.sc { background: rgba(254,252,249,.95); } 121[data-theme="light"] #nav.sc::after { background: linear-gradient(90deg, transparent, var(--p5), var(--pk), transparent); } 122[data-theme="light"] .n-links a { color: rgba(26,18,32,.6); } 123[data-theme="light"] .n-links a:hover { color: var(--text); background: rgba(0,0,0,.05); } 124[data-theme="light"] .n-logo { -webkit-text-fill-color: var(--text); color: var(--text); background: none; } 125[data-theme="light"] .n-logo::before { color: var(--p5); -webkit-text-fill-color: var(--p5); } 126[data-theme="light"] .hmb span { background: var(--text); } 127[data-theme="light"] .n-acts .btn-g { background: rgba(0,0,0,.04); border-color: rgba(0,0,0,.1); color: rgba(26,18,32,.7); } 128[data-theme="light"] .n-acts .btn-g:hover { background: rgba(0,0,0,.08); color: var(--text); } 129[data-theme="light"] .btn-g { background: rgba(0,0,0,.04); border-color: rgba(0,0,0,.1); color: rgba(26,18,32,.7); } 130[data-theme="light"] .btn-g:hover { background: rgba(0,0,0,.08); color: var(--text); } 131[data-theme="light"] .n-srch-panel { background: rgba(255,255,255,.97); border-color: rgba(0,0,0,.1); } 132[data-theme="light"] .n-srch-inp { background: rgba(0,0,0,.04); border-color: rgba(0,0,0,.12); color: var(--text); } 133[data-theme="light"] .lang-dd { background: rgba(255,255,255,.97); border-color: rgba(0,0,0,.1); } 134[data-theme="light"] .lang-opt { color: rgba(26,18,32,.6); } 135[data-theme="light"] .lang-opt:hover { color: var(--text); } 136[data-theme="light"] .mob-menu { background: rgba(255,255,255,.97); } 137[data-theme="light"] .mob-inner a { color: rgba(26,18,32,.6); } 138[data-theme="light"] .mob-inner a:hover { color: var(--text); } 139[data-theme="light"] .hero-photo::before { background: linear-gradient(to right, var(--bg) 0%, rgba(254,252,249,.72) 25%, rgba(254,252,249,.15) 60%, transparent 100%); } 140[data-theme="light"] .hero-photo::after { background: linear-gradient(to bottom, rgba(254,252,249,.5) 0%, transparent 20%, transparent 80%, rgba(254,252,249,.62) 100%); } 141[data-theme="light"] .hero-hl { color: var(--text); } 142[data-theme="light"] .hero-hl em { color: rgba(26,18,32,.7); } 143[data-theme="light"] .hero-sub { color: rgba(26,18,32,.6); } 144[data-theme="light"] .hero-eyebrow-tag { background: rgba(230,26,26,.1); border-color: rgba(230,26,26,.25); color: var(--p5d); } 145[data-theme="light"] .hero-eyebrow-sub { color: rgba(26,18,32,.5); } 146[data-theme="light"] .trust-item { color: rgba(26,18,32,.55); } 147[data-theme="light"] .hero-countdown { color: rgba(26,18,32,.7); } 148[data-theme="light"] .sec-title { color: var(--text); } 149[data-theme="light"] .sec-sub { color: rgba(26,18,32,.72); } 150[data-theme="light"] .p-card { background: rgba(0,0,0,.03); border-color: rgba(0,0,0,.08); } 151[data-theme="light"] .p-card:hover { border-color: rgba(230,26,26,.3); box-shadow: 0 10px 40px rgba(0,0,0,.08); } 152[data-theme="light"] .p-name { color: var(--text); } 153[data-theme="light"] .p-cat { color: rgba(26,18,32,.5); } 154[data-theme="light"] .p-empty { color: rgba(26,18,32,.45); } 155[data-theme="light"] .p-err { color: var(--cr); } 156[data-theme="light"] .stats-strip { background: var(--bg2); } 157[data-theme="light"] .stats-strip::before { background: linear-gradient(135deg, rgba(230,26,26,.03), rgba(188,49,148,.02)); } 158[data-theme="light"] .stat-item { background: transparent; } 159[data-theme="light"] .stat-num { background: linear-gradient(135deg, var(--text), rgba(26,18,32,.68)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } 160[data-theme="light"] .stat-lbl { color: rgba(26,18,32,.55); } 161[data-theme="light"] .stat-src { color: rgba(26,18,32,.45); } 162[data-theme="light"] .stat-src a { color: var(--p5d); border-bottom-color: rgba(230,26,26,.3); } 163[data-theme="light"] .stat-bar { background: rgba(0,0,0,.06); } 164[data-theme="light"] .stat-icon { filter: grayscale(.15); } 165[data-theme="light"] .feat-sec { background: var(--bg2); } 166[data-theme="light"] .feat-sec::before { mix-blend-mode: normal; } 167[data-theme="light"] .feat-card { background: rgba(255,255,255,.7); border-color: rgba(0,0,0,.08); } 168[data-theme="light"] .feat-card:hover { background: rgba(255,255,255,.9); border-color: rgba(230,26,26,.3); box-shadow: 0 16px 48px rgba(0,0,0,.08); } 169[data-theme="light"] .feat-t { color: var(--text); } 170[data-theme="light"] .feat-d { color: rgba(26,18,32,.6); } 171[data-theme="light"] .feat-card:hover .feat-d { color: rgba(26,18,32,.8); } 172[data-theme="light"] .feat-ico { background: linear-gradient(135deg, rgba(230,26,26,.12), rgba(188,49,148,.08)); border-color: rgba(230,26,26,.25); } 173[data-theme="light"] .feat-ico svg { color: var(--p5d); } 174[data-theme="light"] .rev-sec { background: var(--bg); } 175[data-theme="light"] .rev-card { background: rgba(0,0,0,.03); border-color: rgba(0,0,0,.08); } 176[data-theme="light"] .rev-body { color: rgba(26,18,32,.72); } 177[data-theme="light"] .rev-name { color: var(--text); } 178[data-theme="light"] .rev-role { color: rgba(26,18,32,.5); } 179[data-theme="light"] .rev-card::before { color: rgba(230,26,26,.2); } 180[data-theme="light"] .rev-stars span { color: #d4940a !important; } 181[data-theme="light"] .rev-stars span[style*="0.2"] { color: rgba(26,18,32,.15) !important; } 182[data-theme="light"] .fact-card { background: rgba(255,255,255,.7); border-color: rgba(0,0,0,.1); } 183[data-theme="light"] .fact-card::before { background: linear-gradient(to bottom, var(--p5), var(--pk)); } 184[data-theme="light"] .fact-k { color: var(--p5d); -webkit-text-fill-color: var(--p5d); } 185[data-theme="light"] .fact-t { color: var(--text); } 186[data-theme="light"] .fact-d { color: rgba(26,18,32,.65); } 187[data-theme="light"] .fact-src { color: rgba(26,18,32,.5); } 188[data-theme="light"] .fact-src a { color: var(--p5d); border-bottom-color: rgba(230,26,26,.35); } 189[data-theme="light"] .facts-sec { background: var(--bg2); border-top-color: rgba(0,0,0,.06); border-bottom-color: rgba(0,0,0,.06); } 190[data-theme="light"] .subs-sec { background: var(--bg2); } 191[data-theme="light"] .subs-card { background: rgba(255,255,255,.6); border-color: rgba(0,0,0,.08); color: var(--text); } 192[data-theme="light"] .subs-card:hover { border-color: rgba(230,26,26,.3); } 193[data-theme="light"] .subs-card.selected { border-color: var(--p5); background: rgba(255,255,255,.85); } 194[data-theme="light"] .subs-card-name { color: var(--text); } 195[data-theme="light"] .subs-card-name em { background: rgba(230,26,26,.1); color: var(--p5d); } 196[data-theme="light"] .subs-card-price { color: var(--text); -webkit-text-fill-color: var(--text); } 197[data-theme="light"] .subs-card-price small { color: rgba(26,18,32,.5); } 198[data-theme="light"] .subs-card-d { color: rgba(26,18,32,.6); } 199[data-theme="light"] .subs-card-feats span { color: rgba(26,18,32,.55); background: rgba(0,0,0,.04); } 200[data-theme="light"] .subs-card-feats span svg { color: #0a8f6a; } 201[data-theme="light"] .bloom-foot { background: var(--bg2); } 202[data-theme="light"] .foot-brand { color: var(--text); -webkit-text-fill-color: var(--text); background: none; } 203[data-theme="light"] .foot-tag { color: rgba(26,18,32,.55); } 204[data-theme="light"] .foot-col h4 { color: var(--text); } 205[data-theme="light"] .foot-col a { color: rgba(26,18,32,.55); } 206[data-theme="light"] .foot-col a:hover { color: var(--text); } 207[data-theme="light"] .foot-bottom { border-top-color: rgba(0,0,0,.08); color: rgba(26,18,32,.4); } 208[data-theme="light"] .foot-soc a { background: rgba(0,0,0,.04); border-color: rgba(0,0,0,.08); color: rgba(26,18,32,.5); } 209[data-theme="light"] .foot-soc a:hover { background: rgba(230,26,26,.1); color: var(--p5); border-color: rgba(230,26,26,.25); } 210[data-theme="light"] .nl-inp { background: rgba(0,0,0,.04); border-color: rgba(0,0,0,.1); color: var(--text); } 211[data-theme="light"] .btt { background: var(--p5); border-color: var(--p5d); color: #fff; } 212[data-theme="light"] .overlay .modal { background: #fff; border-color: rgba(0,0,0,.1); } 213[data-theme="light"] .m-cls { background: rgba(0,0,0,.04); border-color: rgba(0,0,0,.1); color: var(--text); } 214[data-theme="light"] .m-sub { color: rgba(26,18,32,.6); } 215[data-theme="light"] .fi-lbl { color: rgba(26,18,32,.6); } 216[data-theme="light"] .fi-inp { background: rgba(0,0,0,.03); border-color: rgba(0,0,0,.1); color: var(--text); } 217[data-theme="light"] .div-lbl { color: rgba(26,18,32,.4); } 218[data-theme="light"] .div-lbl::before, [data-theme="light"] .div-lbl::after { background: rgba(0,0,0,.1); } 219[data-theme="light"] .a-tab { color: rgba(26,18,32,.55); } 220[data-theme="light"] .occ-btn { border-color: rgba(0,0,0,.1); background: rgba(0,0,0,.02); color: rgba(26,18,32,.7); } 221[data-theme="light"] .occ-btn:hover { border-color: rgba(230,26,26,.3); background: rgba(230,26,26,.05); color: var(--text); } 222[data-theme="light"] .occ-btn.selected { border-color: var(--p5); background: rgba(230,26,26,.08); color: var(--text); } 223[data-theme="light"] .pw-tog { color: rgba(26,18,32,.5); } 224[data-theme="light"] .pw-tog:hover { color: var(--text); } 225[data-theme="light"] .fpl-btn { color: rgba(26,18,32,.55); } 226[data-theme="light"] .fpl-btn:hover { color: var(--p5); } 227[data-theme="light"] .str-lbl { color: rgba(26,18,32,.5); } 228[data-theme="light"] .toast { background: rgba(255,255,255,.96); border-color: rgba(0,0,0,.1); color: var(--text); box-shadow: 0 10px 40px rgba(0,0,0,.12); } 229[data-theme="light"] .cat-tab { border-color: rgba(0,0,0,.08); background: rgba(0,0,0,.03); color: rgba(26,18,32,.72); } 230[data-theme="light"] .cat-tab:hover { color: var(--text); } 231[data-theme="light"] .cat-tab.active { color: #fff; background: linear-gradient(135deg, var(--p5d), var(--p5)); border-color: var(--p5); } 232[data-theme="light"] .wl-btn { background: rgba(0,0,0,.03); border-color: rgba(0,0,0,.08); color: rgba(26,18,32,.45); } 233[data-theme="light"] .bloom-academic-badge { background: linear-gradient(135deg, rgba(254,252,249,.96), rgba(245,240,235,.96)); border-top-color: rgba(0,0,0,.08); color: rgba(26,18,32,.6); } 234[data-theme="light"] .bloom-academic-badge-close { color: rgba(26,18,32,.4); } 235[data-theme="light"] .bloom-academic-badge-close:hover { color: var(--text); } 236[data-theme="light"] .p5-sec-div { background: linear-gradient(90deg, transparent, rgba(230,26,26,.25), transparent); } 237[data-theme="light"] .delivery-bar { background: rgba(255,255,255,.95); color: rgba(26,18,32,.6); border-bottom-color: rgba(0,0,0,.08); } 238[data-theme="light"] .delivery-pill { background: rgba(230,26,26,.08); border-color: rgba(230,26,26,.2); color: var(--p5d); } 239[data-theme="light"] .dlv-fld { background: rgba(0,0,0,.03); border-color: rgba(0,0,0,.08); } 240[data-theme="light"] .dlv-fld input, [data-theme="light"] .dlv-fld select { color: var(--text); } 241[data-theme="light"] .dlv-fld label { color: rgba(26,18,32,.5); } 242[data-theme="light"] .dlv-eta { color: #0a8f6a; } 243[data-theme="light"] .hc-card { background: rgba(255,255,255,.6); border-color: rgba(0,0,0,.08); } 244[data-theme="light"] .hc-card:hover { border-color: rgba(230,26,26,.25); box-shadow: 0 8px 32px rgba(0,0,0,.06); } 245[data-theme="light"] .hc-title { color: var(--text); } 246[data-theme="light"] .hc-desc { color: rgba(26,18,32,.55); } 247[data-theme="light"] .hc-status { color: rgba(26,18,32,.5); } 248[data-theme="light"] .hero-hl { color: var(--text); text-shadow: none; } 249[data-theme="light"] .hero-sub { color: rgba(26,18,32,.65); text-shadow: none; } 250[data-theme="light"] .hero-eyebrow-sub { color: rgba(26,18,32,.5); } 251[data-theme="light"] .g-txt { background: linear-gradient(135deg, var(--p5d) 0%, var(--p5) 50%, var(--pk2) 100%); background-size: 250% auto; -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } 252[data-theme="light"] .trust-item { color: rgba(26,18,32,.5); } 253[data-theme="light"] .trust-item svg { color: #0a8f6a; } 254[data-theme="light"] .hero-countdown { background: rgba(230,26,26,.06); border-color: rgba(230,26,26,.18); } 255[data-theme="light"] .cd-lbl { color: rgba(26,18,32,.5); } 256[data-theme="light"] .cd-num { color: var(--p5d); } 257[data-theme="light"] .corp-list li { color: rgba(26,18,32,.65); } 258[data-theme="light"] .corp-list svg { color: #0a8f6a; } 259[data-theme="light"] .sec-title { color: var(--text); } 260[data-theme="light"] .sec-sub { color: rgba(26,18,32,.72); } 261[data-theme="light"] .tag-p { color: #A81010; } 262[data-theme="light"] .voice-fab { box-shadow: 0 8px 24px rgba(230,26,26,.3); } 263[data-theme="light"] .p-price { color: #a97800; } 264[data-theme="light"] .p-stars span { color: #d4940a; } 265[data-theme="light"] ::-webkit-scrollbar-track { background: var(--bg); } 266::-webkit-scrollbar { width: 6px; height: 6px; } 267::-webkit-scrollbar-track { background: var(--bg); } 268::-webkit-scrollbar-thumb { background: linear-gradient(var(--p5), var(--pk)); border-radius: 2px; } 269a { text-decoration: none; color: inherit; } 270button { font-family: var(--fb); background: none; border: none; color: inherit; } 271input, textarea, select { font-family: var(--fb); } 272img { max-width: 100%; display: block; } 273:focus-visible { outline: 2px solid var(--p5l); outline-offset: 3px; border-radius: 4px; } 274.sr { position: absolute; width:
274 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; } 275.c-dot { width: 8px; height: 8px; background: #fff; border-radius: 50%; position: fixed; pointer-events: none; z-index: 99999; transform: translate3d(-50%,-50%,0); transition: width .2s, height .2s, background .2s; will-change: transform; } 276.c-ring { width: 36px; height: 36px; border: 1.5px solid rgba(255,255,255,.45); border-radius: 50%; position: fixed; pointer-events: none; z-index: 99998; transform: translate3d(-50%,-50%,0); transition: transform .16s var(--ease), width .28s, height .28s, border-color .28s; will-change: transform; } 277body.c-hover .c-dot { width: 14px; height: 14px; background: var(--p5); } 278body.c-hover .c-ring { width: 52px; height: 52px; border-color: rgba(230,26,26,.7); } 279@media (pointer: coarse), (hover: none) { .c-dot, .c-ring { display: none !important; } } 280#sbar { position: fixed; top: 0; left: 0; height: 3px; background: linear-gradient(90deg, var(--p5), var(--pk), var(--mn)); transform-origin: 0 50%; width: 100%; z-index: 9999; box-shadow: 0 0 10px rgba(230,26,26,.5); transform: scaleX(0); } 281@supports (animation-timeline: scroll()) { 282 #sbar { animation: sb-grow linear both; animation-timeline: scroll(root); } 283 @keyframes sb-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } } 284} 285.skip { position: fixed; top: -80px; left: 20px; z-index: 99990; padding: 10px 20px; background: var(--p5); color: #fff; border-radius: 8px; font-weight: 700; transition: top .2s; text-decoration: none; } 286.skip:focus { top: 20px; } 287.con { max-width: 1280px; margin: 0 auto; padding: 0 40px; } 288@media (max-width: 768px) { .con { padding: 0 20px; } } 289.p5-slash { position: absolute; width: 3px; background: var(--p5); border-radius: 2px; transform: rotate(-18deg); pointer-events: none; } 290.p5-diamond { position: absolute; width: 8px; height: 8px; background: var(--p5); transform: rotate(45deg); pointer-events: none; } 291.p5-label { font-family: var(--fc); font-weight: 900; font-style: italic; font-size: .7rem; letter-spacing: .15em; text-transform: uppercase; color: var(--p5); } 292.p5-splat { position: absolute; pointer-events: none; width: 120px; height: 120px; filter: drop-shadow(0 0 10px rgba(230,26,26,.4)); } 293#nav { position: fixed; top: 0; left: 0; right: 0; z-index: 1000; height: 68px; display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 0 40px; transition: background .4s, backdrop-filter .4s; } 294#nav::after { content: ''; position: absolute; bottom: 0; left: -2%; right: -2%; height: 2px; background: linear-gradient(90deg, transparent, var(--p5), var(--pk), transparent); opacity: 0; transition: opacity .4s; transform: skewY(-0.8deg); filter: drop-shadow(0 0 4px rgba(230,26,26,.4)); } 295#nav.sc { background: rgba(11,5,22,.88); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); } 296#nav.sc::after { opacity: 1; } 297.n-logo { font-family: var(--fd); font-size: 1.3rem; font-weight: 900; letter-spacing: -.03em; background: linear-gradient(135deg, #fff 0%, var(--pk) 60%, var(--p5) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; position: relative; flex-shrink: 0; } 298.n-logo::before { content: '//'; font-family: var(--fc); font-style: italic; font-size: .7rem; position: absolute; top: -4px; left: -14px; color: var(--p5); opacity: .8; -webkit-text-fill-color: var(--p5); } 299.n-links { display: flex; align-items: center; gap: 2px; list-style: none; } 300.n-links a { padding: 8px 14px; border-radius: var(--rx); font-size: .85rem; font-weight: 500; color: rgba(255,255,255,.6); transition: all .2s; position: relative; } 301.n-links a:hover, .n-links a:focus-visible { color: #fff; background: var(--gl); } 302.n-links a::after { content: attr(data-label); font-family: var(--fc); font-style: italic; font-weight: 900; font-size: .6rem; color: var(--p5); position: absolute; top: 2px; left: 50%; transform: translateX(-50%); opacity: 0; transition: opacity .2s; pointer-events: none; letter-spacing: .1em; text-transform: uppercase; } 303.n-links a:hover::after, .n-links a:focus-visible::after { opacity: 1; } 304.n-acts { display: flex; align-items: center; gap: 10px; flex-shrink: 0; } 305.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 10px 20px; border-radius: var(--rs); font-family: var(--fb); font-size: .86rem; font-weight: 600; transition: transform .25s var(--ease), box-shadow .25s var(--ease), background .2s; position: relative; overflow: hidden; white-space: nowrap; } 306.btn::before { content: ''; position: absolute; inset: 0; background: rgba(255,255,255,0); transition: background .2s; pointer-events: none; } 307.btn:hover::before, .btn:focus-visible::before { background: rgba(255,255,255,.06); } 308.btn-p { background: linear-gradient(135deg, var(--p5d), var(--p5)); color: #fff; box-shadow: 0 4px 20px rgba(230,26,26,.35); } 309.btn-p:hover, .btn-p:focus-visible { transform: translateY(-2px); box-shadow: 0 8px 28px rgba(230,26,26,.5); } 310.btn-g { background: var(--gl); border: 1px solid var(--glb); color: rgba(255,255,255,.75); } 311.btn-g:hover, .btn-g:focus-visible { background: rgba(255,255,255,.1); color: #fff; } 312.btn-sm { padding: 8px 14px; font-size: .8rem; height: 36px; } 313.btn-lg { padding: 13px 30px; font-size: .95rem; border-radius: var(--r); } 314.cart-wrap { position: relative; } 315.cart-badge { position: absolute; top: -6px; right: -6px; background: var(--p5); color: #fff; font-size: .62rem; font-weight: 700; min-width: 16px; height: 16px; border-radius: 100px; display: inline-flex; align-items: center; justify-content: center; padding: 0 4px; } 316.n-srch-wrap { position: relative; } 317.n-srch-panel { position: absolute; top: 120%;
317 right: 0; width: min(340px, 90vw); background: rgba(11,5,22,.97); border: 1px solid var(--glb); border-radius: var(--r); padding: 12px; z-index: 200; opacity: 0; pointer-events: none; transform: translateY(-8px) scale(.97); transition: all .22s var(--ease); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); } 318.n-srch-panel.open { opacity: 1; pointer-events: all; transform: none; } 319.n-srch-inp { width: 100%; background: var(--gl); border: 1px solid var(--glb); border-radius: var(--rs); padding: 10px 14px; color: #fff; font-size: .88rem; outline: none; transition: border-color .2s; } 320.n-srch-inp:focus { border-color: var(--p5); box-shadow: 0 0 0 3px rgba(230,26,26,.12); } 321.srch-item { display: flex; align-items: center; gap: 10px; padding: 9px 11px; border-radius: var(--rs); color: #fff; transition: background .15s; width: 100%; text-align: left; font-size: .85rem; } 322.srch-item:hover, .srch-item:focus-visible { background: var(--gl); } 323.srch-item mark { background: rgba(230,26,26,.3); color: #fff; border-radius: 3px; padding: 0 2px; } 324.lang-dd { position: absolute; top: 110%; right: 0; background: rgba(16,7,30,.97); border: 1px solid var(--glb); border-radius: var(--rs); min-width: 168px; z-index: 100; opacity: 0; pointer-events: none; transform: translateY(-5px) scale(.96); transition: all .18s var(--ease); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); overflow: hidden; list-style: none; } 325.lang-dd.open { opacity: 1; pointer-events: all; transform: none; } 326.lang-opt { padding: 11px 14px; font-size: .86rem; color: rgba(255,255,255,.72); transition: background .15s; display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; } 327.lang-opt:hover, .lang-opt:focus-visible { background: rgba(230,26,26,.14); color: #fff; } 328.hmb { display: none; flex-direction: column; gap: 5px; padding: 6px; border-radius: var(--rx); } 329.hmb span { display: block; width: 20px; height: 2px; background: #fff; border-radius: 2px; transition: all .3s var(--ease); } 330.hmb[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); } 331.hmb[aria-expanded="true"] span:nth-child(2) { opacity: 0; transform: scaleX(0); } 332.hmb[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); } 333.mob-menu { position: fixed; inset: 0; z-index: 1500; background: rgba(8,3,16,.97); backdrop-filter: blur(32px); -webkit-backdrop-filter: blur(32px); display: flex; flex-direction: column; align-items: center; justify-content: center; transform: translateX(100%); transition: transform .42s var(--ease); } 334.mob-menu.open { transform: none; } 335.mob-inner { text-align: center; width: 100%; max-width: 300px; } 336.mob-inner ul { list-style: none; display: flex; flex-direction: column; gap: 4px; margin-bottom: 32px; } 337.mob-inner a { color: rgba(255,255,255,.85); font-size: 1.4rem; font-weight: 700; font-family: var(--fd); padding: 13px 22px; display: block; border-radius: var(--r); transition: all .2s; } 338.mob-inner a:hover, .mob-inner a:focus-visible { color: #fff; background: var(--gl); } 339.mob-acts { display: flex; flex-direction: column; gap: 10px; } 340.mob-close { position: absolute; top: 22px; right: 22px; background: var(--gl); border: 1px solid var(--glb); color: #fff; font-size: 1.1rem; width: 42px; height: 42px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: all .2s; } 341.mob-close:hover, .mob-close:focus-visible { background: rgba(230,26,26,.2); } 342.hero { min-height: 100dvh; display: flex; align-items: center; position: relative; overflow: hidden; padding-top: 68px; perspective: 1400px; perspective-origin: 50% 50%; background: var(--ethereal-obsidian); } 343.hero-bg { position: absolute; inset: 0; background: radial-gradient(at 0% 0%, hsla(328,100%,15%,0.3) 0, transparent 50%), radial-gradient(at 100% 0%, hsla(272,100%,15%,0.3) 0, transparent 50%); } 344.hero-bg::before { content: ''; position: absolute; inset: 0; background: radial-gradient(circle at 20% 30%, var(--ethereal-glow-pink), transparent 50%), radial-gradient(circle at 80% 70%, var(--ethereal-glow-red), transparent 50%); filter: blur(80px); opacity: 0.5; animation: etherealPulse 15s ease-in-out infinite alternate; } 345@keyframes etherealPulse { from { transform: scale(1); opacity: 0.4; } to { transform: scale(1.1); opacity: 0.7; } } 346.hero-photo { position: absolute; top: 0; right: 0; width: 62%; height: 100%; background-image: url('/img/hero-flowers.webp'); background-size: cover; background-position: center center; clip-path: polygon(15% 0, 100% 0, 100% 100%, 0 100%); transform: translate3d(calc(var(--px,0) * 12px), calc(var(--py,0) * 8px), 0) scale(1.04); transition: transform .22s linear; will-change: transform; filter: saturate(1.1) brightness(0.95); } 347.hero-photo::before { content: ''; position: absolute; inset: 0; background: linear-gradient(to right, var(--ethereal-obsidian) 0%, rgba(5,2,10,0.85) 20%, rgba(5,2,10,0.3) 50%, rgba(5,2,10,0.1) 75%, transparent 100%); z-index: 1; } 348.hero-photo::after { content: ''; position: absolute; inset: 0; background: linear-gradient(to bottom, rgba(5,2,10,0.3) 0%, transparent 20%, transparent 80%, rgba(5,2,10,0.4) 100%); z-index: 1; } 349.hero-slash-1 { position: absolute; left: 42%; top: -5%; width: 4px; height: 110%; background: linear-gradient(to bottom, transparent, var(--p5), var(--pk), transparent); transform: skewX(-8deg) rotate(-3deg); z-index: 3; opacity: .4; pointer-events: none; filter: drop-shadow(0 0 12px var(--p5)); }
350.hero-scanlines { position: absolute; inset: 0; z-index: 5; pointer-events: none; opacity: .08; background: repeating-linear-gradient(0deg, transparent 0, transparent 3px, rgba(255,255,255,.5) 3px, rgba(255,255,255,.5) 4px); mix-blend-mode: overlay; } 351.hero-noise { position: absolute; inset: 0; z-index: 4; pointer-events: none; opacity: .06; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.8'/%3E%3C/svg%3E"); } 352.hero-grid { position: relative; z-index: 4; width: 100%; display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; padding: 80px 0 60px; transform-style: preserve-3d; } 353.hero-left { transform: translate3d(calc(var(--px,0) * -6px), calc(var(--py,0) * -4px), 0); transition: transform .22s linear; will-change: transform; } 354.hero-eyebrow { display: inline-flex; align-items: center; gap: 10px; margin-bottom: 24px; flex-wrap: wrap; } 355.hero-eyebrow-tag { font-family: var(--fc); font-style: italic; font-weight: 900; font-size: .68rem; letter-spacing: .18em; text-transform: uppercase; color: #fff; background: var(--p5); padding: 5px 14px 5px 16px; position: relative; white-space: nowrap; clip-path: polygon(4px 0, 100% 0, calc(100% - 4px) 100%, 0 100%); transform: skewX(-6deg); } 356.hero-eyebrow-tag > * { transform: skewX(6deg); display: inline-block; } 357.hero-eyebrow-tag::after { display: none; } 358.hero-eyebrow-sub { font-size: .78rem; color: rgba(255,255,255,.62); font-weight: 500; padding-left: 6px; white-space: nowrap; } 359.hero-hl { font-family: var(--fd); font-size: clamp(2.1rem, 5.2vw, 5rem); line-height: 1.15; font-weight: 900; letter-spacing: -.03em; margin-bottom: 24px; padding-bottom: 0.1em; overflow: visible; text-shadow: 0 4px 16px rgba(0,0,0,0.5), 0 2px 4px rgba(0,0,0,0.3); display: flex; flex-direction: column; align-items: flex-start; gap: 0.02em; } 360.hero-hl em { font-style: italic; font-weight: 400; color: rgba(255,255,255,.85); text-shadow: 0 2px 8px rgba(0,0,0,0.4); } 361.g-txt { background: linear-gradient(135deg, #fff 0%, var(--pk) 35%, var(--p5) 70%, var(--pk) 100%); background-size: 250% auto; -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; animation: txt-shine 5s linear infinite; padding-bottom: 0.15em; margin-bottom: -0.15em; display: inline-block; text-shadow: none !important; filter: none !important; } 362#typer { display: inline-grid; align-items: start; justify-items: start; vertical-align: baseline; } 363#typer .g-txt { grid-area: 1/1; opacity: 0; visibility: hidden; transform: translateY(8px); transition: opacity .3s var(--ease), transform .3s var(--ease); } 364#typer .g-txt.active { opacity: 1; visibility: visible; transform: none; } 365@keyframes txt-shine { to { background-position: 250% center; } } 366.hero-sub { font-size: 1.05rem; line-height: 1.72; color: rgba(255,255,255,0.85); max-width: 480px; margin-bottom: 36px; text-wrap: pretty; text-shadow: 0 1px 3px rgba(0,0,0,0.5); } 367.hero-cta { display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 36px; } 368.trust { display: flex; flex-wrap: wrap; gap: 18px; } 369.trust-item { display: flex; align-items: center; gap: 7px; font-size: .75rem; font-weight: 500; color: rgba(255,255,255,.58); } 370.trust-item svg { width: 14px; height: 14px; flex-shrink: 0; color: var(--mn); } 371.hero-countdown { display: inline-flex; align-items: center; gap: 14px; margin-bottom: 28px; background: rgba(230,26,26,.1); border: 1px solid rgba(230,26,26,.28); border-radius: 100px; padding: 7px 18px; } 372.cd-lbl { font-family: var(--fc); font-style: italic; font-weight: 700; font-size: .72rem; letter-spacing: .1em; color: rgba(255,255,255,.5); text-transform: uppercase; } 373.cd-units { display: flex; align-items: center; gap: 5px; } 374.cd-num { font-family: var(--fc); font-weight: 900; font-size: 1.1rem; color: var(--p5); min-width: 1.4em; text-align: center; font-variant-numeric: tabular-nums; } 375.cd-sub { font-size: .6rem; color: rgba(255,255,255,.35); display: block; line-height: 1; letter-spacing: .05em; text-transform: uppercase; text-align: center; } 376.cd-sep { color: var(--p5); font-weight: 900; font-family: var(--fc); } 377.hero-cards { position: relative; height: 520px; transform-style: preserve-3d; perspective: 1200px; } 378.h-card { position: absolute; background: linear-gradient(135deg, rgba(255,255,255,.08), rgba(255,255,255,.02)); border: 1px solid rgba(255,255,255,.15); border-radius: 24px; backdrop-filter: blur(24px) saturate(1.2); -webkit-backdrop-filter: blur(24px) saturate(1.2); padding: 22px; transition: box-shadow .4s var(--ease), border-color .4s; transform-style: preserve-3d; will-change: transform; overflow: visible; box-shadow: 0 16px 40px rgba(0,0,0,.2), inset 0 1px 0 rgba(255,255,255,.1); } 379.h-card::after { content: ''; position: absolute; inset: 0; border-radius: inherit; box-shadow: inset 0 0 20px rgba(230,26,26,.05); pointer-events: none; } 380.h-card::before { content: ''; position: absolute; inset: 0; background: radial-gradient(800px circle at var(--mx,50%) var(--my,50%), rgba(255,255,255,.12), transparent 40%), radial-gradient(400px circle at var(--mx,50%) var(--my,50%), rgba(230,26,26,.15), transparent 40%); opacity: 0; transition: opacity .4s var(--ease); pointer-events: none; border-radius: inherit; z-index: 3; mix-blend-mode: overlay; } 381.h-card:hover::before { opacity: 1; } 382.h-card:hover { box-shadow: 0 32px 80px rgba(168,16,16,.3), inset 0 1px 0 rgba(255,255,255,.2); border-color: rgba(230,26,26,.4); } 383.h-card-img { width: 100%; height: 120px; object-fit: cover; border-radius: 14px; margin-bottom: 12px; transition: transform .6s var(--spring), filter .6s var(--ease); transform: translateZ(20px); filter: brightness(0.95); box-shadow: 0 8px 24px rgba(0,0,0,.2); } 384.h-card:hover .h-card-img { transform: translateZ(40px) scale(1.08); filter: brightness(1.1); box-shadow: 0 16px 32px rgba(230,26,26,.3); } 385.hc-1 { width: 230px; top: 70px; left: 35%; transform: translateX(-50%) translateZ(60px); text-align: center; animation: ag1 8s ease-in-out infinite; z-index: 2; } 386.hc-2 { width: 210px; top: 0px; right: -15px; transform: translateZ(20px); animation: ag2 11s ease-in-out infinite; z-index: 5; } 387.hc-3 { width: 220px; bottom: 10px; left: -15px; transform: translateZ(35px); animation: ag3 9s ease-in-out infinite; z-index: 3; } 388@keyframes ag1 { 0%,100%{transform:translateX(-50%) translateY(0) translateZ(60px) rotate(-2deg) rotateX(4deg)} 50%{transform:translateX(-50%) translateY(-28px) translateZ(80px) rotate(1.5deg) rotateX(-2deg)} } 389@keyframes ag2 { 0%,100%{transform:translateY(0) translateZ(20px) rotate(3deg) rotateY(-4deg)} 50%{transform:translateY(-32px) translateZ(40px) rotate(-1.5deg) rotateY(2deg)} } 390@keyframes ag3 { 0%,100%{transform:translateY(0) translateZ(35px) rotate(-3deg) rotateX(-3deg)} 50%{transform:translateY(-24px) translateZ(55px) rotate(2deg) rotateX(2deg)} } 391.hc-pulse { position: absolute; top: -8px; right: -8px; width: 16px; height: 16px; background: var(--p5); border-radius: 50%; box-shadow: 0 0 12px var(--p5); transform: translateZ(30px); z-index: 5; } 392.hc-pulse::before { content: ''; position: absolute; inset: -6px; border-radius: 50%; background: rgba(230,26,26,.4); animation: ping 2s cubic-bezier(0, 0, 0.2, 1) infinite; } 393@keyframes ping { 0%{transform:scale(0.8);opacity:1} 100%{transform:scale(2.8);opacity:0}
393 } 394.hc-name { font-family: var(--fd); font-size: 1.05rem; font-weight: 700; margin-bottom: 6px; transform: translateZ(15px); text-shadow: 0 2px 8px rgba(0,0,0,.5); line-height: 1.3; } 395.hc-price { font-size: 1.05rem; font-weight: 700; color: var(--gd); transform: translateZ(15px); line-height: 1.3; margin-top: 2px; text-shadow: 0 1px 4px rgba(0,0,0,0.4); } 396.hc-meta { font-size: .75rem; color: rgba(255,255,255,.65); margin-top: 6px; transform: translateZ(10px); line-height: 1.4; text-shadow: 0 1px 2px rgba(0,0,0,0.3); } 397.hc-tag { display: inline-block; font-family: var(--fc); font-style: italic; font-weight: 700; font-size: .7rem; color: #fff; background: linear-gradient(135deg, var(--p5), var(--pk)); letter-spacing: .1em; padding: 5px 14px 5px 16px; margin-bottom: 10px; text-transform: uppercase; transform: translateZ(25px) skewX(-6deg); box-shadow: 0 4px 12px rgba(230,26,26,.3); clip-path: polygon(4px 0, 100% 0, calc(100% - 4px) 100%, 0 100%); white-space: nowrap; } 398.hc-sub { font-size: .85rem; font-weight: 600; color: rgba(255,255,255,.8); transform: translateZ(15px); line-height: 1.4; } 399.hc-status { font-size: .8rem; font-weight: 600; color: var(--mn); margin-top: 6px; display: flex; align-items: center; gap: 6px; transform: translateZ(15px); line-height: 1.4; } 400.hc-status::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--mn); box-shadow: 0 0 10px var(--mn); animation: ping2 2s ease-out infinite; flex-shrink: 0; } 401@keyframes ping2 { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:.4;transform:scale(0.8)} } 402canvas#ptcl { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2; } 403.stats-strip { background: var(--bg2); border-top: 1px solid var(--glb); border-bottom: 1px solid var(--glb); position: relative; overflow: hidden; margin-left: 0; margin-right: 0; } 404.stats-strip .con { max-width: 100%; width: 100%; padding: 0; margin: 0; } 405.stats-strip::before { content: ''; position: absolute; inset: 0; background: linear-gradient(135deg, rgba(230,26,26,.04), rgba(188,49,148,.03)); } 406.stats-inner { display: grid; grid-template-columns: repeat(4, 1fr); position: relative; z-index: 1; width: 100%; } 407.stat-item { padding: 36px 24px; text-align: center; position: relative; } 408.stat-item:not(:last-child)::after { content: ''; position: absolute; right: 0; top: 20%; bottom: 20%; width: 1px; background: var(--glb); } 409.stat-icon { font-size: 1.4rem; margin-bottom: 8px; display: block; } 410.stat-num { font-family: var(--fc); font-style: italic; font-weight: 900; font-size: clamp(1.6rem, 3.4vw, 2.6rem); line-height: 1; margin-bottom: 5px; background: linear-gradient(135deg, #fff, rgba(255,255,255,.68)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-variant-numeric: tabular-nums; } 411.stat-bar { height: 3px; max-width: 140px; background: rgba(255,255,255,.07); border-radius: 2px; margin: 12px auto 0; overflow: hidden; } 412.stat-bar-fill { height: 100%; width: 0; border-radius: 2px; background: linear-gradient(90deg, var(--p5), var(--pk)); transition: width 1.8s var(--ease); } 413.stat-lbl { font-family: var(--fc); font-style: italic; font-size: .72rem; letter-spacing: .12em; color: rgba(255,255,255,.58); text-transform: uppercase; margin-top: 10px; } 414.stat-src { font-size: .62rem; color: rgba(255,255,255,.48); margin-top: 6px; letter-spacing: .05em; } 415.stat-src a { color: rgba(255,255,255,.5); border-bottom: 1px dotted rgba(255,255,255,.2); } 416.stat-src a:hover { color: var(--p5l); border-bottom-color: var(--p5); } 417.bloom-academic-badge { position: fixed; bottom: 0; left: 0; right: 0; z-index: 99998; background: linear-gradient(135deg, rgba(5,2,10,0.95), rgba(30,10,40,0.95)); backdrop-filter: blur(12px); border-top: 1px solid rgba(230,26,26,.2); padding: 8px 16px; display: flex; align-items: center; justify-content: center; gap: 8px; font-size: .72rem; color: rgba(255,255,255,.55); letter-spacing: .03em; text-align: center; line-height: 1.5; } 418.bloom-academic-badge span { color: var(--p5l); font-weight: 600; } 419.bloom-academic-badge-close { background: none; border: none; color: rgba(255,255,255,.4); cursor: pointer; font-size: 1rem; padding: 0 4px; margin-left: 8px; } 420.bloom-academic-badge-close:hover { color: #fff; } 421.ai-gen-label { position: absolute; top: 8px; left: 8px; z-index: 5; display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border-radius: 6px; background: rgba(0,0,0,.65); backdrop-filter: blur(6px); border: 1px solid rgba(255,255,255,.1); font-size: .62rem; font-weight: 600; color: rgba(255,255,255,.7); letter-spacing: .06em; text-transform: uppercase; pointer-events: none; } 422.sec-pad { padding: 96px 0; } 423.sec-hd { display: flex; align-items: flex-end; justify-content: space-between; margin-bottom: 48px; flex-wrap: wrap; gap: 16px; } 424.sec-title { font-family: var(--fd); font-size: clamp(1.7rem, 3.2vw, 2.6rem); font-weight: 900; line-height: 1.1; letter-spacing: -.03em; text-wrap: balance; } 425.sec-sub { font-size: .9rem; color: rgba(255,255,255,.78); line-height: 1.7; margin-top: 8px; max-width: 440px; text-wrap: pretty; } 426.tag { display: inline-flex; align-items: center; gap: 6px; font-family: var(--fc); font-style: italic; font-weight: 700; font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; padding: 5px 16px 5px 18px; margin-bottom: 12px; transform: skewX(-6deg); clip-path: polygon(4px 0, 100% 0, calc(100% - 4px) 100%, 0 100%); white-space: nowrap; } 427.tag-p { background: rgba(230,26,26,.15); border: 1px solid rgba(230,26,26,.3); color: #FFB3B3; } 428.tag-m { background: rgba(0,212,170,.12); border: 1px solid rgba(0,212,170,.25); color: var(--mn); } 429.tag-a { background: rgba(124,58,237,.14); border: 1px solid rgba(124,58,237,.3); color: #a78bfa; } 430.cat-wrap { display: flex; align-items: center; gap: 8px; margin-bottom: 46px; } 431.cat-tabs { display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; padding: 3px 0; scroll-behavior: smooth; } 432.cat-tabs::-webkit-scrollbar { display: none; } 433.cat-tab { padding: 8px 18px; border-radius: 100px; font-family: var(--fc); font-style: italic; font-weight: 700; font-size: .84rem; letter-spacing: .05em; border: 1px solid var(--glb); background: var(--gl); color: rgba(255,255,255,.82); white-space: nowrap; transition: all .22s var(--ease); flex-shrink: 0; text-transform: uppercase; } 434.cat-tab:hover, .cat-tab:focus-visible { background: rgba(255,255,255,.08); color: rgba(255,255,255,.78); } 435.cat-tab.active { background: linear-gradient(135deg, rgba(230,26,26,.22), rgba(188,49,148,.15)); border-color: rgba(230,26,26,.45); color: #fff; } 436.cat-cnt { font-size: .7rem; color: rgba(255,255,255,.38); margin-left: 3px; font-style: normal; font-weight: 400; } 437.cat-arrow { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 50%; background: var(--gl); border: 1px solid var(--glb); color: #fff; flex-shrink: 0; transition: all .2s; font-size: 1rem; } 438.cat-arrow:hover, .cat-arrow:focus-visible { background: rgba(255,255,255,.14); } 439.cat-arrow:disabled { opacity: .3; } 440.p-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; min-height: 280px; perspective: 1000px; } 441.p-card { background: var(--gl); border: 1px solid var(--glb); border-radius: var(--r); padding: 20px; position: relative; transform-style: preserve-3d; opacity: 0; transition: box-shadow .5s var(--spring), border-color .4s, opacity .5s, transform .5s var(--spring); } 442.p-card.vis { opacity: 1; } 443.p-card:hover { border-color: rgba(230,26,26,.4); box-shadow: 0 24px 60px rgba(168,16,16,.3), inset 0 1px 0 rgba(255,255,255,.1); z-index: 10; } 444.p-shine { position: absolute; inset: 0; border-radius: var(--r); background: radial-gradient(circle at 50% -20%, rgba(255,255,255,.15) 0%, transparent 60%); opacity: 0; transition: opacity .4s; pointer-events: none; } 445.p-card:hover .p-shine { opacity: 1; } 446.p5-corner { position: absolute; top: 0; left: 0; width: 0; height: 0; border-top: 28px solid var(--p5); border-right: 28px solid transparent; border-radius: var(--r) 0 0 0; opacity: 0; transition: opacity .4s; } 447.p-card:hover .p5-corner { opacity: .8; filter: drop-shadow(2px 2px 4px rgba(230,26,26,.5)); } 448.p-badge { position: absolute; top: 10px; left: 10px; background: linear-gradient(135deg, var(--p5), var(--pk)); color: #fff; font-family: var(--fc); font-style: italic; font-weight: 900; font-size: .66rem; padding: 4px 12px 4px 14px; letter-spacing: .05em; text-transform: uppercase; z-index: 2; transform: translateZ(20px) skewX(-6deg); box-shadow: 0 4px 10px rgba(230,26,26,.3); clip-path: polygon(4px 0, 100% 0, calc(100% - 4px) 100%, 0 100%); white-space: nowrap; } 449.wl-btn { position: absolute; top: 10px; right: 10px; background: rgba(255,255,255,.07); border: 1px solid var(--glb); border-radius: 50%; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,.4); transition: all .3s var(--spring); z-index: 2; transform: translateZ(20px); backdrop-filter: blur(4px); } 450.wl-btn:hover, .wl-btn:focus-visible, .wl-btn.on { color: #fff; background: linear-gradient(135deg, var(--p5d), var(--p5)); border-color: transparent; box-shadow: 0 4px 12px rgba(230,26,26,.4); transform: translateZ(25px) scale(1.1); } 451.wl-pop { animation: wpop .5s var(--spring); } 452@keyframes wpop { 0%{transform:translateZ(20px) scale(1)} 50%{transform:translateZ(30px) scale(1.4)} 100%{transform:translateZ(25px) scale(1.1)} } 453.p-img { height: 180px; border-radius: 14px; overflow: hidden; background: rgba(230,26,26,.05); margin-bottom: 14px; position: relative; transform: translateZ(15px); transition: transform .4s var(--spring), box-shadow .4s; } 454.p-card:hover .p-img { transform: translateZ(30px); box-shadow: 0 12px 24px rgba(0,0,0,.3); } 455.p-img img { width: 100%; height: 100%; object-fit: cover; transition: transform .8s var(--ease), filter .8s var(--ease); filter: brightness(0.9); } 456.p-card:hover .p-img img { transform: scale(1.1); filter: brightness(1.05); } 457.p-img-ph { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; color: rgba(230,26,26,.35); font-size: 2.4rem; } 458.p-name { font-family: var(--fd); font-size: 1.05rem; font-weight: 700; margin-bottom: 4px; line-height: 1.3; transform: translateZ(20px); transition: transform .4s var(--spring), text-shadow .4s; } 459.p-card:hover .p-name { transform: translateZ(35px); text-shadow: 0 2px 4px rgba(0,0,0,.4); } 460.p-cat { font-family: var(--fc); font-style: italic; font-size: .75rem; color: rgba(255,255,255,.5); letter-spacing: .05em; text-transform: uppercase; margin-bottom: 8px; transform: translateZ(10px); transition: transform .4s var(--spring); } 461.p-card:hover .p-cat { transform: translateZ(25px); color: rgba(255,255,255,.7); } 462.p-stars { display: flex; gap: 1px; margin-bottom: 10px; font-size: .88rem; } 463.p-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; } 464.p-price { font-family: var(--fc); font-weight: 900; color: var(--gd); font-size: 1.1rem; font-variant-numeric: tabular-nums; } 465.p-add { background: linear-gradient(135deg, var(--p5d), var(--p5)); color: #fff; padding: 6px 14px; border-radius: 8px; font-size: .78rem; font-weight: 700; letter-spacing: .03em; transition: transform .2s, box-shadow .2s; } 466.p-add:hover, .p-add:focus-visible { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(230,26,26,.45); } 467.p-add:disabled { opacity: .5; } 468.p-empty { grid-column: 1 / -1; text-align: center; padding: 60px 20px; color: rgba(255,255,255,.45); font-size: .9rem; } 469.p-err { grid-column: 1 / -1; text-align: center; padding: 60px 20px; color: var(--cr); font-size: .9rem; } 470.p-skel { background: var(--gl); border: 1px solid var(--glb); border-radius: var(--r); padding: 20px; } 471.p-skel-img { height: 180px; border-radius: 14px; background: linear-gradient(90deg, var(--gl) 0%, rgba(255,255,255,.08) 50%, var(--gl) 100%); background-size: 200% 100%; animation: sk 1.4s ease-in-out infinite; margin-bottom: 14px; } 472.p-skel-t { height: 14px; border-radius: 4px; background: var(--gl); animation: sk 1.4s ease-in-out infinite; background-size: 200% 100%; background-image: linear-gradient(90deg, var(--gl) 0%, rgba(255,255,255,.08) 50%, var(--gl) 100%); margin-bottom: 8px; width: 70%; } 473.p-skel-s { height: 10px; border-radius: 4px; background: var(--gl); animation: sk 1.4s ease-in-out infinite; background-size: 200% 100%; background-image: linear-gradient(90deg, var(--gl) 0%, rgba(255,255,255,.08) 50%, var(--gl) 100%); width: 40%; } 474@keyframes sk { 0%{background-position:200% 0} 100%{background-position:-200% 0} } 475.feat-sec { background: var(--bg2); position: relative; overflow: hidden; perspective: 1200px; } 476.feat-sec::before { content: ''; position: absolute; top: -100px; left: 50%; transform: translateX(-50%); width: 700px; height: 700px; background: radial-gradient(circle, rgba(230,26,26,.08), transparent 60%); pointer-events: none; mix-blend-mode: screen; animation: p5GlowPulse 8s ease-in-out infinite; } 477.feat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; position: relative; z-index: 1; } 478.feat-card { background: linear-gradient(135deg, rgba(255,255,255,.04), rgba(255,255,255,.01)); border: 1px solid rgba(255,255,255,.08); border-radius: var(--r); padding: 32px 28px; position: relative; transition: transform .5s var(--spring), border-color .4s, box-shadow .5s, background .4s; opacity: 0; transform: translateY(30px) rotateX(10deg); transform-style: preserve-3d; } 479.feat-card.vis { opacity: 1; transform: translateY(0) rotateX(0); } 480.feat-card:hover { transform: translateY(-10px) translateZ(30px) rotateX(4deg); border-color: rgba(230,26,26,.4); box-shadow: 0 24px 60px rgba(168,16,16,.25), inset 0 1px 0 rgba(255,255,255,.1); background: linear-gradient(135deg, rgba(230,26,26,.08), rgba(255,255,255,.02)); z-index: 10; } 481.feat-ico { width: 56px; height: 56px; border-radius: 14px; background: linear-gradient(135deg, rgba(230,26,26,.25), rgba(188,49,148,.15)); border: 1px solid rgba(230,26,26,.4); display: flex; align-items: center; justify-content: center; margin-bottom: 24px; color: var(--p5l); transform: translateZ(20px); transition: transform .4s var(--spring), box-shadow .4s, background .4s; box-shadow: 0 8px 20px rgba(230,26,26,.15); } 482.feat-card:hover .feat-ico { transform: translateZ(40px) scale(1.1); box-shadow: 0 12px 28px rgba(230,26,26,.35); background: linear-gradient(135deg, var(--p5d), var(--p5)); color: #fff; border-color: transparent; } 483.feat-ico svg { width: 24px; height: 24px; } 484.feat-t { font-family: var(--fd); font-size: 1.15rem; font-weight: 700; margin-bottom: 12px; transform: translateZ(15px); transition: transform .4s var(--spring); } 485.feat-card:hover .feat-t { transform: translateZ(30px); text-shadow: 0 2px 4px rgba(0,0,0,.3); } 486.feat-d { font-size: .88rem; color: rgba(255,255,255,.6); line-height: 1.7; transform: translateZ(5px); transition: transform .4s var(--spring), color .4s; } 487.feat-card:hover .feat-d { transform: translateZ(20px); color: rgba(255,255,255,.8); } 488.rev-sec { background: var(--bg); } 489.rev-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; } 490.rev-card { background: var(--gl); border: 1px solid var(--glb); border-radius: var(--r); padding: 28px; position: relative; opacity: 0; transform: translateY(16px); transition: opacity .5s var(--ease), transform .5s var(--ease); } 491.rev-card.vis { opacity: 1; transform: translateY(0); } 492.rev-card::before { content: '"'; position: absolute; top: 14px; right: 22px; font-family: var(--fd); font-size: 4rem; color: rgba(230,26,26,.18); line-height: 1; font-weight: 900; } 493.rev-stars { display: flex; gap: 2px; margin-bottom: 14px; font-size: .95rem; } 494.rev-body { font-size: .9rem; line-height: 1.7; color: rgba(255,255,255,.76); margin-bottom: 18px; text-wrap: pretty; } 495.rev-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; } 496.rev-name { font-family: var(--fd); font-weight: 700; font-size: .9rem; } 497.rev-role { font-size: .72rem; color: rgba(255,255,255,.4); margin-top: 2px; } 498.rev-mob { display: none; align-items: center; justify-content: center; gap: 12px
498; margin-top: 22px; } 499.rev-navb { width: 36px; height: 36px; border-radius: 50%; background: var(--gl); border: 1px solid var(--glb); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 1rem; } 500.rev-navb:hover, .rev-navb:focus-visible { background: rgba(230,26,26,.16); } 501.rev-dots { display: flex; gap: 6px; } 502.rev-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--glb); transition: background .2s, width .2s; } 503.rev-dot.active { background: var(--p5); width: 24px; border-radius: 4px; } 504.facts-sec { background: var(--bg3); border-top: 1px solid var(--glb); border-bottom: 1px solid var(--glb); position: relative; } 505.facts-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; } 506.fact-card { padding: 28px 28px 28px 32px; border-radius: var(--r); background: var(--gl); border: 1px solid var(--glb); position: relative; overflow: hidden; } 507.fact-card::before { content: ''; position: absolute; top: -4px; left: 0; width: 4px; height: calc(100% + 8px); background: linear-gradient(to bottom, var(--p5), var(--pk)); transform: skewY(-4deg); } 508.fact-k { font-family: var(--fc); font-style: italic; font-weight: 900; font-size: 2.4rem; line-height: 1; color: #fff; margin-bottom: 8px; } 509.fact-t { font-family: var(--fd); font-weight: 700; font-size: 1rem; margin-bottom: 10px; } 510.fact-d { font-size: .82rem; color: rgba(255,255,255,.58); line-height: 1.7; margin-bottom: 12px; } 511.fact-src { font-size: .7rem; color: rgba(255,255,255,.4); } 512.fact-src a { color: rgba(255,255,255,.58); border-bottom: 1px dotted rgba(255,255,255,.2); } 513.fact-src a:hover, .fact-src a:focus-visible { color: var(--p5l); border-bottom-color: var(--p5); } 514.corp-sec { background: var(--bg); } 515.corp-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 60px; align-items: start; } 516.corp-photo { border-radius: var(--r); overflow: hidden; aspect-ratio: 4/3; position: relative; background: var(--gl); min-height: 320px; } 517.corp-photo img { width: 100%; height: 100%; object-fit: cover; display: block; } 518.corp-photo::after { content: ''; position: absolute; inset: 0; background: linear-gradient(135deg, transparent 50%, rgba(230,26,26,.2) 100%); } 519.corp-list { list-style: none; display: flex; flex-direction: column; gap: 14px; margin-top: 24px; margin-bottom: 28px; } 520.corp-list li { display: flex; align-items: flex-start; gap: 12px; font-size: .9rem; color: rgba(255,255,255,.72); line-height: 1.6; } 521.corp-list svg { width: 18px; height: 18px; flex-shrink: 0; color: var(--mn); margin-top: 3px; } 522.bloom-foot { background: var(--ink); padding: 72px 0 32px; border-top: 1px solid var(--glb); } 523.foot-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 40px; margin-bottom: 48px; } 524.foot-brand { font-family: var(--fd); font-size: 1.4rem; font-weight: 900; margin-bottom: 14px; background: linear-gradient(135deg, #fff 0%, var(--pk) 60%, var(--p5) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } 525.foot-tag { font-size: .85rem; color: rgba(255,255,255,.54); line-height: 1.7; margin-bottom: 18px; max-width: 340px; text-wrap: pretty; } 526.nl-form { display: flex; gap: 8px; max-width: 340px; align-items: stretch; height: 40px; } 527.nl-inp { flex: 1; background: var(--gl); border: 1px solid var(--glb); border-radius: var(--rs); padding: 0 14px; color: #fff; font-size: .86rem; outline: none; transition: border-color .2s; height: 100%; } 528.nl-form .btn { height: 100%; padding: 0 18px; align-items: center; } 529.nl-inp:focus { border-color: var(--p5); box-shadow: 0 0 0 3px rgba(230,26,26,.12); } 530.foot-col h4 { font-family: var(--fd); font-size: .95rem; font-weight: 700; margin-bottom: 16px; } 531.foot-col ul { list-style: none; display: flex; flex-direction: column; gap: 10px; } 532.foot-col a { font-size: .82rem; color: rgba(255,255,255,.52); transition: color .2s; } 533.foot-col a:hover, .foot-col a:focus-visible { color: var(--p5l); } 534.foot-bottom { display: flex; align-items: center; justify-content: space-between; gap: 20px; padding-top: 24px; border-top: 1px solid var(--glb); font-size: .76rem; color: rgba(255,255,255,.4); flex-wrap: wrap; } 535.foot-soc { display: flex; gap: 10px; } 536.foot-soc a { width: 34px; height: 34px; border-radius: 50%; background: var(--gl); border: 1px solid var(--glb); display: flex; align-items: center; justify-content: center; color: rgba(255,255,255,.6); transition: all .2s; } 537.foot-soc a:hover, .foot-soc a:focus-visible { background: rgba(230,26,26,.16); color: #fff; border-color: rgba(230,26,26,.4); } 538.foot-soc svg { width: 14px; height: 14px; } 539.btt { position: fixed; bottom: 28px; right: 28px; width: 46px; height: 46px; border-radius: 50%; background: linear-gradient(135deg, var(--p5d), var(--p5)); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; opacity: 0; pointer-events: none; transition: all .3s var(--ease); z-index: 900; box-shadow: 0 6px 20px rgba(230,26,26,.35); } 540.btt.vis { opacity: 1; pointer-events: all; } 541.btt:hover, .btt:focus-visible { transform: translateY(-4px); box-shadow: 0 10px 28px rgba(230,26,26,.55); } 542.overlay { position: fixed; inset: 0; z-index: 2000; background: rgba(6,2,14,.82); backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); display: none; align-items: center; justify-content: center; padding: 20px; } 543.overlay.open { display: flex; animation: ofade .22s var(--ease); } 544@keyframes ofade { from{opacity:0}
544 to{opacity:1} } 545.modal { background: linear-gradient(180deg, var(--bg2), var(--bg)); border: 1px solid var(--glb); border-radius: var(--r); padding: 36px; max-width: 440px; width: 100%; position: relative; animation: mpop .32s var(--spring); max-height: 90vh; overflow-y: auto; } 546@keyframes mpop { from{opacity:0;transform:translateY(20px) scale(.96)} to{opacity:1;transform:none} } 547.m-hd { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; } 548.m-cls { background: var(--gl); border: 1px solid var(--glb); color: #fff; width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: .9rem; transition: all .2s; } 549.m-cls:hover, .m-cls:focus-visible { background: rgba(230,26,26,.2); } 550.m-sub { font-size: .9rem; color: rgba(255,255,255,.6); margin-bottom: 22px; line-height: 1.6; } 551.sl-btn { width: 100%; justify-content: center; margin-bottom: 16px; background: #fff; color: var(--ink); } 552.sl-btn:hover { background: rgba(255,255,255,.92); } 553.div-lbl { text-align: center; font-size: .75rem; color: rgba(255,255,255,.4); margin: 16px 0; position: relative; letter-spacing: .1em; text-transform: uppercase; } 554.div-lbl::before, .div-lbl::after { content: ''; position: absolute; top: 50%; width: calc(50% - 30px); height: 1px; background: var(--glb); } 555.div-lbl::before { left: 0; } 556.div-lbl::after { right: 0; } 557.fi { margin-bottom: 14px; } 558.fi-lbl { display: block; font-size: .78rem; color: rgba(255,255,255,.64); margin-bottom: 6px; font-weight: 500; } 559.fi-wrap { position: relative; } 560.fi-inp { width: 100%; background: var(--gl); border: 1px solid var(--glb); border-radius: var(--rs); padding: 11px 14px; color: #fff; font-size: .9rem; outline: none; transition: border-color .2s; } 561.fi-inp:focus { border-color: var(--p5); box-shadow: 0 0 0 3px rgba(230,26,26,.12); } 562.fi-inp[aria-invalid="true"] { border-color: var(--cr); } 563.fe { font-size: .72rem; color: var(--cr); margin-top: 5px; display: block; min-height: 14px; } 564.pw-tog { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); color: rgba(255,255,255,.5); font-size: .75rem; padding: 4px 8px; } 565.pw-tog:hover { color: #fff; } 566.fpl-btn { font-size: .76rem; color: rgba(255,255,255,.6); margin-bottom: 12px; padding: 0; } 567.fpl-btn:hover, .fpl-btn:focus-visible { color: var(--p5l); } 568.str-bar { height: 3px; background: var(--gl); border-radius: 2px; overflow: hidden; margin-top: 6px; margin-bottom: 4px; } 569.str-fill { height: 100%; width: 0; transition: width .3s, background .3s; } 570.str-lbl { font-size: .7rem; color: rgba(255,255,255,.5); } 571.a-tabs { display: flex; gap: 3px; background: var(--gl); border-radius: var(--rs); padding: 3px; margin-bottom: 22px; } 572.a-tab { flex: 1; padding: 8px 14px; border-radius: 9px; font-size: .82rem; font-weight: 600; color: rgba(255,255,255,.55); transition: all .2s; } 573.a-tab.active { background: linear-gradient(135deg, var(--p5d), var(--p5)); color: #fff; box-shadow: 0 4px 14px rgba(230,26,26,.3); } 574.occ-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 20px 0; } 575.occ-btn { padding: 18px 14px; border-radius: var(--rs); border: 1.5px solid var(--glb); background: var(--gl); color: rgba(255,255,255,.8); font-size: .9rem; font-weight: 600; transition: all .24s var(--spring); text-align: center; line-height: 1.3; } 576.occ-btn:hover, .occ-btn:focus-visible { border-color: rgba(230,26,26,.45); background: rgba(230,26,26,.1); color: #fff; transform: translateY(-2px); } 577.occ-btn.selected { border-color: var(--p5); background: linear-gradient(135deg, rgba(230,26,26,.18), rgba(168,16,16,.1)); color: #fff; box-shadow: 0 0 0 3px rgba(230,26,26,.18); } 578.occ-emj { font-size: 1.4rem; display: block; margin-bottom: 6px; } 579.toast-con { position: fixed; top: 88px; right: 24px; z-index: 3000; display: flex; flex-direction: column; gap: 10px; max-width: 360px; pointer-events: none; } 580.toast { background: rgba(16,7,30,.96); border: 1px solid var(--glb); backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px); border-radius: var(--rs); padding: 14px 18px; font-size: .85rem; color: #fff; box-shadow: 0 10px 40px rgba(0,0,0,.4); animation: tslide .3s var(--spring); display: flex; align-items: flex-start; gap: 10px; pointer-events: all; } 581.toast-success { border-left: 3px solid var(--mn); transform: skewX(-1deg); } 582.toast-error { border-left: 3px solid var(--cr); transform: skewX(-1deg); } 583.toast-info { border-left: 3px solid var(--p5l); transform: skewX(-1deg); } 584.toast-ico { flex-shrink: 0; } 585@keyframes tslide { from{transform:translateX(60px);opacity:0}
585 to{transform:none;opacity:1} } 586.anim-in { opacity: 0; transform: translateY(20px); transition: opacity .6s var(--ease), transform .6s var(--ease); } 587.anim-in.vis { opacity: 1; transform: none; } 588@supports (animation-timeline: view()) { 589 .anim-auto { animation: reveal linear both; animation-timeline: view(); animation-range: entry 10% cover 30%; } 590 @keyframes reveal { from { opacity: 0; transform: translateY(40px); } to { opacity: 1; transform: none; } } 591} 592@starting-style { .overlay.open { opacity: 0; } } 593.p5-sec-div { position: relative; height: 80px; overflow: visible; display: flex; align-items: center; justify-content: center; opacity: 1; margin: 0; } 594.p5-sec-div::before { content: ''; position: absolute; left: -5%; top: 50%; width: 110%; height: 3px; background: linear-gradient(90deg, transparent 0%, rgba(230,26,26,0.15) 10%, var(--p5) 30%, var(--pk) 50%, var(--p5) 70%, rgba(230,26,26,0.15) 90%, transparent 100%); transform: skewY(-1.8deg); filter: drop-shadow(0 0 6px rgba(230,26,26,.45)); } 595.p5-sec-div::after { content: ''; position: absolute; left: 50%; top: 50%; width: 10px; height: 10px; background: var(--p5); transform: translate(-50%, -50%) rotate(45deg) skewY(-1.8deg); box-shadow: 0 0 18px 4px rgba(230,26,26,.6), 0 0 40px 8px rgba(230,26,26,.2); } 596.p5-glow { position: absolute; width: 300px; height: 300px; border-radius: 50%; background: radial-gradient(circle, rgba(230,26,26,.12), transparent 70%); pointer-events: none; filter: blur(40px); animation: p5GlowPulse 4s ease-in-out infinite; } 597@keyframes p5GlowPulse { 0%,100% { opacity: .4; transform: scale(1); } 50% { opacity: .7; transform: scale(1.15); } } 598.p5-tilt { transform-style: preserve-3d; transition: transform .4s var(--spring); } 599.p5-tilt:hover { transform: perspective(800px) rotateX(var(--tiltX, 0deg)) rotateY(var(--tiltY, 0deg)) scale(1.02); } 600.p5-tilt-inner { transform: translateZ(30px); } 601.magnetic-btn { position: relative; transition: transform .3s var(--spring); } 602.magnetic-btn:hover { transform: translate(var(--magX, 0), var(--magY, 0)) scale(1.04); } 603.magnetic-btn::after { content: ''; position: absolute; inset: -2px; border-radius: inherit; background: linear-gradient(135deg, var(--p5), var(--pk), var(--p5)); opacity: 0; z-index: -1; filter: blur(8px); transition: opacity .3s; } 604.magnetic-btn:hover::after { opacity: .6; } 605.ripple-effect { position: relative; overflow: hidden; } 606.ripple-effect .ripple { position: absolute; border-radius: 50%; background: rgba(230,26,26,.35); transform: scale(0); animation: rippleAnim .6s ease-out forwards; pointer-events: none; } 607@keyframes rippleAnim { to { transform: scale(4); opacity: 0; } } 608.glass-ethereal { background: linear-gradient(135deg, rgba(255,255,255,.06), rgba(255,255,255,.02)); border: 1px solid rgba(255,255,255,.1); backdrop-filter: blur(24px) saturate(1.4); -webkit-backdrop-filter: blur(24px) saturate(1.4); box-shadow: 0 8px 32px rgba(0,0,0,.3), inset 0 1px 0 rgba(255,255,255,.1); } 609.shimmer { position: relative; overflow: hidden; } 610.shimmer::after { content: ''; position: absolute; top: 0; left: -100%; width: 60%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,.06), transparent); animation: shimmerSlide 3s ease-in-out infinite; } 611@keyframes shimmerSlide { 0% { left: -100%; } 100% { left: 200%; } } 612.float-y { animation: floatY 6s ease-in-out infinite; } 613@keyframes floatY { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-12px); } } 614.hero-3d-scene { perspective: 1200px; perspective-origin: 50% 40%; } 615.stagger-1 { transition-delay: .05s; } 616.stagger-2 { transition-delay: .1s; } 617.stagger-3 { transition-delay: .15s; } 618.stagger-4 { transition-delay: .2s; } 619.stagger-5 { transition-delay: .25s; } 620.stagger-6 { transition-delay: .3s; } 621.stagger-7 { transition-delay: .35s; } 622.stagger-8 { transition-delay: .4s; } 623.p5-line-h { height: 3px; background: linear-gradient(90deg, transparent, var(--p5), var(--pk), transparent); margin: 0 auto; transform: skewY(-1.8deg); filter: drop-shadow(0 0 4px rgba(230,26,26,.3)); } 624.p5-line-v { width: 3px; background: linear-gradient(to bottom, transparent, var(--p5), transparent); transform: skewX(-4deg); } 625.hero-orb { position: absolute; border-radius: 50%; filter: blur(80px); pointer-events: none; will-change: transform; } 626.hero-orb-1 { width: 600px; height: 600px; background: radial-gradient(circle, rgba(230,26,26,.15), transparent 70%); top: -200px; right: -150px; animation: orbDrift1 22s ease-in-out infinite; mix-blend-mode: screen; filter: blur(40px); pointer-events: none; } 627.hero-orb-2 { width: 500px; height: 500px; background: radial-gradient(circle, rgba(188,49,148,.12), transparent 70%); bottom: -150px; left: 5%; animation: orbDrift2 26s ease-in-out infinite; mix-blend-mode: screen; filter: blur(50px); pointer-events: none; }
628@keyframes orbDrift1 { 0%,100% { transform: translate3d(0,0,0) scale(1) rotate(0deg); opacity: 0.7; } 33% { transform: translate3d(60px,-50px,40px) scale(1.15) rotate(10deg); opacity: 1; filter: blur(30px); } 66% { transform: translate3d(-30px,40px,-20px) scale(.9) rotate(-5deg); opacity: 0.6; filter: blur(50px); } } 629@keyframes orbDrift2 { 0%,100% { transform: translate3d(0,0,0) scale(1); opacity: 0.6; } 50% { transform: translate3d(-50px,-40px,30px) scale(1.2); opacity: 0.9; filter: blur(35px); } } 630.p5-card-enter { opacity: 0; transform: translateY(40px) rotateX(8deg); transition: opacity .7s var(--ease), transform .7s var(--ease); } 631.p5-card-enter.vis { opacity: 1; transform: translateY(0) rotateX(0); } 632input:-webkit-autofill, 633input:-webkit-autofill:hover, 634input:-webkit-autofill:focus { 635 -webkit-text-fill-color: #fff; 636 -webkit-box-shadow: 0 0 0 1000px var(--bg2) inset; 637 transition: background-color 5000s ease-in-out 0s; 638} 639@supports (padding: env(safe-area-inset-bottom)) { 640 .bloom-foot { padding-bottom: calc(32px + env(safe-area-inset-bottom)); } 641 .btt { bottom: calc(28px + env(safe-area-inset-bottom)); } 642 #nav { padding-left: max(40px, env(safe-area-inset-left)); padding-right: max(40px, env(safe-area-inset-right)); } 643} 644@media (max-width: 1100px) { 645 .p-grid { grid-template-columns: repeat(3, 1fr); } 646 .feat-grid { grid-template-columns: repeat(2, 1fr); } 647 .facts-grid { grid-template-columns: repeat(3, 1fr); } 648} 649@media (max-width: 900px) { 650 .n-links { display: none; } 651 .hmb { display: flex; } 652 .hero-grid { grid-template-columns: 1fr; padding: 40px 0; } 653 .hero-photo { width: 100%; clip-path: none; opacity: .65; } 654 .hero-slash-1 { display: none; } 655 .hero-cards { display: none; } 656 .stats-inner { grid-template-columns: repeat(2, 1fr); } 657 .stat-item:nth-child(2)::after { display: none; } 658 .p-grid { grid-template-columns: repeat(2, 1fr); } 659 .feat-grid { grid-template-columns: 1fr 1fr; } 660 .rev-grid { grid-template-columns: 1fr; } 661 .rev-grid .rev-card { display: none; } 662 .rev-grid .rev-card.mob-active { display: block; } 663 .rev-mob { display: flex; } 664 .facts-grid { grid-template-columns: 1fr; } 665 .corp-grid { grid-template-columns: 1fr; gap: 32px; } 666 .foot-grid { grid-template-columns: 1fr 1fr; gap: 32px; } 667 #nav { padding: 0 20px; } 668 .n-acts #authBtn, .n-acts #langWrap, .n-acts #wlBtnNav { display: none !important; } 669 .sec-pad { padding: 72px 0; } 670 .toast-con { top: 76px; right: 14px; left: 14px; max-width: none; } 671} 672@media (max-width: 560px) { 673 .p-grid { grid-template-columns: 1fr 1fr; gap: 12px; } 674 .p-card { padding: 14px; } 675 .p-img { height: 140px; } 676 .feat-grid { grid-template-columns: 1fr; } 677 .foot-grid { grid-template-columns: 1fr; } 678 .stat-num { font-size: 1.5rem; } 679} 680#bloomBoot { position: fixed; inset: 0; background: radial-gradient(circle at 50% 50%, oklch(13% .07 292) 0%, var(--bg) 70%); z-index: 100000; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 28px; transition: opacity .6s var(--ease), visibility .6s; } 681#bloomBoot.gone { opacity: 0; visibility: hidden; pointer-events: none; } 682.bloom-flower { position: relative; width: 140px; height: 140px; transform-style: preserve-3d; animation: bloomSpin 8s linear infinite; } 683.bloom-petal { position: absolute; left: 50%; top: 50%; width: 56px; height: 80px; margin: -40px 0 0 -28px; background: linear-gradient(180deg, var(--p5l), var(--p5d)); border-radius: 100% 100% 60% 60% / 70% 70% 60% 60%; transform-origin: 50% 100%; opacity: 0; box-shadow: inset -6px -8px 18px rgba(0,0,0,.32), 0 6px 14px rgba(230,26,26,.35); animation: petalBloom 2.4s var(--p5ease) forwards; } 684.bloom-petal:nth-child(1) { transform: rotate(0deg) translateY(-30px); animation-delay: 0s; } 685.bloom-petal:nth-child(2) { transform: rotate(45deg) translateY(-30px); animation-delay: .12s; } 686.bloom-petal:nth-child(3) { transform: rotate(90deg) translateY(-30px); animation-delay: .24s; } 687.bloom-petal:nth-child(4) { transform: rotate(135deg) translateY(-30px); animation-delay: .36s; } 688.bloom-petal:nth-child(5) { transform: rotate(180deg) translateY(-30px); animation-delay: .48s; } 689.bloom-petal:nth-child(6) { transform: rotate(225deg) translateY(-30px); animation-delay: .6s; } 690.bloom-petal:nth-child(7) { transform: rotate(270deg) translateY(-30px); animation-delay: .72s; } 691.bloom-petal:nth-child(8) { transform: rotate(315deg) translateY(-30px); animation-delay: .84s; } 692.bloom-core { position: absolute; left: 50%; top: 50%; width: 40px; height: 40px; margin: -20px 0 0 -20px; background: radial-gradient(circle, var(--gd), var(--p5)); border-radius: 50%; box-shadow: 0 0 30px rgba(230,26,26,.6), inset 0 0 12px rgba(0,0,0,.3); transform: scale(0); animation: coreBloom 1.6s var(--spring) .9s forwards; } 693@keyframes petalBloom { 0% { opacity: 0; transform: rotate(var(--r,0deg)) translateY(0) scale(.2); } 60% { opacity: 1; transform: rotate(var(--r,0deg)) translateY(-30px) scale(1.08); } 100% { opacity: 1; transform: rotate(var(--r,0deg)) translateY(-30px) scale(1); } } 694@keyframes coreBloom { to { transform: scale(1); } } 695@keyframes bloomSpin { to { transform: rotateZ(360deg); } } 696.bloom-petal:nth-child(1) { --r: 0deg; } .bloom-petal:nth-child(2) { --r: 45deg; } .bloom-petal:nth-child(3) { --r: 90deg; } .bloom-petal:nth-child(4) { --r: 135deg; } .bloom-petal:nth-child(5) { --r: 180deg; } .bloom-petal:nth-child(6) { --r: 225deg; } .bloom-petal:nth-child(7) { --r: 270deg; } .bloom-petal:nth-child(8) { --r: 315deg; } 697.bloom-boot-txt { font-family: var(--fc); font-style: italic; font-weight: 900; letter-spacing: .3em; color: rgba(255,255,255,.55); font-size: .8rem; text-transform: uppercase; animation: bootPulse 2s ease-in-out infinite; } 698@keyframes bootPulse { 0%,100% { opacity: .35; } 50% { opacity: 1; } } 699.bloom-boot-bar { width: 220px; height: 2px; background: rgba(255,255,255,.06); border-radius: 1px; overflow: hidden; } 700.bloom-boot-bar i { display: block; width: 30%; height: 100%; background: linear-gradient(90deg, var(--p5), var(--pk), var(--p5)); animation: bootSlide 1.6s ease-in-out infinite; } 701@keyframes bootSlide { 0% { transform: translateX(-100%); } 100% { transform: translateX(380%); } } 702.p-skel { background: var(--gl); border: 1px solid var(--glb); border-radius: var(--r); padding: 20px; position: relative; overflow: hidden; } 703.p-skel-img { height: 180px; border-radius: 14px; background: radial-gradient(circle at 50% 50%, rgba(230,26,26,.18), rgba(11,5,22,.4)); position: relative; overflow: hidden; margin-bottom: 14px; } 704.p-skel-img::before { content: ''; position: absolute; inset: 0; background: conic-gradient(from 0deg, transparent 0%, rgba(230,26,26,.12) 25%, transparent 50%); animation: skelSpin 1.6s linear infinite; } 705.p-skel-img::after { content: '\1F339'; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: rgba(230,26,26,.45); font-size: 2.2rem; animation: skelBloom 1.8s ease-in-out infinite; } 706@keyframes skelSpin { to { transform: rotate(360deg); } } 707@keyframes skelBloom { 0%,100% { transform: scale(.85); opacity: .35; } 50% { transform: scale(1.1); opacity: .9; } } 708.delivery-bar { position: sticky; top: 68px; z-index: 990; background: linear-gradient(90deg, oklch(15% .08 292 / .96), oklch(11% .06 292 / .92)); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); border-bottom: 2px solid rgba(230,26,26,.22); padding: 10px 0; transition: transform .3s var(--ease); } 709.delivery-bar.hide { transform: translateY(-100%); } 710.delivery-inner { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; justify-content: center; } 711.delivery-pill { display: inline-flex; align-items: center; gap: 8px; padding: 6px 14px; background: rgba(230,26,26,.12); border: 1px solid rgba(230,26,26,.28); border-radius: 100px; font-family: var(--fc); font-style: italic; font-weight: 700; font-size: .72rem; color: var(--p5l); letter-spacing: .12em; text-transform: uppercase; } 712.delivery-pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--mn); box-shadow: 0 0 8px var(--mn); animation: ping2 1.6s ease-out infinite; } 713.delivery-fields { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } 714.dlv-fld { display: flex; align-items: center; gap: 8px; background: var(--gl); border: 1px solid var(--glb); border-radius: 10px; padding: 6px 12px; transition: border-color .2s; } 715.dlv-fld:focus-within { border-color: var(--p5); box-shadow: 0 0 0 3px rgba(230,26,26,.12); } 716.dlv-fld svg { width: 14px; height: 14px; color: var(--p5l); flex-shrink: 0; } 717.dlv-fld label { font-size: .68rem; color: rgba(255,255,255,.5); font-weight: 600; letter-spacing: .05em; text-transform: uppercase; } 718.dlv-fld input, .dlv-fld select { background: transparent; border: none; color: #fff; font-size: .82rem; font-weight: 600; outline: none; min-width: 0; padding: 2px 0; cursor: pointer; } 719.dlv-fld select option { background: var(--bg2); color: #fff; } 720.dlv-eta { font-size: .76rem; color: var(--mn); font-weight: 600; }
721.dlv-eta strong { font-family: var(--fc); font-style: italic; font-weight: 900; } 722@media (max-width: 768px) { 723 .delivery-inner { gap: 8px; } 724 .delivery-pill { font-size: .64rem; padding: 4px 10px; } 725 .dlv-fld { padding: 5px 10px; } 726 .dlv-fld label { display: none; } 727} 728.subs-sec { background: var(--bg2); position: relative; overflow: hidden; } 729.subs-sec::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: linear-gradient(90deg, transparent, var(--p5), var(--pk), transparent); opacity: .4; } 730.subs-grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: 56px; align-items: center; } 731.subs-photo { position: relative; border-radius: var(--r); overflow: hidden; aspect-ratio: 4/3; box-shadow: 0 30px 80px rgba(168,16,16,.32); transform: rotate(-1.5deg); } 732.subs-photo img { width: 100%; height: 100%; object-fit: cover; } 733.subs-photo::before { content: ''; position: absolute; inset: 0; background: linear-gradient(135deg, transparent 50%, rgba(230,26,26,.18)); } 734.subs-photo::after { content: 'WEEKLY'; position: absolute; top: 18px; left: 18px; font-family: var(--fc); font-style: italic; font-weight: 900; font-size: .76rem; letter-spacing: .15em; color: #fff; background: var(--p5); padding: 5px 16px 5px 18px; transform: skewX(-6deg); clip-path: polygon(4px 0, 100% 0, calc(100% - 4px) 100%, 0 100%); } 735.subs-cards { display: flex; flex-direction: column; gap: 14px; } 736.subs-card { background: var(--gl); border: 1px solid var(--glb); border-radius: var(--r); padding: 22px; cursor: pointer; transition: all .25s var(--ease); position: relative; overflow: hidden; } 737.subs-card::before { content: ''; position: absolute; inset: 0; background: linear-gradient(135deg, rgba(230,26,26,.06), transparent 60%); opacity: 0; transition: opacity .3s; } 738.subs-card:hover { border-color: rgba(230,26,26,.4); transform: translateX(6px); } 739.subs-card:hover::before { opacity: 1; } 740.subs-card.selected { border-color: var(--p5); background: rgba(230,26,26,.1); box-shadow: 0 12px 36px rgba(230,26,26,.22); } 741.subs-card-hd { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin-bottom: 8px; position: relative; } 742.subs-card-name { font-family: var(--fd); font-size: 1.15rem; font-weight: 700; } 743.subs-card-name em { font-family: var(--fc); font-style: italic; color: var(--p5l); font-weight: 900; font-size: .68rem; letter-spacing: .12em; text-transform: uppercase; padding: 2px 8px; background: rgba(230,26,26,.18); border-radius: 3px; margin-left: 8px; vertical-align: middle; } 744.subs-card-price { font-family: var(--fc); font-style: italic; font-weight: 900; font-size: 1.4rem; color: var(--gd); white-space: nowrap; } 745.subs-card-price small { font-size: .65rem; color: rgba(255,255,255,.45); font-weight: 600; letter-spacing: .05em; } 746.subs-card-d { font-size: .82rem; color: rgba(255,255,255,.6); line-height: 1.6; margin-bottom: 12px; position: relative; } 747.subs-card-feats { display: flex; flex-wrap: wrap; gap: 6px; position: relative; } 748.subs-card-feats span { font-size: .7rem; color: rgba(255,255,255,.55); padding: 3px 10px; background: rgba(255,255,255,.05); border-radius: 100px; } 749.subs-cta { display: flex; gap: 10px; margin-top: 8px; } 750.subs-cta .btn { flex: 1; justify-content: center; } 751@media (max-width: 900px) { 752 .subs-grid { grid-template-columns: 1fr; gap: 32px; } 753 #scGridWrap { grid-template-columns: 1fr !important; } 754 .subs-photo { aspect-ratio: 16/9; } 755} 756.wl-drawer { position: fixed; top: 0; right: 0; bottom: 0; width: min(420px, 100vw); background: rgba(11,5,22,.97); backdrop-filter: blur(28px); -webkit-backdrop-filter: blur(28px); border-left: 1px solid rgba(230,26,26,.22); transform: translateX(100%); transition: transform .42s var(--ease); z-index: 1400; display: flex; flex-direction: column; } 757.wl-drawer.open { transform: none; } 758.wl-drawer-hd { padding: 22px 24px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--glb); } 759.wl-drawer-hd h3 { font-family: var(--fd); font-weight: 900; font-size: 1.2rem; } 760.wl-drawer-hd small { display: block; font-family: var(--fc); font-style: italic; font-size: .68rem; color: var(--p5l); letter-spacing: .15em; text-transform: uppercase; margin-top: 2px; } 761.wl-drawer-cls { width: 36px; height: 36px; border-radius: 50%; background: var(--gl); border: 1px solid var(--glb); color: #fff; display: flex; align-items: center; justify-content: center; transition: all .2s; } 762.wl-drawer-cls:hover { background: rgba(230,26,26,.18); } 763.wl-drawer-body { flex: 1; overflow-y: auto; padding: 16px 20px; } 764.wl-empty { text-align: center; padding: 60px 24px; color: rgba(255,255,255,.4); } 765.wl-empty-ico { font-size: 3rem; color: rgba(230,26,26,.4); margin-bottom: 14px; } 766.wl-row { display: flex; gap: 12px; padding: 12px; border-radius: var(--rs); transition: background .2s; align-items: center; } 767.wl-row:hover { background: var(--gl); } 768.wl-row-img { width: 60px; height: 60px; border-radius: 10px; overflow: hidden; background: var(--gl); flex-shrink: 0; } 769.wl-row-img img { width: 100%; height: 100%; object-fit: cover; } 770.wl-row-body { flex: 1; min-width: 0; } 771.wl-row-name { font-weight: 600; font-size: .88rem; margin-bottom: 2px; } 772.wl-row-price { font-family: var(--fc); font-weight: 900; color: var(--gd); font-size: .92rem; font-style: italic; } 773.wl-row-x { background: var(--gl); border: 1px solid var(--glb); border-radius: 50%; width: 28px; height: 28px; color: rgba(255,255,255,.5); display: flex; align-items: center; justify-content: center; transition: all .2s; flex-shrink: 0; font-size: .8rem; } 774.wl-row-x:hover { background: rgba(230,26,26,.2); color: #fff; } 775.wl-drawer-ft { padding: 18px 24px; border-top: 1px solid var(--glb); } 776.voice-fab { position: fixed; bottom: 86px; right: 24px; width: 56px; height: 56px; border-radius: 50%; background: linear-gradient(135deg, var(--p5d), var(--p5)); color: #fff; border: 2px solid rgba(255,255,255,.18); box-shadow: 0 12px 36px rgba(230,26,26,.45); z-index: 990; display: flex; align-items: center; justify-content: center; transition: transform .3s var(--spring), box-shadow .3s, opacity .3s, visibility .3s; opacity: 0; visibility: hidden; } 777.voice-fab.show { opacity: 1; visibility: visible; } 778.voice-fab:hover, .voice-fab:focus-visible { transform: translateY(-3px) scale(1.08); box-shadow: 0 18px 50px rgba(230,26,26,.55); } 779.voice-fab.listening { animation: voicePulse 1.2s ease-in-out infinite; background: linear-gradient(135deg, var(--cr), var(--p5)); } 780@keyframes voicePulse { 0%,100% { box-shadow: 0 12px 36px rgba(230,26,26,.45), 0 0 0 0 rgba(230,26,26,.7); } 50% { box-shadow: 0 12px 36px rgba(230,26,26,.6), 0 0 0 18px rgba(230,26,26,0); } } 781.voice-fab svg { width: 22px; height: 22px; } 782.voice-status { position: fixed; bottom: 158px; right: 24px; background: rgba(11,5,22,.96); border: 1px solid rgba(230,26,26,.32); border-radius: 14px; padding: 10px 16px; max-width: 280px; font-size: .82rem; color: #fff; z-index: 991; opacity: 0; transform: translateY(8px); transition: all .3s var(--ease); pointer-events: none; backdrop-filter: blur(20px); } 783.voice-status.show { opacity: 1; transform: none; pointer-events: all; } 784.voice-status small { display: block; font-family: var(--fc); font-style: italic; font-weight: 700; color: var(--p5l); font-size: .66rem; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 3px; } 785@media (max-width: 560px) { 786 .voice-fab { bottom: 74px; right: 14px; width: 48px; height: 48px; } 787 .voice-status { right: 14px; bottom: 132px; } 788} 789.vid-msg-block { background: var(--gl); border: 1px dashed var(--glb); border-radius: var(--rs); padding: 16px; margin-top: 16px; } 790.vid-msg-hd { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; } 791.vid-msg-hd h4 { font-family: var(--fd); font-weight: 700; font-size: .92rem; } 792.vid-msg-hd small { font-size: .7rem; color: rgba(255,255,255,.45); } 793.vid-preview { width: 100%; aspect-ratio: 16/9; background: #000; border-radius: 10px; overflow: hidden; position: relative; margin-bottom: 10px; } 794.vid-preview video { width: 100%; height: 100%; object-fit: cover; display: block; } 795.vid-rec-dot { position: absolute; top: 10px; left: 10px; display: none; align-items: center; gap: 6px; padding: 4px 10px; background: rgba(230,26,26,.92); border-radius: 100px; font-family: var(--fc); font-style: italic; font-weight: 900; font-size: .7rem; letter-spacing: .12em; text-transform: uppercase; color: #fff; } 796.vid-rec-dot.on { display: inline-flex; } 797.vid-rec-dot::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: #fff; animation: vidPulse 1s ease-in-out infinite; } 798@keyframes vidPulse { 50% { opacity: .35; } } 799.vid-msg-actions { display: flex; gap: 8px; flex-wrap: wrap; } 800.vid-msg-actions .btn { flex: 1; min-width: 110px; justify-content: center; padding: 8px 12px; font-size: .78rem; } 801.err-summary { background: rgba(245,77,77,.08); border: 1px solid rgba(245,77,77,.32); border-left: 4px solid var(--cr); border-radius: var(--rs); padding: 14px 16px; margin-bottom: 16px; display: none; } 802.err-summary.on { display: block; animation: errShake .4s ease-out; } 803.err-summary h4 { font-family: var(--fd); font-weight: 700; font-size: .88rem; color: var(--cr); margin-bottom: 6px; display: flex; align-items: center; gap: 8px; } 804.err-summary ul { list-style: none; padding: 0; margin: 0; } 805.err-summary li { font-size: .8rem; color: rgba(255,255,255,.78); padding: 3px 0; } 806.err-summary li a { color: var(--cr); border-bottom: 1px dotted rgba(245,77,77,.35); } 807.err-summary li a:hover, .err-summary li a:focus-visible { color: #fff; border-bottom-color: #fff; } 808@keyframes errShake { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } 809.funnel-bar { position: fixed; bottom: 0; left: 0; right: 0; background: rgba(11,5,22,.94); backdrop-filter: blur(18px); border-top: 1px solid rgba(230,26,26,.2); z-index: 985; padding: 8px 16px; transform: translateY(100%); transition: transform .3s var(--ease); display: none; } 810.funnel-bar.show { transform: none; } 811.funnel-track { display: flex; align-items: center; justify-content: space-between; gap: 12px; max-width: 720px; margin: 0 auto; } 812.funnel-step { display: flex; align-items: center; gap: 6px; font-family: var(--fc); font-style: italic; font-weight: 700; font-size: .68rem; letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.4); transition: color .3s; } 813.funnel-step.done { color: var(--mn); } 814.funnel-step.active { color: var(--p5l); } 815.funnel-step::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: currentColor; box-shadow: 0 0 0 0 currentColor; } 816.funnel-step.active::before { animation: ping 1.4s ease-out infinite; } 817.funnel-conn { flex: 1; height: 2px; background: linear-gradient(90deg, currentColor, transparent); opacity: .3; } 818.btn-voice-toggle { position: relative; } 819.btn-voice-toggle.listening::after { content: ''; position: absolute; inset: -3px; border: 2px solid var(--p5); border-radius: var(--rs); animation: voicePulse 1.2s ease-in-out infinite; } 820.subs-card-feats span svg { width: 11px; height: 11px; color: var(--mn); display: inline-block; vertical-align: -2px; margin-right: 3px; } 821.search-results-virt { max-height: 60vh; overflow-y: auto; } 822.search-results-virt::-webkit-scrollbar { width: 4px; } 823@media (max-width: 768px) { 824 .delivery-bar { top: 68px; padding: 8px 0; } 825 .funnel-bar { padding: 6px 10px; } 826 .funnel-step { font-size: .6rem; } 827} 828@media (max-width: 720px) { 829 #voiceNavBtn { display: none !important; } 830} 831@media (max-width: 540px) { 832 #wlBtnNav { display: none !important; } 833} 834.bloom-cookie, #cookieBanner, [class*="cookie-consent"] { opacity: 0; visibility: hidden; transition: opacity .4s ease .2s, visibility 0s linear .6s; } 835.bloom-cookie.ready, #cookieBanner.ready, [class*="cookie-consent"].ready { opacity: 1; visibility: visible; transition: opacity .4s ease, visibility 0s; } 836 837 838#cinematicHero { width: 100% !important; max-width: 100vw !important; overflow-x: clip; left: 0; right: 0; margin: 0; } 839#cinematicHero, #cinematicHero * { box-sizing: border-box; } 840 841@media (max-width: 900px) { 842 #cinematicHero .ch-main-card { width: calc(100% - 20px) !important; height: calc(100dvh - 20px) !important; max-width: calc(100% - 20px) !important; border-radius: 24px !important; } 843 #cinematicHero .ch-mockup-wrapper { height: 320px !important; } 844} 845 846@media (max-width: 640px) { 847 #cinematicHero { height: 100dvh !important; min-height: 100svh !important; } 848 #cinematicHero .ch-main-card { width: calc(100% - 12px) !important; height: calc(100dvh - 12px) !important; border-radius: 20px !important; padding: 0 !important; } 849 #cinematicHero .ch-mockup-wrapper { height: 260px !important; } 850 #cinematicHero .ch-floating-badge { transform: scale(.85); } 851 #cinematicHero .ch-floating-badge[style*="left:-15px"] { left: 4px !important; } 852 #cinematicHero .ch-floating-badge[style*="right:-15px"] { right: 4px !important; } 853 #cinematicHero .ch-card-right-text h2 { font-size: clamp(2.2rem, 12vw, 4rem) !important; } 854 #cinematicHero .ch-hero-text-wrapper h1 { font-size: clamp(1.8rem, 8vw, 3rem) !important; } 855} 856 857@media (max-width: 380px) { 858 #cinematicHero .ch-floating-badge { display: none !important; } 859 #cinematicHero .ch-mockup-wrapper { height: 220px !important; } 860} 861</style> 862</head> 863<body> 864<div id="promoBanner" class="promo-banner" style="display:none; justify-content:center; align-items:center; background:linear-gradient(135deg,var(--p5),oklch(50% .22 340)); color:#fff; font-family:var(--fc); font-weight:700; font-size:0.82rem; letter-spacing:0.08em; text-transform:uppercase; padding:8px 16px; text-align:center; z-index:1000; position:relative; box-shadow:0 4px 15px rgba(230,26,26,0.25);" role="region" aria-label="Announcement"> 865 <span data-content-key="banner">ð¸ Free delivery on orders over â±4,350</span> 866</div>
867<div id="bloomBoot" role="status" aria-live="polite" aria-label="Bloom is loading"> 868 <div class="bloom-flower" aria-hidden="true"> 869 <span class="bloom-petal"></span><span class="bloom-petal"></span><span class="bloom-petal"></span><span class="bloom-petal"></span> 870 <span class="bloom-petal"></span><span class="bloom-petal"></span><span class="bloom-petal"></span><span class="bloom-petal"></span> 871 <span class="bloom-core"></span> 872 </div> 873 <div class="bloom-boot-bar" aria-hidden="true"><i></i></div> 874 <div class="bloom-boot-txt">Crafting your bouquet</div> 875</div> 876<a href="#main" class="skip">Skip to content</a> 877<a href="#shop" class="skip" style="left: 160px">Skip to shop</a> 878<div class="c-ring" id="cRing" aria-hidden="true"></div> 879<div class="c-dot" id="cDot" aria-hidden="true"></div> 880<div id="sbar" aria-hidden="true"></div> 881<nav id="nav" class="bloom-nav" role="navigation" aria-label="Main navigation"> 882 <a href="/" class="n-logo">Bloom</a> 883 <button class="hmb" id="hmb" aria-label="Open menu" aria-expanded="false" aria-controls="mobMenu"> 884 <span></span><span></span><span></span> 885 </button> 886 <ul class="n-links" role="list"> 887 <li><a href="/#shop" data-label="shop" data-i18n="nav.shop">Shop</a></li> 888 <li><a href="/catalog.html" data-label="catalog" data-i18n="nav.catalog">Catalog</a></li> 889 <li><a href="/#subs" data-label="recurring" data-i18n="nav.subscriptions">Subscriptions</a></li> 890 <li><a href="/#corp" data-label="corp" data-i18n="nav.corporate">Corporate</a></li> 891 <li><a href="/#features" data-label="why" data-i18n="nav.why">Why Bloom</a></li> 892 </ul> 893 <div class="n-acts"> 894 <div class="n-srch-wrap" id="srchWrap"> 895 <button class="btn btn-g btn-sm" id="srchTog" aria-label="Search" aria-expanded="false" aria-controls="srchPanel"> 896 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg> 897 </button> 898 <div class="n-srch-panel" id="srchPanel" role="search" aria-hidden="true"> 899 <input type="search" class="n-srch-inp" id="srchInp" placeholder="Search bouquetsâ¦" autocomplete="off" aria-label="Search products"> 900 <div id="srchRes" role="listbox" style="margin-top:8px"></div> 901 </div> 902 </div> 903 <div style="position:relative" id="langWrap"> 904 <button class="btn btn-g btn-sm" id="langBtn" aria-label="Language selector" aria-expanded="false" aria-haspopup="listbox"> 905 <span id="langFlag" aria-hidden="true">ðºð¸</span> 906 <span id="langLbl">EN</span> 907 </button> 908 <ul id="langDd" class="lang-dd" role="listbox" aria-hidden="true" inert> 909 <li><button class="lang-opt" role="option" data-lang="en" data-flag="ðºð¸" data-lbl="EN"><span aria-hidden="true">ðºð¸</span> English</button></li> 910 <li><button class="lang-opt" role="option" data-lang="fil" data-flag="ðµð" data-lbl="PH"><span aria-hidden="true">ðµð</span> Filipino</button></li> 911 <li><button class="lang-opt" role="option" data-lang="es" data-flag="ðªð¸" data-lbl="ES"><span aria-hidden="true">ðªð¸</span> Español</button></li> 912 <li><button class="lang-opt" role="option" data-lang="ja" data-flag="ð¯ðµ" data-lbl="JA"><span aria-hidden="true">ð¯ðµ</span> æ¥æ¬èª</button></li> 913 </ul> 914 </div> 915 <button class="btn btn-g btn-sm btn-voice-toggle" id="voiceNavBtn" aria-label="Voice navigation" aria-pressed="false" hidden> 916 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M12 2a3 3 0 0 0-3 3v6a3 3 0 1 0 6 0V5a3 3 0 0 0-3-3z"/><path d="M19 10v1a7 7 0 0 1-14 0v-1"/><path d="M12 18v4"/><path d="M8 22h8"/></svg> 917 </button> 918 <button class="btn btn-g btn-sm cart-wrap" id="wlBtnNav" aria-label="Open wishlist" aria-haspopup="dialog" aria-controls="wlDrawer" style="position:relative"> 919 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3" aria-hidden="true"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>
920 <span class="cart-badge" id="wlBadge" style="display:none">0</span> 921 </button> 922 <button class="btn btn-g btn-sm" id="themeToggle" aria-label="Toggle theme" data-i18n-aria="theme.toggle"> 923 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true" id="themeIcon"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg> 924 </button> 925 <a href="/cart.html" class="btn btn-g btn-sm cart-wrap" aria-label="Cart" id="cartBtn"> 926 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3" aria-hidden="true"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg> 927 <span class="cart-badge" id="cartBadge" style="display:none" aria-live="polite">0</span> 928 </a> 929 <button class="btn btn-p btn-sm" id="authBtn" data-i18n="nav.signin">Sign In</button> 930 </div> 931</nav> 932<div class="mob-menu" id="mobMenu" aria-hidden="true" role="dialog" aria-label="Mobile navigation"> 933 <div class="mob-inner"> 934 <button class="mob-close" id="mobClose" aria-label="Close menu">â</button> 935 <ul role="list"> 936 <li><a href="/#shop" data-i18n="nav.shop">Shop</a></li> 937 <li><a href="/catalog.html" data-i18n="nav.catalog">Catalog</a></li> 938 <li><a href="/#subs" data-i18n="nav.subscriptions">Subscriptions</a></li> 939 <li><a href="/#corp" data-i18n="nav.corporate">Corporate</a></li> 940 <li><a href="/#features" data-i18n="nav.why">Why Bloom</a></li> 941 </ul> 942 <div class="mob-acts"> 943 <button class="btn btn-p" id="authBtnMob" style="justify-content:center">Sign In</button> 944 </div> 945 </div> 946</div> 947<div class="delivery-bar" id="dlvBar" role="region" aria-label="Pre-select your delivery"> 948 <div class="con"> 949 <div class="delivery-inner"> 950 <span class="delivery-pill" aria-hidden="true">Plan first · Browse next</span> 951 <div class="delivery-fields"> 952 <label class="dlv-fld" for="dlvDate"> 953 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/></svg> 954 <span><label for="dlvDate">Deliver on</label><br><input type="date" id="dlvDate" aria-label="Delivery date"></span> 955 </label> 956 <label class="dlv-fld" for="dlvLoc"> 957 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.3" aria-hidden="true"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0z"/><circle cx="12" cy="10" r="3"/></svg> 958 <span><label for="dlvLoc">To</label><br> 959 <select id="dlvLoc" aria-label="Delivery location"> 960 <option value="metro-manila">Metro Manila</option> 961 <option value="batangas" selected>Batangas</option> 962 <option value="cebu">Cebu City</option> 963 <option value="laguna">Laguna</option> 964 <option value="cavite">Cavite</option> 965 <option value="rizal">Rizal</option> 966 <option value="bulacan">Bulacan</option> 967 <option value="pampanga">Pampanga</option> 968 <option value="baguio">Baguio</option> 969 </select> 970 </span> 971 </label> 972 </div> 973 <div class="dlv-eta" id="dlvEta" aria-live="polite">Lead time: <strong>48h</strong></div> 974 </div> 975 </div> 976</div> 977<main id="main"> 978<section id="cinematicHero" aria-label="Cinematic Hero" style="position:relative;width:100%;max-width:100%;height:100dvh;min-height:100svh;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#05020a;font-family:var(--fb);-webkit-font-smoothing:antialiased;perspective:1500px;box-sizing:border-box;margin:0;left:0;right:0"> 979 <div class="ch-ethereal-bg" aria-hidden="true"> 980 <div class="ch-bg-frame frame-1" data-bg="/img/ch-frame-1.webp" style="background-image: url('/img/ch-frame-1.webp');"></div> 981 <div class="ch-bg-frame frame-2" data-bg="/img/ch-frame-2.webp"></div> 982 <div class="ch-bg-frame frame-3" data-bg="/img/ch-frame-3.webp"></div> 983 <div class="ch-bg-frame frame-4" data-bg="/img/ch-frame-4.webp"></div> 984 <div class="ch-bg-frame frame-5" data-bg="/img/ch-frame-5.webp"></div> 985
985<script>(function(){function l(){document.querySelectorAll('.ch-bg-frame[data-bg]').forEach(function(e){if(!e.style.backgroundImage){e.style.backgroundImage="url('"+e.dataset.bg+"')";}});}if('requestIdleCallback'in window){requestIdleCallback(l,{timeout:2500});}else{setTimeout(l,1800);}})();</script>
985 986 </div> 987 <div class="ch-film-grain" aria-hidden="true"></div> 988 <div class="ch-bg-grid" style="position:absolute;inset:0;z-index:0;pointer-events:none;opacity:.5" aria-hidden="true"></div> 989 <div class="ch-hero-text-wrapper" style="position:absolute;left:0;right:0;z-index:10;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;width:100%;padding:0 16px;will-change:transform"> 990 <h1 class="ch-text-track ch-gsap-reveal ch-text-3d-matte" style="font-family:var(--fd);font-size:clamp(2.4rem,5.5vw,6rem);font-weight:700;letter-spacing:-.03em;margin-bottom:8px;line-height:1.1">A small gesture,</h1> 991 <h1 class="ch-text-days ch-gsap-reveal ch-text-silver-matte" style="font-family:var(--fd);font-size:clamp(2.4rem,5.5vw,6rem);font-weight:900;letter-spacing:-.04em;line-height:1.1">a quiet comfort.</h1> 992 </div> 993 <div class="ch-cta-wrapper" style="position:absolute;left:0;right:0;z-index:10;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;width:100%;padding:0 16px;pointer-events:auto;will-change:transform" aria-hidden="false"> 994 <h2 class="ch-text-silver-matte" style="font-family:var(--fd);font-size:clamp(2rem,5vw,4.5rem);font-weight:700;margin-bottom:24px;letter-spacing:-.03em;line-height:1.1">Browse gently.</h2> 995 <p style="color:var(--text-muted);font-size:clamp(.9rem,1.2vw,1.25rem);margin-bottom:48px;max-width:520px;margin-left:auto;margin-right:auto;font-weight:300;line-height:1.7">Handcrafted bouquets and floral arrangements. Designed with care, delivered gently to the door - no rush, no pressure.</p> 996 <div style="display:flex;flex-direction:column;gap:16px;align-items:center"> 997 <a href="#shop" class="ch-btn-modern-light" style="display:inline-flex;align-items:center;justify-content:center;gap:12px;padding:14px 32px;border-radius:20px;text-decoration:none;font-weight:700;font-size:1rem;font-family:var(--fb)"> 998 <svg style="width:20px;height:20px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M12 2v6M12 22v-6M4.22 4.22l4.24 4.24M15.54 15.54l4.24 4.24M2 12h6M22 12h-6M4.22 19.78l4.24-4.24M15.54 8.46l4.24-4.24"/></svg> 999 <span>Browse Bouquets</span> 1000 </a> 1001 <a href="/catalog.html" class="ch-btn-modern-dark" style="display:inline-flex;align-items:center;justify-content:center;gap:12px;padding:14px 32px;border-radius:20px;text-decoration:none;font-weight:700;font-size:1rem;font-family:var(--fb)"> 1002 <svg style="width:20px;height:20px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M6 2 3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4Z"/><path d="M3 6h18"/><path d="M16 10a4 4 0 0 1-8 0"/></svg> 1003 <span>Full Catalog</span> 1004 </a> 1005 </div> 1006 </div> 1007 <div style="position:absolute;inset:0;z-index:20;display:flex;align-items:center;justify-content:center;pointer-events:none;perspective:1500px"> 1008 <div class="ch-main-card ch-depth-card ch-gsap-reveal" style="position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;pointer-events:auto;width:min(92%, 1280px);height:min(92dvh, 900px);max-width:calc(100% - 16px);max-height:calc(100dvh - 16px);border-radius:clamp(20px, 4vw, 32px);box-sizing:border-box" role="complementary" aria-label="Bloom Preview"> 1009 <div class="ch-card-sheen" aria-hidden="true"></div> 1010 <div style="position:relative;width:100%;height:100%;max-width:1280px;margin:0 auto;padding:16px;display:flex;flex-direction:column;justify-content:space-evenly;align-items:center;z-index:10"> 1011 <div class="ch-card-right-text ch-gsap-reveal" style="display:flex;justify-content:center;z-index:20;width:100%;order:1"> 1012 <h2 class="ch-text-card-silver" style="font-family:var(--fc);font-size:clamp(3rem,8vw,8rem);font-weight:900;text-transform:uppercase;letter-spacing:-.06em;line-height:1">Bloom</h2> 1013 </div> 1014 <div class="ch-mockup-wrapper" style="order:2;position:relative;width:100%;height:380px;display:flex;align-items:center;justify-content:center;z-index:10;perspective:1000px"> 1015 <div style="position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;transform:scale(.65)"> 1016 <div class="ch-mockup-bezel ch-iphone-bezel" style="position:relative;width:280px;height:580px;border-radius:3rem;display:flex;flex-direction:column;will-change:transform;transform-style:preserve-3d"> 1017 <div class="ch-hw-btn" style="position:absolute;top:120px;left:-3px;width:3px;height:25px;border-radius:4px 0 0 4px;z-index:0" aria-hidden="true"></div> 1018 <div class="ch-hw-btn" style="position:absolute;top:160px;left:-3px;width:3px;height:45px;border-radius:4px 0 0 4px;z-index:0" aria-hidden="true"></div> 1019 <div class="ch-hw-btn" style="position:absolute;top:220px;left:-3px;width:3px;height:45px;border-radius:4px 0 0 4px;z-index:0" aria-hidden="true"></div> 1020 <div class="ch-hw-btn" style="position:absolute;top:170px;right:-3px;width:3px;height:70px;border-radius:0 4px 4px 0;z-index:0;
1020transform:scaleX(-1)" aria-hidden="true"></div> 1021 <div style="position:absolute;inset:7px;background:#050914;border-radius:2.5rem;overflow:hidden;box-shadow:inset 0 0 15px rgba(0,0,0,1);color:#fff;z-index:10"> 1022 <div class="ch-screen-glare" style="position:absolute;inset:0;z-index:40;pointer-events:none" aria-hidden="true"></div> 1023 <div style="position:absolute;top:5px;left:50%;transform:translateX(-50%);width:100px;height:28px;background:#000;border-radius:9999px;z-index:50;display:flex;align-items:center;justify-content:flex-end;padding:0 12px;box-shadow:inset 0 -1px 2px rgba(255,255,255,.1)"> 1024 <div style="width:6px;height:6px;border-radius:50%;background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.8);animation:ping2 2s ease-out infinite"></div> 1025 </div> 1026 <div style="position:relative;width:100%;height:100%;padding:48px 20px 32px;display:flex;flex-direction:column"> 1027 <div class="ch-phone-widget" style="display:flex;justify-content:space-between;align-items:center;margin-bottom:32px"> 1028 <div style="display:flex;flex-direction:column"> 1029 <span style="font-size:10px;color:#a1a1aa;text-transform:uppercase;letter-spacing:.15em;font-weight:700;margin-bottom:4px">Today</span> 1030 <span style="font-size:1.25rem;font-weight:700;letter-spacing:-.03em;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.4)">My Bouquet</span> 1031 </div> 1032 <div style="width:36px;height:36px;border-radius:50%;background:rgba(255,255,255,.05);color:#e4e4e7;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:13px;border:1px solid rgba(255,255,255,.1);box-shadow:0 4px 12px rgba(0,0,0,.5)">B</div> 1033 </div> 1034 <div class="ch-phone-widget" style="position:relative;width:176px;height:176px;margin:0 auto 32px;filter:drop-shadow(0 15px 25px rgba(0,0,0,.8))"> 1035 <svg style="position:absolute;inset:0;width:100%;height:100%" aria-hidden="true"> 1036 <circle cx="88" cy="88" r="64" fill="none" stroke="rgba(255,255,255,.03)" stroke-width="12"/> 1037 <circle class="ch-progress-ring" cx="88" cy="88" r="64" fill="none" stroke="var(--p5)" stroke-width="12"/> 1038 </svg> 1039 <div style="position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:10"> 1040 <span class="ch-counter-val" style="font-size:2.5rem;font-weight:900;letter-spacing:-.04em;color:#fff">0</span> 1041 <span style="font-size:8px;color:rgba(255,107,107,.5);text-transform:uppercase;letter-spacing:.1em;font-weight:700;margin-top:2px">Orders</span> 1042 </div> 1043 </div> 1044 <div style="display:flex;flex-direction:column;gap:12px"> 1045 <div class="ch-phone-widget ch-widget-depth" style="border-radius:16px;padding:12px;display:flex;align-items:center"> 1046 <div style="width:40px;height:40px;border-radius:12px;background:linear-gradient(135deg,rgba(230,26,26,.2),rgba(230,26,26,.05));display:flex;align-items:center;justify-content:center;margin-right:12px;border:1px solid rgba(230,26,26,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)"> 1047 <svg style="width:16px;height:16px;color:var(--p5l)" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg> 1048 </div> 1049 <div style="flex:1"><div style="height:8px;width:80px;background:#d4d4d8;border-radius:9999px;margin-bottom:8px;box-shadow:inset 0 1px 1px rgba(0,0,0,.2)"></div><div style="height:6px;width:48px;background:#525252;border-radius:9999px;box-shadow:inset 0 1px 1px rgba(0,0,0,.2)"></div></div> 1050 </div> 1051 <div class="ch-phone-widget ch-widget-depth" style="border-radius:16px;padding:12px;display:flex;align-items:center"> 1052 <div style="width:40px;height:40px;border-radius:12px;background:linear-gradient(135deg,rgba(16,185,129,.2),rgba(16,185,129,.05));display:flex;align-items:center;justify-content:center;margin-right:12px;border:1px solid rgba(16,185,129,.2);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)"> 1053 <svg style="width:16px;height:16px;color:#34d399" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg> 1054 </div> 1055 <div style="flex:1"><div style="height:8px;width:64px;background:#d4d4d8;border-radius:9999px;margin-bottom:8px;box-shadow:inset 0 1px 1px rgba(0,0,0,.2)"></div><div style="height:6px;width:96px;background:#525252;border-radius:9999px;box-shadow:inset 0 1px 1px rgba(0,0,0,.2)"></div></div> 1056 </div> 1057 </div> 1058 <div style="position:absolute;bottom:8px;left:50%;transform:translateX(-50%);width:120px;height:4px;background:rgba(255,255,255,.2);border-radius:9999px;box-shadow:0 1px 2px rgba(0,0,0,.5)"></div> 1059 </div> 1060 </div> 1061 </div> 1062 <div class="ch-floating-badge ch-floating-ui-badge" style="position:absolute;display:flex;top:24px;left:clamp(0px, -15px, 0px);border-radius:12px;padding:12px;align-items:center;gap:12px;z-index:30;max-width:calc(100% - 16px)"> 1063 <div style="width:32px;height:32px;border-radius:50%;background:linear-gradient(180deg,rgba(230,26,26,.2),rgba(230,26,26,.1));display:flex;align-items:center;justify-content:center;border:1px solid rgba(230,26,26,.3);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)"><span style="font-size:1rem" aria-hidden="true">ð¸</span></div> 1064 <div><p style="color:#fff;font-size:12px;font-weight:700;letter-spacing:-.02em">Fresh Today</p><p style="color:rgba(255,107,107,.5);font-size:10px;font-weight:500">Freshness modeled</p></div> 1065 </div> 1066 <div class="ch-floating-badge ch-floating-ui-badge" style="position:absolute;display:flex;bottom:48px;right:clamp(0px, -15px, 0px);border-radius:12px;padding:12px;align-items:center;gap:12px;z-index:30;max-width:calc(100% - 16px)"> 1067 <div style="width:32px;height:32px;border-radius:50%;background:linear-gradient(180deg,rgba(124,58,237,.2),rgba(124,58,237,.1));display:flex;align-items:center;justify-content:center;border:1px solid rgba(124,58,237,.3);box-shadow:inset 0 1px 2px rgba(0,0,0,.3)"><span style="font-size:1rem" aria-hidden="true">ð¦</span></div> 1068 <div><p style="color:#fff;font-size:12px;font-weight:700;letter-spacing:-.02em">Delivered</p><p style="color:rgba(255,107,107,.5);font-size:10px;font-weight:500">Photo confirmed</p></div> 1069 </div> 1070 </div> 1071 </div> 1072 <div class="ch-card-left-text ch-gsap-reveal" style="order:3;display:flex;flex-direction:column;justify-content:center;text-align:center;z-index:20;width:100%;padding:0 16px"> 1073 <h3 style="color:#fff;font-family:var(--fd);font-size:clamp(1.2rem,2.5vw,2.2rem);font-weight:700;margin-bottom:0;letter-spacing:-.03em">
1073Handcrafted with care.</h3> 1074 <p style="display:none;color:rgba(147,197,253,.7);font-size:clamp(.82rem,.9vw,1rem);font-weight:400;line-height:1.7;max-width:400px;margin:16px auto 0" class="ch-card-desc-desktop">Bloom empowers every flower moment with carefully crafted custom bouquets, built with passion by STI LIPA BSIT students.</p> 1075 </div> 1076 </div> 1077 </div> 1078 </div> 1079</section> 1080<section class="hero" aria-label="Hero" id="heroSec"> 1081 <div class="hero-bg" aria-hidden="true" style="position:absolute;inset:0;background: radial-gradient(circle at 10% 20%, rgba(230,26,26,0.12) 0%, transparent 60%), radial-gradient(circle at 90% 80%, rgba(124,58,237,0.1) 0%, transparent 60%), var(--bg); animation: ethereal 20s cubic-bezier(0.4, 0, 0.2, 1) infinite alternate; transform-style: preserve-3d; will-change: filter, transform;"></div> 1082 <style> 1083 @keyframes ethereal { 0% { filter: hue-rotate(0deg) contrast(1); transform: scale(1) translateZ(-20px); opacity: 0.8; } 50% { filter: hue-rotate(20deg) contrast(1.1); transform: scale(1.05) translateZ(10px); opacity: 1; } 100% { filter: hue-rotate(-10deg) contrast(1.05); transform: scale(1.02) translateZ(0); opacity: 0.9; } } 1084 </style> 1085 <div class="hero-photo" id="heroPhoto" aria-hidden="true"></div> 1086 <div class="hero-bokeh" id="heroBokeh" aria-hidden="true" style="position:absolute;inset:0;background-image:none;background-size:cover;background-position:center;opacity:.28;mix-blend-mode:screen;filter:blur(3px) saturate(1.4);z-index:1;pointer-events:none;animation:bokehDrift 28s cubic-bezier(0.4, 0, 0.2, 1) infinite alternate; will-change: transform;"></div> 1087 <style>@keyframes bokehDrift{0%{transform:scale(1.05) translate3d(0,0,0) rotate(0deg); opacity: 0.25}50%{transform:scale(1.1) translate3d(-2%,-1.5%,40px) rotate(1deg); filter:blur(5px) saturate(1.6); opacity: 0.35}100%{transform:scale(1.06) translate3d(1.5%,1%,-20px) rotate(-1deg); filter:blur(4px) saturate(1.3); opacity: 0.28}}@media (prefers-reduced-motion:reduce){.hero-bokeh{animation:none!important}}</style> 1088 <canvas id="ptcl" aria-hidden="true"></canvas> 1089 <div class="hero-noise" aria-hidden="true"></div> 1090 <div class="hero-scanlines" aria-hidden="true"></div> 1091 <div class="hero-slash-1" aria-hidden="true"></div> 1092 <div class="hero-orb hero-orb-1" aria-hidden="true"></div> 1093 <div class="hero-orb hero-orb-2" aria-hidden="true"></div> 1094 <div class="con" style="width:100%"> 1095 <div class="hero-grid"> 1096 <div class="hero-left"> 1097 <div class="hero-countdown" id="cdWrap" aria-live="polite" aria-atomic="true"></div> 1098 <div class="hero-eyebrow"> 1099 <span class="hero-eyebrow-tag">Pre-order</span> 1100 <span class="hero-eyebrow-tag">Freshness-first</span> 1101 <span class="hero-eyebrow-tag">Flexible scheduling</span> 1102 <span class="hero-eyebrow-sub" data-content-key="heroBadge">Gentle care · Designed fresh · At your pace</span> 1103 </div> 1104 <h1 class="hero-hl" data-witch-frame="quad"> 1105 <span data-content-key="hero_title_1">A small gesture,</span> 1106 <span id="typer" aria-live="polite"> 1107 <span class="g-txt active" aria-hidden="false" data-content-key="hero_title_2">a quiet comfort.</span> 1108 <span class="g-txt" aria-hidden="true">a gentle reminder.</span> 1109 <span class="g-txt" aria-hidden="true">a little warmth.</span> 1110 <span class="g-txt" aria-hidden="true">a soft thought.</span> 1111 <span class="g-txt" aria-hidden="true">a peaceful moment.</span> 1112 <span class="g-txt" aria-hidden="true">no pressure at all.</span> 1113 </span> 1114 <em>Whenever you're ready.</em> 1115 </h1> 1116 <p class="hero-sub" data-content-key="hero_subtitle">You don't need a reason to send flowers. Handcrafted and developed by STI LIPA BSIT students, delivered gently to the door - no rush, no pressure. Just a moment of warmth, whenever it feels right.</p> 1117 <div class="hero-cta"> 1118 <a href="#shop" class="btn btn-p btn-lg">Browse Gently â</a> 1119 <button class="btn btn-g btn-lg" id="profilingBtn" aria-haspopup="dialog" aria-controls="profMod">Find What Feels Right</button> 1120 </div> 1121 <div class="trust">
1122 <span class="trust-item"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg> Photo confirmation</span> 1123 <span class="trust-item"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg> Flexible delivery windows</span> 1124 <span class="trust-item"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg> We'll make it right</span> 1125 </div> 1126 </div> 1127 <div class="hero-cards" id="heroCards" role="region" aria-label="Featured picks preview"> 1128 <article class="h-card hc-1" id="hc1"> 1129 <div class="hc-pulse" aria-hidden="true"></div> 1130 <img class="h-card-img" src="/uploads/products/crimson-vow.jpg" alt="Hand-tied bouquet of deep crimson roses with lush dark green leaves" loading="lazy" decoding="async" width="220" height="110" onerror="this.onerror=null;this.style.display='none'"> 1131 <div class="hc-name">Crimson Vow</div> 1132 <div class="hc-price">â±2,480</div> 1133 <div class="hc-meta" id="hcLive">Ready within 48 hours</div> 1134 </article> 1135 <article class="h-card hc-2" id="hc2"> 1136 <div class="hc-tag">Today's Pick</div> 1137 <img class="h-card-img" src="/uploads/products/neon-blossom.jpg" alt="Vibrant floral arrangement featuring neon pink ranunculus and sunflowers" loading="lazy" decoding="async" width="200" height="110" onerror="this.onerror=null;this.src='/uploads/products/crimson-vow.jpg'"> 1138 <div class="hc-sub">Neon Blossom</div> 1139 <div class="hc-status">Fresh and waiting</div> 1140 </article> 1141 <article class="h-card hc-3" id="hc3"> 1142 <div class="hc-tag">For Teams</div> 1143 <img class="h-card-img" src="/uploads/products/executive-crimson.jpg" alt="Professional floral arrangement with deep red amaryllis in a black granite vase" loading="lazy" decoding="async" width="210" height="110" onerror="this.onerror=null;this.src='/uploads/products/crimson-vow.jpg'"> 1144 <div class="hc-sub">Thoughtful batch orders</div> 1145 <div class="hc-status">At your schedule</div> 1146 </article> 1147 </div> 1148 </div> 1149 </div> 1150</section> 1151<div class="p5-sec-div" aria-hidden="true"></div> 1152<section class="stats-strip" aria-label="Service facts"> 1153 <div class="con"> 1154 <div class="stats-inner"> 1155 <div class="stat-item"> 1156 <span class="stat-icon" aria-hidden="true">âï¸</span> 1157 <div class="stat-num" id="sCold">Protocol</div> 1158 <div class="stat-bar"><div class="stat-bar-fill" data-w="100"></div></div> 1159 <div class="stat-lbl">Freshness-first logistics</div> 1160 <div class="stat-src">Based on <a href="https://postharvest.ucdavis.edu/" target="_blank" rel="noopener">UC Davis</a> guidelines</div> 1161 </div> 1162 <div class="stat-item"> 1163 <span class="stat-icon" aria-hidden="true">ð¦</span> 1164 <div class="stat-num" id="sOrders">Beta</div> 1165 <div class="stat-bar"><div class="stat-bar-fill" data-w="25"></div></div> 1166 <div class="stat-lbl">Academic prototype</div> 1167 <div class="stat-src">Capstone project · 2026</div> 1168 </div> 1169 <div class="stat-item"> 1170 <span class="stat-icon" aria-hidden="true">â¿</span> 1171 <div class="stat-num" id="sWcag">AA</div> 1172 <div class="stat-bar"><div class="stat-bar-fill" data-w="95"></div></div> 1173 <div class="stat-lbl">Accessibility target</div> 1174 <div class="stat-src"><a href="https://www.w3.org/TR/WCAG21/" target="_blank" rel="noopener">WCAG 2.1</a> Level AA</div> 1175 </div> 1176 <div class="stat-item"> 1177 <span class="stat-icon" aria-hidden="true">ð</span> 1178 <div class="stat-num" id="sRating">STI</div> 1179 <div class="stat-bar"><div class="stat-bar-fill" data-w="100"></div></div> 1180 <div class="stat-lbl">Built by students</div> 1181 <div class="stat-src"><a href="https://www.sti.edu/campuses-details.asp?campus_id=LIP" target="_blank" rel="noopener">STI College Lipa</a> BSIT</div> 1182 </div> 1183 </div> 1184 </div> 1185</section> 1186<div class="p5-sec-div" aria-hidden="true"></div> 1187<section class="sec-pad" id="shop" aria-label="Shop featured products"> 1188 <div class="con"> 1189 <div class="sec-hd"> 1190 <div>
1191 <span class="tag tag-p">Featured</span> 1192 <h2 class="sec-title">Tell us the occasion. We'll handle the flowers.</h2> 1193 <p class="sec-sub">Browse our catalog, filter by occasion, and choose what feels right. Every order includes a delivery window you pick at checkout, so it arrives when it matters most.</p> 1194 </div> 1195 <a href="/catalog.html" class="btn btn-g">View all â</a> 1196 </div> 1197 <div class="cat-wrap"> 1198 <button class="cat-arrow" id="catL" aria-label="Scroll categories left" disabled>â¹</button> 1199 <div class="cat-tabs" id="catTabs" role="tablist" aria-label="Product categories"> 1200 <button class="cat-tab active" data-cat="all" role="tab" aria-selected="true" id="tab-all">All <span class="cat-cnt" id="cnt-all"></span></button> 1201 <button class="cat-tab" data-cat="bouquets" role="tab" aria-selected="false">ð Bouquets <span class="cat-cnt" id="cnt-bouquets"></span></button> 1202 <button class="cat-tab" data-cat="arrangements" role="tab" aria-selected="false">ð¸ Arrangements <span class="cat-cnt" id="cnt-arrangements"></span></button> 1203 <button class="cat-tab" data-cat="fresh" role="tab" aria-selected="false">ð· Fresh <span class="cat-cnt" id="cnt-fresh"></span></button> 1204 <button class="cat-tab" data-cat="dried" role="tab" aria-selected="false">ð¿ Dried <span class="cat-cnt" id="cnt-dried"></span></button> 1205 <button class="cat-tab" data-cat="corporate" role="tab" aria-selected="false">ð¼ Corporate <span class="cat-cnt" id="cnt-corporate"></span></button> 1206 </div> 1207 <button class="cat-arrow" id="catR" aria-label="Scroll categories right">âº</button> 1208 </div> 1209 <div class="p-grid" id="pGrid" role="tabpanel" aria-labelledby="tab-all" aria-live="polite" aria-busy="true"></div> 1210 </div> 1211</section> 1212<div class="p5-sec-div" aria-hidden="true"></div> 1213<section class="feat-sec sec-pad" id="features" aria-label="Why Bloom" data-atelier-reveal data-atelier-sigil="bloom corner-tr lg"> 1214 <div class="con"> 1215 <div class="sec-hd" style="flex-direction:column;align-items:flex-start;text-align:left"> 1216 <span class="tag tag-m">Our promise</span> 1217 <h2 class="sec-title" style="max-width:680px">What we care about when handling your order.</h2> 1218 <p class="sec-sub" style="max-width:680px">Four things we designed around from day one: keeping flowers fresh, delivering on time, making the site usable for everyone, and being honest about what we can do.</p> 1219 </div> 1220 <div class="feat-grid"> 1221 <article class="feat-card anim-in"> 1222 <div class="feat-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M12 2v6M12 22v-6M4.22 4.22l4.24 4.24M15.54 15.54l4.24 4.24M2 12h6M22 12h-6M4.22 19.78l4.24-4.24M15.54 8.46l4.24-4.24"/></svg></div> 1223 <h3 class="feat-t">Keeping flowers fresh</h3> 1224 <p class="feat-d">We follow temperature handling practices recommended by UC Davis postharvest research to help your flowers last longer after delivery.</p> 1225 </article> 1226 <article class="feat-card anim-in"> 1227 <div class="feat-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg></div> 1228 <h3 class="feat-t">You pick the delivery time</h3> 1229 <p class="feat-d">At checkout, choose a delivery window that works for you, including evening slots. We do our best to deliver within that window.</p> 1230 </article> 1231 <article class="feat-card anim-in"> 1232 <div class="feat-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="4"/></svg></div> 1233 <h3 class="feat-t">Designed for everyone</h3> 1234 <p class="feat-d">This site works with keyboards, screen readers, and respects reduced-motion preferences. We test against WCAG 2.1 AA accessibility standards.</p> 1235 </article> 1236 <article class="feat-card anim-in"> 1237 <div class="feat-ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="m9 11 3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></div> 1238 <h3 class="feat-t">We show you, not just tell you</h3> 1239 <p class="feat-d">When your order is delivered, we send a photo so you can see it arrived safely. If something doesn't look right, reach out and we'll help fix it.</p> 1240 </article> 1241 </div> 1242 </div> 1243</section> 1244<div class="p5-sec-div" aria-hidden="true"></div> 1245<section class="sec-pad" id="traceability" aria-label="Supply chain traceability" style="background:var(--bg)"> 1246 <div class="con"> 1247 <div class="sec-hd"> 1248 <div>
1249 <span class="tag tag-m">Transparency</span> 1250 <h2 class="sec-title" style="max-width:680px">See where your flowers come from.</h2> 1251 <p class="sec-sub" style="max-width:680px">We work with growers near Lipa City, Batangas. Each order includes a QR code you can scan to see its journey from harvest to your door, with live weather data from Windy.com for each farm location.</p> 1252 </div> 1253 </div> 1254 <div style="max-width:960px;margin:0 auto" id="scGridWrap"> 1255 <div id="supplyChainTrace"></div> 1256 </div> 1257 </div> 1258</section> 1259<div class="p5-sec-div" aria-hidden="true"></div> 1260<section class="rev-sec sec-pad" aria-label="Customer stories" data-atelier-reveal data-atelier-sigil="quill corner-tr"> 1261 <div class="con"> 1262 <div class="sec-hd"> 1263 <div> 1264 <span class="tag tag-a">What people say</span> 1265 <h2 class="sec-title">Words from people who trusted us with their moment.</h2> 1266 <p class="sec-sub">These are sample testimonials representing the kind of experiences we aim to deliver. As an academic prototype, real customer reviews will appear here once the platform launches publicly.</p> 1267 </div> 1268 </div> 1269 <div class="rev-grid" id="revGrid" aria-live="polite"></div> 1270 <div class="rev-mob" id="revMob" role="region" aria-label="Review navigation"> 1271 <button class="rev-navb" id="revPrev" aria-label="Previous review">â¹</button> 1272 <div class="rev-dots" id="revDots" role="tablist"></div> 1273 <button class="rev-navb" id="revNext" aria-label="Next review">âº</button> 1274 </div> 1275 </div> 1276</section> 1277<div class="p5-sec-div" aria-hidden="true"></div> 1278<section class="facts-sec sec-pad" aria-label="Verified facts"> 1279 <div class="con"> 1280 <div class="sec-hd" style="flex-direction:column;align-items:flex-start"> 1281 <span class="tag tag-p">How we built this</span> 1282 <h2 class="sec-title wabi-underline" style="max-width:640px">What we used, where we learned it, and why it matters.</h2> 1283 </div> 1284 <div class="facts-grid"> 1285 <article class="fact-card"> 1286 <div class="fact-k">0 to 4°C</div> 1287 <div class="fact-t">Temperature-aware handling</div> 1288 <div class="fact-d">Flowers last longer when kept cool. We follow the 0 to 4°C recommended range from UC Davis postharvest research to help your arrangement stay fresh.</div> 1289 <div class="fact-src">Source: <a href="https://postharvest.ucdavis.edu/" target="_blank" rel="noopener">UC Davis Postharvest Technology Center</a></div> 1290 </article> 1291 <article class="fact-card"> 1292 <div class="fact-k">BSIT</div> 1293 <div class="fact-t">Student-built from scratch</div> 1294 <div class="fact-d">Every line of code, every design decision, and every feature on this platform was built by BSIT students at STI College Lipa as a capstone project.</div> 1295 <div class="fact-src">Source: <a href="https://www.sti.edu/campuses-details.asp?campus_id=LIP" target="_blank" rel="noopener">STI College Lipa</a> · BSIT Program</div> 1296 </article> 1297 <article class="fact-card"> 1298 <div class="fact-k">WCAG 2.1</div> 1299 <div class="fact-t">Accessible to more people</div> 1300 <div class="fact-d">We target Level AA. This means the site is designed to be usable by people with visual, motor, and cognitive differences, including keyboard navigation, readable contrast, and screen reader support.</div> 1301 <div class="fact-src">Source: <a href="https://www.w3.org/TR/WCAG21/" target="_blank" rel="noopener">W3C Web Content Accessibility Guidelines 2.1</a></div> 1302 </article> 1303 <article class="fact-card"> 1304 <div class="fact-k">SDG 17</div> 1305 <div class="fact-t">Partnerships for the goals</div> 1306 <div class="fact-d">Bloom connects BSIT students with local flower growers in Lipa City and open-source tools like Windy.com and Web Crypto API. This forms a student, community, and technology partnership aligned with UN Sustainable Development Goal 17.</div> 1307 <div class="fact-src">Source: <a href="https://sdgs.un.org/goals/goal17" target="_blank" rel="noopener">UN SDG 17</a> · <a href="https://www.sti.edu/campuses-details.asp?campus_id=LIP" target="_blank" rel="noopener">
1307STI Lipa</a></div> 1308 </article> 1309 <article class="fact-card"> 1310 <div class="fact-k">HTTPS + JWT</div> 1311 <div class="fact-t">Your data stays protected</div> 1312 <div class="fact-d">All connections use HTTPS encryption. Your password is hashed with bcrypt (never stored in plain text). Login sessions use secure, HTTP-only tokens that can't be accessed by scripts.</div> 1313 <div class="fact-src">Source: OWASP authentication cheat sheet · <a href="https://owasp.org/www-project-cheat-sheets/" target="_blank" rel="noopener">OWASP</a></div> 1314 </article> 1315 <article class="fact-card"> 1316 <div class="fact-k">Photo proof</div> 1317 <div class="fact-t">You'll see it when it arrives</div> 1318 <div class="fact-d">We take a photo when your order is delivered so you know it got there safely. If anything looks off, let us know and we'll work with you to make it right.</div> 1319 <div class="fact-src">Policy: <a href="/returns.html">Bloom Service Promise</a></div> 1320 </article> 1321 </div> 1322 </div> 1323</section> 1324<div class="p5-sec-div" aria-hidden="true"></div> 1325<section class="corp-sec sec-pad" id="corp" aria-label="For teams and groups"> 1326 <div class="con"> 1327 <div class="corp-grid"> 1328 <div class="corp-photo"> 1329 <img src="/img/corporate-flowers.jpg" alt="Sleek matching minimalist floral arrangements in matte black vases on a boardroom table" loading="lazy" decoding="async" width="900" height="675" onerror="this.onerror=null;this.src='/img/vow-crimson.png'"> 1330 </div> 1331 <div> 1332 <span class="tag tag-a">For Teams</span> 1333 <h2 class="sec-title" style="margin-bottom:16px" data-content-key="corpHeadline">Flowers for your team,<br>without the hassle.</h2> 1334 <p class="sec-sub" style="max-width:none;margin-bottom:18px">Whether you are celebrating a work anniversary, saying thank you to a client, or making someone's Monday better, simply tell us what you need and we will take care of the rest.</p> 1335 <ul class="corp-list"> 1336 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Custom wraps with personal notes, starting at 10 orders</li> 1337 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Deliver weekly, monthly, or just when you need it</li> 1338 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>One invoice for the whole batch, easy to export</li> 1339 <li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg>Talk to a real person via email or Viber</li> 1340 </ul> 1341 <a href="mailto:[email protected]?subject=Corporate%20inquiry" class="btn btn-p btn-lg">Get in touch â</a> 1342 </div> 1343 </div> 1344 </div> 1345</section> 1346<div class="p5-sec-div" aria-hidden="true"></div> 1347<section class="subs-sec sec-pad" id="subs" aria-label="Flower subscriptions" data-atelier-reveal data-atelier-sigil="petal corner-bl"> 1348 <div class="con"> 1349 <div class="sec-hd" style="flex-direction:column;align-items:flex-start;text-align:left;margin-bottom:36px"> 1350 <span class="tag tag-m">Recurring · Pause anytime</span> 1351 <h2 class="sec-title" style="max-width:680px">Fresh flowers on repeat, no commitment.</h2> 1352 <p class="sec-sub" style="max-width:640px">Choose how often you'd like flowers, whether weekly, every two weeks, or monthly. You can skip, swap, or cancel anytime with one click. There are no contracts and no penalties.</p> 1353 </div> 1354 <div class="subs-grid"> 1355 <div class="subs-photo"> 1356 <img src="/uploads/subscriptions/biweekly.jpg" alt="A subscription delivery of fresh seasonal flowers" id="subsPreviewImg" loading="lazy" decoding="async" width="800" height="600" style="transition: opacity 0.2s ease;"> 1357 </div> 1358 <div class="subs-cards" role="radiogroup" aria-label="Subscription cadence"> 1359 <button type="button" class="subs-card" data-sub="weekly" data-price="1499" role="radio" aria-checked="false"> 1360 <div class="subs-card-hd"> 1361 <div class="subs-card-name"><span data-content-key="sub_weekly_name">Weekly Bloom</span> <em>Most Loved</em></div> 1362 <div class="subs-card-price"><span data-content-key="sub_weekly_price">â±1,499</span><small> / box</small></div> 1363 </div> 1364 <div class="subs-card-d">A fresh seasonal bouquet delivered to your door every week. Our florist picks the best in season, and
1364you can swap colors or skip anytime.</div> 1365 <div class="subs-card-feats"> 1366 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>Free vase, week one</span> 1367 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>Skip / pause anytime</span> 1368 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>Fresh handling</span> 1369 </div> 1370 </button> 1371 <button type="button" class="subs-card selected" data-sub="biweekly" data-price="2299" role="radio" aria-checked="true"> 1372 <div class="subs-card-hd"> 1373 <div class="subs-card-name" data-content-key="sub_biweekly_name">Biweekly Refresh</div> 1374 <div class="subs-card-price"><span data-content-key="sub_biweekly_price">â±2,299</span><small> / box</small></div> 1375 </div> 1376 <div class="subs-card-d">A bigger bouquet delivered every two weeks. Great for offices, living rooms, or anywhere that deserves regular fresh flowers.</div> 1377 <div class="subs-card-feats"> 1378 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>40% larger</span> 1379 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>Locked rate, 12 weeks</span> 1380 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>Photo proof</span> 1381 </div> 1382 </button> 1383 <button type="button" class="subs-card" data-sub="monthly" data-price="3499" role="radio" aria-checked="false"> 1384 <div class="subs-card-hd"> 1385 <div class="subs-card-name" data-content-key="sub_monthly_name">Monthly Statement</div> 1386 <div class="subs-card-price"><span data-content-key="sub_monthly_price">â±3,499</span><small> / box</small></div> 1387 </div> 1388 <div class="subs-card-d">One stunning arrangement each month featuring premium flowers, hand-tied wrapping, and a handwritten note from our team.</div> 1389 <div class="subs-card-feats"> 1390 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>Premium varietals</span> 1391 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>Handwritten note</span> 1392 <span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6 9 17l-5-5"/></svg>Free shipping</span> 1393 </div> 1394 </button> 1395 <div class="subs-cta"> 1396 <button type="button" class="btn btn-g" id="subsLearn">How it works</button> 1397 <button type="button" class="btn btn-p" id="subsStart">Start subscription â</button> 1398 </div> 1399 </div> 1400 </div> 1401 </div> 1402</section> 1403<div class="p5-sec-div" aria-hidden="true"></div> 1404<section class="sec-pad" id="supportUs" aria-label="Support the project" style="background:var(--bg)"> 1405 <div class="con"> 1406 <div id="supportUsContent"></div> 1407 </div> 1408</section> 1409<footer class="bloom-foot" role="contentinfo"> 1410 <div class="con"> 1411 <div class="foot-grid"> 1412 <div> 1413 <div class="foot-brand">Bloom</div> 1414 <p class="foot-tag" data-content-key="footerTagline">Fresh flowers, delivered with care. A BSIT capstone project by STI College Lipa.</p> 1415 <form class="nl-form" id="nlForm" aria-label="Newsletter signup"> 1416 <input type="email" class="nl-inp" id="nlEmail" placeholder="[email protected]" aria-label="Email address" required> 1417 <button type="submit" class="btn btn-p btn-sm">Join</button> 1418 </form> 1419 </div> 1420 <div class="foot-col"> 1421 <h4>Shop</h4> 1422 <ul role="list"> 1423 <li><a href="/catalog.html">All products</a></li> 1424 <li><a href="/catalog.html?category=bouquets">Bouquets</a></li> 1425 <li><a href="/catalog.html?category=arrangements">Arrangements</a></li> 1426 <li><a href="/catalog.html?category=corporate">Corporate</a></li> 1427 </ul> 1428 </div> 1429 <div class="foot-col"> 1430 <h4>Company</h4> 1431 <ul role="list"> 1432 <li><a href="/about.html">Our team</a></li> 1433 <li><a href="/#corp">Corporate</a></li> 1434 <li><a href="/blog.html">Journal</a></li> 1435 <li><a href="/contact.html">Contact</a></li> 1436 </ul> 1437 </div> 1438 <div class="foot-col"> 1439 <h4>Support</h4> 1440 <ul role="list"> 1441 <li><a href="/support.html#faqSection">FAQ</a></li> 1442 <li><a href="/shipping.html">Shipping</a></li> 1443 <li><a href="/returns.html">Service Promise</a></li> 1444 <li><a href="/privacy.html">Privacy Policy</a></li> 1445 <li><a href="/terms.html">Terms of Service</a></li> 1446 <li><a href="/disclaimer.html">Disclaimer</a></li> 1447 <li><a href="/cookie-policy.html">Cookie Policy</a></li> 1448 </ul> 1449 </div> 1450 </div> 1451 <div class="foot-bottom"> 1452 <div>© <span id="yr">2026</span> Bloom · Handcrafted in the Philippines</div> 1453 <div class="foot-soc"> 1454 <a href="https://instagram.com/" aria-label="Instagram" target="_blank" rel="noopener noreferrer"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="2" width="20" height="20" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1" fill="currentColor"/></svg></a> 1455 <a href="https://facebook.com/" aria-label="Facebook" target="_blank" rel="noopener noreferrer"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3Z"/></svg></a> 1456 <a href="mailto:[email protected]" aria-label="Email"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m22 6-10 7L2 6"/></svg></a> 1457 </div> 1458 </div> 1459 </div> 1460</footer> 1461<section class="sec-pad section-lazy" id="recentSec" style="display:none" aria-label="Recently Viewed"> 1462 <div class="con"> 1463 <div class="sec-hd"> 1464 <div> 1465 <div class="tag tag-a"><span aria-hidden="true">//</span> History</div> 1466 <h2 class="sec-title" data-i18n="section.recently">Recently Viewed</h2> 1467 </div> 1468 </div> 1469 <div class="p-grid" id="recentGrid" role="list" aria-live="polite" style="grid-template-columns:repeat(auto-fill,minmax(220px,1fr))"></div> 1470 </div> 1471</section> 1472<button class="btt" id="btt" aria-label="Back to top">â</button> 1473</main> 1474<div class="overlay" id="exitMod" role="dialog" aria-modal="true" aria-labelledby="exitTitle" aria-hidden="true" style="display:none"> 1475 <div class="modal" style="max-width:440px;text-align:center;padding:40px 32px"> 1476 <button class="m-cls" id="closeExit" aria-label="Close">â</button> 1477 <div style="font-size:3rem;margin-bottom:16px" aria-hidden="true">ð¸</div> 1478 <h2 id="exitTitle" style="font-family:var(--fd);font-size:1.6rem;font-weight:900;margin-bottom:10px" data-i18n="exit.title">Wait - don't leave empty-handed!</h2> 1479 <p class="m-sub" style="margin-bottom:24px" data-i18n="exit.subtitle">Get 10% off your first order</p> 1480 <div class="fi" style="margin-bottom:16px"> 1481 <div class="fi-wrap"><input type="email" class="fi-inp" id="exitEmail" placeholder="[email protected]" aria-label="Email for discount"></div> 1482 </div> 1483 <button class="btn btn-p btn-lg" style="width:100%;justify-content:center;margin-bottom:12px" id="exitCta" data-i18n="exit.cta">Claim My Discount</button> 1484 <button class="btn btn-g btn-sm" style="width:100%;justify-content:center" id="exitDismiss" data-i18n="exit.dismiss">No thanks</button> 1485 </div> 1486</div> 1487<div class="overlay" id="authMod" role="dialog" aria-modal="true" aria-labelledby="authTitle" aria-hidden="true"> 1488 <div class="modal"> 1489 <div class="m-hd"> 1490 <h2 id="authTitle" style="font-family:var(--fd);font-size:1.5rem;font-weight:700">Welcome to Bloom</h2> 1491 <button class="m-cls" id="closeAuth" aria-label="Close dialog">â</button> 1492 </div> 1493 <div class="a-tabs" role="tablist"> 1494 <button class="a-tab active" data-ftab="login" role="tab" aria-selected="true">Sign In</button> 1495 <button class="a-tab" data-ftab="register" role="tab" aria-selected="false">Register</button> 1496 <button class="a-tab" data-ftab="guest" role="tab" aria-selected="false">Guest</button> 1497 </div>
1498 <div class="err-summary" id="loginErrSum" role="alert" aria-live="assertive"> 1499 <h4><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>Please fix the following:</h4> 1500 <ul></ul> 1501 </div> 1502 <form id="loginF" onsubmit="event.preventDefault();"> 1503 <div class="fi"> 1504 <label class="fi-lbl" for="lEmail">Email</label> 1505 <div class="fi-wrap"> 1506 <input type="email" class="fi-inp" id="lEmail" placeholder="[email protected]" autocomplete="email" aria-describedby="lEmailE" required> 1507 </div> 1508 <span class="fe" id="lEmailE" role="alert"></span> 1509 </div> 1510 <div class="fi"> 1511 <label class="fi-lbl" for="lPass">Password</label> 1512 <div class="fi-wrap"> 1513 <input type="password" class="fi-inp" id="lPass" placeholder="â¢â¢â¢â¢â¢â¢â¢â¢" autocomplete="current-password" aria-describedby="lPassE" required> 1514 <button type="button" class="pw-tog" data-for="lPass" aria-label="Toggle password visibility">show</button> 1515 </div> 1516 <span class="fe" id="lPassE" role="alert"></span> 1517 </div> 1518 <button type="button" class="fpl-btn" id="fplBtn">Forgot password?</button> 1519 <button class="btn btn-p" style="width:100%;justify-content:center;margin-top:6px" id="lSubmit">Sign In â</button> 1520 </form> 1521 <form id="registerF" style="display:none" onsubmit="event.preventDefault();"> 1522 <div class="err-summary" id="regErrSum" role="alert" aria-live="assertive"> 1523 <h4><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>Please fix the following:</h4> 1524 <ul></ul> 1525 </div> 1526 <div class="fi"> 1527 <label class="fi-lbl" for="rName">Name</label> 1528 <div class="fi-wrap"><input type="text" class="fi-inp" id="rName" placeholder="Your name" autocomplete="name" aria-describedby="rNameE" required></div> 1529 <span class="fe" id="rNameE" role="alert"></span> 1530 </div> 1531 <div class="fi"> 1532 <label class="fi-lbl" for="rEmail">Email</label> 1533 <div class="fi-wrap"><input type="email" class="fi-inp" id="rEmail" placeholder="[email protected]" autocomplete="email" aria-describedby="rEmailE" required></div> 1534 <span class="fe" id="rEmailE" role="alert"></span> 1535 </div> 1536 <div class="fi"> 1537 <label class="fi-lbl" for="rPass">Password</label> 1538 <div class="fi-wrap"> 1539 <input type="password" class="fi-inp" id="rPass" placeholder="Min 8 characters" autocomplete="new-password" aria-describedby="rStrE" required minlength="8"> 1540 <button type="button" class="pw-tog" data-for="rPass" aria-label="Toggle password visibility">show</button> 1541 </div> 1542 <div id="rStrE" aria-live="polite"><div class="str-bar"><div class="str-fill" id="strFill"></div></div><span class="str-lbl" id="strLbl"></span></div> 1543 <span class="fe" id="rPassE" role="alert"></span> 1544 </div> 1545 <button class="btn btn-p" style="width:100%;justify-content:center;margin-top:6px" id="rSubmit">Create Account â</button> 1546 </form> 1547 <div id="guestF" style="display:none;text-align:center;padding:14px 0"> 1548 <p class="m-sub">Browse and pre-order without an account. You can claim your order with the confirmation email later.</p> 1549 <button class="btn btn-p" style="width:100%;justify-content:center" id="gSubmit">Continue as Guest â</button> 1550 </div> 1551 </div> 1552</div> 1553<div class="overlay" id="profMod" role="dialog" aria-modal="true" aria-labelledby="profTitle" aria-hidden="true"> 1554 <div class="modal"> 1555 <div class="m-hd"> 1556 <div> 1557 <h2 id="profTitle" style="font-family:var(--fd);font-size:1.4rem;font-weight:700">What's the occasion?</h2> 1558 <p class="m-sub" style="margin-top:6px;margin-bottom:0">Pick one. We'll tune the catalog and pricing tier to match.</p> 1559 </div> 1560 <button class="m-cls" id="closeProf" aria-label="Close dialog">â</button> 1561 </div> 1562 <div class="occ-grid" role="radiogroup" aria-label="Occasion"> 1563 <button class="occ-btn" data-occ="birthday" role="radio" aria-checked="false"><span class="occ-emj" aria-hidden="true">ð</span>Birthday</button> 1564 <button class="occ-btn" data-occ="anniversary" role="radio" aria-checked="false"><span class="occ-emj" aria-hidden="true">ð</span>Anniversary</button> 1565 <button class="occ-btn" data-occ="wedding" role="radio" aria-checked="false"><span class="occ-emj" aria-hidden="true">ð</span>Wedding</button> 1566 <button class="occ-btn" data-occ="sympathy" role="radio" aria-checked="false"><span class="occ-emj" aria-hidden="true">ðï¸</span>Sympathy</button> 1567 <button class="occ-btn" data-occ="congrats" role="radio" aria-checked="false"><span class="occ-emj" aria-hidden="true">ð</span>Congrats</button> 1568 <button class="occ-btn" data-occ="just-because" role="radio" aria-checked="false"><span class="occ-emj" aria-hidden="true">ð»</span>Just because</button> 1569 <button class="occ-btn" data-occ="corporate" role="radio" aria-checked="false"><span class="occ-emj" aria-hidden="true">ð¼</span>Corporate</button> 1570 <button class="occ-btn" data-occ="thanks" role="radio" aria-checked="false"><span class="occ-emj" aria-hidden="true">ð</span>Thanks</button> 1571 </div> 1572 <div style="display:flex;gap:10px"> 1573 <button class="btn btn-g" style="flex:1;justify-content:center" id="profSkip">Skip</button> 1574 <button class="btn btn-p" style="flex:2;justify-content:center" id="profSubmit">Show My Picks â</button> 1575 </div> 1576 </div> 1577</div> 1578<div class="overlay" id="qvMod" role="dialog" aria-modal="true" aria-labelledby="qvTitle" aria-hidden="true"> 1579 <div class="modal" style="max-width:560px"> 1580 <div class="m-hd"> 1581 <h2 id="qvTitle" style="font-family:var(--fd);font-size:1.35rem;font-weight:700"></h2> 1582 <button class="m-cls" id="closeQv" aria-label="Close dialog">â</button> 1583 </div> 1584 <div id="qvContent"></div> 1585 </div> 1586</div> 1587<div class="overlay" id="fplMod" role="dialog" aria-modal="true" aria-labelledby="fplTitle" aria-hidden="true"> 1588 <div class="modal"> 1589 <div class="m-hd"> 1590 <h2 id="fplTitle" style="font-family:var(--fd);font-size:1.35rem;font-weight:700">Reset Password</h2> 1591 <button class="m-cls" id="closeFpl" aria-label="Close dialog">â</button> 1592 </div> 1593 <p class="m-sub">Enter your email. We'll send a secure reset link within 60 seconds.</p> 1594 <div class="fi"> 1595 <label class="fi-lbl" for="fplEmail">Email</label> 1596 <div class="fi-wrap"><input type="email" class="fi-inp" id="fplEmail" placeholder="[email protected]" required></div>
1597 <span class="fe" id="fplEmailE" role="alert"></span> 1598 </div> 1599 <button class="btn btn-p" style="width:100%;justify-content:center" id="fplSubmit">Send Reset Link â</button> 1600 </div> 1601</div> 1602<div class="wl-drawer" id="wlDrawer" role="dialog" aria-modal="true" aria-labelledby="wlDrawerTitle" aria-hidden="true"> 1603 <div class="wl-drawer-hd"> 1604 <div> 1605 <h3 id="wlDrawerTitle">Wishlist</h3> 1606 <small><span id="wlCount">0</span> saved</small> 1607 </div> 1608 <button type="button" class="wl-drawer-cls" id="wlDrawerCls" aria-label="Close wishlist">â</button> 1609 </div> 1610 <div class="wl-drawer-body" id="wlDrawerBody"> 1611 <div class="wl-empty" id="wlEmpty"> 1612 <div class="wl-empty-ico" aria-hidden="true">â¡</div> 1613 <h4 style="font-family:var(--fd);font-weight:700;font-size:1rem;margin-bottom:6px">Nothing saved yet</h4> 1614 <p style="font-size:.84rem;line-height:1.6">Tap the heart on any bouquet to save it. Your wishlist syncs across devices when you sign in.</p> 1615 </div> 1616 </div> 1617 <div class="wl-drawer-ft"> 1618 <button type="button" class="btn btn-p" id="wlClear" style="width:100%;justify-content:center" hidden>Clear all</button> 1619 </div> 1620</div> 1621<button type="button" class="voice-fab" id="voiceFab" aria-label="Voice navigation - press and speak" aria-pressed="false" hidden> 1622 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M12 2a3 3 0 0 0-3 3v6a3 3 0 1 0 6 0V5a3 3 0 0 0-3-3z"/><path d="M19 10v1a7 7 0 0 1-14 0v-1"/><path d="M12 18v4"/><path d="M8 22h8"/></svg> 1623</button> 1624<div class="voice-status" id="voiceStatus" aria-live="polite" role="status"><small>Listening</small><span id="voiceText">Try: "Show bouquets" or "Open cart"</span></div> 1625<div class="funnel-bar" id="funnelBar" aria-label="Browsing progress" role="status"> 1626 <div class="funnel-track"> 1627 <span class="funnel-step active" data-step="hero">Hero</span> 1628 <span class="funnel-conn" aria-hidden="true"></span> 1629 <span class="funnel-step" data-step="shop">Shop</span> 1630 <span class="funnel-conn" aria-hidden="true"></span> 1631 <span class="funnel-step" data-step="subs">Subscribe</span> 1632 <span class="funnel-conn" aria-hidden="true"></span> 1633 <span class="funnel-step" data-step="cart">Cart</span> 1634 <span class="funnel-conn" aria-hidden="true"></span> 1635 <span class="funnel-step" data-step="checkout">Checkout</span> 1636 </div> 1637</div> 1638<div class="toast-con" id="toastCon" aria-live="polite" aria-atomic="false" role="status"></div>
1639<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/motion.js" defer></script>
vendor: 2 bytes, line 1639
1639
1640<script src="/socket.io/socket.io.js" defer></script>
vendor: 2 bytes, line 1640
1640
1641<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/motion.js"></script>
vendor: 1 bytes, line 1641
1641
1642<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
vendor: 1 bytes, line 1642
1642
1643<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ScrollTrigger.min.js"></script>
vendor: 1 bytes, line 1643
1643
1644<script src="/js/core.bundle.min.js"></script>
vendor: 1 bytes, line 1644
1644
1645<script src="/js/core/AmbientAudio.js" defer></script>
vendor: 2 bytes, line 1645
1645
1646<script src="/js/core/BloomCursor.js" defer></script>
vendor: 2 bytes, line 1646
1646
1647<script src="/js/core/ExhibitTicketing.js" defer></script>
vendor: 2 bytes, line 1647
1647
1648<script src="/js/core/ExpoGallery.js" defer></script>
vendor: 2 bytes, line 1648
1648
1649<script src="/js/core/AtelierForge.js" defer></script>
vendor: 2 bytes, line 1649
1649
1650<script> 1651(function () { 1652 'use strict'; 1653 var Api = window.Api; 1654 var Store = window.Store; 1655 function qs(s, r) { return (r || document).querySelector(s); } 1656 function qsa(s, r) { return Array.from((r || document).querySelectorAll(s)); } 1657 function on(el, ev, fn, o) { if (el) el.addEventListener(ev, fn, o || false); } 1658 function reducedMotion() { return window.matchMedia('(prefers-reduced-motion: reduce)').matches; } 1659 function escapeHtml(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c]; }); } 1660 function money(n) { return '\u20B1' + Number(n || 0).toLocaleString('en-PH', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } 1661 var FALLBACK_IMG = '/uploads/products/crimson-vow.jpg'; 1662 var FALLBACK_CAT_IMG = { 1663 bouquets: '/uploads/products/crimson-vow.jpg', 1664 arrangements: '/uploads/products/neon-blossom.jpg', 1665 fresh: '/uploads/products/velvet-midnight.jpg', 1666 dried: '/uploads/products/obsidian-rose.jpg', 1667 corporate: '/uploads/products/executive-crimson.jpg' 1668 }; 1669 var FALLBACK_PRODUCTS = []; 1670 var FEATURED_REVIEWS = [ 1671 { name: 'Maria C.', rating: 5, body: "I ordered flowers for my mom's birthday and they arrived looking even better than the photos. The silk wrap was beautiful and the delivery was right on time.", role: 'Sample · Birthday' }, 1672 { name: 'James R.', rating: 5, body: 'We needed 40 matching bouquets for a company event. The ordering process was straightforward and every arrangement looked consistent. Will definitely order again.', role: 'Sample · Corporate' }, 1673 { name: 'Ana S.', rating: 5, body: 'Surprised my wife with an evening delivery on our anniversary. Getting the photo confirmation before she even called me was a really nice touch.', role: 'Sample · Anniversary' }, 1674 { name: 'Carlo M.', rating: 5, body: 'Sent flowers to a friend who was going through a hard time. Bloom handled the personal note carefully and delivered within the time window I picked.', role: 'Sample · Sympathy' }, 1675 { name: 'Rina L.', rating: 5, body: 'Just wanted to brighten up my partner\u2019s Tuesday. Pre-ordered on Saturday, arrived Tuesday evening as planned. Still fresh a week later.', role: 'Sample · Just because' } 1676 ]; 1677 var toastCount = 0; 1678 var MAX_TOASTS = 5; 1679 window.showToast = function (msg, type) { 1680 type = type || 'info'; 1681 var con = qs('#toastCon'); 1682 if (!con) return; 1683 if (toastCount >= MAX_TOASTS) return; 1684 toastCount++; 1685 var icons = { success: '\u2714', error: '\u2715', info: '\u25C6' }; 1686 var t = document.createElement('div'); 1687 t.className = 'toast toast-' + type; 1688 t.setAttribute('role', type === 'error' ? 'alert' : 'status'); 1689 t.innerHTML = '<span class="toast-ico" aria-hidden="true">' + icons[type] + '</span><span>' + escapeHtml(msg) + '</span>'; 1690 con.appendChild(t); 1691 setTimeout(function () { 1692 t.style.opacity = '0'; 1693 t.style.transform = 'translateX(80px)'; 1694 t.style.transition = 'all .3s var(--ease)'; 1695 setTimeout(function () { t.remove(); toastCount--; }, 320); 1696 }, 3800); 1697 }; 1698 var showToast = window.showToast; 1699 function initCursor() { 1700 if (window.matchMedia('(pointer: coarse)').matches || window.matchMedia('(hover: none)').matches) return; 1701 var dot = qs('#cDot'); 1702 var ring = qs('#cRing'); 1703 if (!dot || !ring) return; 1704 var mx = window.innerWidth / 2, my = window.innerHeight / 2; 1705 var rx = mx, ry = my; 1706 on(window, 'mousemove', function (e) { mx = e.clientX; my = e.clientY; dot.style.transform = 'translate3d(' + mx + 'px,' + my + 'px,0) translate(-50%,-50%)'; }); 1707 (function frame() { rx += (mx - rx) * 0.18; ry += (my - ry) * 0.18; ring.style.transform = 'translate3d(' + rx + 'px,' + ry + 'px,0) translate(-50%,-50%)'; requestAnimationFrame(frame); })(); 1708 qsa('a, button, input, textarea, select, [role="button"], [role="tab"], [role="option"]').forEach(function (el) { 1709 on(el, 'pointerenter', function () { document.body.classList.add('c-hover'); }); 1710 on(el, 'pointerleave', function () { document.body.classList.remove('c-hover'); }); 1711 });
1712 var mo = new MutationObserver(function () { 1713 qsa('a, button, input, textarea, select, [role="button"], [role="tab"], [role="option"]').forEach(function (el) { 1714 if (el._cbnd) return; 1715 el._cbnd = 1; 1716 on(el, 'pointerenter', function () { document.body.classList.add('c-hover'); }); 1717 on(el, 'pointerleave', function () { document.body.classList.remove('c-hover'); }); 1718 }); 1719 }); 1720 mo.observe(document.body, { childList: true, subtree: true }); 1721 } 1722 function initParticles() { 1723 var c = qs('#ptcl'); 1724 if (!c || reducedMotion()) return; 1725 var ctx = c.getContext('2d', { alpha: true }); 1726 var parts = []; 1727 var dpr = Math.min(window.devicePixelRatio || 1, 2); 1728 var cores = navigator.hardwareConcurrency || 4; 1729 var mem = navigator.deviceMemory || 4; 1730 var isMobile = window.matchMedia('(max-width: 768px)').matches; 1731 var perfTier = (cores >= 8 && mem >= 8) ? 'high' : (cores >= 4 && mem >= 4) ? 'mid' : 'low'; 1732 var baseCount = isMobile ? 18 : (perfTier === 'high' ? 80 : perfTier === 'mid' ? 48 : 24); 1733 var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; 1734 if (connection && (connection.saveData || /2g|slow-2g/.test(connection.effectiveType || ''))) baseCount = Math.min(baseCount, 14); 1735 if (window.matchMedia('(prefers-reduced-data: reduce)').matches) baseCount = Math.min(baseCount, 14); 1736 var connectDist = isMobile ? 100 : 140; 1737 var mouseX = -9999, mouseY = -9999, mouseActive = false; 1738 on(c.parentElement || c, 'mousemove', function (e) { 1739 var r = c.getBoundingClientRect(); 1740 mouseX = (e.clientX - r.left) * dpr; 1741 mouseY = (e.clientY - r.top) * dpr; 1742 mouseActive = true; 1743 }); 1744 on(c.parentElement || c, 'mouseleave', function () { mouseActive = false; }); 1745 function size() { 1746 var hero = qs('#heroSec'); 1747 if (!hero) return; 1748 var r = hero.getBoundingClientRect(); 1749 c.width = r.width * dpr; 1750 c.height = r.height * dpr; 1751 c.style.width = r.width + 'px'; 1752 c.style.height = r.height + 'px'; 1753 } 1754 size(); 1755 on(window, 'resize', size); 1756 var depthLayers = [ 1757 { speed: 0.3, sizeMin: 0.4, sizeMax: 1.2, opacity: 0.15, count: Math.floor(baseCount * 0.35) }, 1758 { speed: 0.6, sizeMin: 0.8, sizeMax: 2.0, opacity: 0.35, count: Math.floor(baseCount * 0.4) }, 1759 { speed: 1.0, sizeMin: 1.4, sizeMax: 3.0, opacity: 0.55, count: Math.floor(baseCount * 0.25) } 1760 ]; 1761 var hueChoices = ['p5', 'pk', 'mn', 'gd', 'w']; 1762 depthLayers.forEach(function (layer, li) { 1763 for (var i = 0; i < layer.count; i++) { 1764 var h = hueChoices[Math.floor(Math.random() * hueChoices.length)]; 1765 parts.push({ 1766 x: Math.random() * (c.width || 1920), y: Math.random() * (c.height || 1080), 1767 r: Math.random() * (layer.sizeMax - layer.sizeMin) + layer.sizeMin, 1768 vx: (Math.random() - 0.5) * 0.4 * layer.speed, 1769 vy: -(Math.random() * 0.5 + 0.08) * layer.speed, 1770 o: Math.random() * layer.opacity + 0.1, 1771 baseO: layer.opacity, 1772 hue: h, 1773 layer: li, 1774 phase: Math.random() * Math.PI * 2, 1775 pulseSpeed: Math.random() * 0.02 + 0.008, 1776 wobbleAmp: Math.random() * 0.3 + 0.1 1777 }); 1778 } 1779 }); 1780 var auroraPhase = 0; 1781 var time = 0; 1782 var raf; 1783 var visible = true; 1784 var io = new IntersectionObserver(function (es) { es.forEach(function (e) { visible = e.isIntersecting; }); }, { threshold: 0.01 }); 1785 io.observe(c); 1786 function getColor(hue, alpha) { 1787 if (hue === 'p5') return 'rgba(230,26,26,' + alpha + ')'; 1788 if (hue === 'pk') return 'rgba(238,90,160,' + alpha + ')'; 1789 if (hue === 'mn') return 'rgba(0,212,170,' + alpha + ')'; 1790 if (hue === 'gd') return 'rgba(255,215,0,' + alpha + ')'; 1791 return 'rgba(255,255,255,' + (alpha * 0.7) + ')'; 1792 } 1793 function frame() { 1794 raf = requestAnimationFrame(frame); 1795 if (!visible) return; 1796 time += 0.016; 1797 auroraPhase += 0.003; 1798 ctx.clearRect(0, 0, c.width, c.height); 1799 /* --- Ethereal aurora waves --- */ 1800 if (!isMobile || perfTier !== 'low') { 1801 ctx.save(); 1802 ctx.globalCompositeOperation = 'screen'; 1803 for (var aw = 0; aw < 3; aw++) { 1804 var auroraY = c.height * (0.25 + aw * 0.2); 1805 var gradient = ctx.createLinearGradient(0, auroraY - 80 * dpr, 0, auroraY + 80 * dpr); 1806 var auroraColors = [ 1807 ['rgba(230,26,26,0.025)', 'rgba(238,90,160,0.04)', 'rgba(230,26,26,0.025)'], 1808 ['rgba(124,58,237,0.02)', 'rgba(0,212,170,0.03)', 'rgba(124,58,237,0.02)'], 1809 ['rgba(238,90,160,0.018)', 'rgba(255,215,0,0.025)', 'rgba(238,90,160,0.018)'] 1810 ]; 1811 gradient.addColorStop(0, auroraColors[aw][0]); 1812 gradient.addColorStop(0.5, auroraColors[aw][1]); 1813 gradient.addColorStop(1, auroraColors[aw][2]); 1814 ctx.fillStyle = gradient; 1815 ctx.beginPath(); 1816 ctx.moveTo(0, auroraY); 1817 for (var ax = 0; ax <= c.width; ax += 4) { 1818 var waveY = auroraY + Math.sin(ax * 0.003 + auroraPhase + aw * 1.8) * 40 * dpr
1819 + Math.sin(ax * 0.007 - auroraPhase * 0.7 + aw) * 20 * dpr 1820 + Math.cos(ax * 0.0015 + time * 0.5) * 30 * dpr; 1821 ctx.lineTo(ax, waveY); 1822 } 1823 ctx.lineTo(c.width, c.height); 1824 ctx.lineTo(0, c.height); 1825 ctx.closePath(); 1826 ctx.fill(); 1827 } 1828 ctx.restore(); 1829 } 1830 /* --- Mouse reactive glow --- */ 1831 if (mouseActive && !isMobile) { 1832 ctx.save(); 1833 ctx.globalCompositeOperation = 'screen'; 1834 var glowRad = 180 * dpr; 1835 var mg = ctx.createRadialGradient(mouseX, mouseY, 0, mouseX, mouseY, glowRad); 1836 mg.addColorStop(0, 'rgba(230,26,26,0.08)'); 1837 mg.addColorStop(0.3, 'rgba(238,90,160,0.04)'); 1838 mg.addColorStop(0.6, 'rgba(124,58,237,0.02)'); 1839 mg.addColorStop(1, 'rgba(0,0,0,0)'); 1840 ctx.fillStyle = mg; 1841 ctx.fillRect(mouseX - glowRad, mouseY - glowRad, glowRad * 2, glowRad * 2); 1842 ctx.restore(); 1843 } 1844 /* --- Constellation connections --- */ 1845 if (perfTier !== 'low') { 1846 ctx.save(); 1847 ctx.globalCompositeOperation = 'screen'; 1848 var cd2 = connectDist * connectDist * dpr * dpr; 1849 for (var ci = 0; ci < parts.length; ci++) { 1850 for (var cj = ci + 1; cj < parts.length; cj++) { 1851 if (parts[ci].layer !== parts[cj].layer) continue; 1852 var dx = parts[ci].x - parts[cj].x; 1853 var dy = parts[ci].y - parts[cj].y; 1854 var d2 = dx * dx + dy * dy; 1855 if (d2 < cd2) { 1856 var dist = Math.sqrt(d2); 1857 var lineAlpha = (1 - dist / (connectDist * dpr)) * 0.12 * Math.min(parts[ci].o, parts[cj].o); 1858 ctx.beginPath();
1859 ctx.moveTo(parts[ci].x, parts[ci].y); 1860 ctx.lineTo(parts[cj].x, parts[cj].y); 1861 ctx.strokeStyle = getColor(parts[ci].hue, lineAlpha); 1862 ctx.lineWidth = 0.5 * dpr; 1863 ctx.stroke(); 1864 } 1865 } 1866 } 1867 ctx.restore(); 1868 } 1869 /* --- Particles with glow halos --- */ 1870 for (var k = 0; k < parts.length; k++) { 1871 var p = parts[k]; 1872 p.phase += p.pulseSpeed; 1873 var pulse = 0.7 + Math.sin(p.phase) * 0.3; 1874 p.x += (p.vx + Math.sin(time * 0.5 + p.phase) * p.wobbleAmp) * dpr; 1875 p.y += p.vy * dpr; 1876 /* Mouse attraction for foreground particles */ 1877 if (mouseActive && !isMobile && p.layer === 2) { 1878 var mdx = mouseX - p.x; 1879 var mdy = mouseY - p.y; 1880 var md = Math.sqrt(mdx * mdx + mdy * mdy); 1881 if (md < 200 * dpr && md > 0) { 1882 var force = (1 - md / (200 * dpr)) * 0.4; 1883 p.x += (mdx / md) * force * dpr; 1884 p.y += (mdy / md) * force * dpr; 1885 } 1886 } 1887 if (p.y < -10) { p.y = c.height + 10; p.x = Math.random() * c.width; } 1888 if (p.x < -10) p.x = c.width + 10; 1889 if (p.x > c.width + 10) p.x = -10; 1890 var drawO = p.o * pulse; 1891 /* Glow halo for larger/foreground particles */ 1892 if (p.layer >= 1 && p.r > 1.2) { 1893 ctx.save(); 1894 ctx.globalCompositeOperation = 'screen'; 1895 var gr = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, p.r * 4 * dpr); 1896 gr.addColorStop(0, getColor(p.hue, drawO * 0.3)); 1897 gr.addColorStop(0.5, getColor(p.hue, drawO * 0.08)); 1898 gr.addColorStop(1, 'rgba(0,0,0,0)'); 1899 ctx.fillStyle = gr; 1900 ctx.fillRect(p.x - p.r * 4 * dpr, p.y - p.r * 4 * dpr, p.r * 8 * dpr, p.r * 8 * dpr); 1901 ctx.restore(); 1902 } 1903 ctx.beginPath(); 1904 ctx.arc(p.x, p.y, p.r * dpr * (0.9 + pulse * 0.1), 0, Math.PI * 2); 1905 ctx.fillStyle = getColor(p.hue, drawO); 1906 ctx.fill(); 1907 } 1908 } 1909 frame(); 1910 document.addEventListener('visibilitychange', function () { if (document.hidden) cancelAnimationFrame(raf); else frame(); }); 1911 } 1912 function initHeroParallax() { 1913 if (reducedMotion()) return; 1914 var hero = qs('#heroSec'); 1915 if (!hero) return; 1916 var tx = 0, ty = 0, cx = 0, cy = 0; 1917 on(hero, 'mousemove', function (e) { 1918 var r = hero.getBoundingClientRect(); 1919 tx = ((e.clientX - r.left) / r.width - 0.5) * 2; 1920 ty = ((e.clientY - r.top) / r.height - 0.5) * 2; 1921 }); 1922 on(hero, 'mouseleave', function () { tx = 0; ty = 0; }); 1923 (function frame() { 1924 cx += (tx - cx) * 0.08; 1925 cy += (ty - cy) * 0.08; 1926 hero.style.setProperty('--px', cx.toFixed(3)); 1927 hero.style.setProperty('--py', cy.toFixed(3)); 1928 requestAnimationFrame(frame); 1929 })(); 1930 qsa('.h-card').forEach(function (card) { 1931 var lx = 0, ly = 0, rx = 0, ry = 0; 1932 on(card, 'mousemove', function (e) { 1933 var r = card.getBoundingClientRect(); 1934 lx = ((e.clientX - r.left) / r.width - 0.5) * 2; 1935 ly = ((e.clientY - r.top) / r.height - 0.5) * 2; 1936 card.style.setProperty('--mx', ((lx + 1) * 50) + '%'); 1937 card.style.setProperty('--my', ((ly + 1) * 50) + '%'); 1938 }); 1939 on(card, 'mouseleave', function () { lx = 0; ly = 0; }); 1940 (function f() { 1941 rx += (lx - rx) * 0.14; 1942 ry += (ly - ry) * 0.14; 1943 var z = card.classList.contains('hc-1') ? 40 : (card.classList.contains('hc-2') ? 10 : 25); 1944 var tf = 'translateZ(' + z + 'px) rotateY(' + (rx * 6) + 'deg) rotateX(' + (-ry * 6) + 'deg)'; 1945 if (card.classList.contains('hc-1')) tf = 'translateX(-50%) ' + tf; 1946 card.style.transform = tf; 1947 requestAnimationFrame(f); 1948 })(); 1949 }); 1950 } 1951 function initNav() { 1952 var nav = qs('#nav'); 1953 var last = 0; 1954 function onScroll() { 1955 var y = window.scrollY || window.pageYOffset; 1956 if (y > 12) nav.classList.add('sc'); else nav.classList.remove('sc'); 1957 last = y; 1958 } 1959 onScroll(); 1960 on(window, 'scroll', onScroll, { passive: true });
1961 var hmb = qs('#hmb'); 1962 var mob = qs('#mobMenu'); 1963 var mobCls = qs('#mobClose'); 1964 on(hmb, 'click', function () { 1965 var open = mob.classList.toggle('open'); 1966 hmb.setAttribute('aria-expanded', String(open)); 1967 mob.setAttribute('aria-hidden', String(!open)); 1968 document.body.classList.toggle('modal-open', open); 1969 }); 1970 on(mobCls, 'click', function () { 1971 mob.classList.remove('open'); 1972 hmb.setAttribute('aria-expanded', 'false'); 1973 mob.setAttribute('aria-hidden', 'true'); 1974 document.body.classList.remove('modal-open'); 1975 }); 1976 qsa('.mob-inner a').forEach(function (a) { 1977 on(a, 'click', function () { 1978 mob.classList.remove('open'); 1979 hmb.setAttribute('aria-expanded', 'false'); 1980 mob.setAttribute('aria-hidden', 'true'); 1981 document.body.classList.remove('modal-open'); 1982 }); 1983 }); 1984 on(window, 'resize', function () { 1985 if (window.innerWidth > 900 && mob.classList.contains('open')) { 1986 mob.classList.remove('open'); 1987 hmb.setAttribute('aria-expanded', 'false'); 1988 mob.setAttribute('aria-hidden', 'true'); 1989 document.body.classList.remove('modal-open'); 1990 } 1991 }); 1992 } 1993 function initTyper() { 1994 var el = qs('#typer'); 1995 if (!el) return; 1996 var items = el.querySelectorAll('.g-txt'); 1997 if (items.length === 0) return; 1998 var i = 0; 1999 function swap() { 2000 items[i].classList.remove('active'); 2001 items[i].setAttribute('aria-hidden', 'true'); 2002 i = (i + 1) % items.length; 2003 items[i].classList.add('active'); 2004 items[i].setAttribute('aria-hidden', 'false'); 2005 } 2006 if (!reducedMotion()) setInterval(swap, 3500); 2007 } 2008 function initCountdown() { 2009 var el = qs('#cdWrap'); 2010 if (!el) return; 2011 var target = new Date(); 2012 target.setDate(target.getDate() + 7); 2013 target.setHours(23, 59, 59, 999); 2014 var cdInterval = null; 2015 function tick() { 2016 var diff = target - new Date(); 2017 if (diff <= 0) { el.textContent = 'This week\'s batch is closed - next opens Monday.'; if (cdInterval) { clearInterval(cdInterval); cdInterval = null; } return; } 2018 var d = Math.floor(diff / 864e5); 2019 var h = Math.floor((diff % 864e5) / 36e5); 2020 var m = Math.floor((diff % 36e5) / 6e4); 2021 var s = Math.floor((diff % 6e4) / 1e3); 2022 el.innerHTML = '<span class="cd-lbl">Next batch closes in</span><span class="cd-units">' + 2023 '<span class="cd-num">' + d + '<span class="cd-sub">d</span></span><span class="cd-sep">:</span>' + 2024 '<span class="cd-num">' + String(h).padStart(2, '0') + '<span class="cd-sub">h</span></span><span class="cd-sep">:</span>' + 2025 '<span class="cd-num">' + String(m).padStart(2, '0') + '<span class="cd-sub">m</span></span><span class="cd-sep">:</span>' + 2026 '<span class="cd-num">' + String(s).padStart(2, '0') + '<span class="cd-sub">s</span></span></span>'; 2027 } 2028 tick(); 2029 cdInterval = setInterval(tick, 1000); 2030 } 2031 function initSearch() { 2032 var wrap = qs('#srchWrap'); 2033 var tog = qs('#srchTog'); 2034 var panel = qs('#srchPanel'); 2035 var inp = qs('#srchInp'); 2036 var res = qs('#srchRes'); 2037 if (!wrap || !tog || !panel || !inp || !res) return; 2038 var deb = null; 2039 function openP() { panel.classList.add('open'); panel.setAttribute('aria-hidden', 'false'); tog.setAttribute('aria-expanded', 'true'); setTimeout(function () { inp.focus(); }, 80); } 2040 function closeP() { panel.classList.remove('open'); panel.setAttribute('aria-hidden', 'true'); tog.setAttribute('aria-expanded', 'false'); } 2041 on(tog, 'click', function (e) { e.stopPropagation(); panel.classList.contains('open') ? closeP() : openP(); }); 2042 on(document, 'click', function (e) { if (wrap && !wrap.contains(e.target)) closeP(); }); 2043 on(document, 'keydown', function (e) { if (e.key === 'Escape') closeP(); }); 2044 on(inp, 'input', function () { 2045 clearTimeout(deb); 2046 var v = inp.value.trim(); 2047 if (!v) { res.innerHTML = ''; return; } 2048 deb = setTimeout(function () { doSearch(v); }, 220); 2049 });
2050 async function doSearch(q) { 2051 res.innerHTML = '<div style="padding:10px;color:rgba(255,255,255,.4);font-size:.82rem">Searching¦</div>'; 2052 try { 2053 var d = Api ? await Api.get('/products?search=' + encodeURIComponent(q) + '&limit=6') : { products: filterFallback(q) }; 2054 var list = (d && d.products) || d || []; 2055 if (!list.length) { res.innerHTML = '<div style="padding:10px;color:rgba(255,255,255,.4);font-size:.82rem">No matches</div>'; return; } 2056 res.innerHTML = list.map(function (p) { 2057 var n = escapeHtml(p.name || ''); 2058 var hl = n.replace(new RegExp('(' + q.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ')', 'ig'), '<mark>$1</mark>'); 2059 return '<button class="srch-item" data-id="' + escapeHtml(p.id) + '"><span style="flex:1">' + hl + '</span><span style="font-size:.76rem;color:var(--gd)">' + money(p.base_price || p.price) + '</span></button>'; 2060 }).join(''); 2061 qsa('.srch-item', res).forEach(function (b) { 2062 on(b, 'click', function () { window.location.href = '/catalog.html?id=' + encodeURIComponent(b.dataset.id); }); 2063 }); 2064 } catch (e) { 2065 res.innerHTML = '<div style="padding:10px;color:var(--cr);font-size:.82rem">Search unavailable</div>'; 2066 } 2067 } 2068 function filterFallback(q) { 2069 q = q.toLowerCase(); 2070 return FALLBACK_PRODUCTS.filter(function (p) { return (p.name || '').toLowerCase().indexOf(q) !== -1 || (p.category || '').toLowerCase().indexOf(q) !== -1; }).slice(0, 6); 2071 } 2072 } 2073 function initLang() { 2074 var btn = qs('#langBtn'); 2075 var dd = qs('#langDd'); 2076 var flag = qs('#langFlag'); 2077 var lbl = qs('#langLbl'); 2078 if (!btn || !dd) return; 2079 on(btn, 'click', function (e) { 2080 e.stopPropagation(); 2081 var open = dd.classList.toggle('open'); 2082 dd.setAttribute('aria-hidden', String(!open)); 2083 if (open) dd.removeAttribute('inert'); else dd.setAttribute('inert', ''); 2084 btn.setAttribute('aria-expanded', String(open)); 2085 }); 2086 on(document, 'click', function () { dd.classList.remove('open'); dd.setAttribute('aria-hidden', 'true'); dd.setAttribute('inert', ''); btn.setAttribute('aria-expanded', 'false'); }); 2087 qsa('.lang-opt', dd).forEach(function (o) { 2088 on(o, 'click', function (e) { 2089 e.stopPropagation(); 2090 flag.textContent = o.dataset.flag; 2091 lbl.textContent = o.dataset.lbl; 2092 dd.classList.remove('open'); 2093 dd.setAttribute('aria-hidden', 'true'); 2094 dd.setAttribute('inert', ''); 2095 btn.setAttribute('aria-expanded', 'false'); 2096 if (Store && Store.setLang) Store.setLang(o.dataset.lang); 2097 if (window.I18n) I18n.setLang(o.dataset.lang); 2098 showToast('Language set to ' + o.textContent.trim(), 'info'); 2099 }); 2100 }); 2101 } 2102 var modalStack = []; 2103 function openModal(sel) { 2104 var m = typeof sel === 'string' ? qs(sel) : sel; 2105 if (!m) return; 2106 m.classList.add('open'); 2107 m.setAttribute('aria-hidden', 'false'); 2108 document.body.classList.add('modal-open'); 2109 modalStack.push(m); 2110 var focusable = m.querySelector('input, button, [tabindex]:not([tabindex="-1"])'); 2111 if (focusable) setTimeout(function () { focusable.focus(); }, 80); 2112 } 2113 function closeModal(sel) { 2114 var m = typeof sel === 'string' ? qs(sel) : sel; 2115 if (!m) return; 2116 m.classList.remove('open'); 2117 m.setAttribute('aria-hidden', 'true'); 2118 modalStack = modalStack.filter(function (x) { return x !== m; }); 2119 if (!modalStack.length) document.body.classList.remove('modal-open'); 2120 } 2121 on(document, 'keydown', function (e) { 2122 if (e.key === 'Escape' && modalStack.length) closeModal(modalStack[modalStack.length - 1]); 2123 }); 2124 qsa('.overlay').forEach(function (o) { 2125 on(o, 'click', function (e) { if (e.target === o) closeModal(o); }); 2126 }); 2127 function initAuth() { 2128 var authBtn = qs('#authBtn'); 2129 var authBtnMob = qs('#authBtnMob'); 2130 var authMod = qs('#authMod'); 2131 on(authBtn, 'click', function () { openModal(authMod); }); 2132 on(authBtnMob, 'click', function () { 2133 qs('#mobMenu').classList.remove('open'); 2134 qs('#hmb').setAttribute('aria-expanded', 'false'); 2135 openModal(authMod); 2136 });
2137 on(qs('#closeAuth'), 'click', function () { closeModal(authMod); }); 2138 qsa('.a-tab', authMod).forEach(function (t) { 2139 on(t, 'click', function () { 2140 qsa('.a-tab', authMod).forEach(function (x) { x.classList.remove('active'); x.setAttribute('aria-selected', 'false'); }); 2141 t.classList.add('active'); t.setAttribute('aria-selected', 'true'); 2142 var f = t.dataset.ftab; 2143 qs('#loginF').style.display = f === 'login' ? 'block' : 'none'; 2144 qs('#registerF').style.display = f === 'register' ? 'block' : 'none'; 2145 qs('#guestF').style.display = f === 'guest' ? 'block' : 'none'; 2146 }); 2147 }); 2148 qsa('.pw-tog').forEach(function (b) { 2149 on(b, 'click', function () { 2150 var inp = qs('#' + b.dataset.for); 2151 if (!inp) return; 2152 var shown = inp.type === 'text'; 2153 inp.type = shown ? 'password' : 'text'; 2154 b.textContent = shown ? 'show' : 'hide'; 2155 }); 2156 }); 2157 on(qs('#rPass'), 'input', function () { 2158 var v = this.value; 2159 var s = 0; 2160 if (v.length >= 8) s++; 2161 if (/[a-z]/.test(v) && /[A-Z]/.test(v)) s++; 2162 if (/\d/.test(v)) s++; 2163 if (/[^a-zA-Z0-9]/.test(v)) s++; 2164 var pct = (s / 4) * 100; 2165 var fill = qs('#strFill'); 2166 var lbl = qs('#strLbl'); 2167 var cols = ['var(--cr)', 'var(--cr)', 'var(--gd)', 'var(--mn)', 'var(--mn)']; 2168 var txt = ['Too short', 'Weak', 'Okay', 'Good', 'Strong']; 2169 if (fill) { fill.style.width = pct + '%'; fill.style.background = cols[s]; } 2170 if (lbl) lbl.textContent = v ? txt[s] : ''; 2171 }); 2172 function setErr(id, msg) { var el = qs('#' + id); if (el) el.textContent = msg || ''; var inp = qs('#' + id.replace('E', '')); if (inp) inp.setAttribute('aria-invalid', msg ? 'true' : 'false'); } 2173 function clearErrs() { qsa('.fe', authMod).forEach(function (x) { x.textContent = ''; }); qsa('.fi-inp', authMod).forEach(function (x) { x.setAttribute('aria-invalid', 'false'); }); } 2174 on(qs('#lSubmit'), 'click', async function () { 2175 clearErrs(); 2176 var em = qs('#lEmail').value.trim(); 2177 var pw = qs('#lPass').value; 2178 var ok = true; 2179 if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(em)) { setErr('lEmailE', 'Enter a valid email'); ok = false; } 2180 if (pw.length < 1) { setErr('lPassE', 'Enter your password'); ok = false; } 2181 if (!ok) return; 2182 var btn = this; btn.disabled = true; btn.textContent = 'Signing in¦'; 2183 try { 2184 if (!Api) throw new Error('offline'); 2185 var r = await Api.post('/auth/login', { email: em, password: pw }); 2186 try { localStorage.setItem('bloom_token', r.token); localStorage.setItem('bloom_user', JSON.stringify(r.user)); } catch (e) {} 2187 if (Store) { Store.set('token', r.token); Store.set('user', r.user); } 2188 showToast('Welcome back, ' + (r.user && r.user.name || 'friend') + '!', 'success'); 2189 closeModal(authMod); 2190 setTimeout(function () { location.reload(); }, 700); 2191 } catch (e) { 2192 setErr('lPassE', (e && e.message) || 'Sign-in failed'); 2193 showToast('Sign-in failed', 'error'); 2194 } finally { btn.disabled = false; btn.textContent = 'Sign In â'; } 2195 }); 2196 on(qs('#rSubmit'), 'click', async function () { 2197 clearErrs(); 2198 var n = qs('#rName').value.trim(); 2199 var e = qs('#rEmail').value.trim(); 2200 var p = qs('#rPass').value; 2201 var ok = true; 2202 if (n.length < 2) { setErr('rNameE', 'Name required'); ok = false; } 2203 if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(e)) { setErr('rEmailE', 'Enter a valid email'); ok = false; } 2204 if (p.length < 8) { setErr('rPassE', 'Min 8 characters'); ok = false; } 2205 if (!ok) return; 2206 var btn = this; btn.disabled = true; btn.textContent = 'Creating¦'; 2207 try { 2208 if (!Api) throw new Error('offline'); 2209 var r = await Api.post('/auth/register', { name: n, email: e, password: p }); 2210 try { localStorage.setItem('bloom_token', r.token); localStorage.setItem('bloom_user', JSON.stringify(r.user)); } catch (e) {} 2211 if (Store) { Store.set('token', r.token); Store.set('user', r.user); } 2212 showToast('Welcome to Bloom, ' + (r.user && r.user.name || 'friend') + '!', 'success'); 2213 closeModal(authMod); 2214 setTimeout(function () { location.reload(); }, 700); 2215 } catch (err) { 2216 setErr('rEmailE', (err && err.message) || 'Registration failed'); 2217 showToast('Could not create account', 'error'); 2218 } finally { btn.disabled = false; btn.textContent = 'Create Account â'; } 2219 });
2220 on(qs('#gSubmit'), 'click', function () { showToast('Continuing as guest', 'info'); closeModal(authMod); }); 2221 on(qs('#gBtn'), 'click', function () { 2222 if (Api && Api.baseUrl) window.location.href = Api.baseUrl + '/auth/google'; 2223 else showToast('Google sign-in unavailable', 'error'); 2224 }); 2225 on(qs('#fplBtn'), 'click', function () { closeModal(authMod); openModal('#fplMod'); }); 2226 on(qs('#closeFpl'), 'click', function () { closeModal('#fplMod'); }); 2227 on(qs('#fplSubmit'), 'click', async function () { 2228 var e = qs('#fplEmail').value.trim(); 2229 var ee = qs('#fplEmailE'); 2230 if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(e)) { ee.textContent = 'Enter a valid email'; return; } 2231 ee.textContent = ''; 2232 var btn = this; btn.disabled = true; btn.textContent = 'Sending¦'; 2233 try { 2234 if (Api) await Api.post('/auth/forgot-password', { email: e }); 2235 showToast('If an account exists, a reset link is on its way.', 'success'); 2236 closeModal('#fplMod'); 2237 } catch (err) { 2238 showToast('Could not send reset link', 'error'); 2239 } finally { btn.disabled = false; btn.textContent = 'Send Reset Link â'; } 2240 }); 2241 try { 2242 var u = JSON.parse(localStorage.getItem('bloom_user') || 'null'); 2243 if (u && u.name) { 2244 var first = (u.name || '').split(' ')[0]; 2245 if (authBtn) authBtn.textContent = 'Hi, ' + first; 2246 if (authBtnMob) authBtnMob.textContent = 'Hi, ' + first; 2247 } 2248 } catch (e) {} 2249 } 2250 function initProfiling() { 2251 var openBtn = qs('#profilingBtn'); 2252 var mod = qs('#profMod'); 2253 var cls = qs('#closeProf'); 2254 on(openBtn, 'click', function () { openModal(mod); }); 2255 on(cls, 'click', function () { closeModal(mod); }); 2256 qsa('.occ-btn').forEach(function (b) { 2257 on(b, 'click', function () { 2258 qsa('.occ-btn').forEach(function (x) { x.classList.remove('selected'); x.setAttribute('aria-checked', 'false'); }); 2259 b.classList.add('selected'); 2260 b.setAttribute('aria-checked', 'true'); 2261 }); 2262 }); 2263 on(qs('#profSkip'), 'click', function () { closeModal(mod); }); 2264 on(qs('#profSubmit'), 'click', function () { 2265 var sel = qs('.occ-btn.selected'); 2266 if (!sel) { showToast('Pick an occasion first', 'info'); return; } 2267 if (Store && Store.setOccasion) Store.setOccasion(sel.dataset.occ); 2268 closeModal(mod); 2269 window.location.href = '/catalog.html?occasion=' + encodeURIComponent(sel.dataset.occ); 2270 }); 2271 }
2272 function renderStars(rating) { 2273 var r = Number(rating) || 0; 2274 var out = ''; 2275 for (var i = 0; i < 5; i++) out += '<span style="color:' + (i < Math.round(r) ? 'var(--gd)' : 'rgba(255,255,255,.18)') + '" aria-hidden="true">â </span>'; 2276 return out; 2277 } 2278 function renderProduct(p) { 2279 var img = (p.images && p.images[0]) || p.image_url || FALLBACK_CAT_IMG[p.category] || FALLBACK_IMG; 2280 var price = p.base_price || p.price || 0; 2281 var cat = (p.category || '').replace(/^./, function (c) { return c.toUpperCase(); }); 2282 var name = escapeHtml(p.name || 'Unnamed'); 2283 var badge = p.badge ? '<span class="p-badge">' + escapeHtml(p.badge) + '</span>' : ''; 2284 return '<article class="p-card" data-id="' + escapeHtml(p.id) + '" tabindex="0" role="button" aria-label="' + name + ', ' + money(price) + '">' + 2285 '<div class="p-shine" aria-hidden="true"></div>' + 2286 '<div class="p5-corner" aria-hidden="true"></div>' + 2287 badge + 2288 '<button class="wl-btn" aria-label="Add to wishlist" data-id="' + escapeHtml(p.id) + '">â¡</button>' + 2289 '<div class="p-img"><img src="' + escapeHtml(img) + '" alt="' + name + '" loading="lazy" decoding="async" width="300" height="180" onerror="this.onerror=null;this.style.display=\'none\';this.parentElement.innerHTML=\'<div class=p-img-ph>ð¸</div>\'"></div>' + 2290 '<div class="p-name">' + name + '</div>' + 2291 '<div class="p-cat">' + escapeHtml(cat) + '</div>' + 2292 '<div class="p-stars" role="img" aria-label="' + (p.rating || 0) + ' out of 5">' + renderStars(p.rating) + '</div>' + 2293 '<div class="p-foot"><div class="p-price">' + money(price) + '</div><button class="p-add" data-id="' + escapeHtml(p.id) + '">+ Cart</button></div>' + 2294 '</article>'; 2295 }
2296 function renderSkeletons(n) { 2297 var out = ''; 2298 for (var i = 0; i < n; i++) out += '<div class="p-skel"><div class="p-skel-img"></div><div class="p-skel-t"></div><div class="p-skel-s"></div></div>'; 2299 return out; 2300 } 2301 async function loadFeatured(cat) { 2302 cat = cat || 'all'; 2303 var grid = qs('#pGrid'); 2304 if (!grid) return; 2305 grid.setAttribute('aria-busy', 'true'); 2306 grid.innerHTML = renderSkeletons(8); 2307 var list = []; 2308 try { 2309 if (Api) { 2310 var q = cat !== 'all' ? '?category=' + encodeURIComponent(cat) + '&limit=8' : '?limit=8'; 2311 var d = await Api.get('/products' + q); 2312 list = (d && d.products) || d || []; 2313 } else { throw new Error('no-api'); } 2314 } catch (e) { 2315 list = []; 2316 } 2317 if (!list.length) { grid.innerHTML = '<div class="p-empty">No products in this category yet.</div>'; grid.setAttribute('aria-busy', 'false'); return; } 2318 grid.innerHTML = list.map(renderProduct).join(''); 2319 grid.setAttribute('aria-busy', 'false'); 2320 var cards = qsa('.p-card', grid); 2321 cards.forEach(function (c, i) { 2322 setTimeout(function () { c.classList.add('vis'); }, i * 60); 2323 }); 2324 qsa('.p-add', grid).forEach(function (b) { 2325 on(b, 'click', async function (e) { 2326 e.stopPropagation(); 2327 var orig = b.textContent; 2328 b.disabled = true; b.textContent = '¦'; 2329 try { 2330 if (Api) { 2331 await Api.post('/cart/items', { productId: b.dataset.id, qty: 1 }); 2332 var cart = await Api.get('/cart'); 2333 if (Store) { 2334 Store.set('cart', cart); 2335 if (Store.updateCartCount) Store.updateCartCount((cart.items || []).reduce(function (s, i) { return s + (i.qty || 1); }, 0)); 2336 } 2337 var badge = qs('#cartBadge'); 2338 if (badge) { 2339 var cnt = (cart.items || []).reduce(function (s, i) { return s + (i.qty || 1); }, 0); 2340 badge.textContent = cnt; 2341 badge.style.display = cnt > 0 ? 'inline-flex' : 'none'; 2342 } 2343 } 2344 showToast('Added to cart', 'success'); 2345 } catch (err) { 2346 showToast('Could not add to cart', 'error'); 2347 } finally { b.disabled = false; b.textContent = orig; } 2348 }); 2349 }); 2350 qsa('.wl-btn', grid).forEach(function (b) { 2351 on(b, 'click', async function (e) { 2352 e.stopPropagation(); 2353 var card = b.closest('.p-card'); 2354 var nameEl = card && card.querySelector('.p-name'); 2355 var priceEl = card && card.querySelector('.p-price'); 2356 var img = card && card.querySelector('.p-img img'); 2357 var item = { id: b.dataset.id, name: nameEl ? nameEl.textContent.trim() : 'Bouquet', price: priceEl ? Number(String(priceEl.textContent).replace(/[^\d.]/g, '')) : 0, image: img ? img.src : '/img/hero-flowers.webp' }; 2358 var added = window.addToWishlist ? window.addToWishlist(item) : true; 2359 b.classList.add('wl-pop'); 2360 setTimeout(function () { b.classList.remove('wl-pop'); }, 420); 2361 try { 2362 if (Api) { 2363 if (added) await Api.post('/wishlist', { productId: b.dataset.id }); 2364 else await Api.delete('/wishlist/' + encodeURIComponent(b.dataset.id)); 2365 } 2366 showToast(added ? 'Saved to wishlist' : 'Removed from wishlist', added ? 'success' : 'info'); 2367 } catch (err) { showToast(added ? 'Saved locally' : 'Removed', 'info'); } 2368 }); 2369 }); 2370 qsa('.p-card', grid).forEach(function (c) { 2371 var openQv = function (e) { 2372 if (e.target.closest('button')) return; 2373 openQuickView(c.dataset.id); 2374 }; 2375 on(c, 'click', openQv); 2376 on(c, 'keydown', function (e) { 2377 if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openQv(e); } 2378 }); 2379 }); 2380 } 2381 async function openQuickView(id) { 2382 var mod = qs('#qvMod'); 2383 var title = qs('#qvTitle'); 2384 var body = qs('#qvContent'); 2385 if (!mod || !body) return; 2386 title.textContent = 'Loading¦'; 2387 body.innerHTML = '<div style="padding:20px;text-align:center;color:rgba(255,255,255,.4)">Loading¦</div>'; 2388 openModal(mod); 2389 var p = null; 2390 try { 2391 if (Api) p = await Api.get('/products/' + encodeURIComponent(id)); 2392 } catch (e) {} 2393 if (!p) p = FALLBACK_PRODUCTS.find(function (x) { return x.id === id; }); 2394 if (!p) { body.innerHTML = '<p>Could not load this product.</p>'; return; } 2395 title.textContent = p.name; 2396 var img = (p.images && p.images[0]) || FALLBACK_CAT_IMG[p.category] || FALLBACK_IMG; 2397 var lt = (Api ? '48h-14d pre-order window' : '48h minimum lead time'); 2398 body.innerHTML = 2399 '<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px">' + 2400 '<div style="border-radius:14px;overflow:hidden;aspect-ratio:1;background:var(--gl)"><img src="' + escapeHtml(img) + '" alt="' + escapeHtml(p.name) + '" style="width:100%;height:100%;object-fit:cover"></div>' + 2401 '<div>' + 2402 '<div class="p-cat" style="margin-bottom:8px">' + escapeHtml(p.category || '') + '</div>' + 2403 '<div style="display:inline-flex;align-items:center">
2403<div class="p-stars" role="img" aria-label="' + (p.rating || 0) + ' out of 5">' + renderStars(p.rating) + '</div><span style="font-size:.78rem;color:rgba(255,255,255,.5);margin-left:6px">' + (p.review_count || 0) + ' reviews</span></div>' + 2404 '<p style="font-size:.88rem;color:rgba(255,255,255,.68);line-height:1.7;margin:14px 0">' + escapeHtml(p.description || 'Handcrafted by Bloom florists. Developed by STI LIPA BSIT students.') + '</p>' + 2405 '<div style="display:flex;align-items:center;gap:6px;font-size:.74rem;color:var(--mn);margin-bottom:14px"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>' + lt + '</div>' + 2406 '<div style="font-family:var(--fc);font-weight:900;font-size:1.8rem;color:var(--gd);margin-bottom:14px">' + money(p.base_price || p.price) + '</div>' + 2407 '<button class="btn btn-p" style="width:100%;justify-content:center" id="qvAdd">Add to cart â</button>' + 2408 '<a href="/catalog.html?id=' + encodeURIComponent(p.id) + '" class="btn btn-g" style="width:100%;justify-content:center;margin-top:8px">View full details</a>' + 2409 '</div></div>' + 2410 buildVideoMessageBlock(p.id); 2411 attachVideoMessageHandlers(p.id); 2412 on(qs('#qvAdd'), 'click', async function () { 2413 var btn = this; btn.disabled = true; btn.textContent = 'Adding¦'; 2414 try { 2415 if (Api) { 2416 await Api.post('/cart/items', { productId: p.id, qty: 1 }); 2417 var cart = await Api.get('/cart'); 2418 if (Store) { Store.set('cart', cart); if (Store.updateCartCount) Store.updateCartCount((cart.items || []).reduce(function (s, i) { return s + (i.qty || 1); }, 0)); } 2419 } 2420 showToast('Added to cart', 'success'); 2421 closeModal(mod); 2422 } catch (e) { showToast('Could not add', 'error'); } finally { btn.disabled = false; btn.textContent = 'Add to cart â'; } 2423 }); 2424 on(qs('#closeQv'), 'click', function () { closeModal(mod); }); 2425 } 2426 function initCategories() { 2427 var tabs = qsa('.cat-tab'); 2428 var tabsWrap = qs('#catTabs'); 2429 var catL = qs('#catL'); 2430 var catR = qs('#catR');
2431 tabs.forEach(function (t) { 2432 on(t, 'click', function () { 2433 tabs.forEach(function (x) { x.classList.remove('active'); x.setAttribute('aria-selected', 'false'); }); 2434 t.classList.add('active'); 2435 t.setAttribute('aria-selected', 'true'); 2436 loadFeatured(t.dataset.cat); 2437 }); 2438 }); 2439 function updateArrows() { 2440 if (!tabsWrap) return; 2441 var sl = tabsWrap.scrollLeft; 2442 var max = tabsWrap.scrollWidth - tabsWrap.clientWidth; 2443 if (catL) catL.disabled = sl < 4; 2444 if (catR) catR.disabled = sl >= max - 4; 2445 } 2446 on(catL, 'click', function () { tabsWrap.scrollBy({ left: -220, behavior: 'smooth' }); }); 2447 on(catR, 'click', function () { tabsWrap.scrollBy({ left: 220, behavior: 'smooth' }); }); 2448 if (tabsWrap) { on(tabsWrap, 'scroll', updateArrows, { passive: true }); setTimeout(updateArrows, 200); } 2449 } 2450 function renderReviews() { 2451 var grid = qs('#revGrid'); 2452 var dots = qs('#revDots'); 2453 if (!grid) return; 2454 grid.innerHTML = FEATURED_REVIEWS.slice(0, 3).map(function (r, i) { 2455 return '<article class="rev-card anim-in ' + (i === 0 ? 'mob-active' : '') + '">' + 2456 '<div class="rev-stars" role="img" aria-label="' + r.rating + ' out of 5">' + renderStars(r.rating) + '</div>' + 2457 '<p class="rev-body">' + escapeHtml(r.body) + '</p>' + 2458 '<div class="rev-foot"><div><div class="rev-name">' + escapeHtml(r.name) + '</div><div class="rev-role">' + escapeHtml(r.role) + '</div></div></div>' + 2459 '</article>'; 2460 }).join(''); 2461 if (dots) { 2462 dots.innerHTML = FEATURED_REVIEWS.slice(0, 3).map(function (_, i) { 2463 return '<button class="rev-dot ' + (i === 0 ? 'active' : '') + '" role="tab" aria-selected="' + (i === 0 ? 'true' : 'false') + '" aria-label="Review ' + (i + 1) + '" data-i="' + i + '"></button>'; 2464 }).join(''); 2465 qsa('.rev-dot', dots).forEach(function (d) { 2466 on(d, 'click', function () { setActiveReview(Number(d.dataset.i)); }); 2467 }); 2468 } 2469 on(qs('#revPrev'), 'click', function () { changeRev(-1); }); 2470 on(qs('#revNext'), 'click', function () { changeRev(1); }); 2471 } 2472 var revIdx = 0; 2473 function setActiveReview(i) { 2474 revIdx = ((i % 3) + 3) % 3; 2475 qsa('.rev-card').forEach(function (c, k) { c.classList.toggle('mob-active', k === revIdx); }); 2476 qsa('.rev-dot').forEach(function (d, k) { d.classList.toggle('active', k === revIdx); d.setAttribute('aria-selected', k === revIdx ? 'true' : 'false'); }); 2477 } 2478 function changeRev(d) { setActiveReview(revIdx + d); } 2479 function initStats() { 2480 qsa('.stat-bar-fill').forEach(function (el) { 2481 var obs = new IntersectionObserver(function (ents) { 2482 if (ents[0].isIntersecting) { el.style.width = (el.dataset.w || '85') + '%'; obs.disconnect(); } 2483 }, { threshold: 0.4 }); 2484 obs.observe(el); 2485 }); 2486 } 2487 function initReveal() { 2488 if (!('IntersectionObserver' in window)) { qsa('.anim-in').forEach(function (el) { el.classList.add('vis'); }); return; } 2489 var obs = new IntersectionObserver(function (ents) { 2490 ents.forEach(function (e) { 2491 if (e.isIntersecting) { e.target.classList.add('vis'); obs.unobserve(e.target); } 2492 }); 2493 }, { threshold: 0.12, rootMargin: '0px 0px -40px 0px' }); 2494 qsa('.anim-in').forEach(function (el) { obs.observe(el); }); 2495 } 2496 function initBtt() { 2497 var b = qs('#btt'); 2498 if (!b) return; 2499 on(window, 'scroll', function () { 2500 if (window.scrollY > 520) b.classList.add('vis'); else b.classList.remove('vis'); 2501 }, { passive: true }); 2502 on(b, 'click', function () { window.scrollTo({ top: 0, behavior: 'smooth' }); }); 2503 } 2504 function initNewsletter() { 2505 on(qs('#nlForm'), 'submit', async function (e) { 2506 e.preventDefault(); 2507 var em = qs('#nlEmail').value.trim(); 2508 if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(em)) { showToast('Enter a valid email', 'error'); return; } 2509 var sub = e.target.querySelector('button'); 2510 sub.disabled = true; sub.textContent = '¦'; 2511 try { 2512 if (Api) await Api.post('/newsletter', { email: em }); 2513 showToast('Subscribed. Welcome aboard.', 'success'); 2514 qs('#nlEmail').value = ''; 2515 } catch (err) { showToast('Could not subscribe right now', 'error'); } finally { sub.disabled = false; sub.textContent = 'Join'; } 2516 });
2517 } 2518 async function loadCart() { 2519 if (!Api) return; 2520 try { 2521 var cart = await Api.get('/cart'); 2522 if (Store) Store.set('cart', cart); 2523 var cnt = (cart.items || []).reduce(function (s, i) { return s + (i.qty || 1); }, 0); 2524 var badge = qs('#cartBadge'); 2525 if (badge) { badge.textContent = cnt; badge.style.display = cnt > 0 ? 'inline-flex' : 'none'; } 2526 } catch (e) {} 2527 } 2528 async function loadCounts() { 2529 var cats = ['bouquets', 'arrangements', 'fresh', 'dried', 'corporate']; 2530 if (!Api) { 2531 cats.forEach(function (c) { 2532 var el = qs('#cnt-' + c); 2533 if (el) el.textContent = '(' + FALLBACK_PRODUCTS.filter(function (p) { return p.category === c; }).length + ')'; 2534 }); 2535 var all = qs('#cnt-all'); if (all) all.textContent = '(' + FALLBACK_PRODUCTS.length + ')'; 2536 return; 2537 } 2538 try { 2539 var d = await Api.get('/products?limit=200'); 2540 var list = (d && d.products) || d || []; 2541 var total = list.length; 2542 var all = qs('#cnt-all'); if (all) all.textContent = total ? '(' + total + ')' : ''; 2543 cats.forEach(function (c) { 2544 var n = list.filter(function (p) { return (p.category || '').toLowerCase() === c; }).length; 2545 var el = qs('#cnt-' + c); 2546 if (el) el.textContent = n ? '(' + n + ')' : ''; 2547 }); 2548 } catch (e) {} 2549 } 2550 async function loadSiteContent() { 2551 if (!Api) return; 2552 try { 2553 var c = await Api.get('/content'); 2554 if (!c) return; 2555 document.querySelectorAll('[data-content-key]').forEach(el => { 2556 var key = el.getAttribute('data-content-key'); 2557 var dbKey = key; 2558 if (key === 'heroHeadline' && c.heroHeadline === undefined) dbKey = 'hero_title_2'; 2559 if (key === 'hero_title_2' && c.hero_title_2 === undefined) dbKey = 'heroHeadline'; 2560 2561 if (c[dbKey] !== undefined && c[dbKey] !== null && c[dbKey] !== '') { 2562 var val = c[dbKey]; 2563 if (dbKey.includes('price') || dbKey.includes('Threshold')) { 2564 val = '\u20B1' + Number(val).toLocaleString(undefined, {minimumFractionDigits:0, maximumFractionDigits:2}); 2565 } 2566 if (el.tagName === 'INPUT') el.value = val; 2567 else el.textContent = val; 2568 } 2569 }); 2570 if (c.bannerActive !== undefined) { 2571 var banner = document.getElementById('promoBanner'); 2572 if (banner) banner.style.display = c.bannerActive ? 'flex' : 'none'; 2573 } 2574 if (c.instagramUrl) { 2575 document.querySelectorAll('a[href*="instagram.com"]').forEach(el => el.setAttribute('href', c.instagramUrl)); 2576 } 2577 if (c.facebookUrl) { 2578 document.querySelectorAll('a[href*="facebook.com"]').forEach(el => el.setAttribute('href', c.facebookUrl)); 2579 } 2580 } catch (e) {} 2581 } 2582 function initSocket() { 2583 if (!Store || !Store.on) return; 2584 Store.on('catalog_update', function () { 2585 var act = qs('.cat-tab.active'); 2586 loadFeatured(act ? act.dataset.cat : 'all'); 2587 loadCounts(); 2588 }); 2589 Store.on('content_update', loadSiteContent); 2590 Store.on('cart_update', loadCart); 2591 } 2592 function initTilt() { 2593 if (reducedMotion()) return; 2594 qsa('.p5-tilt, .feat-card, .fact-card, .rev-card').forEach(function (card) { 2595 on(card, 'mousemove', function (e) { 2596 var r = card.getBoundingClientRect(); 2597 var x = (e.clientX - r.left) / r.width - 0.5; 2598 var y = (e.clientY - r.top) / r.height - 0.5; 2599 card.style.transform = 'perspective(800px) rotateY(' + (x * 8) + 'deg) rotateX(' + (-y * 8) + 'deg) scale(1.02)'; 2600 }); 2601 on(card, 'mouseleave', function () { 2602 card.style.transform = ''; 2603 }); 2604 }); 2605 } 2606 function initMagnetic() { 2607 if (reducedMotion()) return; 2608 qsa('.btn-p.btn-lg, .magnetic-btn').forEach(function (btn) { 2609 on(btn, 'mousemove', function (e) { 2610 var r = btn.getBoundingClientRect(); 2611 var x = e.clientX - r.left - r.width / 2; 2612 var y = e.clientY - r.top - r.height / 2; 2613 btn.style.transform = 'translate(' + (x * 0.15) + 'px,' + (y * 0.15) + 'px) scale(1.04)'; 2614 }); 2615 on(btn, 'mouseleave', function () { 2616 btn.style.transform = ''; 2617 }); 2618 });
2619 } 2620 function initRipple() { 2621 on(document, 'click', function (e) { 2622 var btn = e.target.closest('.btn-p, .p-add'); 2623 if (!btn) return; 2624 var r = btn.getBoundingClientRect(); 2625 var rip = document.createElement('span'); 2626 rip.className = 'ripple'; 2627 var sz = Math.max(r.width, r.height); 2628 rip.style.width = rip.style.height = sz + 'px'; 2629 rip.style.left = (e.clientX - r.left - sz / 2) + 'px'; 2630 rip.style.top = (e.clientY - r.top - sz / 2) + 'px'; 2631 btn.style.position = 'relative'; 2632 btn.style.overflow = 'hidden'; 2633 btn.appendChild(rip); 2634 setTimeout(function () { rip.remove(); }, 600); 2635 }); 2636 } 2637 var FUNNEL_ORDER = ['hero', 'shop', 'subs', 'cart', 'checkout']; 2638 var funnelState = { hero: false, shop: false, subs: false, cart: false, checkout: false }; 2639 function bloomTrack(name, payload) { 2640 payload = payload || {}; 2641 try { (window.dataLayer = window.dataLayer || []).push({ event: name, ts: Date.now(), ...payload }); } catch (e) {} 2642 try { if (window.clarity && typeof window.clarity === 'function') window.clarity('event', name); } catch (e) {} 2643 try { if (window.hj && typeof window.hj === 'function') window.hj('event', name); } catch (e) {} 2644 try { if (window.gtag && typeof window.gtag === 'function') window.gtag('event', name, payload); } catch (e) {} 2645 } 2646 window.bloomTrack = bloomTrack; 2647 function initFunnelTracking() { 2648 var bar = qs('#funnelBar'); 2649 var sections = [ 2650 { id: 'heroSec', step: 'hero' }, 2651 { id: 'shop', step: 'shop' }, 2652 { id: 'subs', step: 'subs' } 2653 ]; 2654 if (!('IntersectionObserver' in window)) return; 2655 var obs = new IntersectionObserver(function (ents) { 2656 ents.forEach(function (e) { 2657 if (!e.isIntersecting) return; 2658 var sec = sections.find(function (s) { return s.id === e.target.id; }); 2659 if (!sec) return; 2660 if (!funnelState[sec.step]) { 2661 funnelState[sec.step] = true; 2662 bloomTrack('funnel_' + sec.step + '_view'); 2663 } 2664 var idx = FUNNEL_ORDER.indexOf(sec.step); 2665 qsa('.funnel-step').forEach(function (el) { 2666 var i = FUNNEL_ORDER.indexOf(el.dataset.step); 2667 el.classList.toggle('active', i === idx); 2668 el.classList.toggle('done', i < idx && funnelState[el.dataset.step]); 2669 }); 2670 if (bar && idx > 0) bar.classList.add('show'); 2671 }); 2672 }, { threshold: 0.45 }); 2673 sections.forEach(function (s) { var el = qs('#' + s.id); if (el) obs.observe(el); }); 2674 on(document, 'click', function (e) { 2675 var add = e.target.closest('.p-add, #qvAdd'); 2676 if (add) { funnelState.cart = true; bloomTrack('funnel_cart_add'); markFunnel('cart'); } 2677 var checkout = e.target.closest('[href*="checkout" i], #checkoutBtn'); 2678 if (checkout) { funnelState.checkout = true; bloomTrack('funnel_checkout_start'); markFunnel('checkout'); } 2679 }); 2680 } 2681 function markFunnel(step) { 2682 var idx = FUNNEL_ORDER.indexOf(step); 2683 qsa('.funnel-step').forEach(function (el) { 2684 var i = FUNNEL_ORDER.indexOf(el.dataset.step); 2685 el.classList.toggle('active', i === idx); 2686 el.classList.toggle('done', i < idx); 2687 }); 2688 } 2689 function initBloomBoot() { 2690 var boot = qs('#bloomBoot'); 2691 if (!boot) return; 2692 function hide() { 2693 boot.classList.add('gone'); 2694 setTimeout(function () { boot.style.display = 'none'; }, 700); 2695 } 2696 if (document.readyState === 'complete') setTimeout(hide, 400); 2697 else window.addEventListener('load', function () { setTimeout(hide, 400); }); 2698 setTimeout(hide, 4500); 2699 } 2700 var DELIVERY_LEAD = { 2701 'metro-manila': { hours: 48, label: '48h' }, 2702 'batangas': { hours: 48, label: '48h' }, 2703 'cebu': { hours: 96, label: '4 days' }, 2704 'laguna': { hours: 72, label: '3 days' }, 2705 'cavite': { hours: 72, label: '3 days' }, 2706 'rizal': { hours: 72, label: '3 days' }, 2707 'bulacan': { hours: 72, label: '3 days' }, 2708 'pampanga': { hours: 96, label: '4 days' }, 2709 'baguio': { hours: 120, label: '5 days' } 2710 }; 2711 function initDelivery() { 2712 var dateInp = qs('#dlvDate'); 2713 var locSel = qs('#dlvLoc'); 2714 var etaEl = qs('#dlvEta'); 2715 var bar = qs('#dlvBar'); 2716 if (!dateInp || !locSel || !etaEl || !bar) return; 2717 var saved = {}; 2718 try { saved = JSON.parse(localStorage.getItem('bloom_delivery') || '{}'); } catch (e) {} 2719 var minH = DELIVERY_LEAD[saved.loc || locSel.value]?.hours || 48; 2720 var minDate = new Date(Date.now() + minH * 36e5); 2721 dateInp.min = minDate.toISOString().slice(0, 10); 2722 if (saved.date && new Date(saved.date) >= minDate) dateInp.value = saved.date; 2723 else dateInp.value = minDate.toISOString().slice(0, 10); 2724 if (saved.loc && DELIVERY_LEAD[saved.loc]) locSel.value = saved.loc; 2725 function updateEta() { 2726 var info = DELIVERY_LEAD[locSel.value] || DELIVERY_LEAD['metro-manila']; 2727 var newMin = new Date(Date.now() + info.hours * 36e5); 2728 dateInp.min = newMin.toISOString().slice(0, 10); 2729 if (new Date(dateInp.value) < newMin) dateInp.value = newMin.toISOString().slice(0, 10); 2730 etaEl.innerHTML = 'Lead time: <strong>' + info.label + '</strong>';
2731 try { localStorage.setItem('bloom_delivery', JSON.stringify({ date: dateInp.value, loc: locSel.value })); } catch (e) {} 2732 bloomTrack('delivery_set', { location: locSel.value, date: dateInp.value }); 2733 } 2734 on(locSel, 'change', updateEta); 2735 on(dateInp, 'change', updateEta); 2736 updateEta(); 2737 var lastY = window.scrollY; 2738 on(window, 'scroll', function () { 2739 var y = window.scrollY; 2740 if (y > 600 && y > lastY) bar.classList.add('hide'); 2741 else bar.classList.remove('hide'); 2742 lastY = y; 2743 }, { passive: true }); 2744 } 2745 function getWishlist() { 2746 try { return JSON.parse(localStorage.getItem('bloom_wishlist') || '[]'); } catch (e) { return []; } 2747 } 2748 function saveWishlist(items) { 2749 try { localStorage.setItem('bloom_wishlist', JSON.stringify(items)); } catch (e) {} 2750 updateWlUi(); 2751 } 2752 function updateWlUi() { 2753 var items = getWishlist(); 2754 var badge = qs('#wlBadge'); 2755 var count = qs('#wlCount'); 2756 var clear = qs('#wlClear'); 2757 if (badge) { badge.textContent = items.length; badge.style.display = items.length ? 'inline-flex' : 'none'; } 2758 if (count) count.textContent = items.length; 2759 if (clear) clear.hidden = !items.length; 2760 qsa('.wl-btn').forEach(function (b) { 2761 var on = items.some(function (x) { return x.id === b.dataset.id; }); 2762 b.classList.toggle('on', on); 2763 b.textContent = on ? 'â¥' : 'â¡'; 2764 }); 2765 var body = qs('#wlDrawerBody'); 2766 var empty = qs('#wlEmpty'); 2767 if (!body) return; 2768 qsa('.wl-row', body).forEach(function (r) { r.remove(); }); 2769 if (!items.length) { if (empty) empty.style.display = ''; return; } 2770 if (empty) empty.style.display = 'none'; 2771 items.forEach(function (it) { 2772 var row = document.createElement('div'); 2773 row.className = 'wl-row'; 2774 row.innerHTML = '<a class="wl-row-img" href="/catalog.html?id=' + encodeURIComponent(it.id) + '">
2774<img src="' + escapeHtml(it.image || '/img/hero-flowers.webp') + '" alt=""></a>' + 2775 '<div class="wl-row-body"><div class="wl-row-name">' + escapeHtml(it.name || 'Bouquet') + '</div><div class="wl-row-price">' + money(it.price || 0) + '</div></div>' + 2776 '<button type="button" class="wl-row-x" aria-label="Remove from wishlist" data-rm="' + escapeHtml(it.id) + '">â</button>'; 2777 body.appendChild(row); 2778 }); 2779 qsa('.wl-row-x', body).forEach(function (x) { 2780 on(x, 'click', function () { 2781 var id = x.dataset.rm; 2782 var next = getWishlist().filter(function (i) { return i.id !== id; }); 2783 saveWishlist(next); 2784 bloomTrack('wishlist_remove', { id: id }); 2785 }); 2786 }); 2787 } 2788 window.addToWishlist = function (item) { 2789 var items = getWishlist(); 2790 if (items.some(function (i) { return i.id === item.id; })) { 2791 saveWishlist(items.filter(function (i) { return i.id !== item.id; })); 2792 return false; 2793 } 2794 items.unshift(item); 2795 saveWishlist(items.slice(0, 100)); 2796 bloomTrack('wishlist_add', { id: item.id }); 2797 return true; 2798 }; 2799 function initWishlist() { 2800 var drawer = qs('#wlDrawer'); 2801 var openBtn = qs('#wlBtnNav'); 2802 var clsBtn = qs('#wlDrawerCls'); 2803 var clear = qs('#wlClear'); 2804 if (!drawer) return; 2805 function openD() { drawer.classList.add('open'); drawer.setAttribute('aria-hidden', 'false'); document.body.classList.add('modal-open'); updateWlUi(); bloomTrack('wishlist_open'); } 2806 function closeD() { drawer.classList.remove('open'); drawer.setAttribute('aria-hidden', 'true'); document.body.classList.remove('modal-open'); } 2807 on(openBtn, 'click', openD); 2808 on(clsBtn, 'click', closeD); 2809 on(document, 'keydown', function (e) { if (e.key === 'Escape' && drawer.classList.contains('open')) closeD(); }); 2810 on(clear, 'click', function () { saveWishlist([]); showToast('Wishlist cleared', 'info'); }); 2811 updateWlUi(); 2812 on(document, 'click', function (e) { 2813 var b = e.target.closest('.wl-btn'); 2814 if (!b) return; 2815 e.stopPropagation(); 2816 var card = b.closest('.p-card'); 2817 var nameEl = card && card.querySelector('.p-name'); 2818 var priceEl = card && card.querySelector('.p-price'); 2819 var img = card && card.querySelector('.p-img img'); 2820 var item = { id: b.dataset.id, name: nameEl ? nameEl.textContent.trim() : 'Bouquet', price: priceEl ? Number(String(priceEl.textContent).replace(/[^\d.]/g, '')) : 0, image: img ? img.src : '/img/hero-flowers.webp' }; 2821 var added = window.addToWishlist(item); 2822 b.classList.add('wl-pop'); 2823 setTimeout(function () { b.classList.remove('wl-pop'); }, 420); 2824 showToast(added ? 'Saved to wishlist' : 'Removed from wishlist', added ? 'success' : 'info'); 2825 }); 2826 } 2827 function initSubscriptions() { 2828 var sec = qs('#subs'); 2829 if (!sec) return; 2830 var cards = qsa('.subs-card', sec); 2831 var startBtn = qs('#subsStart'); 2832 var learnBtn = qs('#subsLearn'); 2833 var previewImg = qs('#subsPreviewImg'); 2834 cards.forEach(function (c) { 2835 on(c, 'click', function () { 2836 cards.forEach(function (x) { x.classList.remove('selected'); x.setAttribute('aria-checked', 'false'); }); 2837 c.classList.add('selected'); 2838 c.setAttribute('aria-checked', 'true'); 2839 var plan = c.dataset.sub; 2840 if (previewImg && plan) { 2841 previewImg.style.opacity = '0'; 2842 setTimeout(function() { 2843 previewImg.src = '/uploads/subscriptions/' + plan + '.jpg'; 2844 previewImg.style.opacity = '1'; 2845 }, 200); 2846 } 2847 bloomTrack('subscription_select', { plan: plan, price: c.dataset.price }); 2848 }); 2849 on(c, 'keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); c.click(); } }); 2850 }); 2851 on(startBtn, 'click', async function () { 2852 var sel = qs('.subs-card.selected', sec); 2853 if (!sel) { showToast('Pick a cadence first', 'info'); return; } 2854 var plan = sel.dataset.sub; 2855 var price = sel.dataset.price; 2856 bloomTrack('subscription_start', { plan: plan, price: price }); 2857 showToast('Redirecting to secure checkout...', 'success'); 2858 window.location.href = '/checkout.html?subscription=' + encodeURIComponent(plan) + '&price=' + encodeURIComponent(price); 2859 });
2860 on(learnBtn, 'click', function () { window.location.href = '/subscriptions.html'; }); 2861 } 2862 function buildVideoMessageBlock(productId) { 2863 return '<div id="vmContainer_' + productId + '" style="margin-top: 24px;"></div>'; 2864 } 2865 function attachVideoMessageHandlers(productId) { 2866 // Ensure the new robust VideoMessage.js module handles the UI 2867 if (window.BloomVideoMessage) { 2868 window.BloomVideoMessage.attachTo('vmContainer_' + productId); 2869 // Listen for the genuinely recorded Blob and attach it via IndexedDB 2870 // This ensures real persistence across the site without needing a mock backend 2871 document.addEventListener('bloom:video-attached', function (e) { 2872 var blob = e.detail.blob; 2873 if (!blob) return; 2874 try { 2875 var dbReq = indexedDB.open('BloomDB', 1); 2876 dbReq.onupgradeneeded = function(e) { 2877 e.target.result.createObjectStore('videos'); 2878 }; 2879 dbReq.onsuccess = function(e) { 2880 var db = e.target.result; 2881 var tx = db.transaction('videos', 'readwrite'); 2882 tx.objectStore('videos').put(blob, 'vm_' + productId); 2883 bloomTrack('video_message_attached', { productId: productId, size: blob.size }); 2884 }; 2885 } catch (err) { 2886 console.warn('Could not save video to IndexedDB', err); 2887 } 2888 }); 2889 } 2890 } 2891 window.buildVideoMessageBlock = buildVideoMessageBlock; 2892 window.attachVideoMessageHandlers = attachVideoMessageHandlers; 2893 function summarizeFormErrors(formEl, summaryEl) { 2894 var errs = []; 2895 qsa('.fe', formEl).forEach(function (e) { 2896 var msg = (e.textContent || '').trim(); 2897 if (!msg) return; 2898 var fi = e.closest('.fi') || formEl; 2899 var inp = fi.querySelector('input,textarea,select'); 2900 var labelEl = inp ? formEl.querySelector('label[for="' + inp.id + '"]') : null; 2901 var label = inp ? ((labelEl && labelEl.textContent.trim()) || inp.id) : ''; 2902 errs.push({ id: inp ? inp.id : '', label: label, msg: msg }); 2903 }); 2904 var ul = summaryEl.querySelector('ul'); 2905 if (!ul) return; 2906 if (!errs.length) { summaryEl.classList.remove('on'); ul.innerHTML = ''; return; } 2907 ul.innerHTML = errs.map(function (e) { 2908 var anchor = e.id ? '<a href="#' + e.id + '" data-fid="' + e.id + '">' + escapeHtml(e.label || e.id) + '</a>: ' : ''; 2909 return '<li>' + anchor + escapeHtml(e.msg) + '</li>'; 2910 }).join(''); 2911 summaryEl.classList.add('on'); 2912 summaryEl.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); 2913 qsa('a[data-fid]', summaryEl).forEach(function (a) { 2914 on(a, 'click', function (ev) { ev.preventDefault(); var t = qs('#' + a.dataset.fid); if (t) { t.focus(); t.scrollIntoView({ behavior: 'smooth', block: 'center' }); } }); 2915 }); 2916 } 2917 window.summarizeFormErrors = summarizeFormErrors; 2918 function initFormErrSummaries() { 2919 var loginBtn = qs('#lSubmit'); 2920 var regBtn = qs('#rSubmit'); 2921 var loginSum = qs('#loginErrSum'); 2922 var regSum = qs('#regErrSum'); 2923 function patch(btn, formId, sumEl) { 2924 if (!btn || !sumEl) return; 2925 var origClick = btn.onclick; 2926 on(btn, 'click', function () { 2927 setTimeout(function () { var f = qs('#' + formId); if (f) summarizeFormErrors(f, sumEl); }, 60); 2928 }); 2929 } 2930 patch(loginBtn, 'loginF', loginSum); 2931 patch(regBtn, 'registerF', regSum); 2932 } 2933 function initVirtualization() { 2934 if (!('IntersectionObserver' in window)) return; 2935 var grids = ['pGrid', 'recentGrid']; 2936 grids.forEach(function (id) { 2937 var grid = qs('#' + id); 2938 if (!grid) return; 2939 var obs = new IntersectionObserver(function (ents) { 2940 ents.forEach(function (e) { 2941 var img = e.target.querySelector ? e.target.querySelector('img') : null; 2942 if (e.isIntersecting) { 2943 e.target.style.contentVisibility = 'visible'; 2944 if (img && img.dataset.src && !img.src) img.src = img.dataset.src; 2945 } else { 2946 e.target.style.contentVisibility = 'auto'; 2947 e.target.style.containIntrinsicSize = '320px'; 2948 } 2949 }); 2950 }, { rootMargin: '600px 0px', threshold: 0 }); 2951 var mo = new MutationObserver(function () {
2952 qsa('.p-card', grid).forEach(function (c) { 2953 if (c._virt) return; 2954 c._virt = 1; 2955 c.style.contentVisibility = 'auto'; 2956 c.style.containIntrinsicSize = '320px'; 2957 obs.observe(c); 2958 }); 2959 }); 2960 mo.observe(grid, { childList: true }); 2961 }); 2962 } 2963 function loadHeatmaps() { 2964 var clarityId = (document.querySelector('meta[name="clarity-id"]') || {}).content; 2965 if (clarityId) { 2966 (function (c, l, a, r, i, t, y) { c[a] = c[a] || function () { (c[a].q = c[a].q || []).push(arguments); }; t = l.createElement(r); t.async = 1; t.src = 'https://www.clarity.ms/tag/' + i; y = l.getElementsByTagName(r)[0]; y.parentNode.insertBefore(t, y); })(window, document, 'clarity', 'script', clarityId); 2967 } 2968 var hjId = (document.querySelector('meta[name="hotjar-id"]') || {}).content; 2969 if (hjId) { 2970 (function (h, o, t, j, a, r) { h.hj = h.hj || function () { (h.hj.q = h.hj.q || []).push(arguments); }; h._hjSettings = { hjid: Number(hjId), hjsv: 6 }; a = o.getElementsByTagName('head')[0]; r = o.createElement('script'); r.async = 1; r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv; a.appendChild(r); })(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv='); 2971 } 2972 } 2973 function initYear() { 2974 var y = qs('#yr'); 2975 if (y) y.textContent = new Date().getFullYear(); 2976 } 2977 window.addEventListener('unhandledrejection', function (e) { 2978 console.warn('[Bloom] Unhandled promise rejection:', e.reason); 2979 }); 2980 window.addEventListener('error', function (e) { 2981 console.warn('[Bloom] Runtime error:', e.message); 2982 }); 2983 document.addEventListener('DOMContentLoaded', function () { 2984 Api = window.Api; 2985 Store = window.Store; 2986 initBloomBoot(); 2987 initYear(); 2988 initCursor(); 2989 initNav(); 2990 initTyper(); 2991 initCountdown(); 2992 initParticles(); 2993 initHeroParallax(); 2994 initSearch(); 2995 initLang(); 2996 initAuth(); 2997 initProfiling(); 2998 initCategories(); 2999 loadFeatured('all'); 3000 loadCounts(); 3001 loadCart(); 3002 loadSiteContent(); 3003 renderReviews(); 3004 initStats(); 3005 initReveal(); 3006 initBtt(); 3007 initNewsletter(); 3008 initSocket(); 3009 initTilt(); 3010 initMagnetic(); 3011 initRipple(); 3012 initDelivery(); 3013 initWishlist(); 3014 initSubscriptions(); 3015 3016 initFunnelTracking(); 3017 initVirtualization(); 3018 initFormErrSummaries(); 3019 loadHeatmaps(); 3020 }); 3021})(); 3022</script>
vendor: 2 bytes, line 3022
3022
3023<script> 3024if ('serviceWorker' in navigator) { 3025 window.addEventListener('load', function () { 3026 }); 3027} 3028var _deferredInstall = null; 3029window.addEventListener('beforeinstallprompt', function (e) { 3030 e.preventDefault(); 3031 _deferredInstall = e; 3032}); 3033(function () { 3034 var thBtn = document.getElementById('themeToggle'); 3035 if (thBtn) { 3036 thBtn.addEventListener('click', function () { 3037 if (window.Store) Store.toggleTheme(); 3038 }); 3039 } 3040 function renderRecent() { 3041 if (!window.Store) return; 3042 var items = Store.get('recentlyViewed') || []; 3043 var sec = document.getElementById('recentSec'); 3044 var grid = document.getElementById('recentGrid'); 3045 if (!sec || !grid) return; 3046 if (!items.length) { sec.style.display = 'none'; return; } 3047 sec.style.display = ''; 3048 grid.innerHTML = items.slice(0, 6).map(function (p) { 3049 var img = String(p.image || '').replace(/["<>]/g, ''); 3050 var name = String(p.name || '').replace(/[<>&"']/g, ''); 3051 return '<div class="p-card vis" role="listitem" style="padding:14px">' + 3052 '<div style="aspect-ratio:4/3;border-radius:var(--rs);overflow:hidden;margin-bottom:10px;background:var(--gl)">' + 3053 '<img src="' + img + '" alt="' + name + '" loading="lazy" decoding="async" style="width:100%;height:100%;object-fit:cover" onerror="this.onerror=null;this.style.display=\'none\'">' + 3054 '</div>' + 3055 '<div style="font-weight:600;font-size:.88rem">' + name + '</div>' + 3056 '<div style="font-size:.82rem;color:var(--text-muted)">' + (window.I18n ? I18n.formatMoney(p.price) : '\u20B1' + Number(p.price||0).toFixed(2)) + '</div>' + 3057 '</div>'; 3058 }).join(''); 3059 } 3060 if (window.Store) Store.on('recentlyViewed', renderRecent); 3061 document.addEventListener('DOMContentLoaded', renderRecent); 3062 var _exitShown = false; 3063 document.addEventListener('mouseleave', function (e) { 3064 if (e.clientY > 10) return; 3065 if (_exitShown) return; 3066 if (window.Store && Store.get('hasSeenExitIntent')) return; 3067 if (window.Store && Store.get('user')) return; 3068 _exitShown = true; 3069 var mod = document.getElementById('exitMod'); 3070 if (mod) { 3071 mod.style.display = ''; 3072 requestAnimationFrame(function () { 3073 mod.classList.add('open'); 3074 mod.setAttribute('aria-hidden', 'false'); 3075 document.body.classList.add('modal-open'); 3076 var firstFocus = mod.querySelector('input, button'); 3077 if (firstFocus) firstFocus.focus(); 3078 }); 3079 } 3080 }); 3081 var exitClose = document.getElementById('closeExit'); 3082 var exitDismiss = document.getElementById('exitDismiss'); 3083 function closeExit() { 3084 var mod = document.getElementById('exitMod'); 3085 if (mod) { 3086 mod.classList.remove('open'); 3087 mod.setAttribute('aria-hidden', 'true'); 3088 mod.style.display = 'none'; 3089 } 3090 document.body.classList.remove('modal-open'); 3091 if (window.Store && typeof Store.markExitIntent === 'function') Store.markExitIntent(); 3092 } 3093 if (exitClose) exitClose.addEventListener('click', closeExit); 3094 if (exitDismiss) exitDismiss.addEventListener('click', closeExit); 3095 var exitCta = document.getElementById('exitCta'); 3096 if (exitCta) { 3097 exitCta.addEventListener('click', function () { 3098 var email = document.getElementById('exitEmail'); 3099 if (email && email.value) { 3100 if (window.showToast) showToast('Discount code sent! Check your inbox ð¸', 'success'); 3101 } 3102 closeExit(); 3103 }); 3104 } 3105})(); 3106</script>
vendor: 2 bytes, line 3106
3106
3107<script> 3108(function(){ 3109 if(sessionStorage.getItem('bloom_badge_dismissed')) return; 3110 var b=document.createElement('div'); 3111 b.className='bloom-academic-badge'; 3112 b.setAttribute('role','status'); 3113 b.innerHTML='ð <span>Academic Prototype</span>. This platform is a BSIT Capstone project by STI College Lipa students. All prices, transactions, and metrics are simulated for demonstration purposes only.<button class="bloom-academic-badge-close" aria-label="Dismiss">\u00d7</button>'; 3114 document.body.appendChild(b); 3115 b.querySelector('.bloom-academic-badge-close').addEventListener('click',function(){b.remove();sessionStorage.setItem('bloom_badge_dismissed','1');}); 3116})(); 3117</script>
vendor: 2 bytes, line 3117
3117
3118<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js" defer></script>
vendor: 2 bytes, line 3118
3118
3119<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ScrollTrigger.min.js" defer></script>
vendor: 2 bytes, line 3119
3119
3120<script src="/js/core/VoiceNav.js" defer></script>
vendor: 2 bytes, line 3120
3120
3121<script src="/js/core/VideoMessage.js" defer></script>
vendor: 2 bytes, line 3121
3121
3122<script src="/js/core/SupplyChain.js" defer></script>
vendor: 2 bytes, line 3122
3122
3123<script src="/js/core/SupportUs.js" defer></script>
vendor: 2 bytes, line 3123
3123
3124<script src="/js/cookie-consent.js" defer></script>
vendor: 2 bytes, line 3124
3124
3125<script> 3126(function(){var d=false;function a(){if(d)return;d=true;var s=document.createElement('script');s.src='/js/core/GrainOverlay.js';s.defer=true;document.head.appendChild(s);}if('requestIdleCallback'in window){requestIdleCallback(a,{timeout:3000});}else{window.addEventListener('load',function(){setTimeout(a,1500);});}})(); 3127window.addEventListener('load',function(){var b=document.getElementById('heroBokeh');if(b){setTimeout(function(){b.style.backgroundImage="url('/img/hero-bokeh.webp')";},400);}}); 3128document.addEventListener('DOMContentLoaded', function () { 3129 if (window.BloomSupplyChain) { 3130 window.BloomSupplyChain.renderTraceability('supplyChainTrace', 'BLOOM-' + Date.now().toString(36).toUpperCase()); 3131 } 3132 if (window.BloomSupport) { 3133 window.BloomSupport.renderSupportSection('supportUsContent'); 3134 window.BloomSupport.renderFloatingButton(); 3135 } 3136}); 3137window.addEventListener('load',function(){setTimeout(function(){document.querySelectorAll('.bloom-cookie, #cookieBanner, [class*="cookie-consent"]').forEach(function(e){e.classList.add('ready');});},800);}); 3138</script>
3138 3139</body> 3140</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.