/* The Kintsugi Garden — visual identity * * Palette tokens. The kintsugi seam (--kg-gold) is the only accent; * the rest of the surface is warm paper and charcoal-brown ink. */ :root { --kg-gold: #BF953F; --kg-gold-deep: #8C6A1F; --kg-paper: #F4EFE4; --kg-paper-deep: #EAE2D0; --kg-ink: #2B2622; --kg-ink-soft: #6F6558; --kg-crack: #D9C99A; color-scheme: light; } /* Defeat any automatic dark-mode that the user-agent or Gradio's runtime * may try to apply. The kintsugi metaphor — black ink on warm paper — * doesn't translate to dark mode, and the theme tokens we set above * already cover the main surfaces. These rules catch anything that * slips through (form controls, scrollbars, system UI). */ html, body, .dark, body.dark, .gradio-container, .gradio-container.dark { background-color: var(--kg-paper) !important; color: var(--kg-ink) !important; } .dark input, .dark textarea, .dark select, body.dark input, body.dark textarea, body.dark select { background-color: var(--kg-paper-deep) !important; color: var(--kg-ink) !important; border-color: var(--kg-crack) !important; } .dark .block, .dark .form, .dark .panel, .dark .tabitem, .dark .markdown { background-color: var(--kg-paper) !important; color: var(--kg-ink) !important; } /* Page surface — narrower than Gradio's default, generous outer padding. */ .gradio-container { max-width: 1100px !important; padding: 40px 24px 80px !important; } /* Header band: mark on the left, wordmark + subtitle on the right, a single gold seam beneath the whole row. */ #kg-header h1 { font-size: 2.4rem; letter-spacing: -0.01em; margin: 0 0 4px; font-weight: 500; } #kg-header em { color: var(--kg-ink-soft); font-style: italic; } #kg-header { padding-bottom: 24px; border-bottom: 1px solid var(--kg-crack); position: relative; margin-bottom: 8px; } .kg-header-row { display: flex; align-items: center; gap: 20px; } .kg-header-mark { flex: 0 0 76px; width: 76px; height: 76px; line-height: 0; } .kg-header-mark svg { display: block; width: 100%; height: 100%; } .kg-header-text { min-width: 0; } .kg-header-text p { margin: 0; } .kg-header-text .kg-tagline { margin-top: 4px; font-size: 0.86rem; opacity: 0.85; } @media (max-width: 560px) { .kg-header-row { flex-direction: column; align-items: flex-start; gap: 12px; } } #kg-header::after { content: ""; position: absolute; left: 0; bottom: -1px; height: 2px; width: 120px; background: var(--kg-gold); } /* Disclaimer — a quiet framing line, not a slab. Gradio wraps the * Markdown in a .block container that defeats display:inline-block on * the host element, so we treat the disclaimer as a wide-but-light * band: smaller mono type, paper-deep wash, gold left-rule. The bold * "Disclaimer:" label still anchors the eye, but the line recedes * compared to the header above it. */ #kg-disclaimer { font-family: "SF Mono", "JetBrains Mono", ui-monospace, monospace; font-size: 0.74rem; line-height: 1.55; letter-spacing: 0.03em; color: var(--kg-ink-soft); border-left: 2px solid var(--kg-gold); padding: 8px 14px; background: var(--kg-paper-deep); margin: 12px 0 28px; } #kg-disclaimer strong { color: var(--kg-ink); font-weight: 500; } /* Privacy disclosure: quieter sibling to the disclaimer chip above — * same mono family + ink-soft color, but no gold rule, no wash, smaller * + lower opacity so it recedes. Honors the "data stays in your browser" * promise visibly without competing with the main disclaimer. */ #kg-privacy-note { font-family: "SF Mono", "JetBrains Mono", ui-monospace, monospace; font-size: 0.68rem; line-height: 1.5; letter-spacing: 0.03em; color: var(--kg-ink-soft); opacity: 0.75; padding: 0 16px; margin: -20px 0 24px; } /* Tabs: erase the default box; show a single gold underline on the * active tab that animates in like a freshly drawn seam. * * Selector note: Gradio 6.5.1 renders the tab strip as * .tabs > .tab-wrapper > .tab-container[role="tablist"] > button * earlier Gradio versions used .tab-nav. We list both so this CSS * survives a minor-version revert in either direction. The "kg-seam" * animation is load-bearing — it's the visual signature that gives the * page its kintsugi recurrence; without these selectors, Gradio's * theme accent leaks through and the seam never animates. */ .tab-nav, .tabs > .tab-wrapper, .tabs .tab-container[role="tablist"] { border-bottom: 1px solid var(--kg-crack) !important; background: transparent !important; } .tab-nav button, .tabs .tab-container[role="tablist"] > button { background: transparent !important; border: none !important; color: var(--kg-ink-soft) !important; font-size: 0.95rem; padding: 12px 18px !important; font-family: inherit; letter-spacing: 0.01em; } .tab-nav button.selected, .tabs .tab-container[role="tablist"] > button.selected, .tabs .tab-container[role="tablist"] > button[aria-selected="true"] { color: var(--kg-ink) !important; position: relative; } .tab-nav button.selected::after, .tabs .tab-container[role="tablist"] > button.selected::after, .tabs .tab-container[role="tablist"] > button[aria-selected="true"]::after { content: ""; position: absolute; left: 18px; right: 18px; bottom: -1px; height: 2px; background: var(--kg-gold); animation: kg-seam 0.6s ease-out; } @keyframes kg-seam { from { transform: scaleX(0); transform-origin: left; } to { transform: scaleX(1); } } /* Tab overflow indicator — at narrow viewports Gradio 6.5.1 measures * the tab strip and hides tabs that don't fit behind a three-dot * overflow affordance. Untouched it renders in ink-black at low * contrast against paper, easy to miss. We tint it kg-gold so the * "more tabs hide here" signal reads as a kintsugi seam too. */ .tabs .overflow-menu > button { color: var(--kg-gold) !important; padding: 0 8px !important; } .tabs .overflow-menu > button:hover { color: var(--kg-gold-deep) !important; } .tabs .overflow-dropdown { background: var(--kg-paper) !important; border: 1px solid var(--kg-crack) !important; border-top: 2px solid var(--kg-gold) !important; border-radius: 0 !important; } .tabs .overflow-dropdown button { color: var(--kg-ink) !important; font-family: inherit !important; padding: 10px 14px !important; background: transparent !important; } .tabs .overflow-dropdown button:hover { background: var(--kg-paper-deep) !important; } /* Primary button: kintsugi gold, flat, with a subtle deeper-gold drop. */ button.primary, .primary { background: var(--kg-gold) !important; color: var(--kg-paper) !important; padding: 10px 28px !important; font-family: inherit; letter-spacing: 0.02em; box-shadow: 0 1px 0 var(--kg-gold-deep) !important; } button.primary:hover, .primary:hover { background: var(--kg-gold-deep) !important; } /* Entry-type row: bottom-align the dropdown field with the Reflect * button. Without this, the button column stretches to fill the row * height while the dropdown's label sits at the top of its column — * the field and the button end up at different baselines and the * button looks oversized. We anchor everything to the bottom of the * row, constrain the Reflect button to roughly the dropdown field * height, and remove the wrapper column's default top padding so the * baselines line up cleanly. */ #kg-entry-row { align-items: flex-end !important; } #kg-reflect-col { align-self: flex-end !important; padding-top: 0 !important; } #kg-reflect-btn { align-self: flex-end !important; } #kg-reflect-btn button { min-height: 0 !important; height: 48px !important; padding: 0 28px !important; line-height: 48px !important; font-size: 1.05rem; } /* Secondary buttons — transparent with a gold border. */ button.secondary, .secondary { background: transparent !important; border: 1px solid var(--kg-gold) !important; color: var(--kg-ink) !important; } /* Soul Map tables — strip the spreadsheet look; gold underline beneath * headers. The .dataframe selectors used to be enough when Gradio * rendered a pandas-styled table, but Gradio 6.x emits a Svelte * component tree whose classes are hashed (.svelte-XYZ) and the * .dataframe class no longer reaches the visible cells. We anchor on * the elem_id/elem_classes set in app.py and force the palette down * through every nested table-ish element. Heavy use of !important is * deliberate — Gradio's runtime applies inline styles that otherwise * win specificity. * * Selector coverage: real ///
/, ARIA-role * grid/row/cell variants (the editable variant uses divs with roles), * and the .cell-wrap wrapper that Gradio nests value cells inside. */ .kg-soul-table, .kg-soul-table * { font-family: inherit; } .kg-soul-table table, .kg-soul-table [role="grid"], .kg-soul-table [role="table"] { border-collapse: collapse; background-color: var(--kg-paper) !important; } .kg-soul-table thead, .kg-soul-table thead tr, .kg-soul-table thead th, .kg-soul-table [role="rowgroup"]:first-child, .kg-soul-table [role="columnheader"] { background-color: var(--kg-paper-deep) !important; color: var(--kg-ink-soft) !important; font-weight: 500 !important; text-transform: lowercase; letter-spacing: 0.04em; border-bottom: 1px solid var(--kg-gold) !important; } .kg-soul-table tbody, .kg-soul-table tbody tr, .kg-soul-table tbody td, .kg-soul-table [role="rowgroup"]:not(:first-child) [role="row"], .kg-soul-table [role="cell"], .kg-soul-table [role="gridcell"] { background-color: var(--kg-paper) !important; color: var(--kg-ink) !important; border-color: var(--kg-crack) !important; } .kg-soul-table tbody tr:nth-child(even) td, .kg-soul-table tbody tr:nth-child(even) [role="cell"], .kg-soul-table tbody tr:nth-child(even) [role="gridcell"] { background-color: var(--kg-paper-deep) !important; } .kg-soul-table th, .kg-soul-table td { border: none !important; padding: 10px 12px !important; } /* The inner cell-wrap div Gradio uses for value content. */ .kg-soul-table .cell-wrap, .kg-soul-table .table-wrap { background-color: transparent !important; color: var(--kg-ink) !important; } /* Dark-mode runtime override — Gradio sometimes flips internal cell * backgrounds to a CSS variable like --table-row-bg that resolves to * a dark color under .dark. Pin those variables here. */ .dark .kg-soul-table, .kg-soul-table.dark { --table-row-bg: var(--kg-paper); --table-row-bg-odd: var(--kg-paper); --table-row-bg-even: var(--kg-paper-deep); --table-header-bg: var(--kg-paper-deep); --table-header-fg: var(--kg-ink-soft); --table-text-color: var(--kg-ink); --table-border-color: var(--kg-crack); --body-text-color: var(--kg-ink); } /* The Mandala — fixed-aspect square with a hairline gold frame. */ #kg-mandala { aspect-ratio: 1 / 1; border: 1px solid var(--kg-crack); padding: 12px; background: var(--kg-paper); box-shadow: 0 0 0 8px var(--kg-paper), 0 0 0 9px var(--kg-gold); position: relative; } /* Empty-mandala state: before the first Reflect, Gradio's image * component renders a large grey placeholder icon. On a quiet paper * surface that placeholder reads as broken-image clutter, not as * "awaiting input." We use :has() to detect the absence of a populated * and (a) hide the Gradio default chrome inside the frame, and * (b) draw an ink-soft italic line centred in the empty square. Once * a real appears, the rules deactivate and the * mandala renders normally. */ #kg-mandala:not(:has(img[src])) > * { visibility: hidden; } #kg-mandala:not(:has(img[src]))::after { content: "A mandala will appear here."; position: absolute; inset: 12px; display: flex; align-items: center; justify-content: center; text-align: center; font-style: italic; color: var(--kg-ink-soft); font-size: 0.95rem; visibility: visible; padding: 0 16px; } /* Markdown reading prose — serif, generous leading, gold-deep headings. */ .prose, .markdown { font-size: 1.05rem; line-height: 1.75; color: var(--kg-ink); } .prose h2, .markdown h2 { font-size: 1.15rem; font-weight: 500; color: var(--kg-gold-deep); letter-spacing: 0.02em; margin: 28px 0 10px; } /* h3 voice — used by Soul Map's "Symbols" / "Themes" headings. Echoes * the gold-deep h2 voice one notch smaller so the section labels read * as kin to the reading prose above. */ .prose h3, .markdown h3 { font-size: 0.95rem; font-weight: 500; color: var(--kg-gold-deep); letter-spacing: 0.06em; text-transform: lowercase; margin: 24px 0 8px; } /* Footer note — italic serif, centered, ink-soft. The horizontal rule * carries a small gold pinpoint at its centre — a final echo of the * kintsugi seam from the header, closing the page with the same * signature it opened with. */ #kg-footer { text-align: center; color: var(--kg-ink-soft); font-style: italic; margin-top: 40px; } #kg-footer hr { border: none; border-top: 1px solid var(--kg-crack); margin: 32px auto 16px; max-width: 200px; position: relative; } #kg-footer hr::after { content: ""; position: absolute; left: 50%; top: -3px; width: 7px; height: 7px; background: var(--kg-gold); border-radius: 50%; transform: translateX(-50%); } /* Gradio's default page footer ("Use via API · Built with Gradio · * Settings"). On a paper-and-ink surface the row reads as foreign * chrome — we tone it down to small mono in ink-soft so it recedes * beneath the kg-footer prose. Attribution stays visible; volume * drops. */ footer.svelte-zxu34v, .gradio-container > footer, body > footer { font-family: "SF Mono", "JetBrains Mono", ui-monospace, monospace !important; font-size: 0.7rem !important; color: var(--kg-ink-soft) !important; opacity: 0.75; margin-top: 8px !important; padding-top: 12px !important; } footer.svelte-zxu34v button, footer.svelte-zxu34v a, .gradio-container > footer button, .gradio-container > footer a { color: var(--kg-ink-soft) !important; font-family: inherit !important; font-size: inherit !important; } footer.svelte-zxu34v img, .gradio-container > footer img { opacity: 0.55; } /* Mobile adjustments. */ @media (max-width: 640px) { .gradio-container { padding: 24px 14px 48px !important; } #kg-header h1 { font-size: 1.7rem; } #kg-mandala { box-shadow: 0 0 0 4px var(--kg-paper), 0 0 0 5px var(--kg-gold); } }