Upload 5 files
Browse files- app.js +395 -0
- get-organized.html +122 -0
- index.html +162 -0
- resources.html +154 -0
- styles.css +796 -0
app.js
ADDED
@@ -0,0 +1,395 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// DOM Elements
|
2 |
+
const uploadArea = document.getElementById("uploadArea");
|
3 |
+
const imageInput = document.getElementById("imageInput");
|
4 |
+
const imagePreview = document.getElementById("imagePreview");
|
5 |
+
const submitButton = document.getElementById("submitButton");
|
6 |
+
const errorMessage = document.getElementById("errorMessage");
|
7 |
+
const resultSection = document.getElementById("result");
|
8 |
+
const resultStatus = document.getElementById("resultStatus");
|
9 |
+
const resultDescription = document.getElementById("resultDescription");
|
10 |
+
const probabilityValue = document.getElementById("probabilityValue");
|
11 |
+
const probabilityFill = document.getElementById("probabilityFill");
|
12 |
+
const likelyInfo = document.getElementById("likelyInfo");
|
13 |
+
const resultImage = document.getElementById("resultImage");
|
14 |
+
const actionButtons = document.getElementById("actionButtons");
|
15 |
+
const navButtons = document.querySelectorAll(".nav-button");
|
16 |
+
const pages = document.querySelectorAll(".page");
|
17 |
+
const resourceCategories = document.querySelectorAll(".resource-category");
|
18 |
+
const optInCheckbox = document.getElementById("optInCheckbox");
|
19 |
+
const contactInfoInput = document.getElementById("contactInfo");
|
20 |
+
const contactOptin = document.querySelector(".contact-optin");
|
21 |
+
|
22 |
+
// State
|
23 |
+
let selectedImage = null;
|
24 |
+
|
25 |
+
// Custom dropdown logic
|
26 |
+
const dropdownToggle = document.getElementById("dropdownToggle");
|
27 |
+
const dropdownMenu = document.getElementById("dropdownMenu");
|
28 |
+
const dropdownOptions = dropdownMenu
|
29 |
+
? dropdownMenu.querySelectorAll(".dropdown-option")
|
30 |
+
: [];
|
31 |
+
const selectedModelSpan = document.getElementById("selectedModel");
|
32 |
+
let selectedModelValue = "rupeshs/LCM-runwayml-stable-diffusion-v1-5";
|
33 |
+
const customDropdown = document.getElementById("modelDropdown");
|
34 |
+
|
35 |
+
// Loading animation
|
36 |
+
const loadingContainer = document.createElement("div");
|
37 |
+
loadingContainer.id = "loadingAnimation";
|
38 |
+
loadingContainer.style.display = "none";
|
39 |
+
loadingContainer.style.justifyContent = "center";
|
40 |
+
loadingContainer.style.alignItems = "center";
|
41 |
+
loadingContainer.style.flexDirection = "column";
|
42 |
+
loadingContainer.style.textAlign = "center";
|
43 |
+
loadingContainer.style.position = "absolute";
|
44 |
+
loadingContainer.style.top = "0";
|
45 |
+
loadingContainer.style.left = "0";
|
46 |
+
loadingContainer.style.width = "100%";
|
47 |
+
loadingContainer.style.height = "100%";
|
48 |
+
loadingContainer.style.zIndex = "2";
|
49 |
+
const loadingImg = document.createElement("img");
|
50 |
+
loadingImg.alt = "Loading...";
|
51 |
+
loadingImg.style.width = "64px";
|
52 |
+
loadingImg.style.height = "64px";
|
53 |
+
const loadingMsg = document.createElement("div");
|
54 |
+
loadingMsg.className = "loading-message";
|
55 |
+
loadingMsg.textContent = "Processing";
|
56 |
+
loadingContainer.appendChild(loadingImg);
|
57 |
+
loadingContainer.appendChild(loadingMsg);
|
58 |
+
resultSection.appendChild(loadingContainer);
|
59 |
+
let loadingFrame = 1;
|
60 |
+
let loadingInterval = null;
|
61 |
+
const resultContent = resultSection.querySelector(".result-content");
|
62 |
+
|
63 |
+
// About overlay logic
|
64 |
+
const aboutOverlay = document.getElementById("aboutOverlay");
|
65 |
+
const aboutCloseBtn = document.getElementById("aboutCloseBtn");
|
66 |
+
|
67 |
+
function showLoading() {
|
68 |
+
resultSection.hidden = false;
|
69 |
+
resultSection.style.display = "";
|
70 |
+
if (resultContent) resultContent.style.display = "none";
|
71 |
+
loadingContainer.style.display = "flex";
|
72 |
+
loadingFrame = 1;
|
73 |
+
updateLoadingFrame();
|
74 |
+
loadingInterval = setInterval(() => {
|
75 |
+
loadingFrame = (loadingFrame % 16) + 1;
|
76 |
+
updateLoadingFrame();
|
77 |
+
}, 60);
|
78 |
+
}
|
79 |
+
function hideLoading() {
|
80 |
+
loadingContainer.style.display = "none";
|
81 |
+
if (resultContent) resultContent.style.display = "";
|
82 |
+
if (loadingInterval) clearInterval(loadingInterval);
|
83 |
+
}
|
84 |
+
function updateLoadingFrame() {
|
85 |
+
loadingImg.src = `assets/Infer_LoadingAnimation/Property 1=Variant${loadingFrame}.svg`;
|
86 |
+
}
|
87 |
+
|
88 |
+
function hideResultSection() {
|
89 |
+
resultSection.hidden = true;
|
90 |
+
resultSection.style.display = "none";
|
91 |
+
if (likelyInfo) likelyInfo.hidden = true;
|
92 |
+
if (resultImage) resultImage.hidden = true;
|
93 |
+
if (resultContent) resultContent.style.display = "";
|
94 |
+
loadingContainer.style.display = "none";
|
95 |
+
}
|
96 |
+
|
97 |
+
function showResultSection() {
|
98 |
+
resultSection.hidden = false;
|
99 |
+
resultSection.style.display = "";
|
100 |
+
}
|
101 |
+
|
102 |
+
// Event Listeners
|
103 |
+
uploadArea.addEventListener("click", () => imageInput.click());
|
104 |
+
imageInput.addEventListener("change", handleImageUpload);
|
105 |
+
submitButton.addEventListener("click", handleSubmit);
|
106 |
+
navButtons.forEach((button) => {
|
107 |
+
button.addEventListener("click", () => {
|
108 |
+
const targetPage = button.dataset.page;
|
109 |
+
navigateToPage(targetPage);
|
110 |
+
});
|
111 |
+
});
|
112 |
+
|
113 |
+
// Hide result section initially
|
114 |
+
hideResultSection();
|
115 |
+
|
116 |
+
// Add drag and drop support
|
117 |
+
uploadArea.addEventListener("dragover", (e) => {
|
118 |
+
e.preventDefault();
|
119 |
+
e.stopPropagation();
|
120 |
+
uploadArea.classList.add("dragover");
|
121 |
+
});
|
122 |
+
|
123 |
+
uploadArea.addEventListener("dragleave", (e) => {
|
124 |
+
e.preventDefault();
|
125 |
+
e.stopPropagation();
|
126 |
+
uploadArea.classList.remove("dragover");
|
127 |
+
});
|
128 |
+
|
129 |
+
uploadArea.addEventListener("drop", (e) => {
|
130 |
+
e.preventDefault();
|
131 |
+
e.stopPropagation();
|
132 |
+
uploadArea.classList.remove("dragover");
|
133 |
+
const file = e.dataTransfer.files[0];
|
134 |
+
if (file && file.type.startsWith("image/")) {
|
135 |
+
handleImageUpload({ target: { files: [file] } });
|
136 |
+
}
|
137 |
+
});
|
138 |
+
|
139 |
+
// Resource category selection
|
140 |
+
resourceCategories.forEach((category) => {
|
141 |
+
category.addEventListener("click", () => {
|
142 |
+
resourceCategories.forEach((c) => c.classList.remove("active"));
|
143 |
+
category.classList.add("active");
|
144 |
+
});
|
145 |
+
});
|
146 |
+
|
147 |
+
// Functions
|
148 |
+
function handleImageUpload(event) {
|
149 |
+
const file = event.target.files[0];
|
150 |
+
if (!file) return;
|
151 |
+
|
152 |
+
if (!file.type.startsWith("image/")) {
|
153 |
+
showError("Please select an image file");
|
154 |
+
return;
|
155 |
+
}
|
156 |
+
|
157 |
+
selectedImage = file;
|
158 |
+
errorMessage.textContent = "";
|
159 |
+
submitButton.disabled = false;
|
160 |
+
|
161 |
+
// Hide result section when a new image is selected
|
162 |
+
hideResultSection();
|
163 |
+
|
164 |
+
// Hide contact opt-in on new upload
|
165 |
+
if (contactOptin) contactOptin.style.display = "none";
|
166 |
+
|
167 |
+
const reader = new FileReader();
|
168 |
+
reader.onload = (e) => {
|
169 |
+
imagePreview.src = e.target.result;
|
170 |
+
imagePreview.hidden = false;
|
171 |
+
document.querySelector(".upload-placeholder").style.display = "none";
|
172 |
+
};
|
173 |
+
reader.readAsDataURL(file);
|
174 |
+
}
|
175 |
+
|
176 |
+
async function handleSubmit() {
|
177 |
+
if (!selectedImage) {
|
178 |
+
showError("Please select an image first");
|
179 |
+
return;
|
180 |
+
}
|
181 |
+
|
182 |
+
submitButton.disabled = true;
|
183 |
+
errorMessage.textContent = "";
|
184 |
+
hideResultSection();
|
185 |
+
showLoading();
|
186 |
+
|
187 |
+
if (contactOptin) contactOptin.style.display = "none";
|
188 |
+
|
189 |
+
try {
|
190 |
+
const formData = new FormData();
|
191 |
+
formData.append("image", selectedImage);
|
192 |
+
formData.append("model", selectedModelValue);
|
193 |
+
// Only send opt-in if visible and checked
|
194 |
+
if (
|
195 |
+
contactOptin &&
|
196 |
+
contactOptin.style.display !== "none" &&
|
197 |
+
optInCheckbox &&
|
198 |
+
optInCheckbox.checked &&
|
199 |
+
contactInfoInput &&
|
200 |
+
contactInfoInput.value
|
201 |
+
) {
|
202 |
+
formData.append("opt_in", "true");
|
203 |
+
formData.append("contact_info", contactInfoInput.value);
|
204 |
+
} else {
|
205 |
+
formData.append("opt_in", "false");
|
206 |
+
}
|
207 |
+
|
208 |
+
const response = await fetch(
|
209 |
+
"https://s-ahal-infer.hf.space/api/check-membership",
|
210 |
+
{
|
211 |
+
method: "POST",
|
212 |
+
body: formData,
|
213 |
+
}
|
214 |
+
);
|
215 |
+
|
216 |
+
if (!response.ok) {
|
217 |
+
throw new Error(`Server responded with ${response.status}`);
|
218 |
+
}
|
219 |
+
|
220 |
+
const data = await response.json();
|
221 |
+
displayResult(data);
|
222 |
+
} catch (error) {
|
223 |
+
showError(`Error: ${error.message}`);
|
224 |
+
console.error("Error:", error);
|
225 |
+
hideLoading();
|
226 |
+
} finally {
|
227 |
+
submitButton.disabled = false;
|
228 |
+
}
|
229 |
+
}
|
230 |
+
|
231 |
+
function displayResult(data) {
|
232 |
+
const probability = data.probability * 100;
|
233 |
+
const isLikely = data.probability > 0.5;
|
234 |
+
|
235 |
+
resultStatus.textContent = isLikely ? "Likely" : "Unlikely";
|
236 |
+
const modelName = selectedModelSpan.textContent;
|
237 |
+
const desc = `This image <strong class='result-description-strong'>${
|
238 |
+
isLikely ? "probably is" : "is probably not"
|
239 |
+
}</strong> in the training data for the ${modelName} model.`;
|
240 |
+
resultDescription.innerHTML = desc;
|
241 |
+
probabilityValue.innerHTML = `<span class='result-percentage'>${probability.toFixed(
|
242 |
+
1
|
243 |
+
)}%</span>`;
|
244 |
+
probabilityFill.style.width = "0%";
|
245 |
+
setTimeout(() => {
|
246 |
+
probabilityFill.style.width = `${probability}%`;
|
247 |
+
}, 30);
|
248 |
+
|
249 |
+
if (imagePreview && resultImage) {
|
250 |
+
resultImage.src = imagePreview.src;
|
251 |
+
resultImage.hidden = false;
|
252 |
+
}
|
253 |
+
|
254 |
+
if (isLikely) {
|
255 |
+
likelyInfo.hidden = false;
|
256 |
+
let usersText = "";
|
257 |
+
if (typeof data.likely_count === "number" && data.likely_count > 1) {
|
258 |
+
usersText = `There are <strong>${
|
259 |
+
data.likely_count - 1
|
260 |
+
} other user-tested artworks</strong> that were found to likely be included in this model's training data.`;
|
261 |
+
}
|
262 |
+
likelyInfo.querySelector(".likely-users").innerHTML = usersText;
|
263 |
+
// Show contact opt-in below results
|
264 |
+
if (contactOptin) contactOptin.style.display = "";
|
265 |
+
} else {
|
266 |
+
likelyInfo.hidden = true;
|
267 |
+
if (contactOptin) contactOptin.style.display = "none";
|
268 |
+
}
|
269 |
+
|
270 |
+
hideLoading();
|
271 |
+
showResultSection();
|
272 |
+
}
|
273 |
+
|
274 |
+
function showError(message) {
|
275 |
+
errorMessage.textContent = message;
|
276 |
+
}
|
277 |
+
|
278 |
+
function navigateToPage(pageId) {
|
279 |
+
// Update active page
|
280 |
+
pages.forEach((page) => {
|
281 |
+
page.classList.remove("active");
|
282 |
+
if (page.id === pageId) {
|
283 |
+
page.classList.add("active");
|
284 |
+
}
|
285 |
+
});
|
286 |
+
|
287 |
+
// Update active nav button
|
288 |
+
navButtons.forEach((button) => {
|
289 |
+
button.classList.toggle("active", button.dataset.page === pageId);
|
290 |
+
});
|
291 |
+
|
292 |
+
// Scroll to top when changing pages
|
293 |
+
window.scrollTo(0, 0);
|
294 |
+
}
|
295 |
+
|
296 |
+
// Initialize
|
297 |
+
navigateToPage("model-select");
|
298 |
+
|
299 |
+
function closeDropdown() {
|
300 |
+
dropdownMenu.hidden = true;
|
301 |
+
dropdownToggle.setAttribute("aria-expanded", "false");
|
302 |
+
if (customDropdown) customDropdown.classList.remove("open");
|
303 |
+
}
|
304 |
+
|
305 |
+
function openDropdown() {
|
306 |
+
dropdownMenu.hidden = false;
|
307 |
+
dropdownToggle.setAttribute("aria-expanded", "true");
|
308 |
+
if (customDropdown) customDropdown.classList.add("open");
|
309 |
+
// Focus the selected option
|
310 |
+
const selected = dropdownMenu.querySelector(".dropdown-option.selected");
|
311 |
+
if (selected) selected.focus();
|
312 |
+
}
|
313 |
+
|
314 |
+
dropdownToggle.addEventListener("click", (e) => {
|
315 |
+
e.stopPropagation();
|
316 |
+
if (dropdownMenu.hidden) {
|
317 |
+
openDropdown();
|
318 |
+
} else {
|
319 |
+
closeDropdown();
|
320 |
+
}
|
321 |
+
});
|
322 |
+
|
323 |
+
dropdownOptions.forEach((option) => {
|
324 |
+
option.setAttribute("tabindex", "0");
|
325 |
+
option.addEventListener("click", (e) => {
|
326 |
+
dropdownOptions.forEach((opt) => opt.classList.remove("selected"));
|
327 |
+
option.classList.add("selected");
|
328 |
+
selectedModelSpan.textContent = option.textContent;
|
329 |
+
selectedModelValue = option.getAttribute("data-value");
|
330 |
+
closeDropdown();
|
331 |
+
});
|
332 |
+
option.addEventListener("keydown", (e) => {
|
333 |
+
if (e.key === "Enter" || e.key === " ") {
|
334 |
+
option.click();
|
335 |
+
} else if (e.key === "ArrowDown") {
|
336 |
+
e.preventDefault();
|
337 |
+
let next = option.nextElementSibling;
|
338 |
+
if (!next) next = dropdownMenu.firstElementChild;
|
339 |
+
next.focus();
|
340 |
+
} else if (e.key === "ArrowUp") {
|
341 |
+
e.preventDefault();
|
342 |
+
let prev = option.previousElementSibling;
|
343 |
+
if (!prev) prev = dropdownMenu.lastElementChild;
|
344 |
+
prev.focus();
|
345 |
+
} else if (e.key === "Escape") {
|
346 |
+
closeDropdown();
|
347 |
+
dropdownToggle.focus();
|
348 |
+
}
|
349 |
+
});
|
350 |
+
});
|
351 |
+
|
352 |
+
document.addEventListener("click", (e) => {
|
353 |
+
if (!dropdownMenu.hidden) {
|
354 |
+
closeDropdown();
|
355 |
+
}
|
356 |
+
});
|
357 |
+
dropdownToggle.addEventListener("keydown", (e) => {
|
358 |
+
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
|
359 |
+
openDropdown();
|
360 |
+
e.preventDefault();
|
361 |
+
}
|
362 |
+
});
|
363 |
+
|
364 |
+
document.addEventListener("keydown", (e) => {
|
365 |
+
if (e.key === "Escape") {
|
366 |
+
closeDropdown();
|
367 |
+
}
|
368 |
+
});
|
369 |
+
|
370 |
+
// Ensure About overlay logic runs after DOM is loaded
|
371 |
+
window.addEventListener("DOMContentLoaded", function () {
|
372 |
+
const aboutOverlay = document.getElementById("aboutOverlay");
|
373 |
+
const aboutCloseBtn = document.getElementById("aboutCloseBtn");
|
374 |
+
const aboutLink = Array.from(document.querySelectorAll(".nav-link")).find(
|
375 |
+
(link) => link.textContent.trim().toLowerCase() === "about"
|
376 |
+
);
|
377 |
+
if (aboutLink) {
|
378 |
+
aboutLink.addEventListener("click", function (e) {
|
379 |
+
e.preventDefault();
|
380 |
+
if (aboutOverlay) aboutOverlay.style.display = "flex";
|
381 |
+
});
|
382 |
+
}
|
383 |
+
if (aboutCloseBtn) {
|
384 |
+
aboutCloseBtn.addEventListener("click", function () {
|
385 |
+
if (aboutOverlay) aboutOverlay.style.display = "none";
|
386 |
+
});
|
387 |
+
}
|
388 |
+
if (aboutOverlay) {
|
389 |
+
aboutOverlay.addEventListener("click", function (e) {
|
390 |
+
if (e.target === aboutOverlay) {
|
391 |
+
aboutOverlay.style.display = "none";
|
392 |
+
}
|
393 |
+
});
|
394 |
+
}
|
395 |
+
});
|
get-organized.html
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>Infer</title>
|
7 |
+
<link rel="stylesheet" href="styles.css" />
|
8 |
+
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg" />
|
9 |
+
<link rel="icon" type="image/png" href="assets/favicon.png" />
|
10 |
+
</head>
|
11 |
+
<body>
|
12 |
+
<header class="main-header">
|
13 |
+
<div class="header-left">
|
14 |
+
<h1>
|
15 |
+
<a href="index.html" class="home-link"
|
16 |
+
>Infer <span class="star">❊</span></a
|
17 |
+
>
|
18 |
+
</h1>
|
19 |
+
<p class="subtitle">Making AI accountability tools for artists.</p>
|
20 |
+
</div>
|
21 |
+
<nav class="header-nav">
|
22 |
+
<a href="#" class="nav-link">About</a>
|
23 |
+
<span class="nav-separator">⎈</span>
|
24 |
+
<a href="resources.html" class="nav-link">Resources</a>
|
25 |
+
<span class="nav-separator">⎈</span>
|
26 |
+
<a href="mailto:[email protected]" class="nav-link">Contact</a>
|
27 |
+
</nav>
|
28 |
+
</header>
|
29 |
+
<main class="main-content">
|
30 |
+
<section class="get-organized-hero">
|
31 |
+
<h2>Get Organized</h2>
|
32 |
+
<p>Connect with others whose work has also been scraped.</p>
|
33 |
+
</section>
|
34 |
+
<div class="get-organized-columns">
|
35 |
+
<div class="get-organized-left">
|
36 |
+
<p class="big-number">
|
37 |
+
<strong>531 other users</strong> also have work that is likely in
|
38 |
+
the OpenAI CLIP model's training data.
|
39 |
+
</p>
|
40 |
+
<p class="not-alone">
|
41 |
+
<strong>You are not alone.</strong> Hundreds of artists are
|
42 |
+
impacted—many unknowingly.
|
43 |
+
</p>
|
44 |
+
<p class="explanation">
|
45 |
+
Your art may have helped train one of the most powerful AI models in
|
46 |
+
use today—without your consent. You're part of a growing group of
|
47 |
+
creators facing the same situation. This is a moment for collective
|
48 |
+
response.
|
49 |
+
</p>
|
50 |
+
<div class="together-list">
|
51 |
+
<p>Together, we can:</p>
|
52 |
+
<ul>
|
53 |
+
<li><strong>Explore legal options</strong></li>
|
54 |
+
<li><strong>Share tools and tactics</strong></li>
|
55 |
+
<li>
|
56 |
+
<strong>Coordinate public statements and campaigns</strong>
|
57 |
+
</li>
|
58 |
+
</ul>
|
59 |
+
</div>
|
60 |
+
</div>
|
61 |
+
<div class="get-organized-right">
|
62 |
+
<h3>Join the conversation.</h3>
|
63 |
+
<a class="org-btn" href="#"
|
64 |
+
><span>Join the mailing list</span
|
65 |
+
><img src="assets/email_icon.svg" alt="Email"
|
66 |
+
/></a>
|
67 |
+
<a class="org-btn" href="#"
|
68 |
+
><span>Connect on Discord</span
|
69 |
+
><img src="assets/discord_logo.svg" alt="Discord"
|
70 |
+
/></a>
|
71 |
+
<a class="org-btn" href="#"
|
72 |
+
><span>Connect on Signal</span
|
73 |
+
><img src="assets/signal_logo.svg" alt="Signal"
|
74 |
+
/></a>
|
75 |
+
</div>
|
76 |
+
</div>
|
77 |
+
</main>
|
78 |
+
<div id="aboutOverlay" class="about-overlay" style="display:none;">
|
79 |
+
<div class="about-modal">
|
80 |
+
<button class="about-close" id="aboutCloseBtn" aria-label="Close About">×</button>
|
81 |
+
<h2>About Infer</h2>
|
82 |
+
<p>
|
83 |
+
Infer helps artists and image creators check whether their work was likely used to train popular AI models. By comparing your image against model behaviors, we can estimate its presence in the training data—something that's often invisible by design.
|
84 |
+
</p>
|
85 |
+
<p>
|
86 |
+
If your image comes up as a likely match, you'll get two paths:
|
87 |
+
<ul>
|
88 |
+
<li>Protect Your Art with tools to cloak, license, or fight back</li>
|
89 |
+
<li>Get Organized with others facing the same issue—through legal coordination, shared resources, and community defense</li>
|
90 |
+
</ul>
|
91 |
+
</p>
|
92 |
+
</div>
|
93 |
+
</div>
|
94 |
+
<script>
|
95 |
+
document.addEventListener('DOMContentLoaded', function() {
|
96 |
+
var aboutOverlay = document.getElementById('aboutOverlay');
|
97 |
+
var aboutCloseBtn = document.getElementById('aboutCloseBtn');
|
98 |
+
var aboutLink = Array.from(document.querySelectorAll('.nav-link')).find(function(link) {
|
99 |
+
return link.textContent.trim().toLowerCase() === 'about';
|
100 |
+
});
|
101 |
+
if (aboutLink) {
|
102 |
+
aboutLink.addEventListener('click', function(e) {
|
103 |
+
e.preventDefault();
|
104 |
+
if (aboutOverlay) aboutOverlay.style.display = 'flex';
|
105 |
+
});
|
106 |
+
}
|
107 |
+
if (aboutCloseBtn) {
|
108 |
+
aboutCloseBtn.addEventListener('click', function() {
|
109 |
+
if (aboutOverlay) aboutOverlay.style.display = 'none';
|
110 |
+
});
|
111 |
+
}
|
112 |
+
if (aboutOverlay) {
|
113 |
+
aboutOverlay.addEventListener('click', function(e) {
|
114 |
+
if (e.target === aboutOverlay) {
|
115 |
+
aboutOverlay.style.display = 'none';
|
116 |
+
}
|
117 |
+
});
|
118 |
+
}
|
119 |
+
});
|
120 |
+
</script>
|
121 |
+
</body>
|
122 |
+
</html>
|
index.html
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>Infer</title>
|
7 |
+
<link rel="stylesheet" href="styles.css" />
|
8 |
+
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg" />
|
9 |
+
<link rel="icon" type="image/png" href="assets/favicon.png" />
|
10 |
+
</head>
|
11 |
+
<body>
|
12 |
+
<header class="main-header">
|
13 |
+
<div class="header-left">
|
14 |
+
<h1>
|
15 |
+
<a href="index.html" class="home-link"
|
16 |
+
>Infer <span class="star">❊</span></a
|
17 |
+
>
|
18 |
+
</h1>
|
19 |
+
<p class="subtitle">Making AI accountability tools for artists.</p>
|
20 |
+
</div>
|
21 |
+
<nav class="header-nav">
|
22 |
+
<a href="#" class="nav-link">About</a>
|
23 |
+
<span class="nav-separator">⎈</span>
|
24 |
+
<a href="resources.html" class="nav-link">Resources</a>
|
25 |
+
<span class="nav-separator">⎈</span>
|
26 |
+
<a href="mailto:[email protected]" class="nav-link">Contact</a>
|
27 |
+
</nav>
|
28 |
+
</header>
|
29 |
+
<main class="main-content">
|
30 |
+
<div class="home-columns">
|
31 |
+
<section class="upload-section" style="min-height: 540px">
|
32 |
+
<div class="card-header">
|
33 |
+
<h2>Model select</h2>
|
34 |
+
<p>Select an AI model to test against</p>
|
35 |
+
</div>
|
36 |
+
<div class="card-content">
|
37 |
+
<div class="model-selector">
|
38 |
+
<div class="custom-dropdown" id="modelDropdown">
|
39 |
+
<button
|
40 |
+
type="button"
|
41 |
+
class="dropdown-toggle"
|
42 |
+
id="dropdownToggle"
|
43 |
+
>
|
44 |
+
<span id="selectedModel">Runway Stable Diffusion v1.5</span>
|
45 |
+
<img
|
46 |
+
src="assets/arrow-down.svg"
|
47 |
+
alt="Dropdown arrow"
|
48 |
+
id="dropdown-arrow"
|
49 |
+
/>
|
50 |
+
</button>
|
51 |
+
<ul class="dropdown-menu" id="dropdownMenu" hidden>
|
52 |
+
<li
|
53 |
+
class="dropdown-option selected"
|
54 |
+
data-value="rupeshs/LCM-runwayml-stable-diffusion-v1-5"
|
55 |
+
>
|
56 |
+
Runway Stable Diffusion v1.5
|
57 |
+
</li>
|
58 |
+
<li
|
59 |
+
class="dropdown-option"
|
60 |
+
data-value="CompVis/stable-diffusion-v1-4"
|
61 |
+
>
|
62 |
+
CompVis Stable Diffusion v1.4
|
63 |
+
</li>
|
64 |
+
<li
|
65 |
+
class="dropdown-option"
|
66 |
+
data-value="prompthero/openjourney-v4"
|
67 |
+
>
|
68 |
+
OpenJourney v4
|
69 |
+
</li>
|
70 |
+
</ul>
|
71 |
+
</div>
|
72 |
+
</div>
|
73 |
+
<div class="upload-area" id="uploadArea">
|
74 |
+
<input type="file" id="imageInput" accept="image/*" hidden />
|
75 |
+
|
76 |
+
<div class="upload-placeholder">
|
77 |
+
<img
|
78 |
+
src="assets/upload-icon.svg"
|
79 |
+
alt="Upload"
|
80 |
+
id="uploadIcon"
|
81 |
+
/>
|
82 |
+
<p>Click or drag-and-drop to upload a file</p>
|
83 |
+
</div>
|
84 |
+
<img id="imagePreview" class="preview-image" hidden />
|
85 |
+
</div>
|
86 |
+
<div id="errorMessage" class="error-message"></div>
|
87 |
+
<button id="submitButton" class="submit-button" disabled>
|
88 |
+
<span>Let's go</span>
|
89 |
+
<span>⟶</span>
|
90 |
+
</button>
|
91 |
+
</div>
|
92 |
+
</section>
|
93 |
+
<section class="result-section" id="result" hidden>
|
94 |
+
<div class="result-content">
|
95 |
+
<div class="result-image-container">
|
96 |
+
<img id="resultImage" class="result-image" hidden />
|
97 |
+
</div>
|
98 |
+
<h2>Result: <span id="resultStatus"></span></h2>
|
99 |
+
<p id="resultDescription"></p>
|
100 |
+
<div class="probability-section">
|
101 |
+
<p>
|
102 |
+
Predicted membership probability:
|
103 |
+
<span id="probabilityValue"></span>
|
104 |
+
</p>
|
105 |
+
<div class="probability-bar">
|
106 |
+
<div id="probabilityFill" class="probability-fill"></div>
|
107 |
+
</div>
|
108 |
+
</div>
|
109 |
+
<div id="likelyInfo" class="likely-info" hidden>
|
110 |
+
<p class="likely-users">
|
111 |
+
There are <strong>531 other users</strong> that have work that
|
112 |
+
is likely in this model's training data.
|
113 |
+
</p>
|
114 |
+
<h3>What now?</h3>
|
115 |
+
<div class="result-actions">
|
116 |
+
<a href="resources.html" class="action-button"
|
117 |
+
>Protect your work <span class="arrow">⟶</span></a
|
118 |
+
>
|
119 |
+
<a href="get-organized.html" class="action-button"
|
120 |
+
>Get organized <span class="arrow">⟶</span></a
|
121 |
+
>
|
122 |
+
</div>
|
123 |
+
</div>
|
124 |
+
</div>
|
125 |
+
</section>
|
126 |
+
</div>
|
127 |
+
</main>
|
128 |
+
<!-- <div
|
129 |
+
class="contact-optin"
|
130 |
+
style="display: none; margin: 2em auto 0 auto; max-width: 400px"
|
131 |
+
>
|
132 |
+
<input type="checkbox" id="optInCheckbox" />
|
133 |
+
<label for="optInCheckbox"
|
134 |
+
>Notify me if there are updates about this project (optional):</label
|
135 |
+
>
|
136 |
+
<input
|
137 |
+
type="email"
|
138 |
+
id="contactInfo"
|
139 |
+
class="styled-input"
|
140 |
+
placeholder="Your email (optional)"
|
141 |
+
style="margin-left: 0.5em"
|
142 |
+
/>
|
143 |
+
</div> -->
|
144 |
+
<script src="app.js"></script>
|
145 |
+
<div id="aboutOverlay" class="about-overlay" style="display:none;">
|
146 |
+
<div class="about-modal">
|
147 |
+
<button class="about-close" id="aboutCloseBtn" aria-label="Close About">×</button>
|
148 |
+
<h2>About Infer</h2>
|
149 |
+
<p>
|
150 |
+
Infer helps artists and image creators check whether their work was likely used to train popular AI models. By comparing your image against model behaviors, we can estimate its presence in the training data—something that's often invisible by design.
|
151 |
+
</p>
|
152 |
+
<p>
|
153 |
+
If your image comes up as a likely match, you'll get two paths:
|
154 |
+
<ul>
|
155 |
+
<li>Protect Your Art with tools to cloak, license, or fight back</li>
|
156 |
+
<li>Get Organized with others facing the same issue—through legal coordination, shared resources, and community defense</li>
|
157 |
+
</ul>
|
158 |
+
</p>
|
159 |
+
</div>
|
160 |
+
</div>
|
161 |
+
</body>
|
162 |
+
</html>
|
resources.html
ADDED
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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>Infer</title>
|
7 |
+
<link rel="stylesheet" href="styles.css" />
|
8 |
+
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg" />
|
9 |
+
<link rel="icon" type="image/png" href="assets/favicon.png" />
|
10 |
+
</head>
|
11 |
+
<body>
|
12 |
+
<header class="main-header">
|
13 |
+
<div class="header-left">
|
14 |
+
<h1>
|
15 |
+
<a href="index.html" class="home-link"
|
16 |
+
>Infer <span class="star">❊</span></a
|
17 |
+
>
|
18 |
+
</h1>
|
19 |
+
<p class="subtitle">Making AI accountability tools for artists.</p>
|
20 |
+
</div>
|
21 |
+
<nav class="header-nav">
|
22 |
+
<a href="#" class="nav-link">About</a>
|
23 |
+
<span class="nav-separator">⎈</span>
|
24 |
+
<a href="resources.html" class="nav-link">Resources</a>
|
25 |
+
<span class="nav-separator">⎈</span>
|
26 |
+
<a href="mailto:[email protected]" class="nav-link">Contact</a>
|
27 |
+
</nav>
|
28 |
+
</header>
|
29 |
+
<main class="main-content">
|
30 |
+
<section class="resources-section">
|
31 |
+
<div class="card-header">
|
32 |
+
<h2>Resources</h2>
|
33 |
+
<p>
|
34 |
+
A compiled list of applications and legal resources to help you
|
35 |
+
protect your work.
|
36 |
+
</p>
|
37 |
+
</div>
|
38 |
+
<div class="resources-content">
|
39 |
+
<div class="resource-categories">
|
40 |
+
<button
|
41 |
+
class="resource-category active"
|
42 |
+
data-resource="do-not-train"
|
43 |
+
>
|
44 |
+
Do Not Train
|
45 |
+
</button>
|
46 |
+
<button class="resource-category" data-resource="nightshade">
|
47 |
+
Nightshade
|
48 |
+
</button>
|
49 |
+
<button class="resource-category" data-resource="glaze">
|
50 |
+
Glaze
|
51 |
+
</button>
|
52 |
+
<button class="resource-category" data-resource="copyright">
|
53 |
+
Copyright Resources
|
54 |
+
</button>
|
55 |
+
<button class="resource-category" data-resource="licensing">
|
56 |
+
Licensing Options
|
57 |
+
</button>
|
58 |
+
</div>
|
59 |
+
<div class="resource-details">
|
60 |
+
<img
|
61 |
+
src="assets/nightshade-preview.png"
|
62 |
+
alt="Nightshade Preview"
|
63 |
+
class="resource-preview"
|
64 |
+
style="display: none"
|
65 |
+
/>
|
66 |
+
<div class="resource-info" id="resource-info">
|
67 |
+
<!-- JS will inject content here -->
|
68 |
+
</div>
|
69 |
+
</div>
|
70 |
+
</div>
|
71 |
+
</section>
|
72 |
+
</main>
|
73 |
+
<div id="aboutOverlay" class="about-overlay" style="display:none;">
|
74 |
+
<div class="about-modal">
|
75 |
+
<button class="about-close" id="aboutCloseBtn" aria-label="Close About">×</button>
|
76 |
+
<h2>About Infer</h2>
|
77 |
+
<p>
|
78 |
+
Infer helps artists and image creators check whether their work was likely used to train popular AI models. By comparing your image against model behaviors, we can estimate its presence in the training data—something that's often invisible by design.
|
79 |
+
</p>
|
80 |
+
<p>
|
81 |
+
If your image comes up as a likely match, you'll get two paths:
|
82 |
+
<ul>
|
83 |
+
<li>Protect Your Art with tools to cloak, license, or fight back</li>
|
84 |
+
<li>Get Organized with others facing the same issue—through legal coordination, shared resources, and community defense</li>
|
85 |
+
</ul>
|
86 |
+
</p>
|
87 |
+
</div>
|
88 |
+
</div>
|
89 |
+
<script>
|
90 |
+
const resourceData = {
|
91 |
+
"do-not-train": {
|
92 |
+
title: "Do Not Train",
|
93 |
+
html: `<strong>What It Is:</strong> A simple metadata tag artists can add to their images to declare they don't consent to their work being used for training AI.<br><strong>How To Use:</strong> Add a do-not-train tag to your website's HTML or use platforms that support the tag.<br><strong>Note:</strong> It's not enforceable yet, but signals intent for future protections.<br><a href='https://spawning.ai/rightsholders-faq' class='action-button' target='_blank'><span>Learn more</span><span class='arrow'>⟶</span></a>`,
|
94 |
+
},
|
95 |
+
nightshade: {
|
96 |
+
title: "Nightshade",
|
97 |
+
html: `<strong>What It Is:</strong> A tool that poisons your artwork's pixels—imperceptibly to humans, but disruptive to training algorithms.<br><strong>Why It Works:</strong> It corrupts how AI models interpret your work, deterring them from using it.<br><a href='https://nightshade.cs.uchicago.edu/' class='action-button' target='_blank'><span>Try it out</span><span class='arrow'>⟶</span></a>`,
|
98 |
+
},
|
99 |
+
glaze: {
|
100 |
+
title: "Glaze",
|
101 |
+
html: `<strong>What It Is:</strong> A style cloak that protects your artistic fingerprint.<br><strong>What It Does:</strong> Applies a subtle, AI-visible filter that makes your work harder to mimic.<br><strong>Best For:</strong> Artists with a strong visual signature.<br><a href='https://glaze.cs.uchicago.edu/' class='action-button' target='_blank'><span>Try it out</span><span class='arrow'>⟶</span></a>`,
|
102 |
+
},
|
103 |
+
copyright: {
|
104 |
+
title: "Copyright Resources",
|
105 |
+
html: `<strong>Understand Your Rights:</strong><br>In many countries, your work is protected the moment it's created—but enforcing that is another story.<br><br><u>Includes:</u><ul><li>How to formally register your copyright</li><li>Templates for takedown notices</li><li>Intro to fair use & derivative work laws</li></ul>`,
|
106 |
+
},
|
107 |
+
licensing: {
|
108 |
+
title: "Licensing Tools",
|
109 |
+
html: `<strong>Put Terms in Writing:</strong><br>Use free or paid licenses to explicitly control how your work can be used.<br><br><u>Options to Explore:</u><ul><li>Creative Commons with "no AI use" clauses</li><li>Personal licensing agreements</li><li>Open-source licenses adapted for artists</li></ul>`,
|
110 |
+
},
|
111 |
+
};
|
112 |
+
const categories = document.querySelectorAll(".resource-category");
|
113 |
+
const info = document.getElementById("resource-info");
|
114 |
+
function showResource(key) {
|
115 |
+
categories.forEach((btn) =>
|
116 |
+
btn.classList.toggle("active", btn.dataset.resource === key)
|
117 |
+
);
|
118 |
+
info.innerHTML = `<h3>${resourceData[key].title}</h3><p>${resourceData[key].html}</p>`;
|
119 |
+
}
|
120 |
+
categories.forEach((btn) => {
|
121 |
+
btn.addEventListener("click", () => showResource(btn.dataset.resource));
|
122 |
+
});
|
123 |
+
// Show default
|
124 |
+
showResource("do-not-train");
|
125 |
+
</script>
|
126 |
+
<script>
|
127 |
+
document.addEventListener('DOMContentLoaded', function() {
|
128 |
+
var aboutOverlay = document.getElementById('aboutOverlay');
|
129 |
+
var aboutCloseBtn = document.getElementById('aboutCloseBtn');
|
130 |
+
var aboutLink = Array.from(document.querySelectorAll('.nav-link')).find(function(link) {
|
131 |
+
return link.textContent.trim().toLowerCase() === 'about';
|
132 |
+
});
|
133 |
+
if (aboutLink) {
|
134 |
+
aboutLink.addEventListener('click', function(e) {
|
135 |
+
e.preventDefault();
|
136 |
+
if (aboutOverlay) aboutOverlay.style.display = 'flex';
|
137 |
+
});
|
138 |
+
}
|
139 |
+
if (aboutCloseBtn) {
|
140 |
+
aboutCloseBtn.addEventListener('click', function() {
|
141 |
+
if (aboutOverlay) aboutOverlay.style.display = 'none';
|
142 |
+
});
|
143 |
+
}
|
144 |
+
if (aboutOverlay) {
|
145 |
+
aboutOverlay.addEventListener('click', function(e) {
|
146 |
+
if (e.target === aboutOverlay) {
|
147 |
+
aboutOverlay.style.display = 'none';
|
148 |
+
}
|
149 |
+
});
|
150 |
+
}
|
151 |
+
});
|
152 |
+
</script>
|
153 |
+
</body>
|
154 |
+
</html>
|
styles.css
ADDED
@@ -0,0 +1,796 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
@import url("https://fonts.googleapis.com/css?family=Hepta+Slab:400,200|Karla:400,700");
|
2 |
+
|
3 |
+
:root {
|
4 |
+
--primary-color: #e7503e;
|
5 |
+
--background-color: #fefefa;
|
6 |
+
--card-background: #fffde5;
|
7 |
+
--text-color: #e7503e;
|
8 |
+
--border-radius: 4px;
|
9 |
+
}
|
10 |
+
|
11 |
+
* {
|
12 |
+
margin: 0;
|
13 |
+
padding: 0;
|
14 |
+
box-sizing: border-box;
|
15 |
+
}
|
16 |
+
|
17 |
+
body {
|
18 |
+
font-family: "Karla", Helvetica, sans-serif;
|
19 |
+
line-height: 1.6;
|
20 |
+
color: var(--text-color);
|
21 |
+
background-color: var(--background-color);
|
22 |
+
}
|
23 |
+
|
24 |
+
.main-header {
|
25 |
+
display: flex;
|
26 |
+
justify-content: space-between;
|
27 |
+
align-items: flex-start;
|
28 |
+
padding: 1.2rem 40px 0 40px;
|
29 |
+
max-width: 950px;
|
30 |
+
margin: 0 auto;
|
31 |
+
}
|
32 |
+
|
33 |
+
.header-left h1 {
|
34 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
35 |
+
font-weight: 200;
|
36 |
+
font-size: 42px;
|
37 |
+
color: var(--primary-color);
|
38 |
+
margin-bottom: 0.3rem;
|
39 |
+
line-height: 1;
|
40 |
+
}
|
41 |
+
|
42 |
+
.header-left .star {
|
43 |
+
font-size: 1.1em;
|
44 |
+
vertical-align: middle;
|
45 |
+
}
|
46 |
+
|
47 |
+
.subtitle {
|
48 |
+
font-size: 1rem;
|
49 |
+
color: var(--primary-color);
|
50 |
+
font-family: "Karla", Helvetica, sans-serif;
|
51 |
+
}
|
52 |
+
|
53 |
+
.header-nav {
|
54 |
+
display: flex;
|
55 |
+
align-items: center;
|
56 |
+
gap: 12px;
|
57 |
+
margin-top: 0.3rem;
|
58 |
+
}
|
59 |
+
|
60 |
+
.nav-link {
|
61 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
62 |
+
font-size: 1.1rem;
|
63 |
+
color: var(--primary-color);
|
64 |
+
text-decoration: none;
|
65 |
+
transition: text-decoration 0.2s;
|
66 |
+
}
|
67 |
+
|
68 |
+
.nav-link:hover {
|
69 |
+
text-decoration: underline;
|
70 |
+
}
|
71 |
+
|
72 |
+
.nav-separator {
|
73 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
74 |
+
font-size: 1.1rem;
|
75 |
+
color: var(--primary-color);
|
76 |
+
}
|
77 |
+
|
78 |
+
.main-content {
|
79 |
+
max-width: 950px;
|
80 |
+
margin: 0 auto;
|
81 |
+
padding: 1.2rem 40px 1.2rem 40px;
|
82 |
+
}
|
83 |
+
|
84 |
+
.home-columns {
|
85 |
+
display: flex;
|
86 |
+
gap: 8rem;
|
87 |
+
align-items: flex-start;
|
88 |
+
}
|
89 |
+
|
90 |
+
.upload-section {
|
91 |
+
flex: 1 1 0;
|
92 |
+
min-width: 260px;
|
93 |
+
max-width: 400px;
|
94 |
+
background: var(--card-background);
|
95 |
+
border: 2px dashed var(--primary-color);
|
96 |
+
border-radius: var(--border-radius);
|
97 |
+
padding: 0;
|
98 |
+
margin: 0;
|
99 |
+
min-height: 540px;
|
100 |
+
}
|
101 |
+
|
102 |
+
.card-header {
|
103 |
+
background-color: var(--primary-color);
|
104 |
+
color: white;
|
105 |
+
padding: 10px 14px;
|
106 |
+
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
107 |
+
}
|
108 |
+
|
109 |
+
.card-header h2 {
|
110 |
+
color: white;
|
111 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
112 |
+
font-size: 1.3rem;
|
113 |
+
margin-bottom: 0.2rem;
|
114 |
+
}
|
115 |
+
|
116 |
+
.card-header p {
|
117 |
+
color: white;
|
118 |
+
font-size: 0.9rem;
|
119 |
+
}
|
120 |
+
|
121 |
+
.card-content {
|
122 |
+
padding: 1rem 1rem 1.2rem 1rem;
|
123 |
+
background-color: var(--card-background);
|
124 |
+
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
125 |
+
min-height: 400px;
|
126 |
+
}
|
127 |
+
|
128 |
+
.model-selector {
|
129 |
+
margin-bottom: 0.7rem;
|
130 |
+
}
|
131 |
+
|
132 |
+
.model-select {
|
133 |
+
width: 100%;
|
134 |
+
padding: 0.3rem 2rem 0.3rem 0.7rem;
|
135 |
+
font-family: "Karla", Helvetica, sans-serif;
|
136 |
+
font-size: 1rem;
|
137 |
+
color: var(--primary-color);
|
138 |
+
border: 2px dashed var(--primary-color);
|
139 |
+
background-color: white;
|
140 |
+
border-radius: var(--border-radius);
|
141 |
+
appearance: none;
|
142 |
+
background-image: url('data:image/svg+xml;utf8,<svg fill="%23e7503e" height="20" viewBox="0 0 24 24" width="20" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/></svg>');
|
143 |
+
background-repeat: no-repeat;
|
144 |
+
background-position: right 0.5rem center;
|
145 |
+
background-size: 1.1em;
|
146 |
+
box-sizing: border-box;
|
147 |
+
transition: border-color 0.2s;
|
148 |
+
}
|
149 |
+
|
150 |
+
.model-select:focus {
|
151 |
+
outline: none;
|
152 |
+
border-color: var(--primary-color);
|
153 |
+
}
|
154 |
+
|
155 |
+
/* Style the dropdown options (limited by browser support) */
|
156 |
+
.model-select option {
|
157 |
+
color: var(--primary-color);
|
158 |
+
font-family: "Karla", Helvetica, sans-serif;
|
159 |
+
font-size: 1rem;
|
160 |
+
background: white;
|
161 |
+
}
|
162 |
+
|
163 |
+
/* Chrome/Edge: highlight selected/hovered option */
|
164 |
+
.model-select option:checked,
|
165 |
+
.model-select option:focus,
|
166 |
+
.model-select option:hover {
|
167 |
+
background: var(--primary-color);
|
168 |
+
color: white;
|
169 |
+
}
|
170 |
+
|
171 |
+
/* Firefox: highlight selected option */
|
172 |
+
@-moz-document url-prefix() {
|
173 |
+
.model-select option:checked {
|
174 |
+
background: var(--primary-color) !important;
|
175 |
+
color: white !important;
|
176 |
+
}
|
177 |
+
}
|
178 |
+
|
179 |
+
.upload-area {
|
180 |
+
border: 2px dashed var(--primary-color);
|
181 |
+
border-radius: var(--border-radius);
|
182 |
+
padding: 1.1rem;
|
183 |
+
text-align: center;
|
184 |
+
cursor: pointer;
|
185 |
+
transition: border-color 0.3s ease;
|
186 |
+
margin-bottom: 0.7rem;
|
187 |
+
background: rgba(255, 255, 255, 0.32);
|
188 |
+
}
|
189 |
+
|
190 |
+
.upload-area:hover {
|
191 |
+
border-color: var(--primary-color);
|
192 |
+
}
|
193 |
+
|
194 |
+
.upload-placeholder {
|
195 |
+
display: flex;
|
196 |
+
flex-direction: column;
|
197 |
+
align-items: center;
|
198 |
+
gap: 0.7rem;
|
199 |
+
color: var(--primary-color);
|
200 |
+
font-size: 0.95rem;
|
201 |
+
}
|
202 |
+
|
203 |
+
.upload-placeholder img {
|
204 |
+
width: 32px;
|
205 |
+
height: auto;
|
206 |
+
opacity: 0.5;
|
207 |
+
}
|
208 |
+
|
209 |
+
.preview-image {
|
210 |
+
max-width: 100%;
|
211 |
+
max-height: 300px;
|
212 |
+
border-radius: var(--border-radius);
|
213 |
+
margin: 0.7rem 0;
|
214 |
+
}
|
215 |
+
|
216 |
+
.submit-button {
|
217 |
+
background-color: white;
|
218 |
+
color: var(--primary-color);
|
219 |
+
border: 2px solid var(--primary-color);
|
220 |
+
padding: 0.7rem 1.2rem;
|
221 |
+
border-radius: var(--border-radius);
|
222 |
+
cursor: pointer;
|
223 |
+
width: 100%;
|
224 |
+
font-size: 1rem;
|
225 |
+
font-family: "Karla", Helvetica, sans-serif;
|
226 |
+
display: flex;
|
227 |
+
align-items: center;
|
228 |
+
justify-content: center;
|
229 |
+
margin: 1rem 0 0 0;
|
230 |
+
gap: 0.7rem;
|
231 |
+
transition: background 0.2s, color 0.2s;
|
232 |
+
}
|
233 |
+
|
234 |
+
.submit-button:disabled {
|
235 |
+
opacity: 0.5;
|
236 |
+
cursor: not-allowed;
|
237 |
+
}
|
238 |
+
|
239 |
+
.submit-button:hover:not(:disabled) {
|
240 |
+
background-color: var(--primary-color);
|
241 |
+
color: white;
|
242 |
+
}
|
243 |
+
|
244 |
+
.error-message {
|
245 |
+
color: var(--primary-color);
|
246 |
+
margin: 0.7rem 0;
|
247 |
+
text-align: center;
|
248 |
+
font-family: "Karla", Helvetica, sans-serif;
|
249 |
+
font-size: 0.95rem;
|
250 |
+
}
|
251 |
+
|
252 |
+
.result-section {
|
253 |
+
flex: 1 1 0;
|
254 |
+
min-width: 260px;
|
255 |
+
max-width: 400px;
|
256 |
+
background: none;
|
257 |
+
padding: 0 0 0 0;
|
258 |
+
margin: 0;
|
259 |
+
display: flex;
|
260 |
+
flex-direction: column;
|
261 |
+
align-items: stretch;
|
262 |
+
justify-content: center;
|
263 |
+
position: relative;
|
264 |
+
width: 100%;
|
265 |
+
min-height: 350px;
|
266 |
+
}
|
267 |
+
|
268 |
+
.result-image-container {
|
269 |
+
width: 100%;
|
270 |
+
margin-bottom: 0.3rem;
|
271 |
+
text-align: center;
|
272 |
+
}
|
273 |
+
|
274 |
+
.result-image {
|
275 |
+
max-height: 400px;
|
276 |
+
max-width: 400px;
|
277 |
+
width: auto;
|
278 |
+
border: 2px dashed var(--primary-color);
|
279 |
+
border-radius: var(--border-radius);
|
280 |
+
object-fit: contain;
|
281 |
+
display: block;
|
282 |
+
margin-left: auto;
|
283 |
+
margin-right: auto;
|
284 |
+
}
|
285 |
+
|
286 |
+
.result-image-label {
|
287 |
+
font-size: 0.8rem;
|
288 |
+
color: #e7503ebf;
|
289 |
+
margin-top: 0.1rem;
|
290 |
+
font-family: "Karla", Helvetica, sans-serif;
|
291 |
+
}
|
292 |
+
|
293 |
+
.result-section h2 {
|
294 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
295 |
+
font-size: 1.1rem;
|
296 |
+
color: var(--primary-color);
|
297 |
+
margin: 0.7rem 0 0.3rem 0;
|
298 |
+
}
|
299 |
+
|
300 |
+
#resultDescription {
|
301 |
+
color: var(--primary-color);
|
302 |
+
font-size: 0.95rem;
|
303 |
+
margin-bottom: 0.3rem;
|
304 |
+
}
|
305 |
+
|
306 |
+
.probability-section {
|
307 |
+
margin: 0.7rem 0 0.3rem 0;
|
308 |
+
width: 100%;
|
309 |
+
}
|
310 |
+
|
311 |
+
.probability-bar {
|
312 |
+
width: 100%;
|
313 |
+
height: 16px;
|
314 |
+
background-color: #f8f5c8;
|
315 |
+
border-radius: var(--border-radius);
|
316 |
+
overflow: hidden;
|
317 |
+
margin-top: 0.3rem;
|
318 |
+
box-sizing: border-box;
|
319 |
+
}
|
320 |
+
|
321 |
+
.probability-fill {
|
322 |
+
height: 100%;
|
323 |
+
background-color: var(--primary-color);
|
324 |
+
border-radius: 4px 0 0 4px;
|
325 |
+
transition: width 0.8s cubic-bezier(0.4, 1.4, 0.6, 1);
|
326 |
+
}
|
327 |
+
|
328 |
+
.likely-info {
|
329 |
+
margin-top: 1rem;
|
330 |
+
}
|
331 |
+
|
332 |
+
.likely-users {
|
333 |
+
color: var(--primary-color);
|
334 |
+
font-size: 0.95rem;
|
335 |
+
margin-bottom: 0.7rem;
|
336 |
+
}
|
337 |
+
|
338 |
+
.result-section h3 {
|
339 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
340 |
+
font-size: 1rem;
|
341 |
+
color: var(--primary-color);
|
342 |
+
margin: 0.7rem 0 0.3rem 0;
|
343 |
+
}
|
344 |
+
|
345 |
+
.result-actions {
|
346 |
+
display: flex;
|
347 |
+
flex-direction: column;
|
348 |
+
gap: 0.7rem;
|
349 |
+
margin-top: 0.7rem;
|
350 |
+
}
|
351 |
+
|
352 |
+
.action-button {
|
353 |
+
background: white;
|
354 |
+
color: var(--primary-color);
|
355 |
+
border: 2px solid var(--primary-color);
|
356 |
+
border-radius: var(--border-radius);
|
357 |
+
padding: 0.7rem 1.2rem;
|
358 |
+
font-size: 1rem;
|
359 |
+
font-family: "Karla", Helvetica, sans-serif;
|
360 |
+
text-align: center;
|
361 |
+
text-decoration: none;
|
362 |
+
display: flex;
|
363 |
+
align-items: center;
|
364 |
+
justify-content: center;
|
365 |
+
gap: 0.7rem;
|
366 |
+
transition: background 0.2s, color 0.2s;
|
367 |
+
}
|
368 |
+
|
369 |
+
.action-button:hover {
|
370 |
+
background: var(--primary-color);
|
371 |
+
color: white;
|
372 |
+
text-decoration: none;
|
373 |
+
}
|
374 |
+
|
375 |
+
.arrow {
|
376 |
+
font-size: 1.1em;
|
377 |
+
margin-left: 0.3em;
|
378 |
+
}
|
379 |
+
|
380 |
+
@media (max-width: 900px) {
|
381 |
+
.main-header,
|
382 |
+
.main-content {
|
383 |
+
padding: 0.7rem 2vw 0 2vw;
|
384 |
+
}
|
385 |
+
.home-columns {
|
386 |
+
flex-direction: column;
|
387 |
+
gap: 1rem;
|
388 |
+
}
|
389 |
+
.upload-section,
|
390 |
+
.result-section {
|
391 |
+
max-width: 100%;
|
392 |
+
min-width: 0;
|
393 |
+
}
|
394 |
+
}
|
395 |
+
|
396 |
+
.custom-dropdown {
|
397 |
+
position: relative;
|
398 |
+
width: 100%;
|
399 |
+
}
|
400 |
+
|
401 |
+
.dropdown-toggle {
|
402 |
+
width: 100%;
|
403 |
+
background: white;
|
404 |
+
color: var(--primary-color);
|
405 |
+
border: 2px dashed var(--primary-color);
|
406 |
+
border-radius: var(--border-radius);
|
407 |
+
font-family: "Karla", Helvetica, sans-serif;
|
408 |
+
font-size: 1rem;
|
409 |
+
padding: 0 0 0 0.7rem;
|
410 |
+
text-align: left;
|
411 |
+
display: flex;
|
412 |
+
align-items: center;
|
413 |
+
justify-content: space-between;
|
414 |
+
cursor: pointer;
|
415 |
+
transition: border-color 0.2s;
|
416 |
+
box-sizing: border-box;
|
417 |
+
}
|
418 |
+
|
419 |
+
#dropdown-arrow {
|
420 |
+
background-color: #e7503e;
|
421 |
+
border-radius: 0 4px 4px 0;
|
422 |
+
}
|
423 |
+
|
424 |
+
.dropdown-menu {
|
425 |
+
position: static;
|
426 |
+
width: 100%;
|
427 |
+
background: white;
|
428 |
+
border: 2px dashed var(--primary-color);
|
429 |
+
border-top: none;
|
430 |
+
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
431 |
+
box-shadow: none;
|
432 |
+
z-index: 1;
|
433 |
+
margin: 0;
|
434 |
+
list-style: none;
|
435 |
+
max-height: 0;
|
436 |
+
overflow: hidden;
|
437 |
+
transition: max-height 0.25s cubic-bezier(0.4, 1.4, 0.6, 1);
|
438 |
+
}
|
439 |
+
|
440 |
+
.custom-dropdown.open .dropdown-menu {
|
441 |
+
max-height: 400px;
|
442 |
+
transition: max-height 0.35s cubic-bezier(0.4, 1.4, 0.6, 1);
|
443 |
+
}
|
444 |
+
|
445 |
+
.dropdown-option {
|
446 |
+
font-family: "Karla", Helvetica, sans-serif;
|
447 |
+
font-size: 1rem;
|
448 |
+
color: var(--primary-color);
|
449 |
+
background: white;
|
450 |
+
padding: 0.6rem 1rem;
|
451 |
+
cursor: pointer;
|
452 |
+
transition: background 0.15s, color 0.15s;
|
453 |
+
border: none;
|
454 |
+
outline: none;
|
455 |
+
}
|
456 |
+
|
457 |
+
.dropdown-option.selected,
|
458 |
+
.dropdown-option:hover,
|
459 |
+
.dropdown-option:focus {
|
460 |
+
background: var(--primary-color);
|
461 |
+
color: white;
|
462 |
+
}
|
463 |
+
|
464 |
+
.custom-dropdown.open .dropdown-toggle {
|
465 |
+
border-bottom: none;
|
466 |
+
border-bottom-left-radius: 0;
|
467 |
+
border-bottom-right-radius: 0;
|
468 |
+
box-shadow: 0 4px 16px rgba(231, 80, 62, 0.1);
|
469 |
+
transition: box-shadow 0.2s;
|
470 |
+
}
|
471 |
+
|
472 |
+
.custom-dropdown.open .dropdown-menu {
|
473 |
+
border-top-left-radius: 0;
|
474 |
+
border-top-right-radius: 0;
|
475 |
+
}
|
476 |
+
|
477 |
+
.result-percentage {
|
478 |
+
font-weight: bold;
|
479 |
+
}
|
480 |
+
|
481 |
+
.result-description-strong {
|
482 |
+
font-weight: bold;
|
483 |
+
}
|
484 |
+
|
485 |
+
#loadingAnimation {
|
486 |
+
display: none;
|
487 |
+
position: absolute;
|
488 |
+
top: 0;
|
489 |
+
left: 0;
|
490 |
+
right: 0;
|
491 |
+
bottom: 0;
|
492 |
+
width: 100%;
|
493 |
+
height: 100%;
|
494 |
+
/* background: none; */
|
495 |
+
z-index: 2;
|
496 |
+
justify-content: center;
|
497 |
+
align-items: center;
|
498 |
+
flex-direction: column;
|
499 |
+
text-align: center;
|
500 |
+
}
|
501 |
+
|
502 |
+
#loadingAnimation img {
|
503 |
+
width: 64px;
|
504 |
+
height: 64px;
|
505 |
+
margin-bottom: 1rem;
|
506 |
+
}
|
507 |
+
|
508 |
+
#loadingAnimation .loading-message {
|
509 |
+
font-family: "Karla", Helvetica, sans-serif;
|
510 |
+
color: var(--primary-color);
|
511 |
+
font-size: 1.1rem;
|
512 |
+
}
|
513 |
+
|
514 |
+
/* --- Footer Styles --- */
|
515 |
+
.main-footer {
|
516 |
+
text-align: center;
|
517 |
+
font-size: 0.95em;
|
518 |
+
color: #e7503e;
|
519 |
+
margin-top: 3rem;
|
520 |
+
padding: 1.5rem 0 0.5rem 0;
|
521 |
+
background: none;
|
522 |
+
}
|
523 |
+
.footer-nav .nav-link {
|
524 |
+
color: #e7503e;
|
525 |
+
text-decoration: none;
|
526 |
+
margin: 0 0.5em;
|
527 |
+
}
|
528 |
+
.footer-nav .nav-separator {
|
529 |
+
color: #e7503e;
|
530 |
+
margin: 0 0.2em;
|
531 |
+
}
|
532 |
+
|
533 |
+
/* --- Get Organized Page Styles --- */
|
534 |
+
.get-organized-hero {
|
535 |
+
background: #e4573d;
|
536 |
+
color: #fff;
|
537 |
+
padding: 2rem 1.5rem 1rem 1.5rem;
|
538 |
+
border-radius: 4px;
|
539 |
+
margin-bottom: 2rem;
|
540 |
+
}
|
541 |
+
.get-organized-hero h2 {
|
542 |
+
font-size: 2.2rem;
|
543 |
+
margin-bottom: 0.2em;
|
544 |
+
}
|
545 |
+
.get-organized-hero p {
|
546 |
+
font-size: 1.1rem;
|
547 |
+
margin: 0;
|
548 |
+
}
|
549 |
+
.get-organized-columns {
|
550 |
+
display: flex;
|
551 |
+
gap: 3rem;
|
552 |
+
margin-top: 2rem;
|
553 |
+
flex-wrap: wrap;
|
554 |
+
}
|
555 |
+
.get-organized-left {
|
556 |
+
flex: 2;
|
557 |
+
min-width: 320px;
|
558 |
+
}
|
559 |
+
.get-organized-right {
|
560 |
+
flex: 1.2;
|
561 |
+
min-width: 260px;
|
562 |
+
display: flex;
|
563 |
+
flex-direction: column;
|
564 |
+
align-items: flex-start;
|
565 |
+
}
|
566 |
+
.big-number {
|
567 |
+
font-size: 1.5rem;
|
568 |
+
color: #e4573d;
|
569 |
+
font-weight: 700;
|
570 |
+
margin-bottom: 1.2rem;
|
571 |
+
}
|
572 |
+
.not-alone {
|
573 |
+
color: #e4573d;
|
574 |
+
font-weight: 600;
|
575 |
+
margin-bottom: 1rem;
|
576 |
+
}
|
577 |
+
.explanation {
|
578 |
+
color: #b85c4c;
|
579 |
+
margin-bottom: 1.5rem;
|
580 |
+
}
|
581 |
+
.together-list ul {
|
582 |
+
margin: 0.5em 0 0 1.2em;
|
583 |
+
padding: 0;
|
584 |
+
color: #e4573d;
|
585 |
+
}
|
586 |
+
.together-list li {
|
587 |
+
margin-bottom: 0.5em;
|
588 |
+
font-weight: 600;
|
589 |
+
}
|
590 |
+
.get-organized-right h3 {
|
591 |
+
color: #e4573d;
|
592 |
+
font-size: 1.3rem;
|
593 |
+
margin-bottom: 1.2rem;
|
594 |
+
}
|
595 |
+
.org-btn {
|
596 |
+
display: flex;
|
597 |
+
align-items: center;
|
598 |
+
border: 2px solid #e4573d;
|
599 |
+
color: #e4573d;
|
600 |
+
background: none;
|
601 |
+
border-radius: 6px;
|
602 |
+
padding: 0.8em 1.2em;
|
603 |
+
font-size: 1.15rem;
|
604 |
+
font-weight: 500;
|
605 |
+
margin-bottom: 1.1em;
|
606 |
+
text-decoration: none;
|
607 |
+
transition: background 0.15s, color 0.15s;
|
608 |
+
}
|
609 |
+
.org-btn img {
|
610 |
+
width: 1.5em;
|
611 |
+
height: 1.5em;
|
612 |
+
margin-left: 0.7em;
|
613 |
+
}
|
614 |
+
.org-btn:hover {
|
615 |
+
background: #e4573d;
|
616 |
+
color: #fff;
|
617 |
+
}
|
618 |
+
|
619 |
+
.home-link {
|
620 |
+
color: inherit;
|
621 |
+
text-decoration: none;
|
622 |
+
}
|
623 |
+
.home-link:hover {
|
624 |
+
text-decoration: none;
|
625 |
+
}
|
626 |
+
|
627 |
+
.resource-categories {
|
628 |
+
display: flex;
|
629 |
+
flex-direction: column;
|
630 |
+
gap: 0.7rem;
|
631 |
+
width: 320px;
|
632 |
+
}
|
633 |
+
.resource-category {
|
634 |
+
background: none;
|
635 |
+
border: 2px dashed #e7503e;
|
636 |
+
color: #e7503e;
|
637 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
638 |
+
font-size: 1.15rem;
|
639 |
+
padding: 0.8em 1.2em;
|
640 |
+
border-radius: 6px;
|
641 |
+
text-align: left;
|
642 |
+
cursor: pointer;
|
643 |
+
transition: background 0.15s, color 0.15s;
|
644 |
+
}
|
645 |
+
.resource-category.active {
|
646 |
+
background: #e7503e;
|
647 |
+
color: #fff;
|
648 |
+
border-style: solid;
|
649 |
+
}
|
650 |
+
.resources-content {
|
651 |
+
display: flex;
|
652 |
+
gap: 2.5rem;
|
653 |
+
margin-top: 2.5rem;
|
654 |
+
}
|
655 |
+
.resource-details {
|
656 |
+
flex: 1 1 0;
|
657 |
+
min-width: 340px;
|
658 |
+
max-width: 500px;
|
659 |
+
background: none;
|
660 |
+
border: 2px dashed #e7503e;
|
661 |
+
border-radius: 6px;
|
662 |
+
padding: 2.2rem 2.2rem 2.2rem 2.2rem;
|
663 |
+
display: flex;
|
664 |
+
flex-direction: column;
|
665 |
+
align-items: flex-start;
|
666 |
+
justify-content: flex-start;
|
667 |
+
}
|
668 |
+
.resource-preview {
|
669 |
+
width: 100%;
|
670 |
+
max-width: 340px;
|
671 |
+
margin-bottom: 1.2rem;
|
672 |
+
border-radius: 6px;
|
673 |
+
border: 2px dashed #e7503e;
|
674 |
+
display: none;
|
675 |
+
}
|
676 |
+
.resource-info h3 {
|
677 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
678 |
+
font-size: 2rem;
|
679 |
+
color: #e7503e;
|
680 |
+
margin-bottom: 1.1rem;
|
681 |
+
margin-top: 0;
|
682 |
+
}
|
683 |
+
.resource-info p {
|
684 |
+
color: #e7503e;
|
685 |
+
font-size: 1.1rem;
|
686 |
+
margin-bottom: 1.5rem;
|
687 |
+
}
|
688 |
+
.resource-info ul {
|
689 |
+
margin: 0.7em 0 0 1.2em;
|
690 |
+
padding: 0;
|
691 |
+
color: #e7503e;
|
692 |
+
}
|
693 |
+
.resource-info li {
|
694 |
+
margin-bottom: 0.5em;
|
695 |
+
font-weight: 600;
|
696 |
+
}
|
697 |
+
.resource-info .action-button {
|
698 |
+
background: white;
|
699 |
+
color: #e7503e;
|
700 |
+
border: 2px solid #e7503e;
|
701 |
+
border-radius: 6px;
|
702 |
+
padding: 0.7rem 1.2rem;
|
703 |
+
font-size: 1.1rem;
|
704 |
+
font-family: "Karla", Helvetica, sans-serif;
|
705 |
+
text-align: center;
|
706 |
+
text-decoration: none;
|
707 |
+
display: inline-flex;
|
708 |
+
align-items: center;
|
709 |
+
gap: 0.7rem;
|
710 |
+
transition: background 0.2s, color 0.2s;
|
711 |
+
margin-top: 1.2rem;
|
712 |
+
}
|
713 |
+
.resource-info .action-button:hover {
|
714 |
+
background: #e7503e;
|
715 |
+
color: white;
|
716 |
+
text-decoration: none;
|
717 |
+
}
|
718 |
+
|
719 |
+
.styled-input {
|
720 |
+
width: 260px;
|
721 |
+
padding: 0.3rem 2rem 0.3rem 0.7rem;
|
722 |
+
font-family: "Karla", Helvetica, sans-serif;
|
723 |
+
font-size: 1rem;
|
724 |
+
color: var(--primary-color);
|
725 |
+
border: 2px dashed var(--primary-color);
|
726 |
+
background-color: white;
|
727 |
+
border-radius: var(--border-radius);
|
728 |
+
box-sizing: border-box;
|
729 |
+
transition: border-color 0.2s;
|
730 |
+
outline: none;
|
731 |
+
margin-top: 0.5em;
|
732 |
+
}
|
733 |
+
.styled-input:focus {
|
734 |
+
border-color: var(--primary-color);
|
735 |
+
}
|
736 |
+
|
737 |
+
.about-overlay {
|
738 |
+
position: fixed;
|
739 |
+
top: 0;
|
740 |
+
left: 0;
|
741 |
+
right: 0;
|
742 |
+
bottom: 0;
|
743 |
+
background: rgba(231, 80, 62, 0.12);
|
744 |
+
z-index: 1000;
|
745 |
+
display: flex;
|
746 |
+
align-items: center;
|
747 |
+
justify-content: center;
|
748 |
+
}
|
749 |
+
|
750 |
+
.about-modal {
|
751 |
+
background: #fff;
|
752 |
+
border-radius: 8px;
|
753 |
+
max-width: 420px;
|
754 |
+
width: 90vw;
|
755 |
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
|
756 |
+
border: 6px solid #e4573d;
|
757 |
+
padding: 0 0 1.5em 0;
|
758 |
+
position: relative;
|
759 |
+
font-size: 1.1rem;
|
760 |
+
color: #e4573d;
|
761 |
+
margin: 2em 0;
|
762 |
+
}
|
763 |
+
|
764 |
+
.about-modal h2 {
|
765 |
+
background: #e4573d;
|
766 |
+
color: #fff;
|
767 |
+
font-family: "Hepta Slab", Helvetica, sans-serif;
|
768 |
+
font-size: 2rem;
|
769 |
+
margin: 0 0 1em 0;
|
770 |
+
padding: 0.7em 1.2em 0.5em 1.2em;
|
771 |
+
border-radius: 6px 6px 0 0;
|
772 |
+
}
|
773 |
+
|
774 |
+
.about-modal p {
|
775 |
+
margin: 1.2em 1.5em 0.5em 1.5em;
|
776 |
+
color: #e4573d;
|
777 |
+
font-size: 1.08rem;
|
778 |
+
}
|
779 |
+
|
780 |
+
.about-modal ul {
|
781 |
+
margin: 0.7em 2.2em 1em 2.2em;
|
782 |
+
color: #e4573d;
|
783 |
+
font-size: 1.08rem;
|
784 |
+
}
|
785 |
+
|
786 |
+
.about-close {
|
787 |
+
position: absolute;
|
788 |
+
top: 0.5em;
|
789 |
+
right: 1em;
|
790 |
+
background: none;
|
791 |
+
border: none;
|
792 |
+
font-size: 2rem;
|
793 |
+
color: #fff;
|
794 |
+
cursor: pointer;
|
795 |
+
z-index: 10;
|
796 |
+
}
|