*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;font-family:Inter,system-ui,sans-serif;background:#0b0d10;color:#f4f6f8}.app-shell{min-height:100vh}.topbar{height:76px;display:flex;align-items:center;gap:34px;padding:0 5vw;position:sticky;top:0;z-index:20;background:rgba(11,13,16,.78);backdrop-filter:blur(18px);border-bottom:1px solid rgba(255,255,255,.06)}.brand{display:flex;align-items:center;gap:10px;color:#fff;text-decoration:none;font-weight:800;letter-spacing:-.03em}.brand-mark{width:32px;height:32px;display:grid;place-items:center;background:#fff;color:#0b0d10;border-radius:10px}.nav{display:flex;gap:26px;margin-right:auto}.nav a{color:#aeb5bf;text-decoration:none;font-size:14px;font-weight:600}.nav a:hover{color:white}.auth-actions{display:flex;gap:10px}.btn{border:0;border-radius:12px;padding:11px 17px;font:600 14px Inter;cursor:pointer}.btn-ghost{background:transparent;color:#e8eaed}.btn-primary{background:#f4f6f8;color:#111317}.btn-light{background:#fff;color:#111;padding:13px 18px}.avatar{width:38px;height:38px;border:0;border-radius:50%;font-weight:800;cursor:pointer}.hero{min-height:620px;padding:74px 5vw 62px;display:grid;grid-template-columns:1.05fr .95fr;align-items:center;gap:64px;max-width:1500px;margin:auto}.hero h1{font-size:clamp(48px,6vw,88px);line-height:.98;letter-spacing:-.065em;margin:14px 0 24px}.hero h1 span{color:#858d98}.hero p{color:#aeb5bf;max-width:620px;font-size:18px;line-height:1.65}.eyebrow{font-size:11px;letter-spacing:.18em;font-weight:800;color:#7c8590}.hero-search{margin-top:34px;display:flex;align-items:center;gap:12px;max-width:620px;padding:10px 13px;background:#14171b;border:1px solid #23272d;border-radius:15px}.hero-search input{flex:1;background:transparent;color:white;border:0;outline:0;padding:8px 4px;font-size:15px}.hero-search kbd{border:1px solid #323741;border-bottom-width:2px;padding:4px 7px;border-radius:6px;color:#777f89;font:11px Inter}.search-icon{font-size:21px;color:#7e8791}.quick-tags{display:flex;gap:8px;flex-wrap:wrap;margin-top:15px}.quick-tags button,.category-pill{border:1px solid #2a2f36;background:#121519;color:#9da5af;border-radius:999px;padding:8px 12px;font:600 12px Inter;cursor:pointer}.quick-tags button:hover,.category-pill:hover,.category-pill.active{color:#111;background:#fff}.hero-card{height:510px;border-radius:28px;overflow:hidden;position:relative;background:#191d22;box-shadow:0 30px 90px rgba(0,0,0,.35)}.hero-card>img{width:100%;height:100%;object-fit:cover}.hero-card:after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 45%,rgba(0,0,0,.74))}.hero-card-overlay{position:absolute;z-index:2;bottom:0;left:0;right:0;padding:28px;display:flex;align-items:end;justify-content:space-between}.hero-card-overlay div{display:flex;flex-direction:column;gap:5px}.hero-card-overlay span{font-size:11px;color:#d8dde3}.hero-card-overlay strong{font-size:23px}.round-btn{width:48px;height:48px;border-radius:50%;border:0;background:#fff;color:#111;font-size:21px;cursor:pointer}.section{max-width:1500px;margin:auto;padding:48px 5vw}.section-heading{display:flex;align-items:end;justify-content:space-between;gap:20px;margin-bottom:22px}.section h2,.cta h2{font-size:32px;letter-spacing:-.04em;margin:7px 0 0}.category-row{display:flex;gap:10px;flex-wrap:wrap}.category-pill{padding:10px 15px}.gallery-section{padding-top:32px}.result-count{color:#737c87;font-size:13px}.wall-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}.wall-card{position:relative;aspect-ratio:.72;border-radius:18px;overflow:hidden;background:#181c21}.wall-card img{width:100%;height:100%;object-fit:cover;transition:transform .35s ease}.wall-card:hover img{transform:scale(1.035)}.wall-card:after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 45%,rgba(0,0,0,.78))}.wall-meta{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:18px;display:flex;justify-content:space-between;align-items:end}.wall-meta strong{display:block;font-size:15px}.wall-meta span{font-size:11px;color:#bec5cc}.icon-btn{width:36px;height:36px;border:0;border-radius:10px;background:rgba(255,255,255,.92);cursor:pointer;font-size:16px}.cta{max-width:calc(1500px - 10vw);margin:72px auto 76px;background:#eceff2;color:#101215;padding:46px 50px;border-radius:24px;display:flex;align-items:center;justify-content:space-between;gap:24px}.cta p{color:#5a6169;max-width:620px;line-height:1.6}.cta .eyebrow{color:#6e747c}footer{max-width:1500px;margin:auto;padding:30px 5vw 44px;border-top:1px solid #1b1f24;display:flex;justify-content:space-between;align-items:center;color:#737b84;font-size:12px}.modal-backdrop{position:fixed;inset:0;z-index:100;background:rgba(0,0,0,.68);backdrop-filter:blur(10px);display:grid;place-items:center;padding:20px}.modal{position:relative;width:min(430px,100%);background:#121519;border:1px solid #262b31;border-radius:24px;padding:34px;box-shadow:0 30px 100px rgba(0,0,0,.5)}.modal-close{position:absolute;right:18px;top:15px;border:0;background:transparent;color:#7f8791;font-size:28px;cursor:pointer}.modal-brand{margin-bottom:24px}.modal h2{font-size:30px;margin:8px 0}.modal>p{color:#858e98;font-size:13px}.auth-tabs{display:grid;grid-template-columns:1fr 1fr;background:#0c0e11;padding:4px;border-radius:11px;margin:22px 0}.auth-tab{border:0;border-radius:8px;padding:9px;background:transparent;color:#737d88;font-weight:700;cursor:pointer}.auth-tab.active{background:#22272d;color:#fff}form{display:grid;gap:14px}label{display:grid;gap:7px;color:#aeb6bf;font-size:12px;font-weight:600}input{width:100%;border:1px solid #2a3037;background:#0c0e11;color:#fff;border-radius:11px;padding:12px 13px;outline:0}.full{width:100%;margin-top:4px}.divider{display:flex;align-items:center;gap:10px;margin:20px 0;color:#636c76;font-size:11px}.divider:before,.divider:after{content:"";height:1px;flex:1;background:#272c32}.provider-btn{width:100%;border:1px solid #2c3138;background:#181c21;color:white;border-radius:12px;padding:12px;display:flex;align-items:center;justify-content:center;gap:10px;font-weight:700;cursor:pointer}.provider-dot{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;background:#fff;color:#111;font-size:11px}.terms{text-align:center;margin:16px 0 0!important;font-size:10px!important}.toast{position:fixed;right:24px;bottom:24px;z-index:200;background:#f3f5f7;color:#111;padding:13px 16px;border-radius:12px;font-size:13px;font-weight:700;box-shadow:0 15px 50px rgba(0,0,0,.25)}.empty-state{text-align:center;padding:70px 0;color:#7e8791}.empty-state h3{color:#f1f3f5}.empty-icon{font-size:40px}.hidden{display:none!important}@media(max-width:980px){.nav{display:none}.hero{grid-template-columns:1fr;padding-top:50px}.hero-card{height:420px}.wall-grid{grid-template-columns:repeat(2,1fr)}.cta{margin-left:5vw;margin-right:5vw}.topbar{gap:15px}}@media(max-width:600px){.topbar{padding:0 18px}.auth-actions .btn-ghost{display:none}.hero,.section{padding-left:18px;padding-right:18px}.hero h1{font-size:50px}.hero-card{height:390px}.wall-grid{grid-template-columns:1fr 1fr;gap:10px}.wall-card{border-radius:13px}.wall-meta{padding:12px}.wall-meta strong{font-size:12px}.wall-meta span{font-size:9px}.icon-btn{width:30px;height:30px}.cta{margin:44px 18px;padding:30px;display:block}.cta .btn{margin-top:12px}footer{padding:28px 18px;flex-wrap:wrap;gap:20px}}


