From f7c7f9920de7b7178e161d2ff7c22543bfb90705 Mon Sep 17 00:00:00 2001 From: Sanjeev Deori Date: Sun, 19 Oct 2025 21:45:28 +0530 Subject: [PATCH 1/2] Add a Random Password Generator along with its README.md --- .../RandomPasswordGenrator/README.md | 65 ++++ .../RandomPasswordGenrator/index.html | 78 +++++ .../RandomPasswordGenrator/script.js | 285 ++++++++++++++++++ .../RandomPasswordGenrator/styles.css | 113 +++++++ 4 files changed, 541 insertions(+) create mode 100644 Domains/Frontend/MiniProjects/RandomPasswordGenrator/README.md create mode 100644 Domains/Frontend/MiniProjects/RandomPasswordGenrator/index.html create mode 100644 Domains/Frontend/MiniProjects/RandomPasswordGenrator/script.js create mode 100644 Domains/Frontend/MiniProjects/RandomPasswordGenrator/styles.css diff --git a/Domains/Frontend/MiniProjects/RandomPasswordGenrator/README.md b/Domains/Frontend/MiniProjects/RandomPasswordGenrator/README.md new file mode 100644 index 00000000..3484704a --- /dev/null +++ b/Domains/Frontend/MiniProjects/RandomPasswordGenrator/README.md @@ -0,0 +1,65 @@ +# ๐Ÿ” Secure Password Generator + +**Contributor:** [Sanjeev Deori](https://github.com/SanjeevDeori) + +## ๐Ÿงพ Description +A **secure and customizable password generator** web app that helps users create strong passwords for online accounts. Includes options for password length, character types, live strength estimation, and the ability to save passwords locally. + +--- + +## ๐Ÿš€ Features +- Generate passwords of user-defined length +- Include options for: + - Uppercase letters (Aโ€“Z) + - Lowercase letters (aโ€“z) + - Numbers (0โ€“9) + - Symbols (!@#$%^&*) +- Copy password to clipboard +- Display password strength visually +- Save generated passwords locally +- Responsive layout for desktop and mobile + +--- + +## ๐Ÿ’ก Bonus Features +- Dark/Light mode toggle +- Save passwords with custom labels +- Manage saved passwords: Copy, Use, Delete +- LocalStorage-backed saved password list + +--- + +## ๐Ÿงฉ Tech Stack +- **HTML5** โ€“ Structure and layout +- **CSS3** โ€“ Styling, responsiveness, and dark/light theme +- **JavaScript (Vanilla)** โ€“ Password generation logic, clipboard functionality, localStorage + +--- + +## ๐Ÿ•น๏ธ How to Use +1. Open `index.html` in your browser. +2. Select the desired password length and character options. +3. Click **Generate** to create a new password. +4. Use the **Copy** button to copy it to the clipboard. +5. Optionally, save the password with a label using the **Save** button. +6. View, use, or delete saved passwords in the saved passwords section. + +--- + +## ๐Ÿ“ธ Screenshots +*(Add screenshots or GIFs here to showcase the UI, dark/light mode, and saved passwords feature.)* + +--- + +## ๐Ÿ—๏ธ Setup & Run Locally +1. Clone the repository: + ```bash + git clone https://github.com/SanjeevDeori/password-generator.git + +2. Open the project folder: +```bash + +cd password-generator + + +3. Open index.html in your browser to use the app. \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/RandomPasswordGenrator/index.html b/Domains/Frontend/MiniProjects/RandomPasswordGenrator/index.html new file mode 100644 index 00000000..0e243586 --- /dev/null +++ b/Domains/Frontend/MiniProjects/RandomPasswordGenrator/index.html @@ -0,0 +1,78 @@ + + + + + + Password Generator + + + +
+
+

Secure Password Generator

+
+ +
+
+ +
+

Create a password

+ +
+ +
+ + +
+
+ +
+
+ + +
+ +
+ Include + + + + +
+ +
+ +
+ +
+ +
โ€”
+
+
+
+ +
+

Saved Passwords

