"""Guild-dark theme: dark green + gold, matching the original backstory forge. Exports the CSS string and a head-HTML builder (meta tags + JSON-LD). In Gradio 6, css/head are passed to demo.launch(), not gr.Blocks(). """ import html as _html import json # Palette BG = "#2A4032" # deep green page background PANEL = "#3D5A47" # card/panel green GOLD = "#D4AF37" # headings, accents CREAM = "#F2E6CE" # body text CREAM_DIM = "rgba(242, 230, 206, 0.85)" RED = "#A7343B" # Loreify CTA red (matches loreify.ai accent) RED_DARK = "#7E2429" CSS = """ @import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=Inter:wght@400;500;600;700&display=swap'); :root { --lf-bg: #2A4032; --lf-panel: #3D5A47; --lf-panel-deep: #24382C; --lf-gold: #D4AF37; --lf-cream: #F2E6CE; --lf-cream-dim: rgba(242, 230, 206, 0.85); --lf-red: #A7343B; --lf-red-dark: #7E2429; } body, gradio-app, .gradio-container { background-color: var(--lf-bg) !important; color: var(--lf-cream); font-family: 'Inter', system-ui, sans-serif; } .gradio-container { max-width: 72rem !important; margin: 0 auto !important; } /* ---------- typography ---------- */ /* !important: Gradio's dark-theme prose styles (?__theme=dark on the HF embed) otherwise override heading colors to white. */ .lf-page h1 { font-family: 'Press Start 2P', monospace; color: var(--lf-gold) !important; font-size: 1.35rem; line-height: 1.6; margin: 1.25rem 0 0.75rem 0; -webkit-font-smoothing: none; word-wrap: break-word; } .lf-page h2 { font-family: 'Press Start 2P', monospace; color: var(--lf-gold) !important; font-size: 0.95rem; line-height: 1.6; margin: 2rem 0 0.75rem 0; -webkit-font-smoothing: none; } .lf-page h3 { color: var(--lf-gold) !important; } /* native control accents (radios, checkboxes) — gold, not Gradio orange */ .gradio-container input[type="radio"], .gradio-container input[type="checkbox"] { accent-color: var(--lf-gold); } .gradio-container input[type="radio"]:checked, .gradio-container input[type="checkbox"]:checked { background-color: var(--lf-gold) !important; border-color: var(--lf-gold) !important; } .lf-page h3 { color: var(--lf-gold); font-size: 1.05rem; margin: 1.25rem 0 0.5rem 0; font-weight: 700; } .lf-page p, .lf-page li { color: var(--lf-cream-dim); line-height: 1.7; font-size: 1rem; } .lf-page ul, .lf-page ol { padding-left: 1.25rem; margin: 0.75rem 0; } .lf-page li::marker { color: var(--lf-gold); } .lf-page a { color: var(--lf-gold); text-decoration: underline; } .lf-page strong { color: var(--lf-gold); } .lf-tagline { font-size: 1.1rem !important; color: var(--lf-cream) !important; } /* ---------- panels the tool lives in ---------- */ .lf-panel, .lf-page .block, .gradio-container .form { background-color: var(--lf-panel) !important; border: 1px solid rgba(212, 175, 55, 0.35) !important; border-radius: 8px; } .lf-page label span, .lf-page .label-wrap span { color: var(--lf-cream) !important; } .lf-page input, .lf-page textarea, .lf-page select { background-color: var(--lf-panel-deep) !important; color: var(--lf-cream) !important; border-color: rgba(212, 175, 55, 0.35) !important; } /* primary action buttons — gold everywhere, not Gradio's default orange */ .gradio-container button.primary, .lf-page .lf-generate button { background: var(--lf-gold) !important; color: #21301F !important; border: none !important; font-weight: 700; } .gradio-container button.primary:hover { filter: brightness(1.08); } /* wide content (stat tables, battle boards) scrolls inside its container */ .lf-output { overflow-x: auto; } .lf-output table { min-width: 480px; } /* ---------- Loreify CTA blocks ---------- */ .lf-cta { background: linear-gradient(160deg, rgba(167, 52, 59, 0.16), rgba(167, 52, 59, 0.05)); border: 1px solid rgba(212, 175, 55, 0.45); border-radius: 8px; padding: 1.25rem 1.5rem; margin: 1.5rem 0; text-align: center; } .lf-cta p { color: var(--lf-cream); font-size: 1.05rem; margin: 0 0 0.9rem 0; } .lf-cta .lf-cta-btn { display: inline-block; background: var(--lf-red); color: #FFFBE0 !important; border: 2px solid var(--lf-red-dark); border-radius: 6px; padding: 0.7rem 1.5rem; font-weight: 700; font-size: 1rem; text-decoration: none !important; box-shadow: 1px 2px 4px rgba(0,0,0,0.25); } .lf-cta .lf-cta-btn:hover { background: var(--lf-red-dark); } .lf-cta .lf-cta-sub { font-size: 0.85rem; color: var(--lf-cream-dim); margin-top: 0.6rem; margin-bottom: 0; } /* ---------- output / example cards ---------- */ .lf-output, .lf-example { background: var(--lf-panel); border: 1px solid rgba(212, 175, 55, 0.45); border-radius: 8px; padding: 1.25rem 1.5rem; margin: 0.75rem 0; } .lf-output h3, .lf-example h3 { margin-top: 0.75rem; } /* related tools + footer */ .lf-related { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; margin: 1rem 0; } .lf-related a.lf-related-card { display: block; background: var(--lf-panel); border: 1px solid rgba(212, 175, 55, 0.4); border-radius: 8px; padding: 1rem; text-decoration: none; } .lf-related a.lf-related-card:hover { border-color: var(--lf-gold); } .lf-related .lf-related-title { color: var(--lf-gold); font-weight: 700; margin-bottom: 0.35rem; } .lf-related .lf-related-desc { color: var(--lf-cream-dim); font-size: 0.9rem; } .lf-disclaimer { font-size: 0.82rem; color: rgba(242, 230, 206, 0.6); margin: 2rem 0 1rem 0; line-height: 1.6; } /* FAQ */ .lf-faq details { background: var(--lf-panel); border: 1px solid rgba(212, 175, 55, 0.35); border-radius: 8px; padding: 0.85rem 1.1rem; margin: 0.6rem 0; } .lf-faq summary { color: var(--lf-gold); font-weight: 700; cursor: pointer; font-size: 1rem; } .lf-faq details p { margin: 0.7rem 0 0.2rem 0; } /* mobile */ @media (max-width: 640px) { .lf-page h1 { font-size: 1.05rem; } .lf-page h2 { font-size: 0.85rem; } .lf-cta { padding: 1rem; } } footer { display: none !important; } /* offscreen-but-in-DOM (e.g. clipboard source textarea) */ .lf-offscreen { position: absolute !important; left: -99999px !important; top: 0 !important; height: 1px !important; width: 1px !important; overflow: hidden !important; opacity: 0; pointer-events: none; } """ def build_head(config, jsonld_extra: dict | None = None) -> str: """Meta description + WebApplication JSON-LD for the page head.""" desc = _html.escape(config.tagline, quote=True) data = { "@context": "https://schema.org", "@type": "WebApplication", "name": config.h1, "description": config.tagline, "url": config.space_url, "applicationCategory": "GameApplication", "operatingSystem": "Any", "offers": {"@type": "Offer", "price": "0", "priceCurrency": "USD"}, } if jsonld_extra: data.update(jsonld_extra) return ( f'\n' f'' )