/* BlueWall theme */
:root{
  --blue:#2f7cff;
  --blue2:#61a0ff;
  --blueDeep:#08172f;
}
body{
  background:
    radial-gradient(circle at 70% 5%, rgba(47,124,255,.19), transparent 32%),
    radial-gradient(circle at 10% 30%, rgba(22,88,190,.15), transparent 28%),
    #070b12;
}
.brand-mark,.btn-primary,.category-pill.active,.quick-tags button:hover,.category-pill:hover{
  background:linear-gradient(135deg,var(--blue2),var(--blue));
  color:white;
}
.hero h1 span{color:#5f9dff}
.hero-search{border-color:rgba(67,136,255,.26);box-shadow:0 0 0 1px rgba(48,115,220,.04)}
.hero-card{box-shadow:0 35px 100px rgba(20,75,170,.26)}
.wall-card{box-shadow:0 0 0 1px rgba(80,145,255,.07)}
.cta{
  background:linear-gradient(135deg,#eaf3ff,#bfd7ff);
}
.cta .btn-light{background:#0a3b84;color:white}
.modal{border-color:rgba(78,144,255,.35);box-shadow:0 30px 100px rgba(13,56,135,.4)}
.provider-dot{background:var(--blue);color:white}
.settings-list{display:grid;gap:10px;margin:24px 0}
.setting-row{
  display:flex;
  grid-template-columns:none;
  align-items:center;
  justify-content:space-between;
  gap:22px;
  border:1px solid #283345;
  background:#0d1420;
  padding:15px;
  border-radius:14px;
}
.setting-row span{display:grid;gap:4px}
.setting-row strong{color:#f5f8ff;font-size:13px}
.setting-row small{color:#75849a;font-size:11px;line-height:1.4}
.setting-row input[type="checkbox"]{width:20px;height:20px;accent-color:#2f7cff}
body.no-blue-glow{
  background:#070b12;
}
body.no-blue-glow .brand-mark,
body.no-blue-glow .btn-primary,
body.no-blue-glow .category-pill.active{
  background:#f4f6f8;
  color:#101317;
}
body.compact-grid .wall-grid{
  grid-template-columns:repeat(5,1fr);
}from pathlib import Path
import re, zipfile, shutil, textwrap

# Use the latest BlueWall project as the base.
src = Path("/mnt/data/VividWall-Blue-4K")
if not src.exists():
    src = Path("/mnt/data/VividWall-4K-Build")

dst = Path("/mnt/data/BlueWall-4K-Download-Fixed")
if dst.exists():
    shutil.rmtree(dst)
shutil.copytree(src, dst)

html_path = dst / "index.html"
js_path = dst / "app.js"
readme_path = dst / "HOW_TO_OPEN.txt"

html = html_path.read_text(encoding="utf-8")
js = js_path.read_text(encoding="utf-8")

# Ensure download buttons have a clear title and the hero download button remains wired.
html = html.replace('aria-label="Download featured wallpaper">↓</button>',
                    'aria-label="Download featured wallpaper" title="Download 4K wallpaper">↓</button>')

# Replace wallpaper data with explicit download URLs (larger width for 4K-oriented download).
pattern = r'const wallpapers = \[(?:.|\n)*?\];'
m = re.search(pattern, js)
if not m:
    raise RuntimeError("Could not find wallpapers array")

wall_block = m.group(0)
# Add dl property based on each existing img URL, targeting 3840px and q=95.
def add_dl(match):
    title, cat, img = match.group(1), match.group(2), match.group(3)
    # normalize output URL to a 4K-ish download request
    dl = re.sub(r'w=\d+', 'w=3840', img)
    dl = re.sub(r'q=\d+', 'q=95', dl)
    return f'{{title:"{title}",cat:"{cat}",img:"{img}",dl:"{dl}"}}'

new_wall_block = re.sub(
    r'\{title:"([^"]+)",cat:"([^"]+)",img:"([^"]+)"\}',
    add_dl,
    wall_block
)
js = js.replace(wall_block, new_wall_block)

# Replace the old fake download click behavior with a real download helper.
old_doc_click = r'''document.addEventListener("click", e => {
  const dl = e.target.closest("[data-download]");
  if(dl) showToast(`"${dl.dataset.download}" is ready for your download backend.`);
  const opener = e.target.closest("[data-open-auth]");
  if(opener) openAuth(opener.dataset.openAuth);
});'''

new_doc_click = r'''async function downloadWallpaper(title){
  const item = wallpapers.find(w => w.title === title);
  let url = item?.dl;

  // Featured hero image fallback.
  if(!url && title === "Alpine Silence"){
    url = "https://images.unsplash.com/photo-1500530855697-b586d89ba3ee?auto=format&fit=crop&w=3840&q=95";
  }

  if(!url){
    showToast("Wallpaper download link was not found.");
    return;
  }

  showToast(`Preparing "${title}" download...`);

  try{
    // Fetch as a Blob so the browser downloads the file instead of navigating away.
    const response = await fetch(url, {mode:"cors"});
    if(!response.ok) throw new Error("Download request failed");

    const blob = await response.blob();
    const objectUrl = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = objectUrl;
    a.download = `${title.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")}-4k.jpg`;
    document.body.appendChild(a);
    a.click();
    a.remove();
    setTimeout(()=>URL.revokeObjectURL(objectUrl), 2000);
    showToast(`Downloaded "${title}" 4K wallpaper.`);
  }catch(err){
    // Some browsers/providers block cross-origin Blob downloads from local files.
    // In that case, open the full-resolution image so the user can save it.
    const a = document.createElement("a");
    a.href = url;
    a.target = "_blank";
    a.rel = "noopener";
    document.body.appendChild(a);
    a.click();
    a.remove();
    showToast("Opened the 4K image. Use Save image as if the browser blocks direct download.");
  }
}

document.addEventListener("click", e => {
  const dl = e.target.closest("[data-download]");
  if(dl){
    e.preventDefault();
    downloadWallpaper(dl.dataset.download);
  }
  const opener = e.target.closest("[data-open-auth]");
  if(opener) openAuth(opener.dataset.openAuth);
});'''

if old_doc_click in js:
    js = js.replace(old_doc_click, new_doc_click)
else:
    # Replace the relevant click listener more flexibly.
    js = re.sub(
        r'document\.addEventListener\("click", e => \{\s*const dl = e\.target\.closest\("\[data-download\]"\);.*?\n\}\);',
        new_doc_click,
        js,
        count=1,
        flags=re.S
    )

# Update card markup to include title attribute.
js = js.replace('aria-label="Download ${w.title}">↓</button>',
                'aria-label="Download ${w.title}" title="Download ${w.title} in 4K">↓</button>')

js_path.write_text(js, encoding="utf-8")

readme_path.write_text(
    "BlueWall 4K - Download Fixed\n\n"
    "1. Extract this ZIP with 7-Zip.\n"
    "2. Open the extracted folder.\n"
    "3. Double-click START_APP.bat.\n"
    "4. Click the down-arrow button on any wallpaper.\n\n"
    "The download button now attempts a real high-resolution image download.\n"
    "If your browser blocks direct cross-origin downloads while opening the app as a local file, "
    "the full-resolution image opens in a new tab so you can use 'Save image as'.\n\n"
    "Do NOT open app.js directly.\n",
    encoding="utf-8"
)

# Package.
zip_path = Path("/mnt/data/BlueWall-4K-Download-Fixed-7Zip.zip")
if zip_path.exists():
    zip_path.unlink()

with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as z:
    for p in dst.rglob("*"):
        if p.is_file():
            z.write(p, Path(dst.name) / p.relative_to(dst))

print(f"Fixed build created: {zip_path}")
print("Download buttons now attempt a real 4K image download and fall back to opening the full-size image.")


@media(max-width:1100px){
  body.compact-grid .wall-grid{grid-template-columns:repeat(3,1fr)}
}
@media(max-width:600px){
  body.compact-grid .wall-grid{grid-template-columns:repeat(2,1fr)}
}
