MOON
Server: Apache
System: Linux server1.primemusicproductions.com 4.18.0-477.27.2.el8_8.x86_64 #1 SMP Fri Sep 29 08:21:01 EDT 2023 x86_64
User: primrwxj (1001)
PHP: 8.3.3
Disabled: NONE
Upload Files
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>