+
+ + +
+
    +
    + +
    +
    + +
    + Built with โค๏ธ โ€ข HTML โ€ข CSS โ€ข JavaScript +
    +
    + + + + diff --git a/Domains/Frontend/MiniProjects/RandomPasswordGenrator/script.js b/Domains/Frontend/MiniProjects/RandomPasswordGenrator/script.js new file mode 100644 index 00000000..25b787bd --- /dev/null +++ b/Domains/Frontend/MiniProjects/RandomPasswordGenrator/script.js @@ -0,0 +1,285 @@ +// script.js +(() => { + // Character sets + const SETS = { + upper: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + lower: "abcdefghijklmnopqrstuvwxyz", + numbers: "0123456789", + symbols: "!@#$%^&*()_+[]{}|;:,.<>?/~`-=", + }; + + // Elements + const passwordOutput = document.getElementById("passwordOutput"); + const lengthRange = document.getElementById("lengthRange"); + const lengthValue = document.getElementById("lengthValue"); + const upper = document.getElementById("upper"); + const lower = document.getElementById("lower"); + const numbers = document.getElementById("numbers"); + const symbols = document.getElementById("symbols"); + const generateBtn = document.getElementById("generateBtn"); + const copyBtn = document.getElementById("copyBtn"); + const saveBtn = document.getElementById("saveBtn"); + const meterFill = document.getElementById("meterFill"); + const strengthLabel = document.getElementById("strengthLabel"); + const saveForm = document.getElementById("saveForm"); + const saveLabel = document.getElementById("saveLabel"); + const savedList = document.getElementById("savedList"); + const clearAllBtn = document.getElementById("clearAllBtn"); + const themeToggle = document.getElementById("themeToggle"); + + // LocalStorage keys + const LS_SAVED = "pwgen_saved"; + const LS_THEME = "pwgen_theme"; + + // Helper: random integer + function randInt(max) { + return Math.floor(Math.random() * max); + } + + // Generate password + function generatePassword(length) { + const chosenSets = []; + if (upper.checked) chosenSets.push(SETS.upper); + if (lower.checked) chosenSets.push(SETS.lower); + if (numbers.checked) chosenSets.push(SETS.numbers); + if (symbols.checked) chosenSets.push(SETS.symbols); + + if (!chosenSets.length) { + alert("Select at least one character type."); + return ""; + } + + // Ensure at least one from each chosen set for better strength + const guaranteed = chosenSets.map(s => s[randInt(s.length)]); + let allChars = chosenSets.join(""); + let remaining = length - guaranteed.length; + let resultChars = []; + + for (let i = 0; i < remaining; i++) { + resultChars.push(allChars[randInt(allChars.length)]); + } + + // merge guaranteed and remaining and shuffle + resultChars = resultChars.concat(guaranteed); + // Fisher-Yates shuffle + for (let i = resultChars.length - 1; i > 0; i--) { + const j = randInt(i + 1); + [resultChars[i], resultChars[j]] = [resultChars[j], resultChars[i]]; + } + + return resultChars.join(""); + } + + // Strength estimator (simple, intuitive) + function estimateStrength(pw) { + let pool = 0; + if (/[A-Z]/.test(pw)) pool += 26; + if (/[a-z]/.test(pw)) pool += 26; + if (/[0-9]/.test(pw)) pool += 10; + if (/[^A-Za-z0-9]/.test(pw)) pool += 32; + + // entropy bits ~ length * log2(pool) + let bits = pw.length * (pool ? Math.log2(pool) : 0); + // normalize into 0-100 + const score = Math.max(0, Math.min(100, Math.round((bits / 60) * 100))); + + let label = "Too weak"; + if (score < 25) label = "Weak"; + else if (score < 50) label = "Fair"; + else if (score < 75) label = "Good"; + else label = "Excellent"; + + return { score, label, bits: Math.round(bits) }; + } + + // Update strength UI + function updateStrengthUI(pw) { + if (!pw) { + meterFill.style.width = "0%"; + strengthLabel.textContent = "โ€”"; + meterFill.style.background = "transparent"; + return; + } + const { score, label } = estimateStrength(pw); + meterFill.style.width = `${score}%`; + strengthLabel.textContent = label; + // color mapping + if (score < 25) meterFill.style.background = "#ff5f5f"; + else if (score < 50) meterFill.style.background = "#ffb86b"; + else if (score < 75) meterFill.style.background = "#ffd86b"; + else meterFill.style.background = "#7cf59b"; + } + + // Save/Load saved passwords + function loadSaved() { + try { + const raw = localStorage.getItem(LS_SAVED); + return raw ? JSON.parse(raw) : []; + } catch { + return []; + } + } + function saveSaved(list) { + localStorage.setItem(LS_SAVED, JSON.stringify(list)); + } + + function renderSaved() { + const items = loadSaved(); + savedList.innerHTML = ""; + if (!items.length) { + savedList.innerHTML = ``; + return; + } + items.forEach((it, idx) => { + const li = document.createElement("li"); + li.className = "saved-item"; + const meta = document.createElement("div"); + meta.className = "saved-meta"; + meta.innerHTML = `${escapeHtml(it.label || "Untitled")}
    ${escapeHtml(it.value)}
    ${new Date(it.date).toLocaleString()}
    `; + const actions = document.createElement("div"); + actions.style.display = "flex"; + actions.style.gap = "6px"; + const copy = document.createElement("button"); + copy.className = "btn small"; + copy.textContent = "Copy"; + copy.addEventListener("click", () => { + copyToClipboard(it.value); + flash(copy, "Copied!"); + }); + const use = document.createElement("button"); + use.className = "btn small"; + use.textContent = "Use"; + use.addEventListener("click", () => { + passwordOutput.value = it.value; + updateStrengthUI(it.value); + }); + const del = document.createElement("button"); + del.className = "btn small"; + del.textContent = "Delete"; + del.addEventListener("click", () => { + const itemsNow = loadSaved(); + itemsNow.splice(idx, 1); + saveSaved(itemsNow); + renderSaved(); + }); + actions.appendChild(copy); + actions.appendChild(use); + actions.appendChild(del); + li.appendChild(meta); + li.appendChild(actions); + savedList.appendChild(li); + }); + } + + // Utilities + function escapeHtml(s) { + return String(s).replace(/[&<>"']/g, m => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[m])); + } + + function copyToClipboard(text) { + if (!navigator.clipboard) { + // fallback + const ta = document.createElement("textarea"); + ta.value = text; + document.body.appendChild(ta); + ta.select(); + try { document.execCommand("copy"); } catch {} + ta.remove(); + return; + } + return navigator.clipboard.writeText(text); + } + + function flash(el, text = "Done") { + const original = el.textContent; + el.textContent = text; + setTimeout(() => (el.textContent = original), 1200); + } + + // Theme + function initTheme() { + const saved = localStorage.getItem(LS_THEME); + if (saved === "dark") { + document.body.classList.add("dark"); + themeToggle.checked = true; + } else { + document.body.classList.remove("dark"); + themeToggle.checked = false; + } + } + themeToggle.addEventListener("change", () => { + if (themeToggle.checked) { + document.body.classList.add("dark"); + localStorage.setItem(LS_THEME, "dark"); + } else { + document.body.classList.remove("dark"); + localStorage.setItem(LS_THEME, "light"); + } + }); + + // Events + lengthRange.addEventListener("input", () => { + lengthValue.textContent = lengthRange.value; + }); + + generateBtn.addEventListener("click", (e) => { + e.preventDefault(); + const len = parseInt(lengthRange.value, 10); + const pw = generatePassword(len); + passwordOutput.value = pw; + updateStrengthUI(pw); + }); + + // generate on load + window.addEventListener("load", () => { + initTheme(); + lengthValue.textContent = lengthRange.value; + // initial generate + const initial = generatePassword(parseInt(lengthRange.value, 10)); + passwordOutput.value = initial; + updateStrengthUI(initial); + renderSaved(); + }); + + // real-time strength update if someone edits the output (rare) + passwordOutput.addEventListener("input", (e) => { + updateStrengthUI(e.target.value); + }); + + copyBtn.addEventListener("click", async () => { + if (!passwordOutput.value) return; + try { + await copyToClipboard(passwordOutput.value); + flash(copyBtn, "Copied!"); + } catch { + flash(copyBtn, "Copy"); + } + }); + + // Save current + saveBtn.addEventListener("click", (e) => { + e.preventDefault(); + const current = passwordOutput.value; + if (!current) { alert("No password to save."); return; } + const labelText = saveLabel.value.trim(); + const list = loadSaved(); + list.unshift({ value: current, label: labelText || "Untitled", date: new Date().toISOString() }); + saveSaved(list); + saveLabel.value = ""; + renderSaved(); + flash(saveBtn, "Saved!"); + }); + + // Save via form (label + save) + saveForm.addEventListener("submit", (e) => { + e.preventDefault(); + saveBtn.click(); + }); + + clearAllBtn.addEventListener("click", () => { + if (!confirm("Clear all saved passwords?")) return; + localStorage.removeItem(LS_SAVED); + renderSaved(); + }); + +})(); diff --git a/Domains/Frontend/MiniProjects/RandomPasswordGenrator/styles.css b/Domains/Frontend/MiniProjects/RandomPasswordGenrator/styles.css new file mode 100644 index 00000000..819cda86 --- /dev/null +++ b/Domains/Frontend/MiniProjects/RandomPasswordGenrator/styles.css @@ -0,0 +1,113 @@ + + +:root{ + --bg:#f4f7fb; + --card:#ffffff; + --text:#17202a; + --muted:#536170; + --accent:#0066ff; + --danger:#e64c65; + --radius:12px; + --glass: rgba(255,255,255,0.6); +} + +*{box-sizing:border-box} +html,body{height:100%} +body{ + margin:0; + font-family:Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial; + background:linear-gradient(180deg,var(--bg),#e9eef6); + color:var(--text); + -webkit-font-smoothing:antialiased; + -moz-osx-font-smoothing:grayscale; +} + +.container{ + max-width:980px; + margin:28px auto; + padding:20px; +} + +/* header */ +.header{ + display:flex; + justify-content:space-between; + align-items:center; + gap:16px; + margin-bottom:18px; +} +.header h1{margin:0;font-size:1.4rem} +.theme-toggle{display:flex;align-items:center;gap:8px;font-size:0.9rem} +.theme-toggle input{width:18px;height:18px} + +/* cards */ +.card{ + background:var(--card); + border-radius:var(--radius); + padding:16px; + box-shadow:0 6px 18px rgba(23,32,42,0.06); + margin-bottom:16px; +} + +/* output */ +.output-row{display:flex;gap:8px;align-items:center} +.password-output{ + flex:1; + padding:12px 14px; + border-radius:10px; + border:1px solid #e6eef7; + font-family:monospace; + font-size:1rem; + color:var(--text); +} +.output-actions{display:flex;gap:8px} +.btn{ + border:0;padding:8px 12px;border-radius:8px;cursor:pointer;background:#f0f6ff; +} +.btn.small{padding:6px 10px} +.btn.primary{background:linear-gradient(90deg,var(--accent),#3aa1ff);color:white} +.btn.danger{background:linear-gradient(90deg,var(--danger),#ff7b8f);color:white} + +/* controls */ +.controls{display:grid;grid-template-columns:1fr;gap:12px;margin-top:12px} +.control{display:flex;flex-direction:column;gap:6px} +.control label{font-size:0.9rem;color:var(--muted)} +input[type="range"]{width:100%} +.checkboxes{display:flex;flex-wrap:wrap;gap:10px;padding:10px;border-radius:8px;background:var(--glass);border:1px solid #eef6ff} +.checkboxes label{font-size:0.9rem} + +/* meter */ +.meter-row{display:flex;align-items:center;gap:12px;margin-top:8px} +.strength-meter{flex:1;height:12px;background:#eef7ff;border-radius:999px;overflow:hidden;border:1px solid #e1efff} +.meter-fill{height:100%;width:0%;transition:width 240ms ease} +.strength-label{min-width:90px;text-align:right;font-weight:600;color:var(--muted)} + +/* saved */ +.save-form{display:flex;gap:8px;margin-bottom:10px} +.save-form input{flex:1;padding:9px;border-radius:8px;border:1px solid #e6eef7} +.saved-list{list-style:none;padding:0;margin:0;display:grid;gap:8px;max-height:260px;overflow:auto} +.saved-item{ + display:flex;align-items:center;gap:8px;padding:8px;border-radius:8px;border:1px solid #eef6ff;background:#fbfdff; +} +.saved-meta{flex:1;font-size:0.9rem;word-break:break-all} +.saved-actions{display:flex;justify-content:flex-end;margin-top:8px} + +/* footer */ +.footer{margin-top:10px;text-align:center;color:var(--muted)} + +/* responsive */ +@media (min-width:720px){ + .controls{grid-template-columns:repeat(2,1fr)} +} + +/* dark theme */ +body.dark{ + --bg:#0f1720; + --card:#0b1220; + --text:#e6eef8; + --muted:#a8b3c3; + --accent:#4ea6ff; + --danger:#ff8f9b; + background:linear-gradient(180deg,#071018,#081218); +} +body.dark .password-output{background:#071427;color:var(--text);border-color:#0f2436} From b139b7dfc951eeebfb03aa0c4080c047751b6995 Mon Sep 17 00:00:00 2001 From: Sanjeev Deori Date: Sun, 19 Oct 2025 21:54:28 +0530 Subject: [PATCH 2/2] Created a BMI calculator and added README.md along with necessary folder and files --- .../MiniProjects/BMICalculator/README.md | 58 ++++++++++ .../MiniProjects/BMICalculator/index.html | 45 ++++++++ .../MiniProjects/BMICalculator/script.js | 58 ++++++++++ .../MiniProjects/BMICalculator/styles.css | 109 ++++++++++++++++++ 4 files changed, 270 insertions(+) create mode 100644 Domains/Frontend/MiniProjects/BMICalculator/README.md create mode 100644 Domains/Frontend/MiniProjects/BMICalculator/index.html create mode 100644 Domains/Frontend/MiniProjects/BMICalculator/script.js create mode 100644 Domains/Frontend/MiniProjects/BMICalculator/styles.css diff --git a/Domains/Frontend/MiniProjects/BMICalculator/README.md b/Domains/Frontend/MiniProjects/BMICalculator/README.md new file mode 100644 index 00000000..9a2d372b --- /dev/null +++ b/Domains/Frontend/MiniProjects/BMICalculator/README.md @@ -0,0 +1,58 @@ +# ๐Ÿ‹๏ธโ€โ™‚๏ธ BMI Calculator + +**Contributor:** [Sanjeev Deori](https://github.com/SanjeevDeori) + +## ๐Ÿงพ Description +A **simple and responsive BMI Calculator** web app that allows users to calculate their Body Mass Index (BMI) based on weight and height. The app provides instant health feedback with animated results and supports dark/light mode. + +--- + +## ๐Ÿš€ Features +- Input fields for **weight (kg)** and **height (cm)** +- Calculate BMI on button click +- Display **BMI value** and **health category** + - Underweight + - Normal + - Overweight + - Obese +- Responsive design for mobile and desktop + +--- + +## ๐Ÿ’ก Bonus Features +- Dark/Light mode toggle +- Animated feedback when displaying BMI result + +--- + +## ๐Ÿงฉ Tech Stack +- **HTML5** โ€“ Structure and layout +- **CSS3** โ€“ Styling, responsiveness, dark/light theme +- **JavaScript (Vanilla)** โ€“ BMI calculation, animations, theme toggle + +--- + +## ๐Ÿ•น๏ธ How to Use +1. Open `index.html` in your browser. +2. Enter your **weight (kg)** and **height (cm)**. +3. Click **Calculate BMI**. +4. View your BMI value and category with animated feedback. +5. Toggle **Dark/Light mode** using the checkbox in the header. + +--- + +## ๐Ÿ“ธ Screenshots +*(Add screenshots or GIFs here to showcase the UI, BMI calculation, and dark/light mode.)* + +--- + +## ๐Ÿ—๏ธ Setup & Run Locally +1. Clone the repository: + ```bash + git clone https://github.com/SanjeevDeori/bmi-calculator.git +2. Navigate to the project folder: +```bash +cd bmi-calculator + + +3. Open index.html in your browser. \ No newline at end of file diff --git a/Domains/Frontend/MiniProjects/BMICalculator/index.html b/Domains/Frontend/MiniProjects/BMICalculator/index.html new file mode 100644 index 00000000..55bc08a7 --- /dev/null +++ b/Domains/Frontend/MiniProjects/BMICalculator/index.html @@ -0,0 +1,45 @@ + + + + + + BMI Calculator + + + +
    +
    +

    BMI Calculator

    + +
    + +
    +
    + + +
    + +
    + + +
    + + + +
    +

    Your BMI: โ€”

    +

    Category: โ€”

    +
    +
    + +
    + Built with โค๏ธ โ€ข HTML โ€ข CSS โ€ข JavaScript +
    +
    + + + + diff --git a/Domains/Frontend/MiniProjects/BMICalculator/script.js b/Domains/Frontend/MiniProjects/BMICalculator/script.js new file mode 100644 index 00000000..3ab3788b --- /dev/null +++ b/Domains/Frontend/MiniProjects/BMICalculator/script.js @@ -0,0 +1,58 @@ +// script.js + +const weightInput = document.getElementById("weight"); +const heightInput = document.getElementById("height"); +const calculateBtn = document.getElementById("calculateBtn"); +const bmiValue = document.getElementById("bmiValue"); +const bmiCategory = document.getElementById("bmiCategory"); +const resultDiv = document.getElementById("result"); +const themeToggle = document.getElementById("themeToggle"); + +// Dark/Light mode +function initTheme() { + const saved = localStorage.getItem("bmi_theme"); + if(saved==="dark") document.body.classList.add("dark"), themeToggle.checked=true; +} +initTheme(); + +themeToggle.addEventListener("change", () => { + if(themeToggle.checked){ + document.body.classList.add("dark"); + localStorage.setItem("bmi_theme","dark"); + }else{ + document.body.classList.remove("dark"); + localStorage.setItem("bmi_theme","light"); + } +}); + +// BMI Calculation +function calculateBMI(){ + const weight = parseFloat(weightInput.value); + const heightCm = parseFloat(heightInput.value); + if(!weight || !heightCm){ + alert("Please enter valid weight and height"); + return; + } + + const heightM = heightCm / 100; + const bmi = weight / (heightM * heightM); + const roundedBMI = bmi.toFixed(1); + bmiValue.textContent = roundedBMI; + + let category = ""; + let color = ""; + + if(bmi<18.5){category="Underweight"; color="#ffd86b";} + else if(bmi<25){category="Normal"; color="#7cf59b";} + else if(bmi<30){category="Overweight"; color="#ffb86b";} + else{category="Obese"; color="#ff5f5f";} + + bmiCategory.textContent = category; + resultDiv.style.color = color; + + // Simple animation + resultDiv.style.transform="scale(1.1)"; + setTimeout(()=>resultDiv.style.transform="scale(1)",300); +} + +calculateBtn.addEventListener("click", calculateBMI); diff --git a/Domains/Frontend/MiniProjects/BMICalculator/styles.css b/Domains/Frontend/MiniProjects/BMICalculator/styles.css new file mode 100644 index 00000000..f016b119 --- /dev/null +++ b/Domains/Frontend/MiniProjects/BMICalculator/styles.css @@ -0,0 +1,109 @@ +:root { + --bg: #f4f7fb; + --card: #ffffff; + --text: #17202a; + --muted: #536170; + --accent: #0066ff; + --radius: 12px; + --danger: #e64c65; + --success: #3ae374; +} + +*{box-sizing:border-box;} +body{ + margin:0; + font-family:Inter, sans-serif; + background: var(--bg); + color: var(--text); + display:flex; + justify-content:center; + align-items:flex-start; + min-height:100vh; + padding:20px; + transition: background 0.3s, color 0.3s; +} + +.container{ + max-width: 400px; + width:100%; +} + +.header{ + display:flex; + justify-content:space-between; + align-items:center; + margin-bottom:16px; +} + +.header h1{margin:0;font-size:1.6rem;} +.theme-toggle{display:flex;align-items:center;gap:8px;font-size:0.9rem;} +.theme-toggle input{width:18px;height:18px;} + +.card{ + background: var(--card); + padding:20px; + border-radius:var(--radius); + box-shadow:0 6px 18px rgba(23,32,42,0.06); +} + +.input-group{ + display:flex; + flex-direction:column; + margin-bottom:12px; +} + +.input-group label{ + font-size:0.9rem; + margin-bottom:4px; +} + +.input-group input{ + padding:10px; + font-size:1rem; + border-radius:8px; + border:1px solid #e6eef7; +} + +.btn{ + width:100%; + padding:10px; + border:0; + border-radius:8px; + cursor:pointer; + font-weight:600; + margin-top:8px; +} + +.btn.primary{ + background: linear-gradient(90deg, var(--accent), #3aa1ff); + color:white; +} + +.result{ + margin-top:16px; + text-align:center; + font-weight:600; + font-size:1rem; + transition: transform 0.3s, color 0.3s; +} + +.footer{ + text-align:center; + margin-top:12px; + color: var(--muted); + font-size:0.85rem; +} + +/* Dark mode */ +body.dark{ + --bg:#0f1720; + --card:#0b1220; + --text:#e6eef8; + --muted:#a8b3c3; +} + +body.dark .input-group input{ + background:#071427; + color:var(--text); + border:1px solid #0f2436; +}