Upload 14 files
Browse files- .gitattributes +8 -0
- 5f5e9622-f3f6-49e9-bfd3-886ffc2d9496.jpg +0 -0
- IMG_9450.jpg +3 -0
- IMG_9451.jpg +3 -0
- IMG_9453.jpg +3 -0
- IMG_9461.jpg +3 -0
- IMG_9547.jpg +3 -0
- README.md +22 -10
- app.py +20 -0
- index.html +32 -19
- main.js +359 -0
- pngegg.png +3 -0
- style.css +276 -28
- z7273034591306_f2041027e92ac75073dc44d48a044a19.jpg +3 -0
- z7273040168526_69abfd03e0779e60ce9b0b181353a68b.jpg +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,11 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
IMG_9450.jpg filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
IMG_9451.jpg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
IMG_9453.jpg filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
IMG_9461.jpg filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
IMG_9547.jpg filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
pngegg.png filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
z7273034591306_f2041027e92ac75073dc44d48a044a19.jpg filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
z7273040168526_69abfd03e0779e60ce9b0b181353a68b.jpg filter=lfs diff=lfs merge=lfs -text
|
5f5e9622-f3f6-49e9-bfd3-886ffc2d9496.jpg
ADDED
|
IMG_9450.jpg
ADDED
|
Git LFS Details
|
IMG_9451.jpg
ADDED
|
Git LFS Details
|
IMG_9453.jpg
ADDED
|
Git LFS Details
|
IMG_9461.jpg
ADDED
|
Git LFS Details
|
IMG_9547.jpg
ADDED
|
Git LFS Details
|
README.md
CHANGED
|
@@ -1,10 +1,22 @@
|
|
| 1 |
-
---
|
| 2 |
-
title:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo: blue
|
| 6 |
-
sdk: static
|
| 7 |
-
pinned: false
|
| 8 |
-
---
|
| 9 |
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Merry Christmas em iu của anh
|
| 3 |
+
emoji: 🎄
|
| 4 |
+
colorFrom: green
|
| 5 |
+
colorTo: blue
|
| 6 |
+
sdk: static
|
| 7 |
+
pinned: false
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
This project is a client-side Christmas page and can be deployed as a **Static HTML** Hugging Face Space.
|
| 11 |
+
|
| 12 |
+
Quick steps to deploy on Hugging Face Spaces (Static HTML):
|
| 13 |
+
|
| 14 |
+
1. Create a new Space at https://huggingface.co/spaces and choose "Static HTML" as the SDK.
|
| 15 |
+
2. Push this repository to the new Space (the repo should contain `index.html` at the project root and assets at the repo root: `main.js`, `style.css`, `pngegg.png` and the image files).
|
| 16 |
+
3. No `requirements.txt` is required for a static Space.
|
| 17 |
+
|
| 18 |
+
Notes:
|
| 19 |
+
- I updated asset paths in `static/main.js` to be relative so the app works when served statically.
|
| 20 |
+
- You can remove `app.py` (Flask) if you plan to host as a static Space; keep it if you want to run locally with Flask.
|
| 21 |
+
|
| 22 |
+
If you'd rather convert this to a Gradio or Streamlit-based Space (so you can add Python-powered interactivity), tell me and I can scaffold that for you.
|
app.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask, render_template, send_from_directory
|
| 2 |
+
import os
|
| 3 |
+
|
| 4 |
+
app = Flask(__name__)
|
| 5 |
+
|
| 6 |
+
@app.route('/')
|
| 7 |
+
def index():
|
| 8 |
+
return render_template('index.html')
|
| 9 |
+
|
| 10 |
+
@app.route('/images/<path:filename>')
|
| 11 |
+
def images(filename):
|
| 12 |
+
# After flattening repository, images are at the project root. Serve from root.
|
| 13 |
+
return send_from_directory(app.root_path, filename)
|
| 14 |
+
|
| 15 |
+
@app.route('/pngegg.png')
|
| 16 |
+
def tree_png():
|
| 17 |
+
return send_from_directory(app.root_path, 'pngegg.png')
|
| 18 |
+
|
| 19 |
+
if __name__ == '__main__':
|
| 20 |
+
app.run(host='0.0.0.0', port=5000, debug=True)
|
index.html
CHANGED
|
@@ -1,19 +1,32 @@
|
|
| 1 |
-
<!
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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.0">
|
| 6 |
+
<title>Merry Christmas em iu của anh</title>
|
| 7 |
+
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
|
| 8 |
+
<link rel="stylesheet" href="/style.css">
|
| 9 |
+
</head>
|
| 10 |
+
<body class="bg-gradient-to-b from-gray-900 to-gray-800 min-h-screen flex flex-col justify-between relative overflow-hidden">
|
| 11 |
+
<!-- Snow effect -->
|
| 12 |
+
<canvas id="snow-canvas" class="absolute inset-0 w-full h-full pointer-events-none z-0"></canvas>
|
| 13 |
+
<!-- Header -->
|
| 14 |
+
<header class="text-center py-8">
|
| 15 |
+
<h1 class="text-4xl md:text-6xl font-bold text-yellow-300 drop-shadow-lg tracking-wide">Merry Christmas em iu của anh</h1>
|
| 16 |
+
</header>
|
| 17 |
+
<!-- Main Content -->
|
| 18 |
+
<main class="flex-1 flex flex-col items-center justify-center relative z-10 w-full">
|
| 19 |
+
<div id="tree-container" class="relative flex flex-col items-center justify-center w-full max-w-full">
|
| 20 |
+
<!-- Christmas tree will be rendered here by JS -->
|
| 21 |
+
</div>
|
| 22 |
+
<div id="gifts-container" class="flex flex-row flex-wrap justify-center items-end mt-8 space-x-4 w-full max-w-full px-2">
|
| 23 |
+
<!-- Gift boxes will be rendered here by JS -->
|
| 24 |
+
</div>
|
| 25 |
+
</main>
|
| 26 |
+
<!-- Footer -->
|
| 27 |
+
<footer class="text-center py-6">
|
| 28 |
+
<span class="text-lg text-gray-300 font-medium">Made by: @tbaro - your love</span>
|
| 29 |
+
</footer>
|
| 30 |
+
<script src="/main.js"></script>
|
| 31 |
+
</body>
|
| 32 |
+
</html>
|
main.js
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// --- Christmas Tree, Ornaments, Gifts, Snow, Interactivity ---
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
// Romantic quotes (expanded)
|
| 6 |
+
const quotes = [
|
| 7 |
+
"Love is composed of a single soul inhabiting two bodies. – Aristotle",
|
| 8 |
+
"You are my heart, my life, my one and only thought. – Arthur Conan Doyle",
|
| 9 |
+
"I love you not only for what you are, but for what I am when I am with you. – Roy Croft",
|
| 10 |
+
"Whatever our souls are made of, his and mine are the same. – Emily Brontë",
|
| 11 |
+
"You are the finest, loveliest, tenderest, and most beautiful person I have ever known. – F. Scott Fitzgerald",
|
| 12 |
+
"I wish you to know that you have been the last dream of my soul. – Charles Dickens",
|
| 13 |
+
"If I know what love is, it is because of you. – Hermann Hesse",
|
| 14 |
+
"You are my sun, my moon, and all my stars. – E.E. Cummings",
|
| 15 |
+
"I love you more than words can wield the matter. – Shakespeare",
|
| 16 |
+
"To love and be loved is to feel the sun from both sides. – David Viscott",
|
| 17 |
+
"Anh yêu em hơn tất cả những gì anh có thể nói bằng lời.",
|
| 18 |
+
"Em là món quà tuyệt vời nhất mà cuộc đời đã ban tặng cho anh.",
|
| 19 |
+
"Chỉ cần có em bên cạnh, mọi mùa đông đều trở nên ấm áp."
|
| 20 |
+
];
|
| 21 |
+
|
| 22 |
+
// Bauble images - read from project images folder
|
| 23 |
+
const baubleImages = [
|
| 24 |
+
"5f5e9622-f3f6-49e9-bfd3-886ffc2d9496.jpg",
|
| 25 |
+
"IMG_9450.jpg",
|
| 26 |
+
"IMG_9451.jpg",
|
| 27 |
+
"IMG_9453.jpg",
|
| 28 |
+
"IMG_9461.jpg",
|
| 29 |
+
"IMG_9547.jpg",
|
| 30 |
+
"z7273034591306_f2041027e92ac75073dc44d48a044a19.jpg",
|
| 31 |
+
"z7273040168526_69abfd03e0779e60ce9b0b181353a68b.jpg"
|
| 32 |
+
];
|
| 33 |
+
|
| 34 |
+
// Ornaments storage
|
| 35 |
+
const ornaments = [];
|
| 36 |
+
|
| 37 |
+
// Create bauble ornaments - here we just rely on baubleImages used when rendering
|
| 38 |
+
function createBaubleOrnaments() {
|
| 39 |
+
// This is a placeholder; baubles are rendered directly in renderTree using baubleImages
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
// Create smaller decorative ornaments (circles) with relative positions (rx, ry)
|
| 43 |
+
function createTreeOrnaments() {
|
| 44 |
+
ornaments.length = 0;
|
| 45 |
+
const count = 12;
|
| 46 |
+
for (let i = 0; i < count; i++) {
|
| 47 |
+
ornaments.push({
|
| 48 |
+
type: 'circle',
|
| 49 |
+
color: i % 2 === 0 ? '#FFD700' : '#E63946',
|
| 50 |
+
size: window.innerWidth < 600 ? 12 : 18,
|
| 51 |
+
rx: 0.25 + Math.random() * 0.5, // relative x position inside tree image
|
| 52 |
+
ry: 0.2 + Math.random() * 0.6 // relative y position inside tree image
|
| 53 |
+
});
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
function renderTree() {
|
| 58 |
+
// Use a single cartoon tree image as centerpiece
|
| 59 |
+
const treeContainer = document.getElementById('tree-container');
|
| 60 |
+
treeContainer.innerHTML = '';
|
| 61 |
+
|
| 62 |
+
// wrapper to align baubles relative to the image
|
| 63 |
+
const wrapper = document.createElement('div');
|
| 64 |
+
wrapper.className = 'tree-wrapper';
|
| 65 |
+
wrapper.style.position = 'relative';
|
| 66 |
+
wrapper.style.display = 'inline-block';
|
| 67 |
+
|
| 68 |
+
const treeImg = document.createElement('img');
|
| 69 |
+
// use relative route for static deployment
|
| 70 |
+
treeImg.src = 'pngegg.png';
|
| 71 |
+
treeImg.alt = 'Christmas Tree';
|
| 72 |
+
treeImg.className = 'cartoon-tree-img';
|
| 73 |
+
treeImg.style.display = 'block';
|
| 74 |
+
treeImg.style.margin = '0 auto';
|
| 75 |
+
// Larger tree sizes for a premium look
|
| 76 |
+
// let CSS control responsive width; remove hard-coded inline width
|
| 77 |
+
// treeImg.style.width = window.innerWidth < 600 ? '220px' : (window.innerWidth < 900 ? '340px' : '480px');
|
| 78 |
+
treeImg.style.height = 'auto';
|
| 79 |
+
treeImg.style.position = 'relative';
|
| 80 |
+
treeImg.style.zIndex = 2;
|
| 81 |
+
wrapper.appendChild(treeImg);
|
| 82 |
+
treeContainer.appendChild(wrapper);
|
| 83 |
+
|
| 84 |
+
// Overlay baubles (images) on the tree image in a circular/spiral pattern
|
| 85 |
+
const baubleCount = baubleImages.length;
|
| 86 |
+
function placeBaublesAndOrnaments() {
|
| 87 |
+
const rect = treeImg.getBoundingClientRect();
|
| 88 |
+
const w = Math.round(rect.width);
|
| 89 |
+
const h = Math.round(rect.height);
|
| 90 |
+
// clear previous ornaments inside wrapper
|
| 91 |
+
wrapper.querySelectorAll('.ornament').forEach(e => e.remove());
|
| 92 |
+
for (let i = 0; i < baubleCount; i++) {
|
| 93 |
+
const angle = (i / baubleCount) * Math.PI * 2 - Math.PI / 2;
|
| 94 |
+
const radius = w * 0.32 + (i % 2) * 18;
|
| 95 |
+
const x = w / 2 + Math.cos(angle) * radius;
|
| 96 |
+
const y = h * 0.45 + Math.sin(angle) * (radius * 0.7);
|
| 97 |
+
const bauble = document.createElement('div');
|
| 98 |
+
bauble.className = 'ornament';
|
| 99 |
+
bauble.style.position = 'absolute';
|
| 100 |
+
bauble.style.left = (x - 22) + 'px';
|
| 101 |
+
bauble.style.top = (y - 22) + 'px';
|
| 102 |
+
// larger baubles for better visibility
|
| 103 |
+
bauble.style.width = window.innerWidth < 600 ? '44px' : (window.innerWidth < 900 ? '64px' : '80px');
|
| 104 |
+
bauble.style.height = window.innerWidth < 600 ? '44px' : (window.innerWidth < 900 ? '64px' : '80px');
|
| 105 |
+
bauble.style.background = `url('${baubleImages[i]}') center/cover no-repeat`;
|
| 106 |
+
bauble.style.border = '3px solid #fff8';
|
| 107 |
+
bauble.style.boxShadow = '0 6px 18px 4px rgba(0,0,0,0.35), 0 0 24px 6px #FFD70044';
|
| 108 |
+
bauble.style.borderRadius = '50%';
|
| 109 |
+
bauble.style.zIndex = 60;
|
| 110 |
+
// gentle float animation
|
| 111 |
+
bauble.style.animation = `float ${3 + Math.random()*2}s ${i * 100}ms ease-in-out infinite`;
|
| 112 |
+
wrapper.appendChild(bauble);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
// Render extra small ornaments (circles) from ornaments array (rx/ry - relative coords)
|
| 116 |
+
ornaments.forEach(o => {
|
| 117 |
+
if (o.type === 'circle') {
|
| 118 |
+
const el = document.createElement('div');
|
| 119 |
+
el.className = 'ornament';
|
| 120 |
+
const x = Math.round(o.rx * w);
|
| 121 |
+
const y = Math.round(o.ry * h);
|
| 122 |
+
const size = o.size || (window.innerWidth < 600 ? 14 : 26);
|
| 123 |
+
el.style.position = 'absolute';
|
| 124 |
+
el.style.left = (x - size / 2) + 'px';
|
| 125 |
+
el.style.top = (y - size / 2) + 'px';
|
| 126 |
+
el.style.width = size + 'px';
|
| 127 |
+
el.style.height = size + 'px';
|
| 128 |
+
el.style.borderRadius = '50%';
|
| 129 |
+
el.style.background = o.color || '#FFD700';
|
| 130 |
+
el.style.border = '2px solid #fff4';
|
| 131 |
+
el.style.boxShadow = '0 6px 14px 3px rgba(0,0,0,0.28)';
|
| 132 |
+
el.style.zIndex = 55;
|
| 133 |
+
el.style.opacity = 0.95;
|
| 134 |
+
wrapper.appendChild(el);
|
| 135 |
+
}
|
| 136 |
+
});
|
| 137 |
+
|
| 138 |
+
wrapper.style.width = w + 'px';
|
| 139 |
+
wrapper.style.height = h + 'px';
|
| 140 |
+
// Ensure wrapper is centered in container
|
| 141 |
+
wrapper.style.display = 'block';
|
| 142 |
+
wrapper.style.margin = '0 auto';
|
| 143 |
+
}
|
| 144 |
+
// use load event for reliability
|
| 145 |
+
treeImg.onload = () => {
|
| 146 |
+
placeBaublesAndOrnaments();
|
| 147 |
+
// now we can safely render gift boxes positioned relative to the tree
|
| 148 |
+
renderGiftBoxes();
|
| 149 |
+
};
|
| 150 |
+
if (treeImg.complete) {
|
| 151 |
+
placeBaublesAndOrnaments();
|
| 152 |
+
renderGiftBoxes();
|
| 153 |
+
}
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
// Render gift boxes
|
| 157 |
+
function renderGiftBoxes() {
|
| 158 |
+
const giftsContainer = document.getElementById('gifts-container');
|
| 159 |
+
giftsContainer.innerHTML = '';
|
| 160 |
+
const wrapper = document.querySelector('.tree-wrapper');
|
| 161 |
+
const boxCount = window.innerWidth > 1200 ? 8 : window.innerWidth > 900 ? 6 : (window.innerWidth < 600 ? 3 : 5);
|
| 162 |
+
|
| 163 |
+
// If wrapper exists, place boxes around base of the tree
|
| 164 |
+
if (wrapper) {
|
| 165 |
+
// remove any old boxes and any previous row
|
| 166 |
+
wrapper.querySelectorAll('.gift-box.inside').forEach(e => e.remove());
|
| 167 |
+
wrapper.querySelectorAll('.boxes-row').forEach(e => e.remove());
|
| 168 |
+
const w = wrapper.clientWidth;
|
| 169 |
+
const h = wrapper.clientHeight;
|
| 170 |
+
// preferred sizes (relative to container)
|
| 171 |
+
let desiredBox = Math.round(Math.min(110, w * 0.18));
|
| 172 |
+
let gap = Math.round(Math.max(8, w * 0.02));
|
| 173 |
+
const padding = 12;
|
| 174 |
+
// compute max possible box size to fit
|
| 175 |
+
const maxBox = Math.floor((w - padding * 2 - (boxCount - 1) * gap) / boxCount);
|
| 176 |
+
let boxSize = Math.max(36, Math.min(desiredBox, maxBox));
|
| 177 |
+
// if still too big, reduce gap and try again
|
| 178 |
+
if (boxSize * boxCount + (boxCount - 1) * gap + padding * 2 > w) {
|
| 179 |
+
gap = Math.max(6, Math.floor((w - padding * 2 - boxCount * boxSize) / Math.max(1, boxCount - 1)));
|
| 180 |
+
boxSize = Math.max(32, Math.floor((w - padding * 2 - (boxCount - 1) * gap) / boxCount));
|
| 181 |
+
}
|
| 182 |
+
const totalWidth = boxCount * boxSize + (boxCount - 1) * gap;
|
| 183 |
+
// create a centered, responsive row container that sits visually in front of the tree
|
| 184 |
+
const row = document.createElement('div');
|
| 185 |
+
row.className = 'boxes-row';
|
| 186 |
+
row.style.position = 'absolute';
|
| 187 |
+
row.style.left = '50%';
|
| 188 |
+
row.style.transform = 'translateX(-50%)';
|
| 189 |
+
row.style.width = totalWidth + 'px';
|
| 190 |
+
row.style.display = 'flex';
|
| 191 |
+
row.style.gap = gap + 'px';
|
| 192 |
+
row.style.justifyContent = 'center';
|
| 193 |
+
row.style.flexWrap = 'nowrap';
|
| 194 |
+
row.style.bottom = '-' + Math.round(boxSize / 2) + 'px';
|
| 195 |
+
row.style.zIndex = 140;
|
| 196 |
+
row.style.pointerEvents = 'auto';
|
| 197 |
+
// fill row
|
| 198 |
+
for (let i = 0; i < boxCount; i++) {
|
| 199 |
+
const box = document.createElement('div');
|
| 200 |
+
box.className = 'gift-box inside';
|
| 201 |
+
box.style.width = boxSize + 'px';
|
| 202 |
+
box.style.height = boxSize + 'px';
|
| 203 |
+
box.style.boxShadow = '0 16px 40px rgba(0,0,0,0.5), 0 0 18px 6px #FFD70033';
|
| 204 |
+
box.innerHTML = `<div class="gift-ribbon"></div><div class="gift-bow"></div>`;
|
| 205 |
+
box.onclick = () => showQuotePopup();
|
| 206 |
+
box.style.animation = `bob 3s ${i * 120}ms ease-in-out infinite`;
|
| 207 |
+
// subtle rotation
|
| 208 |
+
box.style.transform = (i % 2 === 0) ? 'rotate(-2deg)' : 'rotate(2deg)';
|
| 209 |
+
row.appendChild(box);
|
| 210 |
+
}
|
| 211 |
+
// append to wrapper so it always aligns with the tree image
|
| 212 |
+
wrapper.appendChild(row);
|
| 213 |
+
} else {
|
| 214 |
+
// fallback: render in gifts container
|
| 215 |
+
for (let i = 0; i < boxCount; i++) {
|
| 216 |
+
const box = document.createElement('div');
|
| 217 |
+
box.className = 'gift-box';
|
| 218 |
+
box.innerHTML = `<div class="gift-ribbon"></div><div class="gift-bow"></div>`;
|
| 219 |
+
box.onclick = () => showQuotePopup();
|
| 220 |
+
giftsContainer.appendChild(box);
|
| 221 |
+
}
|
| 222 |
+
giftsContainer.style.justifyContent = 'center';
|
| 223 |
+
giftsContainer.style.gap = '12px';
|
| 224 |
+
}
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
// Show quote popup
|
| 228 |
+
let lastQuoteIndex = -1;
|
| 229 |
+
function showQuotePopup() {
|
| 230 |
+
// Remove any existing popup
|
| 231 |
+
const old = document.querySelector('.quote-popup');
|
| 232 |
+
if (old) old.remove();
|
| 233 |
+
// Pick a new quote, not the same as last
|
| 234 |
+
let idx;
|
| 235 |
+
do {
|
| 236 |
+
idx = Math.floor(Math.random() * quotes.length);
|
| 237 |
+
} while (quotes.length > 1 && idx === lastQuoteIndex);
|
| 238 |
+
lastQuoteIndex = idx;
|
| 239 |
+
const popup = document.createElement('div');
|
| 240 |
+
popup.className = 'quote-popup';
|
| 241 |
+
const quote = quotes[idx];
|
| 242 |
+
popup.innerHTML = `<button class="close-btn">×</button><div>${quote}</div>`;
|
| 243 |
+
popup.querySelector('.close-btn').onclick = () => popup.remove();
|
| 244 |
+
document.body.appendChild(popup);
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
// Snow effect
|
| 248 |
+
function snowEffect() {
|
| 249 |
+
const canvas = document.getElementById('snow-canvas');
|
| 250 |
+
const ctx = canvas.getContext('2d');
|
| 251 |
+
let W = window.innerWidth, H = window.innerHeight;
|
| 252 |
+
canvas.width = W;
|
| 253 |
+
canvas.height = H;
|
| 254 |
+
let mp = 80;
|
| 255 |
+
let particles = [];
|
| 256 |
+
for (let i = 0; i < mp; i++) {
|
| 257 |
+
particles.push({
|
| 258 |
+
x: Math.random() * W,
|
| 259 |
+
y: Math.random() * H,
|
| 260 |
+
r: 2 + Math.random() * 4,
|
| 261 |
+
d: Math.random() * mp
|
| 262 |
+
});
|
| 263 |
+
}
|
| 264 |
+
function draw() {
|
| 265 |
+
ctx.clearRect(0, 0, W, H);
|
| 266 |
+
ctx.fillStyle = "rgba(255,255,255,0.85)";
|
| 267 |
+
ctx.beginPath();
|
| 268 |
+
for (let i = 0; i < mp; i++) {
|
| 269 |
+
let p = particles[i];
|
| 270 |
+
ctx.moveTo(p.x, p.y);
|
| 271 |
+
ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2, true);
|
| 272 |
+
}
|
| 273 |
+
ctx.fill();
|
| 274 |
+
update();
|
| 275 |
+
}
|
| 276 |
+
let angle = 0;
|
| 277 |
+
function update() {
|
| 278 |
+
angle += 0.01;
|
| 279 |
+
for (let i = 0; i < mp; i++) {
|
| 280 |
+
let p = particles[i];
|
| 281 |
+
p.y += Math.cos(angle + p.d) + 1 + p.r / 2;
|
| 282 |
+
p.x += Math.sin(angle) * 2;
|
| 283 |
+
if (p.x > W + 5 || p.x < -5 || p.y > H) {
|
| 284 |
+
if (i % 3 > 0) {
|
| 285 |
+
particles[i] = {x: Math.random() * W, y: -10, r: p.r, d: p.d};
|
| 286 |
+
} else {
|
| 287 |
+
if (Math.sin(angle) > 0) {
|
| 288 |
+
particles[i] = {x: -5, y: Math.random() * H, r: p.r, d: p.d};
|
| 289 |
+
} else {
|
| 290 |
+
particles[i] = {x: W + 5, y: Math.random() * H, r: p.r, d: p.d};
|
| 291 |
+
}
|
| 292 |
+
}
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
}
|
| 296 |
+
setInterval(draw, 33);
|
| 297 |
+
window.addEventListener('resize', () => {
|
| 298 |
+
W = window.innerWidth;
|
| 299 |
+
H = window.innerHeight;
|
| 300 |
+
canvas.width = W;
|
| 301 |
+
canvas.height = H;
|
| 302 |
+
});
|
| 303 |
+
}
|
| 304 |
+
|
| 305 |
+
// --- INIT & Responsive ---
|
| 306 |
+
function renderAll() {
|
| 307 |
+
ornaments.length = 0;
|
| 308 |
+
createBaubleOrnaments();
|
| 309 |
+
createTreeOrnaments();
|
| 310 |
+
renderTree();
|
| 311 |
+
renderGiftBoxes();
|
| 312 |
+
}
|
| 313 |
+
function renderMoonAndStars() {
|
| 314 |
+
// Add a moon and stars to the background
|
| 315 |
+
let moon = document.getElementById('moon');
|
| 316 |
+
if (!moon) {
|
| 317 |
+
moon = document.createElement('div');
|
| 318 |
+
moon.id = 'moon';
|
| 319 |
+
moon.style.position = 'fixed';
|
| 320 |
+
moon.style.top = '60px';
|
| 321 |
+
moon.style.right = '80px';
|
| 322 |
+
moon.style.width = '80px';
|
| 323 |
+
moon.style.height = '80px';
|
| 324 |
+
moon.style.borderRadius = '50%';
|
| 325 |
+
moon.style.background = 'radial-gradient(circle at 60% 40%, #fffbe6 70%, #ffe066 100%, #fff0 100%)';
|
| 326 |
+
moon.style.boxShadow = '0 0 60px 10px #fffbe6cc, 0 0 120px 40px #ffe06644';
|
| 327 |
+
moon.style.zIndex = 1;
|
| 328 |
+
document.body.appendChild(moon);
|
| 329 |
+
}
|
| 330 |
+
// Remove old stars
|
| 331 |
+
document.querySelectorAll('.starry-star').forEach(e => e.remove());
|
| 332 |
+
// Add random stars
|
| 333 |
+
for (let i = 0; i < 40; i++) {
|
| 334 |
+
const star = document.createElement('div');
|
| 335 |
+
star.className = 'starry-star';
|
| 336 |
+
star.style.position = 'fixed';
|
| 337 |
+
star.style.top = (Math.random() * 40 + 10) + '%';
|
| 338 |
+
star.style.left = (Math.random() * 100) + '%';
|
| 339 |
+
const size = Math.random() * 2.5 + 1.5;
|
| 340 |
+
star.style.width = size + 'px';
|
| 341 |
+
star.style.height = size + 'px';
|
| 342 |
+
star.style.background = 'white';
|
| 343 |
+
star.style.borderRadius = '50%';
|
| 344 |
+
star.style.opacity = 0.7 + Math.random() * 0.3;
|
| 345 |
+
star.style.zIndex = 1;
|
| 346 |
+
star.style.boxShadow = `0 0 ${size*4}px ${size/2}px #fff8`;
|
| 347 |
+
document.body.appendChild(star);
|
| 348 |
+
}
|
| 349 |
+
}
|
| 350 |
+
|
| 351 |
+
document.addEventListener('DOMContentLoaded', () => {
|
| 352 |
+
renderAll();
|
| 353 |
+
snowEffect();
|
| 354 |
+
renderMoonAndStars();
|
| 355 |
+
window.addEventListener('resize', () => {
|
| 356 |
+
renderAll();
|
| 357 |
+
renderMoonAndStars();
|
| 358 |
+
});
|
| 359 |
+
});
|
pngegg.png
ADDED
|
Git LFS Details
|
style.css
CHANGED
|
@@ -1,28 +1,276 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Premium, warm, romantic Christmas styles */
|
| 2 |
+
body {
|
| 3 |
+
font-family: 'Segoe UI', 'Roboto', 'Arial', sans-serif;
|
| 4 |
+
background: linear-gradient(180deg, #232946 0%, #1a202c 100%);
|
| 5 |
+
}
|
| 6 |
+
|
| 7 |
+
#tree-container {
|
| 8 |
+
min-height: 320px;
|
| 9 |
+
min-width: 220px;
|
| 10 |
+
width: 100vw;
|
| 11 |
+
max-width: 100vw;
|
| 12 |
+
display: flex;
|
| 13 |
+
justify-content: center;
|
| 14 |
+
align-items: center;
|
| 15 |
+
}
|
| 16 |
+
|
| 17 |
+
/* Christmas tree styles */
|
| 18 |
+
/* Beautiful, lush, premium Christmas tree */
|
| 19 |
+
/* Cartoon tree image style */
|
| 20 |
+
.cartoon-tree-img {
|
| 21 |
+
display: block;
|
| 22 |
+
margin: 0 auto;
|
| 23 |
+
width: min(72vw, 520px);
|
| 24 |
+
max-width: 92vw;
|
| 25 |
+
height: auto;
|
| 26 |
+
filter: drop-shadow(0 0 26px #fff8) drop-shadow(0 0 48px #FFD70044);
|
| 27 |
+
border-radius: 18px;
|
| 28 |
+
background: none;
|
| 29 |
+
z-index: 2;
|
| 30 |
+
box-shadow: 0 0 0 6px #fff2;
|
| 31 |
+
transition: width 0.25s ease, height 0.25s ease, transform 0.25s ease;
|
| 32 |
+
}
|
| 33 |
+
@media (max-width: 1200px) {
|
| 34 |
+
.cartoon-tree-img {
|
| 35 |
+
width: min(72vw, 420px);
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
@media (max-width: 900px) {
|
| 39 |
+
.cartoon-tree-img {
|
| 40 |
+
width: min(80vw, 360px);
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
@media (max-width: 600px) {
|
| 44 |
+
.cartoon-tree-img {
|
| 45 |
+
width: min(92vw, 220px);
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
.christmas-tree {
|
| 49 |
+
width: 260px;
|
| 50 |
+
height: 400px;
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
@media (max-width: 600px) {
|
| 54 |
+
.christmas-tree {
|
| 55 |
+
width: 220px;
|
| 56 |
+
height: 320px;
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
.tree-part {
|
| 61 |
+
position: absolute;
|
| 62 |
+
left: 50%;
|
| 63 |
+
transform: translateX(-50%);
|
| 64 |
+
border-radius: 50%;
|
| 65 |
+
background: linear-gradient(135deg, #2d6a4f 60%, #1b4332 100%);
|
| 66 |
+
box-shadow: 0 0 40px 10px #14532d44;
|
| 67 |
+
border: 2px solid #fff2;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
/* Glowing star */
|
| 71 |
+
.tree-star {
|
| 72 |
+
position: absolute;
|
| 73 |
+
left: 50%;
|
| 74 |
+
transform: translateX(-50%);
|
| 75 |
+
width: 60px;
|
| 76 |
+
height: 60px;
|
| 77 |
+
z-index: 40;
|
| 78 |
+
animation: twinkle 2s infinite alternate;
|
| 79 |
+
filter: drop-shadow(0 0 18px #fff8) drop-shadow(0 0 32px #FFD700);
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
@keyframes twinkle {
|
| 83 |
+
0% { filter: brightness(1.2); }
|
| 84 |
+
100% { filter: brightness(2.2); }
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
/* tree wrapper for relative placements */
|
| 88 |
+
.tree-wrapper {
|
| 89 |
+
position: relative;
|
| 90 |
+
display: inline-block;
|
| 91 |
+
overflow: visible;
|
| 92 |
+
padding-bottom: 48px; /* space for gifts */
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
/* centered row of gift boxes */
|
| 96 |
+
.boxes-row {
|
| 97 |
+
display: flex;
|
| 98 |
+
justify-content: center;
|
| 99 |
+
align-items: flex-end;
|
| 100 |
+
gap: 18px;
|
| 101 |
+
pointer-events: auto;
|
| 102 |
+
}
|
| 103 |
+
@media (max-width: 600px) {
|
| 104 |
+
.boxes-row {
|
| 105 |
+
gap: 10px;
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
/* star twinkle */
|
| 110 |
+
.starry-star {
|
| 111 |
+
animation: starTwinkle 3s infinite ease-in-out;
|
| 112 |
+
}
|
| 113 |
+
@keyframes starTwinkle {
|
| 114 |
+
0% { opacity: 0.6; transform: scale(1); }
|
| 115 |
+
50% { opacity: 1; transform: scale(1.4); }
|
| 116 |
+
100% { opacity: 0.6; transform: scale(1); }
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
/* Ornaments */
|
| 120 |
+
.ornament {
|
| 121 |
+
position: absolute;
|
| 122 |
+
border-radius: 50%;
|
| 123 |
+
transition: transform 0.3s, box-shadow 0.3s;
|
| 124 |
+
cursor: pointer;
|
| 125 |
+
border: 2.5px solid #fff8;
|
| 126 |
+
box-shadow: 0 0 12px 2px #fff8, 0 0 18px 4px #FFD70044;
|
| 127 |
+
background: #fff;
|
| 128 |
+
z-index: 10;
|
| 129 |
+
}
|
| 130 |
+
.ornament:hover {
|
| 131 |
+
transform: scale(1.18) rotate(-2deg);
|
| 132 |
+
box-shadow: 0 0 32px 8px #fff9, 0 0 18px 4px #FFD70099;
|
| 133 |
+
z-index: 99;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
/* Gift boxes */
|
| 137 |
+
|
| 138 |
+
.gift-box {
|
| 139 |
+
width: 100px;
|
| 140 |
+
height: 100px;
|
| 141 |
+
background: linear-gradient(135deg, #e63946 60%, #fbefef 100%);
|
| 142 |
+
border-radius: 14px;
|
| 143 |
+
box-shadow: 0 12px 36px 0 rgba(0,0,0,0.35);
|
| 144 |
+
position: relative;
|
| 145 |
+
cursor: pointer;
|
| 146 |
+
transition: transform 0.25s, box-shadow 0.25s;
|
| 147 |
+
margin-bottom: 16px;
|
| 148 |
+
border: 2.5px solid #fff6;
|
| 149 |
+
overflow: hidden;
|
| 150 |
+
}
|
| 151 |
+
.gift-box:hover {
|
| 152 |
+
transform: scale(1.14) translateY(-6px) rotate(-2deg);
|
| 153 |
+
box-shadow: 0 18px 44px 0 rgba(0,0,0,0.45), 0 0 18px 6px #FFD70088;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
.gift-box.inside {
|
| 157 |
+
cursor: pointer;
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
@keyframes bob {
|
| 161 |
+
0% { transform: translateY(0); }
|
| 162 |
+
50% { transform: translateY(-8px); }
|
| 163 |
+
100% { transform: translateY(0); }
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
@keyframes float {
|
| 167 |
+
0% { transform: translateY(0); }
|
| 168 |
+
50% { transform: translateY(-6px); }
|
| 169 |
+
100% { transform: translateY(0); }
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
@media (max-width: 900px) {
|
| 173 |
+
.gift-box {
|
| 174 |
+
width: 80px;
|
| 175 |
+
height: 80px;
|
| 176 |
+
}
|
| 177 |
+
.gift-ribbon {
|
| 178 |
+
width: 80px;
|
| 179 |
+
top: 28px;
|
| 180 |
+
}
|
| 181 |
+
.gift-bow {
|
| 182 |
+
left: 24px;
|
| 183 |
+
top: 16px;
|
| 184 |
+
}
|
| 185 |
+
}
|
| 186 |
+
@media (max-width: 600px) {
|
| 187 |
+
.gift-box {
|
| 188 |
+
width: 56px;
|
| 189 |
+
height: 56px;
|
| 190 |
+
}
|
| 191 |
+
.gift-ribbon {
|
| 192 |
+
width: 56px;
|
| 193 |
+
top: 18px;
|
| 194 |
+
}
|
| 195 |
+
.gift-bow {
|
| 196 |
+
left: 12px;
|
| 197 |
+
top: 6px;
|
| 198 |
+
width: 10px;
|
| 199 |
+
height: 10px;
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
.gift-ribbon {
|
| 204 |
+
position: absolute;
|
| 205 |
+
top: 46%;
|
| 206 |
+
left: 0;
|
| 207 |
+
width: 100%;
|
| 208 |
+
height: 12px;
|
| 209 |
+
background: linear-gradient(90deg, #c1121f 30%, #e63946 70%);
|
| 210 |
+
border-radius: 6px;
|
| 211 |
+
box-shadow: inset 0 -2px 6px rgba(0,0,0,0.25);
|
| 212 |
+
}
|
| 213 |
+
.gift-ribbon::before {
|
| 214 |
+
content: '';
|
| 215 |
+
position: absolute;
|
| 216 |
+
left: 50%;
|
| 217 |
+
transform: translateX(-50%);
|
| 218 |
+
top: -8px;
|
| 219 |
+
width: 12px;
|
| 220 |
+
height: 32px;
|
| 221 |
+
background: linear-gradient(180deg, #ffdede, #ff7b7b);
|
| 222 |
+
border-radius: 4px;
|
| 223 |
+
opacity: 0.9;
|
| 224 |
+
}
|
| 225 |
+
.gift-bow {
|
| 226 |
+
position: absolute;
|
| 227 |
+
top: 30%;
|
| 228 |
+
left: 50%;
|
| 229 |
+
transform: translate(-50%, -50%);
|
| 230 |
+
width: 18px;
|
| 231 |
+
height: 18px;
|
| 232 |
+
background: radial-gradient(circle, #fff 40%, #ffccd5 100%);
|
| 233 |
+
border-radius: 6px;
|
| 234 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
/* Popup styles */
|
| 239 |
+
.quote-popup {
|
| 240 |
+
position: fixed;
|
| 241 |
+
left: 50%;
|
| 242 |
+
top: 60%;
|
| 243 |
+
transform: translate(-50%, -50%);
|
| 244 |
+
background: rgba(34, 40, 49, 0.98);
|
| 245 |
+
color: #ffd6e0;
|
| 246 |
+
border-radius: 16px;
|
| 247 |
+
box-shadow: 0 8px 32px 0 #0008;
|
| 248 |
+
padding: 32px 40px;
|
| 249 |
+
font-size: 1.25rem;
|
| 250 |
+
font-family: 'Georgia', serif;
|
| 251 |
+
z-index: 50;
|
| 252 |
+
animation: fadeIn 0.5s;
|
| 253 |
+
max-width: 90vw;
|
| 254 |
+
word-break: break-word;
|
| 255 |
+
}
|
| 256 |
+
@media (max-width: 600px) {
|
| 257 |
+
.quote-popup {
|
| 258 |
+
padding: 16px 10px;
|
| 259 |
+
font-size: 1rem;
|
| 260 |
+
}
|
| 261 |
+
}
|
| 262 |
+
@keyframes fadeIn {
|
| 263 |
+
from { opacity: 0; transform: translate(-50%, -60%); }
|
| 264 |
+
to { opacity: 1; transform: translate(-50%, -50%); }
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
.quote-popup .close-btn {
|
| 268 |
+
position: absolute;
|
| 269 |
+
top: 12px;
|
| 270 |
+
right: 18px;
|
| 271 |
+
background: none;
|
| 272 |
+
border: none;
|
| 273 |
+
color: #fff;
|
| 274 |
+
font-size: 1.5rem;
|
| 275 |
+
cursor: pointer;
|
| 276 |
+
}
|
z7273034591306_f2041027e92ac75073dc44d48a044a19.jpg
ADDED
|
Git LFS Details
|
z7273040168526_69abfd03e0779e60ce9b0b181353a68b.jpg
ADDED
|
Git LFS Details
|