File: /home/primrwxj/sidegigs.info/css-from-description.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>CSS Tool: Generate + Modify</title>
<style>
:root { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif; }
body { margin: 24px; max-width: 1100px; }
h1 { font-size: 20px; margin: 0 0 10px; }
p { margin: 0 0 14px; color: #444; }
.tabs { display:flex; gap:10px; margin: 12px 0 16px; flex-wrap: wrap; }
.tab {
border: 1px solid #ddd;
background: #fff;
padding: 10px 12px;
border-radius: 999px;
cursor: pointer;
font-weight: 700;
}
.tab[aria-selected="true"] { background: #f6f6f6; }
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
textarea, pre {
width: 100%;
border: 1px solid #ddd;
border-radius: 12px;
padding: 12px;
font-size: 13px;
line-height: 1.45;
box-sizing: border-box;
background: #fff;
white-space: pre;
}
textarea { min-height: 190px; }
pre { min-height: 190px; overflow: auto; background: #fafafa; }
.row { display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-top: 10px; }
button {
border: 1px solid #ddd;
background: #fff;
padding: 10px 12px;
border-radius: 12px;
cursor: pointer;
font-weight: 700;
}
button:hover { background: #f6f6f6; }
.pill { font-size: 12px; background: #f1f1f1; padding: 4px 8px; border-radius: 999px; }
.hint { font-size: 12px; color: #555; margin-top: 10px; }
.fieldset { border: 1px solid #eee; border-radius: 12px; padding: 10px 12px; }
.fieldset legend { font-size: 12px; font-weight: 800; padding: 0 8px; color:#333; }
label { font-size: 13px; }
.muted { color:#555; font-size:12px; }
.hidden { display:none !important; }
</style>
</head>
<body>
<h1>CSS Tool: Generate New CSS or Modify Existing CSS</h1>
<p>
Use <b>Modify</b> to paste an existing stylesheet and transform it (Patch recommended). Use <b>Generate</b> to create CSS from a description.
</p>
<div class="tabs" role="tablist" aria-label="CSS tool tabs">
<button class="tab" id="tabModify" role="tab" aria-selected="true" aria-controls="panelModify">Modify existing CSS</button>
<button class="tab" id="tabGenerate" role="tab" aria-selected="false" aria-controls="panelGenerate">Generate new CSS</button>
</div>
<!-- ============ MODIFY PANEL ============ -->
<section id="panelModify" role="tabpanel" aria-labelledby="tabModify">
<div class="grid">
<div>
<textarea id="existingCss" placeholder="Paste your existing CSS here..."></textarea>
<div class="fieldset" style="margin-top:12px;">
<legend>Modification intent</legend>
<div class="row" style="margin-top:0;">
<label><input type="radio" name="mode" value="patch" checked> Patch override (recommended)</label>
<label><input type="radio" name="mode" value="replace"> Rewrite pasted CSS</label>
</div>
<div class="row" style="margin-top:8px;">
<label><input type="radio" name="theme" value="plainLight" checked> Plain background (light)</label>
<label><input type="radio" name="theme" value="plainDark"> Plain background (dark)</label>
<label><input type="radio" name="theme" value="keepColorsRemoveGlass"> Keep colors, remove glass/transparency</label>
</div>
<div class="muted" style="margin-top:8px;">
Tip: Patch generates safe overrides using <code>!important</code>. Rewrite tries to edit your pasted CSS directly.
</div>
</div>
<div class="row">
<button id="apply">Apply changes</button>
<button id="copyModify">Copy output</button>
<span class="pill" id="statusModify">Ready</span>
</div>
<div class="hint">
Example request you asked for: “Change to something with a plain background.” → choose <b>Plain background (light)</b>.
</div>
</div>
<div>
<pre id="outModify">/* Modified CSS will appear here */</pre>
</div>
</div>
</section>
<!-- ============ GENERATE PANEL (original idea) ============ -->
<section id="panelGenerate" class="hidden" role="tabpanel" aria-labelledby="tabGenerate">
<div class="grid">
<div>
<textarea id="desc" placeholder="Describe your design..."></textarea>
<div class="row">
<button id="gen">Generate CSS</button>
<button id="copyGen">Copy CSS</button>
<span class="pill" id="statusGen">Ready</span>
</div>
<div class="hint">
Try: <code>modern card, rounded corners, soft shadow, centered, max width 460px, blue accent</code><br/>
Or: <code>minimal navbar, sticky top, subtle border, spaced links</code>
</div>
</div>
<div>
<pre id="outGen">/* Your generated CSS will appear here */</pre>
</div>
</div>
</section>
<script>
/* =========================
TAB UI
========================= */
const tabModify = document.getElementById("tabModify");
const tabGenerate = document.getElementById("tabGenerate");
const panelModify = document.getElementById("panelModify");
const panelGenerate = document.getElementById("panelGenerate");
function setTab(which) {
const isModify = which === "modify";
tabModify.setAttribute("aria-selected", String(isModify));
tabGenerate.setAttribute("aria-selected", String(!isModify));
panelModify.classList.toggle("hidden", !isModify);
panelGenerate.classList.toggle("hidden", isModify);
}
tabModify.addEventListener("click", () => setTab("modify"));
tabGenerate.addEventListener("click", () => setTab("generate"));
/* =========================
MODIFY EXISTING CSS
========================= */
// Normalize selector string for matching (simple)
function normalizeSelector(sel) {
return sel.replace(/\s+/g, " ").trim().toLowerCase();
}
// Very small CSS parser (good enough for simple stylesheets like yours)
// Returns array of { selector, body } where body is raw "prop:val; prop:val;"
function parseCssRules(cssText) {
// Remove <style> wrappers if present
let css = cssText
.replace(/<\/?style[^>]*>/gi, "")
.trim();
// Remove comments
css = css.replace(/\/\*[\s\S]*?\*\//g, "");
const rules = [];
// Split by "}" and parse "{"
const chunks = css.split("}");
for (const chunk of chunks) {
const idx = chunk.indexOf("{");
if (idx === -1) continue;
const selector = chunk.slice(0, idx).trim();
const body = chunk.slice(idx + 1).trim();
if (selector && body) rules.push({ selector, body });
}
return rules;
}
// Parse declarations into map
function parseDeclarations(body) {
const decls = {};
const parts = body.split(";");
for (const part of parts) {
const p = part.trim();
if (!p) continue;
const colon = p.indexOf(":");
if (colon === -1) continue;
const prop = p.slice(0, colon).trim().toLowerCase();
const val = p.slice(colon + 1).trim();
decls[prop] = val;
}
return decls;
}
// Build declarations string from map (stable-ish ordering)
function declarationsToString(decls) {
const order = ["margin","padding","max-width","width","font-family","background","color","border","border-radius","box-shadow","line-height"];
const keys = Object.keys(decls);
keys.sort((a,b) => {
const ia = order.indexOf(a), ib = order.indexOf(b);
if (ia !== -1 || ib !== -1) return (ia === -1 ? 999 : ia) - (ib === -1 ? 999 : ib);
return a.localeCompare(b);
});
return keys.map(k => `${k}:${decls[k]};`).join(" ");
}
function findRuleIndex(rules, selectorList) {
// selectorList: array of acceptable selector matches
const normalizedTargets = selectorList.map(normalizeSelector);
return rules.findIndex(r => normalizedTargets.includes(normalizeSelector(r.selector)));
}
function ensureRule(rules, selector) {
const i = findRuleIndex(rules, [selector]);
if (i !== -1) return i;
rules.push({ selector, body: "" });
return rules.length - 1;
}
function applyThemeToRules(rules, theme) {
// Ensure key rules exist
const iBody = ensureRule(rules, "body");
const iCard = ensureRule(rules, ".card");
const iText = ensureRule(rules, "p,li");
const iA = ensureRule(rules, "a");
// Parse decls
const bodyDecl = parseDeclarations(rules[iBody].body);
const cardDecl = parseDeclarations(rules[iCard].body);
const textDecl = parseDeclarations(rules[iText].body);
const aDecl = parseDeclarations(rules[iA].body);
// Common improvements: ensure readable defaults
if (!bodyDecl["font-family"]) bodyDecl["font-family"] = "system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif";
if (!bodyDecl["margin"]) bodyDecl["margin"] = "0";
// Detect current accent (fallback to a decent blue)
const currentLink = aDecl["color"] || "#2563eb";
let accent = currentLink;
// If link is white-ish and we're going light, switch to blue
const looksWhite = /#fff|#ffffff|rgba?\(\s*2?5?5\s*,\s*2?5?5\s*,\s*2?5?5/i.test(String(currentLink));
if (theme === "plainLight" && looksWhite) accent = "#2563eb";
if (theme === "plainLight") {
bodyDecl["background"] = "#ffffff";
bodyDecl["color"] = "#0f172a";
// "Plain" card: white background, subtle border, no glass
cardDecl["background"] = "#ffffff";
cardDecl["border"] = "1px solid rgba(15,23,42,.12)";
cardDecl["box-shadow"] = "none";
textDecl["color"] = "rgba(15,23,42,.82)";
textDecl["line-height"] = textDecl["line-height"] || "1.7";
aDecl["color"] = accent;
}
if (theme === "plainDark") {
bodyDecl["background"] = "#0b1220";
bodyDecl["color"] = "#e5e7eb";
cardDecl["background"] = "#0f172a";
cardDecl["border"] = "1px solid rgba(255,255,255,.10)";
cardDecl["box-shadow"] = "none";
textDecl["color"] = "rgba(229,231,235,.82)";
textDecl["line-height"] = textDecl["line-height"] || "1.7";
// Keep current link if it already works; otherwise make it a soft blue
if (looksWhite) aDecl["color"] = "#93c5fd";
}
if (theme === "keepColorsRemoveGlass") {
// keep body background/color as-is, but remove transparency/glass effects in .card
// If card background is rgba/transparent, make it solid-ish while staying close.
const bg = String(cardDecl["background"] || "");
const isTransparent = /rgba\(|hsla\(|transparent/i.test(bg);
if (isTransparent) {
// pick a sane solid fallback based on body background (best effort)
const bbg = String(bodyDecl["background"] || "").trim();
const darkMode = /#0|#1|#2|#3|rgb\(\s*\d{1,2}\s*,\s*\d{1,2}\s*,\s*\d{1,2}\s*\)/i.test(bbg);
cardDecl["background"] = darkMode ? "#0f172a" : "#ffffff";
}
// border: if very faint, keep; otherwise set a normal one
if (!cardDecl["border"]) {
// infer mode from body color
const bc = String(bodyDecl["color"] || "");
const isLightText = /#e|#f|rgba?\(\s*2[0-5]\d/i.test(bc);
cardDecl["border"] = isLightText ? "1px solid rgba(255,255,255,.12)" : "1px solid rgba(15,23,42,.12)";
}
cardDecl["box-shadow"] = "none";
}
// Write back
rules[iBody].body = declarationsToString(bodyDecl);
rules[iCard].body = declarationsToString(cardDecl);
rules[iText].body = declarationsToString(textDecl);
rules[iA].body = declarationsToString(aDecl);
return rules;
}
function rulesToCss(rules) {
return rules
.map(r => `${r.selector}{${r.body}}`)
.join("\n");
}
function generatePatch(theme) {
// Patch = safe overrides with !important, targeting the most likely selectors
if (theme === "plainLight") {
return `/* === Plain Theme Override (paste AFTER existing CSS) === */
body{
background:#ffffff !important;
color:#0f172a !important;
}
.card{
background:#ffffff !important;
border:1px solid rgba(15,23,42,.12) !important;
box-shadow:none !important;
}
p, li{
color:rgba(15,23,42,.82) !important;
line-height:1.7 !important;
}
a{
color:#2563eb !important;
}`;
}
if (theme === "plainDark") {
return `/* === Plain Dark Theme Override (paste AFTER existing CSS) === */
body{
background:#0b1220 !important;
color:#e5e7eb !important;
}
.card{
background:#0f172a !important;
border:1px solid rgba(255,255,255,.10) !important;
box-shadow:none !important;
}
p, li{
color:rgba(229,231,235,.82) !important;
line-height:1.7 !important;
}
a{
color:#93c5fd !important;
}`;
}
// keep colors remove glass
return `/* === Remove "glass" transparency from cards (paste AFTER existing CSS) === */
.card{
background:#ffffff !important; /* adjust if you want dark */
box-shadow:none !important;
}
`;
}
const existingCss = document.getElementById("existingCss");
const outModify = document.getElementById("outModify");
const statusModify = document.getElementById("statusModify");
document.getElementById("apply").addEventListener("click", () => {
const css = existingCss.value.trim();
if (!css) {
outModify.textContent = "/* Paste your existing CSS first. */";
statusModify.textContent = "Needs CSS";
return;
}
const mode = document.querySelector('input[name="mode"]:checked').value;
const theme = document.querySelector('input[name="theme"]:checked').value;
try {
if (mode === "patch") {
outModify.textContent = `<style>\n${generatePatch(theme)}\n</style>`;
statusModify.textContent = "Patch generated";
return;
}
// replacement
const rules = parseCssRules(css);
const updated = applyThemeToRules(rules, theme);
outModify.textContent = `<style>\n${rulesToCss(updated)}\n</style>`;
statusModify.textContent = "CSS rewritten";
} catch (e) {
outModify.textContent = `/* Error while modifying CSS: ${String(e)} */`;
statusModify.textContent = "Error";
}
});
document.getElementById("copyModify").addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(outModify.textContent);
statusModify.textContent = "Copied";
} catch {
statusModify.textContent = "Copy failed";
}
});
/* =========================
GENERATE NEW CSS (kept from earlier version, light-weight)
========================= */
const KEYWORDS = {
card: ["card", "panel", "surface", "tile"],
button: ["button", "cta", "call to action"],
navbar: ["navbar", "nav", "navigation", "header bar", "top bar"],
form: ["form", "input", "textfield", "text field", "search"],
hero: ["hero", "banner", "header section"],
rounded: ["rounded", "radius", "pill", "curved"],
shadow: ["shadow", "elevation", "depth"],
border: ["border", "outlined", "stroke"],
glass: ["glass", "glassmorphism", "frosted"],
gradient: ["gradient"],
dark: ["dark", "dark mode"],
light: ["light", "bright", "white background"],
center: ["center", "centered", "align center", "middle"],
fullwidth: ["full width", "full-width", "100%", "stretch"],
responsive: ["responsive", "mobile", "fluid"],
};
const NAMED_COLORS = {
blue: "#2563eb", indigo: "#4f46e5", purple: "#7c3aed", pink: "#db2777",
red: "#dc2626", orange: "#ea580c", amber: "#d97706", yellow: "#ca8a04",
green: "#16a34a", teal: "#0f766e", cyan: "#0891b2", slate: "#334155",
gray: "#6b7280", black: "#111827", white: "#ffffff",
};
function hasAny(text, words) {
const t = text.toLowerCase();
return words.some(w => t.includes(w));
}
function pickIntent(text) {
const t = text.toLowerCase();
const intents = [];
for (const [intent, words] of Object.entries(KEYWORDS)) {
if (["card","button","navbar","form","hero"].includes(intent) && hasAny(t, words)) intents.push(intent);
}
return intents.length ? intents : ["card"];
}
function extractHexColor(text) {
const m = text.match(/#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})\b/);
if (!m) return null;
const h = m[0];
if (h.length === 4) return "#" + h[1]+h[1] + h[2]+h[2] + h[3]+h[3];
return h.toLowerCase();
}
function extractNamedColor(text) {
const t = text.toLowerCase();
for (const name of Object.keys(NAMED_COLORS)) {
const re = new RegExp("\\b" + name + "\\b", "i");
if (re.test(t)) return NAMED_COLORS[name];
}
return null;
}
function extractSize(text, label) {
const t = text.toLowerCase();
const patterns = {
maxWidth: [/max[-\s]?width[:\s]+(\d+)(px|rem|em|%)?/i],
padding: [/padding[:\s]+(\d+)(px|rem|em)?/i],
radius: [/border[-\s]?radius[:\s]+(\d+)(px|rem|em)?/i, /radius[:\s]+(\d+)(px|rem|em)?/i],
};
const pats = patterns[label] || [];
for (const pat of pats) {
const m = t.match(pat);
if (m) {
const n = parseInt(m[1], 10);
const unit = m[2] || "px";
if (Number.isFinite(n)) return `${n}${unit}`;
}
}
return null;
}
function tone(text) {
const t = text.toLowerCase();
const isDark = hasAny(t, KEYWORDS.dark);
const isLight = hasAny(t, KEYWORDS.light);
if (isDark && !isLight) return "dark";
return "light";
}
function buildDesignSystem(text) {
const t = text.toLowerCase();
const accent = extractHexColor(text) || extractNamedColor(text) || "#2563eb";
const mode = tone(text);
let bg = mode === "dark" ? "#0b1220" : "#ffffff";
let surface = mode === "dark" ? "rgba(255,255,255,0.06)" : "#ffffff";
let textColor = mode === "dark" ? "#e5e7eb" : "#0f172a";
let muted = mode === "dark" ? "rgba(229,231,235,0.72)" : "#475569";
let border = mode === "dark" ? "rgba(255,255,255,0.10)" : "rgba(15,23,42,0.12)";
const glass = hasAny(t, KEYWORDS.glass);
if (glass) {
surface = mode === "dark" ? "rgba(255,255,255,0.07)" : "rgba(255,255,255,0.65)";
border = mode === "dark" ? "rgba(255,255,255,0.14)" : "rgba(15,23,42,0.10)";
}
const maxW = extractSize(text, "maxWidth") || "520px";
const pad = extractSize(text, "padding") || "16px";
const rad = extractSize(text, "radius") || (hasAny(t, KEYWORDS.rounded) ? "18px" : "12px");
const wantsShadow = hasAny(t, KEYWORDS.shadow);
const shadow = wantsShadow
? (mode === "dark" ? "0 12px 30px rgba(0,0,0,0.45)" : "0 12px 30px rgba(2,6,23,0.12)")
: "none";
return { accent, mode, bg, surface, textColor, muted, border, maxW, pad, rad, shadow, glass };
}
function cssForCard(ds, text) {
const t = text.toLowerCase();
const centered = hasAny(t, KEYWORDS.center);
const wantsBorder = hasAny(t, KEYWORDS.border) || ds.glass;
return `
/* CARD */
.card {
background: ${ds.surface};
color: ${ds.textColor};
border: ${wantsBorder ? `1px solid ${ds.border}` : "none"};
border-radius: ${ds.rad};
padding: ${ds.pad};
box-shadow: ${ds.shadow};
max-width: ${ds.maxW};
${centered ? "margin: 0 auto;" : ""}
${ds.glass ? "backdrop-filter: blur(12px);" : ""}
}
.card__title { font-size: 18px; font-weight: 700; margin: 0 0 8px; }
.card__text { color: ${ds.muted}; margin: 0; line-height: 1.55; }
`.trim();
}
function cssForButton(ds, text) {
const t = text.toLowerCase();
const pill = t.includes("pill") || t.includes("pill-shaped");
const gradient = hasAny(t, KEYWORDS.gradient);
const bg = gradient ? `linear-gradient(135deg, ${ds.accent}, rgba(255,255,255,0))` : ds.accent;
return `
/* BUTTON */
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 10px 14px;
border-radius: ${pill ? "999px" : "14px"};
border: 1px solid rgba(255,255,255,0.0);
background: ${bg};
color: #fff;
font-weight: 700;
text-decoration: none;
cursor: pointer;
transition: transform 120ms ease, filter 120ms ease, box-shadow 120ms ease;
box-shadow: 0 10px 22px rgba(2,6,23,0.18);
}
.btn:hover { transform: translateY(-1px); filter: brightness(1.02); }
.btn:active { transform: translateY(0px); filter: brightness(0.98); }
.btn:focus { outline: 2px solid rgba(37,99,235,0.35); outline-offset: 2px; }
`.trim();
}
function cssForNavbar(ds, text) {
const t = text.toLowerCase();
const sticky = t.includes("sticky");
const wantsBorder = hasAny(t, KEYWORDS.border);
return `
/* NAVBAR */
.navbar {
${sticky ? "position: sticky; top: 0; z-index: 50;" : ""}
background: ${ds.bg};
color: ${ds.textColor};
border-bottom: ${wantsBorder ? `1px solid ${ds.border}` : "none"};
}
.navbar__inner {
max-width: 1100px;
margin: 0 auto;
padding: 12px 16px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
}
.navbar__brand { font-weight: 800; letter-spacing: -0.02em; }
.navbar__links { display: flex; gap: 14px; flex-wrap: wrap; }
.navbar a { color: inherit; text-decoration: none; opacity: 0.9; }
.navbar a:hover { opacity: 1; text-decoration: underline; }
`.trim();
}
function cssForForm(ds, text) {
const t = text.toLowerCase();
const pill = t.includes("pill");
return `
/* FORM / INPUT */
.input {
width: 100%;
padding: 10px 12px;
border-radius: ${pill ? "999px" : "12px"};
border: 1px solid ${ds.border};
background: ${ds.mode === "dark" ? "rgba(255,255,255,0.03)" : "#fff"};
color: ${ds.textColor};
outline: none;
transition: box-shadow 120ms ease, border-color 120ms ease;
}
.input::placeholder { color: ${ds.mode === "dark" ? "rgba(229,231,235,0.55)" : "rgba(71,85,105,0.75)"}; }
.input:focus { border-color: ${ds.accent}; box-shadow: 0 0 0 4px rgba(37,99,235,0.15); }
.label { font-size: 13px; font-weight: 700; margin-bottom: 6px; display: inline-block; }
.formRow { display: grid; gap: 8px; }
`.trim();
}
function cssForHero(ds, text) {
const t = text.toLowerCase();
const gradient = hasAny(t, KEYWORDS.gradient);
const heroBg = gradient
? `linear-gradient(135deg, ${ds.accent}, ${ds.mode === "dark" ? "#0b1220" : "#ffffff"})`
: ds.bg;
return `
/* HERO */
.hero {
padding: 56px 16px;
background: ${heroBg};
color: ${ds.textColor};
}
.hero__inner { max-width: 1100px; margin: 0 auto; display: grid; gap: 14px; }
.hero__title { font-size: clamp(26px, 4vw, 44px); font-weight: 900; margin: 0; letter-spacing: -0.03em; }
.hero__subtitle { margin: 0; color: ${ds.muted}; max-width: 64ch; line-height: 1.55; }
`.trim();
}
function generateCSS(description) {
const ds = buildDesignSystem(description);
const intents = pickIntent(description);
const base = `
/* =========
BASE TOKENS
========= */
:root {
--accent: ${ds.accent};
--bg: ${ds.bg};
--text: ${ds.textColor};
--muted: ${ds.muted};
--border: ${ds.border};
}
/* =========
PAGE BASE
========= */
.page {
background: var(--bg);
color: var(--text);
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
line-height: 1.45;
}
`.trim();
const blocks = [base];
if (intents.includes("card")) blocks.push(cssForCard(ds, description));
if (intents.includes("button")) blocks.push(cssForButton(ds, description));
if (intents.includes("navbar")) blocks.push(cssForNavbar(ds, description));
if (intents.includes("form")) blocks.push(cssForForm(ds, description));
if (intents.includes("hero")) blocks.push(cssForHero(ds, description));
const t = description.toLowerCase();
if (hasAny(t, KEYWORDS.center) || hasAny(t, KEYWORDS.responsive) || hasAny(t, KEYWORDS.fullwidth)) {
blocks.push(`
/* UTILITIES */
.container { max-width: 1100px; margin: 0 auto; padding: 0 16px; }
.stack { display: grid; gap: 12px; }
.center { display: grid; place-items: center; }
`.trim());
}
return blocks.join("\n\n");
}
const desc = document.getElementById("desc");
const outGen = document.getElementById("outGen");
const statusGen = document.getElementById("statusGen");
document.getElementById("gen").addEventListener("click", () => {
const text = desc.value.trim();
if (!text) {
outGen.textContent = "/* Please type a design description first. */";
statusGen.textContent = "Needs description";
return;
}
outGen.textContent = generateCSS(text);
statusGen.textContent = "Generated";
});
document.getElementById("copyGen").addEventListener("click", async () => {
try {
await navigator.clipboard.writeText(outGen.textContent);
statusGen.textContent = "Copied";
} catch {
statusGen.textContent = "Copy failed";
}
});
/* =========================
STARTER CONTENT (your sample)
========================= */
existingCss.value = `<style>
body{margin:0; font-family: system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif; background:#070d16; color:#eaf0ff;}
.wrap{max-width:900px; margin:0 auto; padding:36px 16px;}
.card{border:1px solid rgba(255,255,255,.12); background:rgba(255,255,255,.06); border-radius:16px; padding:18px;}
h1{margin:0 0 10px; font-size:26px}
p,li{color:rgba(234,240,255,.82); line-height:1.7}
a{color:#eaf0ff}
</style>`;
outModify.textContent = `<style>\n${generatePatch("plainLight")}\n</style>`;
desc.value = "Modern card, rounded corners, soft shadow, centered, max width 460px, blue accent. Include a gradient button.";
outGen.textContent = generateCSS(desc.value);
</script>
</body>
</html>